Merge lp:~thisfred/u1db/check-replica-trans-id into lp:u1db

Proposed by Eric Casteleijn
Status: Merged
Approved by: Eric Casteleijn
Approved revision: 331
Merged at revision: 329
Proposed branch: lp:~thisfred/u1db/check-replica-trans-id
Merge into: lp:u1db
Prerequisite: lp:~thisfred/u1db/validate_transaction_id_of_source
Diff against target: 150 lines (+79/-15)
4 files modified
src/u1db.c (+25/-13)
u1db/backends/__init__.py (+6/-0)
u1db/errors.py (+1/-1)
u1db/tests/test_backends.py (+47/-1)
To merge this branch: bzr merge lp:~thisfred/u1db/check-replica-trans-id
Reviewer Review Type Date Requested Status
Samuele Pedroni Approve
John A Meinel (community) Approve
Review via email: mp+110159@code.launchpad.net

Commit message

Use the validate_source method in _put_doc_if_newer to make sure the other replica isn't deluded.

Description of the change

Use the validate_source method in _put_doc_if_newer to make sure the other replica isn't deluded.

To post a comment you must log in.
Revision history for this message
John A Meinel (jameinel) wrote :

Don't you need to free the stored_vc? Or is that code already in place? Is the value getting parsed 2 times?

Things seem to be ok, with the caveat that I think the signature of validate should change a little.

review: Approve
Revision history for this message
Eric Casteleijn (thisfred) wrote :

stored_vc and new_vc were already freed: That code was moved around rather than added, because we needed the vector clocks at an earlier point.

Revision history for this message
Eric Casteleijn (thisfred) wrote :

merged changes from validate branch

