Status: | Merged |
---|---|
Approved by: | Eric Casteleijn |
Approved revision: | 345 |
Merged at revision: | 346 |
Proposed branch: | lp:~thisfred/u1db/simplify |
Merge into: | lp:u1db |
Diff against target: |
623 lines (+155/-132) 11 files modified
include/u1db/u1db_internal.h (+7/-3) src/u1db.c (+54/-38) src/u1db_sync_target.c (+5/-4) u1db/__init__.py (+1/-1) u1db/backends/__init__.py (+18/-11) u1db/backends/inmemory.py (+8/-8) u1db/backends/sqlite_backend.py (+5/-6) u1db/sync.py (+5/-6) u1db/tests/c_backend_wrapper.pyx (+17/-16) u1db/tests/test_backends.py (+8/-35) u1db/tests/test_sync.py (+27/-4) |
To merge this branch: | bzr merge lp:~thisfred/u1db/simplify |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Samuele Pedroni | Approve | ||
Review via email: mp+113783@code.launchpad.net |
Commit message
Simplified the checking of generations/
Description of the change
Simplified the checking of generations/
To post a comment you must log in.
Revision history for this message
Samuele Pedroni (pedronis) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'include/u1db/u1db_internal.h' |
2 | --- include/u1db/u1db_internal.h 2012-07-03 15:48:59 +0000 |
3 | +++ include/u1db/u1db_internal.h 2012-07-06 17:55:21 +0000 |
4 | @@ -223,9 +223,7 @@ |
5 | * superseded. |
6 | */ |
7 | int u1db__validate_source(u1database *db, const char *replica_uid, |
8 | - int replica_gen, const char *replica_trans_id, |
9 | - u1db_vectorclock *cur_vcr, |
10 | - u1db_vectorclock *other_vcr, int *state); |
11 | + int replica_gen, const char *replica_trans_id); |
12 | |
13 | /** |
14 | * Internal API, Get the global database rev. |
15 | @@ -239,6 +237,12 @@ |
16 | char **trans_id); |
17 | |
18 | /** |
19 | + * Internal API, Get the transaction id for the db generation. |
20 | + */ |
21 | +int u1db__get_trans_id_for_gen(u1database *db, int generation, |
22 | + char **trans_id); |
23 | + |
24 | +/** |
25 | * Internal API, Validate generation and transaction id. |
26 | */ |
27 | int u1db_validate_gen_and_trans_id(u1database *db, int generation, |
28 | |
29 | === modified file 'src/u1db.c' |
30 | --- src/u1db.c 2012-07-03 15:48:59 +0000 |
31 | +++ src/u1db.c 2012-07-06 17:55:21 +0000 |
32 | @@ -42,7 +42,6 @@ |
33 | char **doc_rev); |
34 | static int generate_transaction_id(char buf[35]); |
35 | |
36 | - |
37 | static int |
38 | initialize(u1database *db) |
39 | { |
40 | @@ -756,23 +755,17 @@ |
41 | |
42 | int |
43 | u1db__validate_source(u1database *db, const char *replica_uid, int replica_gen, |
44 | - const char *replica_trans_id, u1db_vectorclock *cur, |
45 | - u1db_vectorclock *other, int *state) |
46 | + const char *replica_trans_id) |
47 | { |
48 | int old_generation; |
49 | char *old_trans_id = NULL; |
50 | int status = U1DB_OK; |
51 | |
52 | - *state = U1DB_OK; |
53 | status = u1db__get_replica_gen_and_trans_id( |
54 | db, replica_uid, &old_generation, &old_trans_id); |
55 | if (status != U1DB_OK) |
56 | goto finish; |
57 | if (replica_gen < old_generation) { |
58 | - if (u1db__vectorclock_is_newer(cur, other)) { |
59 | - *state = U1DB_SUPERSEDED; |
60 | - goto finish; |
61 | - } |
62 | status = U1DB_INVALID_GENERATION; |
63 | goto finish; |
64 | } |
65 | @@ -782,7 +775,6 @@ |
66 | status = U1DB_INVALID_TRANSACTION_ID; |
67 | goto finish; |
68 | } |
69 | - *state = U1DB_SUPERSEDED; |
70 | finish: |
71 | if (old_trans_id != NULL) |
72 | free(old_trans_id); |
73 | @@ -830,15 +822,10 @@ |
74 | } |
75 | if (replica_uid != NULL && replica_trans_id != NULL) { |
76 | status = u1db__validate_source( |
77 | - db, replica_uid, replica_gen, replica_trans_id, stored_vc, new_vc, |
78 | - state); |
79 | + db, replica_uid, replica_gen, replica_trans_id); |
80 | if (status != U1DB_OK) { |
81 | goto finish; |
82 | } |
83 | - if (*state != U1DB_OK) { |
84 | - status = u1db__get_generation(db, at_gen); |
85 | - goto finish; |
86 | - } |
87 | } |
88 | if (stored_doc_rev == NULL) { |
89 | status = U1DB_OK; |
90 | @@ -1469,9 +1456,51 @@ |
91 | *trans_id = strdup(tmp); |
92 | if (*trans_id == NULL) { |
93 | status = U1DB_NOMEM; |
94 | - } |
95 | - } |
96 | - } |
97 | + goto finish; |
98 | + } |
99 | + } |
100 | + status = U1DB_OK; |
101 | + } |
102 | +finish: |
103 | + sqlite3_finalize(statement); |
104 | + return status; |
105 | +} |
106 | + |
107 | +int |
108 | +u1db__get_trans_id_for_gen(u1database *db, int generation, |
109 | + char **trans_id) |
110 | +{ |
111 | + int status = U1DB_OK; |
112 | + sqlite3_stmt *statement; |
113 | + const char *tmp; |
114 | + |
115 | + if (db == NULL) { |
116 | + return U1DB_INVALID_PARAMETER; |
117 | + } |
118 | + status = sqlite3_prepare_v2(db->sql_handle, |
119 | + "SELECT transaction_id FROM transaction_log WHERE generation = ?", -1, |
120 | + &statement, NULL); |
121 | + if (status != SQLITE_OK) { goto finish; } |
122 | + status = sqlite3_bind_int(statement, 1, generation); |
123 | + if (status != SQLITE_OK) { goto finish; } |
124 | + status = sqlite3_step(statement); |
125 | + if (status == SQLITE_DONE) { |
126 | + status = U1DB_INVALID_GENERATION; |
127 | + goto finish; |
128 | + } else if (status == SQLITE_ROW) { |
129 | + tmp = (const char *)sqlite3_column_text(statement, 0); |
130 | + if (tmp == NULL) { |
131 | + *trans_id = NULL; |
132 | + } else { |
133 | + *trans_id = strdup(tmp); |
134 | + if (*trans_id == NULL) { |
135 | + status = U1DB_NOMEM; |
136 | + goto finish; |
137 | + } |
138 | + } |
139 | + status = U1DB_OK; |
140 | + } |
141 | +finish: |
142 | sqlite3_finalize(statement); |
143 | return status; |
144 | } |
145 | @@ -1481,34 +1510,21 @@ |
146 | const char *trans_id) |
147 | { |
148 | int status = U1DB_OK; |
149 | - sqlite3_stmt *statement; |
150 | + char *known_trans_id = NULL; |
151 | |
152 | if (generation == 0) |
153 | return status; |
154 | - if (db == NULL) { |
155 | - return U1DB_INVALID_PARAMETER; |
156 | - } |
157 | - status = sqlite3_prepare_v2(db->sql_handle, |
158 | - "SELECT transaction_id FROM transaction_log WHERE generation = ?", -1, |
159 | - &statement, NULL); |
160 | - if (status != SQLITE_OK) { goto finish; } |
161 | - status = sqlite3_bind_int(statement, 1, generation); |
162 | - if (status != SQLITE_OK) { goto finish; } |
163 | - status = sqlite3_step(statement); |
164 | - if (status == SQLITE_DONE) { |
165 | - status = U1DB_INVALID_GENERATION; |
166 | + status = u1db__get_trans_id_for_gen(db, generation, &known_trans_id); |
167 | + if (status != U1DB_OK) |
168 | goto finish; |
169 | - } else if (status == SQLITE_ROW) { |
170 | - // Note: We may want to handle the column containing NULL |
171 | - if (strcmp(trans_id, |
172 | - (const char *)sqlite3_column_text(statement, 0)) == 0) { |
173 | + if (strcmp(trans_id, known_trans_id) == 0) { |
174 | status = U1DB_OK; |
175 | goto finish; |
176 | } |
177 | - status = U1DB_INVALID_TRANSACTION_ID; |
178 | - } |
179 | + status = U1DB_INVALID_TRANSACTION_ID; |
180 | finish: |
181 | - sqlite3_finalize(statement); |
182 | + if (known_trans_id != NULL) |
183 | + free(known_trans_id); |
184 | return status; |
185 | } |
186 | |
187 | |
188 | === modified file 'src/u1db_sync_target.c' |
189 | --- src/u1db_sync_target.c 2012-07-03 15:48:59 +0000 |
190 | +++ src/u1db_sync_target.c 2012-07-06 17:55:21 +0000 |
191 | @@ -105,8 +105,8 @@ |
192 | |
193 | static int |
194 | st_get_sync_info(u1db_sync_target *st, const char *source_replica_uid, |
195 | - const char **st_replica_uid, int *st_gen, int *source_gen, |
196 | - char **source_trans_id) |
197 | + const char **st_replica_uid, int *st_gen, int *source_gen, |
198 | + char **source_trans_id) |
199 | { |
200 | int status = U1DB_OK; |
201 | u1database *db; |
202 | @@ -614,8 +614,9 @@ |
203 | status = u1db_validate_gen_and_trans_id( |
204 | db, local_gen_known_by_target, local_trans_id_known_by_target); |
205 | if (status != U1DB_OK) { goto finish; } |
206 | - status = u1db__get_replica_gen_and_trans_id(db, target_uid, |
207 | - &target_gen_known_by_local, &target_trans_id_known_by_local); |
208 | + status = u1db__get_replica_gen_and_trans_id( |
209 | + db, target_uid, &target_gen_known_by_local, |
210 | + &target_trans_id_known_by_local); |
211 | if (status != U1DB_OK) { goto finish; } |
212 | local_target_trans_id = target_trans_id_known_by_local; |
213 | local_gen = local_gen_known_by_target; |
214 | |
215 | === modified file 'u1db/__init__.py' |
216 | --- u1db/__init__.py 2012-07-03 15:48:59 +0000 |
217 | +++ u1db/__init__.py 2012-07-06 17:55:21 +0000 |
218 | @@ -290,7 +290,7 @@ |
219 | encountered during synchronization. If we've never synchronized |
220 | with the replica, this is (0, ''). |
221 | """ |
222 | - raise NotImplementedError(self._replica_gen_and_trans_id) |
223 | + raise NotImplementedError(self._get_replica_gen_and_trans_id) |
224 | |
225 | def _set_replica_gen_and_trans_id(self, other_replica_uid, |
226 | other_generation, other_transaction_id): |
227 | |
228 | === modified file 'u1db/backends/__init__.py' |
229 | --- u1db/backends/__init__.py 2012-07-03 13:50:27 +0000 |
230 | +++ u1db/backends/__init__.py 2012-07-06 17:55:21 +0000 |
231 | @@ -102,6 +102,14 @@ |
232 | result.append(doc) |
233 | return result |
234 | |
235 | + def _get_trans_id_for_gen(self, generation): |
236 | + """Get the transaction id corresponding to a particular generation. |
237 | + |
238 | + Raises an InvalidGeneration when the generation does not exist. |
239 | + |
240 | + """ |
241 | + raise NotImplementedError(self._get_trans_id_for_gen) |
242 | + |
243 | def validate_gen_and_trans_id(self, generation, trans_id): |
244 | """Validate the generation and transaction id. |
245 | |
246 | @@ -109,10 +117,14 @@ |
247 | InvalidTransactionId when it does but with a different transaction id. |
248 | |
249 | """ |
250 | - raise NotImplementedError(self.validate_gen_and_trans_id) |
251 | + if generation == 0: |
252 | + return |
253 | + known_trans_id = self._get_trans_id_for_gen(generation) |
254 | + if known_trans_id != trans_id: |
255 | + raise errors.InvalidTransactionId |
256 | |
257 | def _validate_source(self, other_replica_uid, other_generation, |
258 | - other_transaction_id, cur_vcr, other_vcr): |
259 | + other_transaction_id): |
260 | """Validate the new generation and transaction id. |
261 | |
262 | other_generation must be greater than what we have stored for this |
263 | @@ -123,13 +135,11 @@ |
264 | old_transaction_id) = self._get_replica_gen_and_trans_id( |
265 | other_replica_uid) |
266 | if other_generation < old_generation: |
267 | - if cur_vcr.is_newer(other_vcr): |
268 | - return 'superseded' |
269 | raise errors.InvalidGeneration |
270 | if other_generation > old_generation: |
271 | - return 'ok' |
272 | + return |
273 | if other_transaction_id == old_transaction_id: |
274 | - return 'superseded' |
275 | + return |
276 | raise errors.InvalidTransactionId |
277 | |
278 | def _put_doc_if_newer(self, doc, save_conflict, replica_uid=None, |
279 | @@ -141,11 +151,8 @@ |
280 | else: |
281 | cur_vcr = VectorClockRev(cur_doc.rev) |
282 | if replica_uid is not None and replica_gen is not None: |
283 | - state = self._validate_source( |
284 | - replica_uid, replica_gen, replica_trans_id, cur_vcr, |
285 | - doc_vcr) |
286 | - if state != 'ok': |
287 | - return state, self._get_generation() |
288 | + self._validate_source( |
289 | + replica_uid, replica_gen, replica_trans_id) |
290 | if doc_vcr.is_newer(cur_vcr): |
291 | rev = doc.rev |
292 | self._prune_conflicts(doc, doc_vcr) |
293 | |
294 | === modified file 'u1db/backends/inmemory.py' |
295 | --- u1db/backends/inmemory.py 2012-07-03 15:48:59 +0000 |
296 | +++ u1db/backends/inmemory.py 2012-07-06 17:55:21 +0000 |
297 | @@ -85,16 +85,16 @@ |
298 | return len(self._transaction_log) |
299 | |
300 | def _get_generation_info(self): |
301 | + if not self._transaction_log: |
302 | + return 0, '' |
303 | return len(self._transaction_log), self._transaction_log[-1][1] |
304 | |
305 | - def validate_gen_and_trans_id(self, generation, trans_id): |
306 | + def _get_trans_id_for_gen(self, generation): |
307 | if generation == 0: |
308 | - return |
309 | + return '' |
310 | if generation > len(self._transaction_log): |
311 | raise errors.InvalidGeneration |
312 | - if self._transaction_log[generation - 1][1] == trans_id: |
313 | - return |
314 | - raise errors.InvalidTransactionId |
315 | + return self._transaction_log[generation - 1][1] |
316 | |
317 | def put_doc(self, doc): |
318 | if doc.doc_id is None: |
319 | @@ -448,10 +448,10 @@ |
320 | class InMemorySyncTarget(CommonSyncTarget): |
321 | |
322 | def get_sync_info(self, source_replica_uid): |
323 | - source_gen, trans_id = self._db._get_replica_gen_and_trans_id( |
324 | + source_gen, source_trans_id = self._db._get_replica_gen_and_trans_id( |
325 | source_replica_uid) |
326 | - return (self._db._replica_uid, len(self._db._transaction_log), |
327 | - source_gen, trans_id) |
328 | + my_gen = self._db._get_generation() |
329 | + return self._db._replica_uid, my_gen, source_gen, source_trans_id |
330 | |
331 | def record_sync_info(self, source_replica_uid, source_replica_generation, |
332 | source_transaction_id): |
333 | |
334 | === modified file 'u1db/backends/sqlite_backend.py' |
335 | --- u1db/backends/sqlite_backend.py 2012-07-03 13:50:27 +0000 |
336 | +++ u1db/backends/sqlite_backend.py 2012-07-06 17:55:21 +0000 |
337 | @@ -274,9 +274,9 @@ |
338 | return(0, val[1]) |
339 | return val |
340 | |
341 | - def validate_gen_and_trans_id(self, generation, trans_id): |
342 | + def _get_trans_id_for_gen(self, generation): |
343 | if generation == 0: |
344 | - return |
345 | + return '' |
346 | c = self._db_handle.cursor() |
347 | c.execute( |
348 | 'SELECT transaction_id FROM transaction_log WHERE generation = ?', |
349 | @@ -284,8 +284,7 @@ |
350 | val = c.fetchone() |
351 | if val is None: |
352 | raise errors.InvalidGeneration |
353 | - if val[0] != trans_id: |
354 | - raise errors.InvalidTransactionId |
355 | + return val[0] |
356 | |
357 | def _get_transaction_log(self): |
358 | c = self._db_handle.cursor() |
359 | @@ -788,10 +787,10 @@ |
360 | class SQLiteSyncTarget(CommonSyncTarget): |
361 | |
362 | def get_sync_info(self, source_replica_uid): |
363 | - source_gen, trans_id = self._db._get_replica_gen_and_trans_id( |
364 | + source_gen, source_trans_id = self._db._get_replica_gen_and_trans_id( |
365 | source_replica_uid) |
366 | my_gen = self._db._get_generation() |
367 | - return self._db._replica_uid, my_gen, source_gen, trans_id |
368 | + return self._db._replica_uid, my_gen, source_gen, source_trans_id |
369 | |
370 | def record_sync_info(self, source_replica_uid, source_replica_generation, |
371 | source_replica_transaction_id): |
372 | |
373 | === modified file 'u1db/sync.py' |
374 | --- u1db/sync.py 2012-07-03 15:48:59 +0000 |
375 | +++ u1db/sync.py 2012-07-06 17:55:21 +0000 |
376 | @@ -97,18 +97,17 @@ |
377 | (self.target_replica_uid, target_gen, target_my_gen, |
378 | target_my_trans_id) = sync_target.get_sync_info( |
379 | self.source._replica_uid) |
380 | - # validate that the generation and transaction id the target knows |
381 | - # about us are valid. |
382 | + # validate the generation and transaction id the target knows about us |
383 | self.source.validate_gen_and_trans_id( |
384 | target_my_gen, target_my_trans_id) |
385 | # what's changed since that generation and this current gen |
386 | my_gen, _, changes = self.source.whats_changed(target_my_gen) |
387 | |
388 | # this source last-seen database generation for the target |
389 | - (target_last_known_gen, |
390 | - target_trans_id) = self.source._get_replica_gen_and_trans_id( |
391 | - self.target_replica_uid) |
392 | + target_last_known_gen, target_last_known_trans_id = \ |
393 | + self.source._get_replica_gen_and_trans_id(self.target_replica_uid) |
394 | if not changes and target_last_known_gen == target_gen: |
395 | + # TODO: we'll need to check the target's transaction id as well. |
396 | return my_gen |
397 | changed_doc_ids = [doc_id for doc_id, _, _ in changes] |
398 | # prepare to send all the changed docs |
399 | @@ -123,7 +122,7 @@ |
400 | # the target, return target synced-up-to gen |
401 | new_gen, new_trans_id = sync_target.sync_exchange( |
402 | docs_by_generation, self.source._replica_uid, |
403 | - target_last_known_gen, target_trans_id, |
404 | + target_last_known_gen, target_last_known_trans_id, |
405 | self._insert_doc_from_target) |
406 | # record target synced-up-to generation including applying what we sent |
407 | self.source._set_replica_gen_and_trans_id( |
408 | |
409 | === modified file 'u1db/tests/c_backend_wrapper.pyx' |
410 | --- u1db/tests/c_backend_wrapper.pyx 2012-07-03 15:48:59 +0000 |
411 | +++ u1db/tests/c_backend_wrapper.pyx 2012-07-06 17:55:21 +0000 |
412 | @@ -81,9 +81,7 @@ |
413 | void *context, u1db_doc_callback cb) |
414 | int u1db_put_doc(u1database *db, u1db_document *doc) |
415 | int u1db__validate_source(u1database *db, const_char_ptr replica_uid, |
416 | - int replica_gen, const_char_ptr replica_trans_id, |
417 | - u1db_vectorclock *cur_vcr, |
418 | - u1db_vectorclock *other_vcr, int *state) |
419 | + int replica_gen, const_char_ptr replica_trans_id) |
420 | int u1db__put_doc_if_newer(u1database *db, u1db_document *doc, |
421 | int save_conflict, char *replica_uid, |
422 | int replica_gen, char *replica_trans_id, |
423 | @@ -206,6 +204,7 @@ |
424 | |
425 | int u1db__get_generation(u1database *, int *db_rev) |
426 | int u1db__get_generation_info(u1database *, int *db_rev, char **trans_id) |
427 | + int u1db__get_trans_id_for_gen(u1database *, int db_rev, char **trans_id) |
428 | int u1db_validate_gen_and_trans_id(u1database *, int db_rev, |
429 | const_char_ptr trans_id) |
430 | char *u1db__allocate_doc_id(u1database *) |
431 | @@ -941,26 +940,16 @@ |
432 | u1db_put_doc(self._db, doc._doc)) |
433 | return doc.rev |
434 | |
435 | - def _validate_source(self, replica_uid, replica_gen, replica_trans_id, |
436 | - cur_vcr, other_vcr): |
437 | + def _validate_source(self, replica_uid, replica_gen, replica_trans_id): |
438 | cdef const_char_ptr c_uid, c_trans_id |
439 | - cdef int c_gen, state = 0 |
440 | - cdef VectorClockRev cur |
441 | - cdef VectorClockRev other |
442 | + cdef int c_gen = 0 |
443 | |
444 | - cur = VectorClockRev(cur_vcr.as_str()) |
445 | - other = VectorClockRev(other_vcr.as_str()) |
446 | c_uid = replica_uid |
447 | c_trans_id = replica_trans_id |
448 | c_gen = replica_gen |
449 | handle_status( |
450 | "invalid generation or transaction id", |
451 | - u1db__validate_source( |
452 | - self._db, c_uid, c_gen, c_trans_id, cur._clock, other._clock, |
453 | - &state)) |
454 | - if state == U1DB_SUPERSEDED: |
455 | - return 'superseded' |
456 | - return 'ok' |
457 | + u1db__validate_source(self._db, c_uid, c_gen, c_trans_id)) |
458 | |
459 | def _put_doc_if_newer(self, CDocument doc, save_conflict, replica_uid=None, |
460 | replica_gen=None, replica_trans_id=None): |
461 | @@ -1100,6 +1089,18 @@ |
462 | "validate_gen_and_trans_id", |
463 | u1db_validate_gen_and_trans_id(self._db, generation, trans_id)) |
464 | |
465 | + def _get_trans_id_for_gen(self, generation): |
466 | + cdef char *trans_id = NULL |
467 | + |
468 | + handle_status( |
469 | + "_get_trans_id_for_gen", |
470 | + u1db__get_trans_id_for_gen(self._db, generation, &trans_id)) |
471 | + raw_trans_id = None |
472 | + if trans_id != NULL: |
473 | + raw_trans_id = trans_id |
474 | + free(trans_id) |
475 | + return raw_trans_id |
476 | + |
477 | def _get_replica_gen_and_trans_id(self, replica_uid): |
478 | cdef int generation, status |
479 | cdef char *trans_id = NULL |
480 | |
481 | === modified file 'u1db/tests/test_backends.py' |
482 | --- u1db/tests/test_backends.py 2012-07-04 15:43:00 +0000 |
483 | +++ u1db/tests/test_backends.py 2012-07-06 17:55:21 +0000 |
484 | @@ -402,11 +402,12 @@ |
485 | |
486 | def test_put_doc_if_newer_same_generation_same_txid(self): |
487 | self.db._set_replica_gen_and_trans_id('other', 1, 'T-sid') |
488 | - doc = self.make_document('doc_id', 'other:2', simple_doc) |
489 | + doc = self.db.create_doc(simple_doc) |
490 | + doc2 = self.make_document(doc.doc_id, 'other:1', simple_doc) |
491 | state, _ = self.db._put_doc_if_newer( |
492 | doc, save_conflict=False, replica_uid='other', replica_gen=1, |
493 | replica_trans_id='T-sid') |
494 | - self.assertEqual('superseded', state) |
495 | + self.assertEqual('converged', state) |
496 | |
497 | def test_put_doc_if_newer_wrong_transaction_id(self): |
498 | self.db._set_replica_gen_and_trans_id('other', 1, 'T-sid') |
499 | @@ -422,10 +423,10 @@ |
500 | doc_rev1 = doc.rev |
501 | doc.set_json(simple_doc) |
502 | self.db.put_doc(doc) |
503 | - self.db._set_replica_gen_and_trans_id('other', 5, 'T-sid') |
504 | + self.db._set_replica_gen_and_trans_id('other', 3, 'T-sid') |
505 | older_doc = self.make_document(doc.doc_id, doc_rev1, simple_doc) |
506 | state, _ = self.db._put_doc_if_newer( |
507 | - older_doc, save_conflict=False, replica_uid='other', replica_gen=3, |
508 | + older_doc, save_conflict=False, replica_uid='other', replica_gen=8, |
509 | replica_trans_id='T-irrelevant') |
510 | self.assertEqual('superseded', state) |
511 | |
512 | @@ -557,45 +558,17 @@ |
513 | |
514 | def test_validate_source_gen_and_trans_id_same(self): |
515 | self.db._set_replica_gen_and_trans_id('other', 1, 'T-sid') |
516 | - v1 = vectorclock.VectorClockRev('other:1|self:1') |
517 | - v2 = vectorclock.VectorClockRev('other:1|self:1') |
518 | - self.assertEqual( |
519 | - 'superseded', |
520 | - self.db._validate_source('other', 1, 'T-sid', v1, v2)) |
521 | + self.db._validate_source('other', 1, 'T-sid') |
522 | |
523 | def test_validate_source_gen_newer(self): |
524 | self.db._set_replica_gen_and_trans_id('other', 1, 'T-sid') |
525 | - v1 = vectorclock.VectorClockRev('other:1|self:1') |
526 | - v2 = vectorclock.VectorClockRev('other:2|self:2') |
527 | - self.assertEqual( |
528 | - 'ok', |
529 | - self.db._validate_source('other', 2, 'T-whatevs', v1, v2)) |
530 | + self.db._validate_source('other', 2, 'T-whatevs') |
531 | |
532 | def test_validate_source_wrong_txid(self): |
533 | self.db._set_replica_gen_and_trans_id('other', 1, 'T-sid') |
534 | - v1 = vectorclock.VectorClockRev('other:1|self:1') |
535 | - v2 = vectorclock.VectorClockRev('other:2|self:2') |
536 | self.assertRaises( |
537 | errors.InvalidTransactionId, |
538 | - self.db._validate_source, 'other', 1, 'T-sad', v1, v2) |
539 | - |
540 | - def test_validate_source_gen_older_and_vcr_older(self): |
541 | - self.db._set_replica_gen_and_trans_id('other', 1, 'T-sid') |
542 | - self.db._set_replica_gen_and_trans_id('other', 2, 'T-sod') |
543 | - v1 = vectorclock.VectorClockRev('other:1|self:1') |
544 | - v2 = vectorclock.VectorClockRev('other:2|self:2') |
545 | - self.assertEqual( |
546 | - 'superseded', |
547 | - self.db._validate_source('other', 1, 'T-sid', v2, v1)) |
548 | - |
549 | - def test_validate_source_gen_older_vcr_newer(self): |
550 | - self.db._set_replica_gen_and_trans_id('other', 1, 'T-sid') |
551 | - self.db._set_replica_gen_and_trans_id('other', 2, 'T-sod') |
552 | - v1 = vectorclock.VectorClockRev('other:1|self:1') |
553 | - v2 = vectorclock.VectorClockRev('other:2|self:2') |
554 | - self.assertRaises( |
555 | - errors.InvalidGeneration, |
556 | - self.db._validate_source, 'other', 1, 'T-sid', v1, v2) |
557 | + self.db._validate_source, 'other', 1, 'T-sad') |
558 | |
559 | |
560 | class LocalDatabaseWithConflictsTests(tests.DatabaseBaseTests): |
561 | |
562 | === modified file 'u1db/tests/test_sync.py' |
563 | --- u1db/tests/test_sync.py 2012-07-04 16:03:39 +0000 |
564 | +++ u1db/tests/test_sync.py 2012-07-06 17:55:21 +0000 |
565 | @@ -424,7 +424,8 @@ |
566 | return db |
567 | |
568 | |
569 | -def sync_via_synchronizer_and_http(test, db_source, db_target, trace_hook=None): |
570 | +def sync_via_synchronizer_and_http(test, db_source, db_target, |
571 | + trace_hook=None): |
572 | if trace_hook: |
573 | test.skipTest("trace_hook unsupported over http") |
574 | path = test._http_at[db_target] |
575 | @@ -988,6 +989,27 @@ |
576 | self.assertRaises( |
577 | errors.InvalidTransactionId, self.sync, self.db1, db3) |
578 | |
579 | + def test_sync_detects_rollback_and_divergence_in_source(self): |
580 | + self.db1.create_doc(tests.simple_doc, doc_id="divergent") |
581 | + self.sync(self.db1, self.db2) |
582 | + self.db1.create_doc(tests.simple_doc) |
583 | + self.db2._set_replica_gen_and_trans_id( |
584 | + self.db1._replica_uid, 2, 'T-madeup') |
585 | + self.assertRaises( |
586 | + errors.InvalidTransactionId, self.sync, self.db1, self.db2) |
587 | + |
588 | + def test_sync_detects_rollback_and_divergence_in_target(self): |
589 | + # TODO: reenable this once we check the trans_id in Synchronizer.sync |
590 | + self.skip("TODO: check target_trans_id") |
591 | + self.db1.create_doc(tests.simple_doc, doc_id="divergent") |
592 | + self.sync(self.db1, self.db2) |
593 | + self.db2.create_doc(tests.simple_doc) |
594 | + self.db1._set_replica_gen_and_trans_id( |
595 | + self.db2._replica_uid, 2, 'T-madeup') |
596 | + self.sync(self.db1, self.db2) |
597 | + self.assertRaises( |
598 | + errors.InvalidTransactionId, self.sync, self.db1, self.db2) |
599 | + |
600 | |
601 | class TestDbSync(tests.TestCaseWithServer): |
602 | """Test db.sync remote sync shortcut""" |
603 | @@ -1032,7 +1054,8 @@ |
604 | self.assertEqual(2, len(self.db2._get_transaction_log())) |
605 | progress1 = [] |
606 | progress2 = [] |
607 | - _do_set_replica_gen_and_trans_id = self.db1._do_set_replica_gen_and_trans_id |
608 | + _do_set_replica_gen_and_trans_id = \ |
609 | + self.db1._do_set_replica_gen_and_trans_id |
610 | |
611 | def set_sync_generation_witness1(other_uid, other_gen, trans_id): |
612 | progress1.append((other_uid, other_gen, |
613 | @@ -1040,8 +1063,8 @@ |
614 | _do_set_replica_gen_and_trans_id(other_uid, other_gen, trans_id) |
615 | self.patch(self.db1, '_do_set_replica_gen_and_trans_id', |
616 | set_sync_generation_witness1) |
617 | - |
618 | - _do_set_replica_gen_and_trans_id2 = self.db2._do_set_replica_gen_and_trans_id |
619 | + _do_set_replica_gen_and_trans_id2 = \ |
620 | + self.db2._do_set_replica_gen_and_trans_id |
621 | |
622 | def set_sync_generation_witness2(other_uid, other_gen, trans_id): |
623 | progress2.append((other_uid, other_gen, |