Revision history for this message
Samuele Pedroni (pedronis) :
review: Approve
Revision history for this message
Ubuntu One Auto Pilot (otto-pilot) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/u1db.c'
2--- src/u1db.c 2012-06-14 11:25:22 +0000
3+++ src/u1db.c 2012-06-14 11:25:22 +0000
4@@ -783,6 +783,31 @@
5 status = lookup_doc(db, doc->doc_id, &stored_doc_rev, &stored_content,
6 &stored_content_len, &statement);
7 if (status != SQLITE_OK) { goto finish; }
8+ // TODO: u1db__vectorclock_from_str returns NULL if there is an error
9+ // in the vector clock, or if we run out of memory... Probably
10+ // shouldn't be U1DB_NOMEM
11+ stored_vc = u1db__vectorclock_from_str(stored_doc_rev);
12+ if (stored_vc == NULL) {
13+ status = U1DB_NOMEM;
14+ goto finish;
15+ }
16+ new_vc = u1db__vectorclock_from_str(doc->doc_rev);
17+ if (new_vc == NULL) {
18+ status = U1DB_NOMEM;
19+ goto finish;
20+ }
21+ if (replica_uid != NULL && replica_trans_id != NULL) {
22+ status = u1db__validate_source(
23+ db, replica_uid, replica_gen, replica_trans_id, stored_vc, new_vc,
24+ state);
25+ if (status != U1DB_OK) {
26+ goto finish;
27+ }
28+ if (*state != U1DB_OK) {
29+ status = u1db__get_generation(db, at_gen);
30+ goto finish;
31+ }
32+ }
33 if (stored_doc_rev == NULL) {
34 status = U1DB_OK;
35 *state = U1DB_INSERTED;
36@@ -792,19 +817,6 @@
37 *state = U1DB_CONVERGED;
38 store = 0;
39 } else {
40- // TODO: u1db__vectorclock_from_str returns NULL if there is an error
41- // in the vector clock, or if we run out of memory... Probably
42- // shouldn't be U1DB_NOMEM
43- stored_vc = u1db__vectorclock_from_str(stored_doc_rev);
44- if (stored_vc == NULL) {
45- status = U1DB_NOMEM;
46- goto finish;
47- }
48- new_vc = u1db__vectorclock_from_str(doc->doc_rev);
49- if (new_vc == NULL) {
50- status = U1DB_NOMEM;
51- goto finish;
52- }
53 if (u1db__vectorclock_is_newer(new_vc, stored_vc)) {
54 // Just take the newer version
55 store = 1;
56
57=== modified file 'u1db/backends/__init__.py'
58--- u1db/backends/__init__.py 2012-06-14 11:25:22 +0000
59+++ u1db/backends/__init__.py 2012-06-14 11:25:22 +0000
60@@ -121,6 +121,12 @@
61 cur_vcr = VectorClockRev(None)
62 else:
63 cur_vcr = VectorClockRev(cur_doc.rev)
64+ if replica_uid is not None and replica_gen is not None:
65+ state = self._validate_source(
66+ replica_uid, replica_gen, replica_trans_id, cur_vcr,
67+ doc_vcr)
68+ if state != 'ok':
69+ return state, self._get_generation()
70 if doc_vcr.is_newer(cur_vcr):
71 self._put_and_update_indexes(cur_doc, doc)
72 self._prune_conflicts(doc, doc_vcr)
73
74=== modified file 'u1db/errors.py'
75--- u1db/errors.py 2012-06-14 11:25:22 +0000
76+++ u1db/errors.py 2012-06-14 11:25:22 +0000
77@@ -44,7 +44,7 @@
78
79
80 class InvalidGeneration(U1DBError):
81- """Generation was previously synced."""
82+ """Generation was previously synced with a different transaction id."""
83
84
85 class ConflictedDoc(U1DBError):
86
87=== modified file 'u1db/tests/test_backends.py'
88--- u1db/tests/test_backends.py 2012-06-14 11:25:22 +0000
89+++ u1db/tests/test_backends.py 2012-06-14 11:25:22 +0000
90@@ -392,6 +392,51 @@
91 # The database wasn't altered
92 self.assertGetDoc(self.db, doc1.doc_id, doc1.rev, simple_doc, False)
93
94+ def test_put_doc_if_newer_newer_generation(self):
95+ self.db._set_sync_info('other', 1, 'T-sid')
96+ doc = self.make_document('doc_id', 'other:2', simple_doc)
97+ state, _ = self.db._put_doc_if_newer(
98+ doc, save_conflict=False, replica_uid='other', replica_gen=2,
99+ replica_trans_id='T-irrelevant')
100+ self.assertEqual('inserted', state)
101+
102+ def test_put_doc_if_newer_same_generation_same_txid(self):
103+ self.db._set_sync_info('other', 1, 'T-sid')
104+ doc = self.make_document('doc_id', 'other:2', simple_doc)
105+ state, _ = self.db._put_doc_if_newer(
106+ doc, save_conflict=False, replica_uid='other', replica_gen=1,
107+ replica_trans_id='T-sid')
108+ self.assertEqual('superseded', state)
109+
110+ def test_put_doc_if_newer_wrong_transaction_id(self):
111+ self.db._set_sync_info('other', 1, 'T-sid')
112+ doc = self.make_document('doc_id', 'other:1', simple_doc)
113+ self.assertRaises(
114+ errors.InvalidTransactionId,
115+ self.db._put_doc_if_newer, doc, save_conflict=False,
116+ replica_uid='other', replica_gen=1, replica_trans_id='T-sad')
117+
118+ def test_put_doc_if_newer_old_generation_older_doc(self):
119+ orig_doc = '{"new": "doc"}'
120+ doc = self.db.create_doc(orig_doc)
121+ doc_rev1 = doc.rev
122+ doc.set_json(simple_doc)
123+ self.db.put_doc(doc)
124+ self.db._set_sync_info('other', 5, 'T-sid')
125+ older_doc = self.make_document(doc.doc_id, doc_rev1, simple_doc)
126+ state, _ = self.db._put_doc_if_newer(
127+ older_doc, save_conflict=False, replica_uid='other', replica_gen=3,
128+ replica_trans_id='T-irrelevant')
129+ self.assertEqual('superseded', state)
130+
131+ def test_put_doc_if_newer_old_generation_newer_doc(self):
132+ self.db._set_sync_info('other', 5, 'T-sid')
133+ doc = self.make_document('doc_id', 'other:1', simple_doc)
134+ self.assertRaises(
135+ errors.InvalidGeneration,
136+ self.db._put_doc_if_newer, doc, save_conflict=False,
137+ replica_uid='other', replica_gen=1, replica_trans_id='T-sad')
138+
139 def test_validate_source_gen_and_trans_id_same(self):
140 self.db._set_sync_info('other', 1, 'T-sid')
141 v1 = vectorclock.VectorClockRev('other:1|self:1')
142@@ -678,7 +723,8 @@
143 doc2 = self.make_document(doc1.doc_id, 'alternate:1', nested_doc)
144 self.db._put_doc_if_newer(doc2, save_conflict=True)
145 self.assertTrue(doc2.has_conflicts)
146- self.assertGetDoc(self.db, doc1.doc_id, 'alternate:1', nested_doc, True)
147+ self.assertGetDoc(
148+ self.db, doc1.doc_id, 'alternate:1', nested_doc, True)
149 self.assertGetDocConflicts(self.db, doc1.doc_id,
150 [('alternate:1', nested_doc), (doc1.rev, None)])
151

Subscribers

People subscribed via source and target branches