Merge lp:~jameinel/u1db/sync_info_999574 into lp:u1db
- sync_info_999574
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 293 |
Proposed branch: | lp:~jameinel/u1db/sync_info_999574 |
Merge into: | lp:u1db |
Diff against target: |
1085 lines (+250/-165) 19 files modified
include/u1db/u1db_internal.h (+13/-6) src/u1db.c (+20/-9) src/u1db_http_sync_target.c (+19/-6) src/u1db_sync_target.c (+24/-12) u1db/__init__.py (+22/-12) u1db/backends/__init__.py (+1/-1) u1db/backends/dbschema.sql (+5/-5) u1db/backends/inmemory.py (+19/-14) u1db/backends/sqlite_backend.py (+19/-12) u1db/remote/http_app.py (+5/-3) u1db/remote/http_target.py (+5/-3) u1db/sync.py (+5/-5) u1db/tests/c_backend_wrapper.pyx (+32/-20) u1db/tests/test_backends.py (+11/-10) u1db/tests/test_c_backend.py (+2/-1) u1db/tests/test_http_app.py (+11/-10) u1db/tests/test_https.py (+2/-2) u1db/tests/test_remote_sync_target.py (+6/-6) u1db/tests/test_sync.py (+29/-28) |
To merge this branch: | bzr merge lp:~jameinel/u1db/sync_info_999574 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Eric Casteleijn (community) | Approve | ||
Review via email: mp+106334@code.launchpad.net |
Commit message
Description of the change
This is a step along the path of getting transaction_ids included in synchronization.
The basic overview is that it gets transaction_ids added to get_sync_info and set_sync_info, which means it also has to be added to the _get_sync_
I'm not very happy with the new names "_get_sync_
Calling it _get_sync_
The next steps are going to be adding the transaction ids to _put_doc_if_newer and whats_changed, which probably also means some sort of insert_from_source, insert_from_target changes.
Preview Diff
1 | === modified file 'include/u1db/u1db_internal.h' |
2 | --- include/u1db/u1db_internal.h 2012-05-17 15:13:42 +0000 |
3 | +++ include/u1db/u1db_internal.h 2012-05-18 08:52:17 +0000 |
4 | @@ -65,10 +65,14 @@ |
5 | * target, matches st_replica_uid |
6 | * @param source_gen (OUT) The last generation of source_replica_uid |
7 | * that st has synchronized with. |
8 | + * @param trans_id (OUT) The transaction id associated with the |
9 | + * source generation, the memory must be freed by |
10 | + * the caller. |
11 | */ |
12 | int (*get_sync_info)(u1db_sync_target *st, |
13 | const char *source_replica_uid, |
14 | - const char **st_replica_uid, int *st_gen, int *source_gen); |
15 | + const char **st_replica_uid, int *st_gen, int *source_gen, |
16 | + char **trans_id); |
17 | /** |
18 | * Set the synchronization information about another replica. |
19 | * |
20 | @@ -78,9 +82,10 @@ |
21 | * want to synchronize from. |
22 | * @param source_gen The last generation of source_replica_uid |
23 | * that st has synchronized with. |
24 | + * @param trans_id The transaction id associated with source_gen |
25 | */ |
26 | int (*record_sync_info)(u1db_sync_target *st, |
27 | - const char *source_replica_uid, int source_gen); |
28 | + const char *source_replica_uid, int source_gen, const char *trans_id); |
29 | |
30 | /** |
31 | * Send documents to the target, and receive the response. |
32 | @@ -249,16 +254,18 @@ |
33 | * @param replica_uid The identifier for the other database |
34 | * @param generation (OUT) The last generation that we know we synchronized |
35 | * with the other database. |
36 | + * @param trans_id (OUT) The transaction id associated with the generation. |
37 | + * Callers must free the data. |
38 | */ |
39 | -int u1db__get_sync_generation(u1database *db, const char *replica_uid, |
40 | - int *generation); |
41 | +int u1db__get_sync_gen_info(u1database *db, const char *replica_uid, |
42 | + int *generation, char **trans_id); |
43 | |
44 | /** |
45 | * Set the known sync generation for another replica. |
46 | * |
47 | */ |
48 | -int u1db__set_sync_generation(u1database *db, const char *replica_uid, |
49 | - int generation); |
50 | +int u1db__set_sync_info(u1database *db, const char *replica_uid, |
51 | + int generation, const char *trans_id); |
52 | |
53 | /** |
54 | * Internal sync api, get the stored information about another machine. |
55 | |
56 | === modified file 'src/u1db.c' |
57 | --- src/u1db.c 2012-05-17 15:26:01 +0000 |
58 | +++ src/u1db.c 2012-05-18 08:52:17 +0000 |
59 | @@ -810,7 +810,7 @@ |
60 | (stored_doc_rev != NULL)); |
61 | } |
62 | if (status == U1DB_OK && replica_uid != NULL) { |
63 | - status = u1db__set_sync_generation(db, replica_uid, replica_gen); |
64 | + status = u1db__set_sync_info(db, replica_uid, replica_gen, "T-sid"); |
65 | } |
66 | if (status == U1DB_OK && at_gen != NULL) { |
67 | status = u1db__get_generation(db, at_gen); |
68 | @@ -1315,18 +1315,22 @@ |
69 | |
70 | |
71 | int |
72 | -u1db__get_sync_generation(u1database *db, const char *replica_uid, |
73 | - int *generation) |
74 | +u1db__get_sync_gen_info(u1database *db, const char *replica_uid, |
75 | + int *generation, char **trans_id) |
76 | { |
77 | int status; |
78 | sqlite3_stmt *statement; |
79 | + const char *tmp; |
80 | |
81 | - if (db == NULL || replica_uid == NULL || generation == NULL) { |
82 | + if (db == NULL || replica_uid == NULL || generation == NULL |
83 | + || trans_id == NULL) |
84 | + { |
85 | return U1DB_INVALID_PARAMETER; |
86 | } |
87 | status = sqlite3_prepare_v2(db->sql_handle, |
88 | - "SELECT known_generation FROM sync_log WHERE replica_uid = ?", -1, |
89 | - &statement, NULL); |
90 | + "SELECT known_generation, known_transaction_id" |
91 | + " FROM sync_log WHERE replica_uid = ?", |
92 | + -1, &statement, NULL); |
93 | if (status != SQLITE_OK) { goto finish; } |
94 | status = sqlite3_bind_text(statement, 1, replica_uid, -1, SQLITE_TRANSIENT); |
95 | if (status != SQLITE_OK) { goto finish; } |
96 | @@ -1334,10 +1338,17 @@ |
97 | if (status == SQLITE_DONE) { |
98 | status = SQLITE_OK; |
99 | *generation = 0; |
100 | + *trans_id = strdup(""); |
101 | } else if (status == SQLITE_ROW) { |
102 | *generation = sqlite3_column_int(statement, 0); |
103 | + // Note: We may want to handle the column containing NULL |
104 | + tmp = (const char *)sqlite3_column_text(statement, 1); |
105 | + *trans_id = strdup(tmp); |
106 | status = SQLITE_OK; |
107 | } |
108 | + if (*trans_id == NULL) { |
109 | + status = U1DB_NOMEM; |
110 | + } |
111 | finish: |
112 | sqlite3_finalize(statement); |
113 | return status; |
114 | @@ -1345,8 +1356,8 @@ |
115 | |
116 | |
117 | int |
118 | -u1db__set_sync_generation(u1database *db, const char *replica_uid, |
119 | - int generation) |
120 | +u1db__set_sync_info(u1database *db, const char *replica_uid, |
121 | + int generation, const char *trans_id) |
122 | { |
123 | int status; |
124 | sqlite3_stmt *statement; |
125 | @@ -1364,7 +1375,7 @@ |
126 | if (status != SQLITE_OK) { goto finish; } |
127 | status = sqlite3_bind_int(statement, 2, generation); |
128 | if (status != SQLITE_OK) { goto finish; } |
129 | - status = sqlite3_bind_text(statement, 3, "", -1, SQLITE_TRANSIENT); |
130 | + status = sqlite3_bind_text(statement, 3, trans_id, -1, SQLITE_TRANSIENT); |
131 | if (status != SQLITE_OK) { goto finish; } |
132 | status = sqlite3_step(statement); |
133 | if (status == SQLITE_DONE) { |
134 | |
135 | === modified file 'src/u1db_http_sync_target.c' |
136 | --- src/u1db_http_sync_target.c 2012-05-09 16:09:04 +0000 |
137 | +++ src/u1db_http_sync_target.c 2012-05-18 08:52:17 +0000 |
138 | @@ -34,17 +34,18 @@ |
139 | |
140 | static int st_http_get_sync_info(u1db_sync_target *st, |
141 | const char *source_replica_uid, |
142 | - const char **st_replica_uid, int *st_gen, int *source_gen); |
143 | + const char **st_replica_uid, int *st_gen, int *source_gen, |
144 | + char **trans_id); |
145 | |
146 | static int st_http_record_sync_info(u1db_sync_target *st, |
147 | - const char *source_replica_uid, int source_gen); |
148 | + const char *source_replica_uid, int source_gen, const char *trans_id); |
149 | |
150 | static int st_http_get_sync_exchange(u1db_sync_target *st, |
151 | const char *source_replica_uid, |
152 | int source_gen, |
153 | u1db_sync_exchange **exchange); |
154 | static int st_http_sync_exchange(u1db_sync_target *st, |
155 | - const char *source_replica_uid, |
156 | + const char *source_replica_uid, |
157 | int n_docs, u1db_document **docs, |
158 | int *generations, int *target_gen, void *context, |
159 | u1db_doc_gen_callback cb); |
160 | @@ -355,7 +356,8 @@ |
161 | static int |
162 | st_http_get_sync_info(u1db_sync_target *st, |
163 | const char *source_replica_uid, |
164 | - const char **st_replica_uid, int *st_gen, int *source_gen) |
165 | + const char **st_replica_uid, int *st_gen, int *source_gen, |
166 | + char **trans_id) |
167 | { |
168 | struct _http_state *state; |
169 | struct _http_request req = {0}; |
170 | @@ -451,6 +453,15 @@ |
171 | goto finish; |
172 | } |
173 | *source_gen = json_object_get_int(obj); |
174 | + obj = json_object_object_get(json, "source_transaction_id"); |
175 | + if (obj == NULL) { |
176 | + status = U1DB_INVALID_HTTP_RESPONSE; |
177 | + goto finish; |
178 | + } |
179 | + *trans_id = strdup(json_object_get_string(obj)); |
180 | + if (*trans_id == NULL) { |
181 | + status = U1DB_NOMEM; |
182 | + } |
183 | finish: |
184 | if (req.header_buffer != NULL) { |
185 | free(req.header_buffer); |
186 | @@ -508,7 +519,7 @@ |
187 | |
188 | static int |
189 | st_http_record_sync_info(u1db_sync_target *st, |
190 | - const char *source_replica_uid, int source_gen) |
191 | + const char *source_replica_uid, int source_gen, const char *trans_id) |
192 | { |
193 | struct _http_state *state; |
194 | struct _http_request req = {0}; |
195 | @@ -537,6 +548,8 @@ |
196 | goto finish; |
197 | } |
198 | json_object_object_add(json, "generation", json_object_new_int(source_gen)); |
199 | + json_object_object_add(json, "transaction_id", |
200 | + json_object_new_string(trans_id)); |
201 | raw_body = json_object_to_json_string(json); |
202 | raw_len = strlen(raw_body); |
203 | req.state = state; |
204 | @@ -561,7 +574,7 @@ |
205 | status = curl_easy_setopt(state->curl, CURLOPT_INFILESIZE_LARGE, |
206 | (curl_off_t)req.num_put_bytes); |
207 | if (status != CURLE_OK) { goto finish; } |
208 | - status = maybe_sign_url(st, "PUT", url, &headers); |
209 | + status = maybe_sign_url(st, "PUT", url, &headers); |
210 | if (status != U1DB_OK) { goto finish; } |
211 | |
212 | // Now actually send the data |
213 | |
214 | === modified file 'src/u1db_sync_target.c' |
215 | --- src/u1db_sync_target.c 2012-05-17 13:25:42 +0000 |
216 | +++ src/u1db_sync_target.c 2012-05-18 08:52:17 +0000 |
217 | @@ -23,10 +23,11 @@ |
218 | |
219 | static int st_get_sync_info(u1db_sync_target *st, |
220 | const char *source_replica_uid, |
221 | - const char **st_replica_uid, int *st_gen, int *source_gen); |
222 | + const char **st_replica_uid, int *st_gen, int *source_gen, |
223 | + char **trans_id); |
224 | |
225 | static int st_record_sync_info(u1db_sync_target *st, |
226 | - const char *source_replica_uid, int source_gen); |
227 | + const char *source_replica_uid, int source_gen, const char *trans_id); |
228 | |
229 | static int st_sync_exchange(u1db_sync_target *st, |
230 | const char *source_replica_uid, int n_docs, |
231 | @@ -100,7 +101,8 @@ |
232 | |
233 | static int |
234 | st_get_sync_info(u1db_sync_target *st, const char *source_replica_uid, |
235 | - const char **st_replica_uid, int *st_gen, int *source_gen) |
236 | + const char **st_replica_uid, int *st_gen, int *source_gen, |
237 | + char **trans_id) |
238 | { |
239 | int status = U1DB_OK; |
240 | u1database *db; |
241 | @@ -119,7 +121,8 @@ |
242 | db = (u1database *)st->implementation; |
243 | status = u1db_get_replica_uid(db, st_replica_uid); |
244 | if (status != U1DB_OK) { goto finish; } |
245 | - status = u1db__get_sync_generation(db, source_replica_uid, source_gen); |
246 | + status = u1db__get_sync_gen_info(db, source_replica_uid, source_gen, |
247 | + trans_id); |
248 | if (status != U1DB_OK) { goto finish; } |
249 | status = u1db__get_generation(db, st_gen); |
250 | finish: |
251 | @@ -129,7 +132,7 @@ |
252 | |
253 | static int |
254 | st_record_sync_info(u1db_sync_target *st, const char *source_replica_uid, |
255 | - int source_gen) |
256 | + int source_gen, const char *trans_id) |
257 | { |
258 | int status; |
259 | u1database *db; |
260 | @@ -141,7 +144,7 @@ |
261 | if (status != U1DB_OK) { goto finish; } |
262 | } |
263 | db = (u1database *)st->implementation; |
264 | - status = u1db__set_sync_generation(db, source_replica_uid, source_gen); |
265 | + status = u1db__set_sync_info(db, source_replica_uid, source_gen, trans_id); |
266 | finish: |
267 | return status; |
268 | } |
269 | @@ -543,6 +546,8 @@ |
270 | struct _whats_changed_doc_ids_state to_send_state = {0}; |
271 | struct _return_doc_state return_doc_state = {0}; |
272 | const char *target_uid, *local_uid; |
273 | + char *target_trans_id_known_by_local = NULL; |
274 | + char *local_trans_id_known_by_target = NULL; |
275 | int target_gen, local_gen; |
276 | int local_gen_known_by_target, target_gen_known_by_local; |
277 | |
278 | @@ -556,10 +561,10 @@ |
279 | if (status != U1DB_OK) { goto finish; } |
280 | // fprintf(stderr, "Local uid: %s\n", local_uid); |
281 | status = target->get_sync_info(target, local_uid, &target_uid, &target_gen, |
282 | - &local_gen_known_by_target); |
283 | + &local_gen_known_by_target, &local_trans_id_known_by_target); |
284 | if (status != U1DB_OK) { goto finish; } |
285 | - status = u1db__get_sync_generation(db, target_uid, |
286 | - &target_gen_known_by_local); |
287 | + status = u1db__get_sync_gen_info(db, target_uid, |
288 | + &target_gen_known_by_local, &target_trans_id_known_by_local); |
289 | if (status != U1DB_OK) { goto finish; } |
290 | local_gen = local_gen_known_by_target; |
291 | |
292 | @@ -589,17 +594,24 @@ |
293 | if (status != U1DB_OK) { goto finish; } |
294 | // Now we successfully sent and received docs, make sure we record the |
295 | // current remote generation |
296 | - status = u1db__set_sync_generation(db, target_uid, |
297 | - target_gen_known_by_local); |
298 | + status = u1db__set_sync_info(db, target_uid, target_gen_known_by_local, |
299 | + "T-sid"); |
300 | if (status != U1DB_OK) { goto finish; } |
301 | if (return_doc_state.num_inserted > 0 && |
302 | ((*local_gen_before_sync + return_doc_state.num_inserted) |
303 | == local_gen)) |
304 | { |
305 | - status = target->record_sync_info(target, local_uid, local_gen); |
306 | + status = target->record_sync_info(target, local_uid, local_gen, |
307 | + "T-sid"); |
308 | if (status != U1DB_OK) { goto finish; } |
309 | } |
310 | finish: |
311 | + if (local_trans_id_known_by_target != NULL) { |
312 | + free(local_trans_id_known_by_target); |
313 | + } |
314 | + if (target_trans_id_known_by_local != NULL) { |
315 | + free(target_trans_id_known_by_local); |
316 | + } |
317 | if (to_send_state.doc_ids_to_return != NULL) { |
318 | int i; |
319 | |
320 | |
321 | === modified file 'u1db/__init__.py' |
322 | --- u1db/__init__.py 2012-05-17 13:22:20 +0000 |
323 | +++ u1db/__init__.py 2012-05-18 08:52:17 +0000 |
324 | @@ -216,29 +216,35 @@ |
325 | from u1db.remote.http_target import HTTPSyncTarget |
326 | return Synchronizer(self, HTTPSyncTarget(url)).sync() |
327 | |
328 | - def _get_sync_generation(self, other_replica_uid): |
329 | - """Return the last known database generation of the other db replica. |
330 | + def _get_sync_gen_info(self, other_replica_uid): |
331 | + """Return the last known information about the other db replica. |
332 | |
333 | When you do a synchronization with another replica, the Database keeps |
334 | - track of what generation the other database replica was at. |
335 | - This way we only have to request data that is newer. |
336 | + track of what generation the other database replica was at, and what |
337 | + the associated transaction id was. This is used to determine what data |
338 | + needs to be sent, and if two databases are claiming to be the same |
339 | + replica. |
340 | |
341 | :param other_replica_uid: The identifier for the other replica. |
342 | - :return: The generation we encountered during synchronization. If we've |
343 | - never synchronized with the replica, this is 0. |
344 | + :return: (gen, trans_id) The generation and transaction id we |
345 | + encountered during synchronization. If we've never synchronized |
346 | + with the replica, this is (0, ''). |
347 | """ |
348 | - raise NotImplementedError(self._get_sync_generation) |
349 | + raise NotImplementedError(self._get_sync_gen_info) |
350 | |
351 | - def _set_sync_generation(self, other_replica_uid, other_generation): |
352 | + def _set_sync_info(self, other_replica_uid, other_generation, |
353 | + other_transaction_id): |
354 | """Set the last-known generation for the other database replica. |
355 | |
356 | We have just performed some synchronization, and we want to track what |
357 | - generation the other replica was at. See also get_sync_generation. |
358 | + generation the other replica was at. See also _get_sync_gen_info. |
359 | :param other_replica_uid: The U1DB identifier for the other replica. |
360 | :param other_generation: The generation number for the other replica. |
361 | + :param other_transaction_id: The transaction id associated with the |
362 | + generation. |
363 | :return: None |
364 | """ |
365 | - raise NotImplementedError(self._set_sync_generation) |
366 | + raise NotImplementedError(self._set_sync_info) |
367 | |
368 | def _put_doc_if_newer(self, doc, save_conflict, replica_uid=None, |
369 | replica_gen=None): |
370 | @@ -338,11 +344,13 @@ |
371 | :param source_replica_uid: Another replica which we might have |
372 | synchronized with in the past. |
373 | :return: (target_replica_uid, target_replica_generation, |
374 | - source_replica_last_known_generation) |
375 | + source_replica_last_known_generation, |
376 | + source_replica_last_known_transaction_id) |
377 | """ |
378 | raise NotImplementedError(self.get_sync_info) |
379 | |
380 | - def record_sync_info(self, source_replica_uid, source_replica_generation): |
381 | + def record_sync_info(self, source_replica_uid, source_replica_generation, |
382 | + source_replica_transaction_id): |
383 | """Record tip information for another replica. |
384 | |
385 | After sync_exchange has been processed, the caller will have |
386 | @@ -358,6 +366,8 @@ |
387 | :param source_replica_uid: The identifier for the source replica. |
388 | :param source_replica_generation: |
389 | The database generation for the source replica. |
390 | + :param source_replica_transaction_id: The transaction id associated |
391 | + with the source replica generation. |
392 | :return: None |
393 | """ |
394 | raise NotImplementedError(self.record_sync_info) |
395 | |
396 | === modified file 'u1db/backends/__init__.py' |
397 | --- u1db/backends/__init__.py 2012-05-17 14:44:25 +0000 |
398 | +++ u1db/backends/__init__.py 2012-05-18 08:52:17 +0000 |
399 | @@ -115,7 +115,7 @@ |
400 | if save_conflict: |
401 | self._force_doc_sync_conflict(doc) |
402 | if replica_uid is not None and replica_gen is not None: |
403 | - self._do_set_sync_generation(replica_uid, replica_gen) |
404 | + self._do_set_sync_info(replica_uid, replica_gen, 'T-sid') |
405 | return state, self._get_generation() |
406 | |
407 | def _ensure_maximal_rev(self, cur_rev, extra_revs): |
408 | |
409 | === modified file 'u1db/backends/dbschema.sql' |
410 | --- u1db/backends/dbschema.sql 2012-05-17 13:59:05 +0000 |
411 | +++ u1db/backends/dbschema.sql 2012-05-18 08:52:17 +0000 |
412 | @@ -1,17 +1,17 @@ |
413 | -- Database schema |
414 | CREATE TABLE transaction_log ( |
415 | generation INTEGER PRIMARY KEY AUTOINCREMENT, |
416 | - doc_id TEXT, |
417 | - transaction_id TEXT |
418 | + doc_id TEXT NOT NULL, |
419 | + transaction_id TEXT NOT NULL |
420 | ); |
421 | CREATE TABLE document ( |
422 | doc_id TEXT PRIMARY KEY, |
423 | - doc_rev TEXT, |
424 | + doc_rev TEXT NOT NULL, |
425 | content TEXT |
426 | ); |
427 | CREATE TABLE document_fields ( |
428 | - doc_id TEXT, |
429 | - field_name TEXT, |
430 | + doc_id TEXT NOT NULL, |
431 | + field_name TEXT NOT NULL, |
432 | value TEXT |
433 | ); |
434 | CREATE INDEX document_fields_field_value_doc_idx |
435 | |
436 | === modified file 'u1db/backends/inmemory.py' |
437 | --- u1db/backends/inmemory.py 2012-05-17 14:44:25 +0000 |
438 | +++ u1db/backends/inmemory.py 2012-05-18 08:52:17 +0000 |
439 | @@ -45,16 +45,20 @@ |
440 | # may be closing it, while another wants to inspect the results. |
441 | pass |
442 | |
443 | - def _get_sync_generation(self, other_replica_uid): |
444 | - return self._other_generations.get(other_replica_uid, 0) |
445 | - |
446 | - def _set_sync_generation(self, other_replica_uid, other_generation): |
447 | - self._do_set_sync_generation(other_replica_uid, other_generation) |
448 | - |
449 | - def _do_set_sync_generation(self, other_replica_uid, other_generation): |
450 | + def _get_sync_gen_info(self, other_replica_uid): |
451 | + return self._other_generations.get(other_replica_uid, (0, '')) |
452 | + |
453 | + def _set_sync_info(self, other_replica_uid, other_generation, |
454 | + other_transaction_id): |
455 | + self._do_set_sync_info(other_replica_uid, other_generation, |
456 | + other_transaction_id) |
457 | + |
458 | + def _do_set_sync_info(self, other_replica_uid, other_generation, |
459 | + other_transaction_id): |
460 | # TODO: to handle race conditions, we may want to check if the current |
461 | # value is greater than this new value. |
462 | - self._other_generations[other_replica_uid] = other_generation |
463 | + self._other_generations[other_replica_uid] = (other_generation, |
464 | + other_transaction_id) |
465 | |
466 | def get_sync_target(self): |
467 | return InMemorySyncTarget(self) |
468 | @@ -334,12 +338,13 @@ |
469 | class InMemorySyncTarget(CommonSyncTarget): |
470 | |
471 | def get_sync_info(self, source_replica_uid): |
472 | - source_gen = self._db._get_sync_generation(source_replica_uid) |
473 | - return ( |
474 | - self._db._replica_uid, len(self._db._transaction_log), source_gen) |
475 | + source_gen, trans_id = self._db._get_sync_gen_info(source_replica_uid) |
476 | + return (self._db._replica_uid, len(self._db._transaction_log), |
477 | + source_gen, trans_id) |
478 | |
479 | - def record_sync_info(self, source_replica_uid, source_replica_generation): |
480 | + def record_sync_info(self, source_replica_uid, source_replica_generation, |
481 | + source_transaction_id): |
482 | if self._trace_hook: |
483 | self._trace_hook('record_sync_info') |
484 | - self._db._set_sync_generation(source_replica_uid, |
485 | - source_replica_generation) |
486 | + self._db._set_sync_info(source_replica_uid, source_replica_generation, |
487 | + source_transaction_id) |
488 | |
489 | === modified file 'u1db/backends/sqlite_backend.py' |
490 | --- u1db/backends/sqlite_backend.py 2012-05-17 15:13:42 +0000 |
491 | +++ u1db/backends/sqlite_backend.py 2012-05-18 08:52:17 +0000 |
492 | @@ -409,26 +409,32 @@ |
493 | this_doc.has_conflicts = True |
494 | return [this_doc] + conflict_docs |
495 | |
496 | - def _get_sync_generation(self, other_replica_uid): |
497 | + def _get_sync_gen_info(self, other_replica_uid): |
498 | c = self._db_handle.cursor() |
499 | - c.execute("SELECT known_generation FROM sync_log" |
500 | + c.execute("SELECT known_generation, known_transaction_id FROM sync_log" |
501 | " WHERE replica_uid = ?", |
502 | (other_replica_uid,)) |
503 | val = c.fetchone() |
504 | if val is None: |
505 | other_gen = 0 |
506 | + trans_id = '' |
507 | else: |
508 | other_gen = val[0] |
509 | - return other_gen |
510 | + trans_id = val[1] |
511 | + return other_gen, trans_id |
512 | |
513 | - def _set_sync_generation(self, other_replica_uid, other_generation): |
514 | + def _set_sync_info(self, other_replica_uid, other_generation, |
515 | + other_transaction_id): |
516 | with self._db_handle: |
517 | - self._do_set_sync_generation(other_replica_uid, other_generation) |
518 | + self._do_set_sync_info(other_replica_uid, other_generation, |
519 | + other_transaction_id) |
520 | |
521 | - def _do_set_sync_generation(self, other_replica_uid, other_generation): |
522 | + def _do_set_sync_info(self, other_replica_uid, other_generation, |
523 | + other_transaction_id): |
524 | c = self._db_handle.cursor() |
525 | c.execute("INSERT OR REPLACE INTO sync_log VALUES (?, ?, ?)", |
526 | - (other_replica_uid, other_generation, '')) |
527 | + (other_replica_uid, other_generation, |
528 | + other_transaction_id)) |
529 | |
530 | def _put_doc_if_newer(self, doc, save_conflict, replica_uid=None, |
531 | replica_gen=None): |
532 | @@ -608,15 +614,16 @@ |
533 | class SQLiteSyncTarget(CommonSyncTarget): |
534 | |
535 | def get_sync_info(self, source_replica_uid): |
536 | - source_gen = self._db._get_sync_generation(source_replica_uid) |
537 | + source_gen, trans_id = self._db._get_sync_gen_info(source_replica_uid) |
538 | my_gen = self._db._get_generation() |
539 | - return self._db._replica_uid, my_gen, source_gen |
540 | + return self._db._replica_uid, my_gen, source_gen, trans_id |
541 | |
542 | - def record_sync_info(self, source_replica_uid, source_replica_generation): |
543 | + def record_sync_info(self, source_replica_uid, source_replica_generation, |
544 | + source_replica_transaction_id): |
545 | if self._trace_hook: |
546 | self._trace_hook('record_sync_info') |
547 | - self._db._set_sync_generation(source_replica_uid, |
548 | - source_replica_generation) |
549 | + self._db._set_sync_info(source_replica_uid, source_replica_generation, |
550 | + source_replica_transaction_id) |
551 | |
552 | |
553 | class SQLitePartialExpandDatabase(SQLiteDatabase): |
554 | |
555 | === modified file 'u1db/remote/http_app.py' |
556 | --- u1db/remote/http_app.py 2012-05-15 13:01:47 +0000 |
557 | +++ u1db/remote/http_app.py 2012-05-18 08:52:17 +0000 |
558 | @@ -290,12 +290,14 @@ |
559 | self.responder.send_response_json(target_replica_uid=result[0], |
560 | target_replica_generation=result[1], |
561 | source_replica_uid=self.source_replica_uid, |
562 | - source_replica_generation=result[2]) |
563 | + source_replica_generation=result[2], |
564 | + source_transaction_id=result[3]) |
565 | |
566 | @http_method(generation=int, |
567 | content_as_args=True, no_query=True) |
568 | - def put(self, generation): |
569 | - self.target.record_sync_info(self.source_replica_uid, generation) |
570 | + def put(self, generation, transaction_id): |
571 | + self.target.record_sync_info(self.source_replica_uid, generation, |
572 | + transaction_id) |
573 | self.responder.send_response_json(ok=True) |
574 | |
575 | # Implements the same logic as LocalSyncTarget.sync_exchange |
576 | |
577 | === modified file 'u1db/remote/http_target.py' |
578 | --- u1db/remote/http_target.py 2012-05-13 09:56:59 +0000 |
579 | +++ u1db/remote/http_target.py 2012-05-18 08:52:17 +0000 |
580 | @@ -42,12 +42,14 @@ |
581 | self._ensure_connection() |
582 | res, _ = self._request_json('GET', ['sync-from', source_replica_uid]) |
583 | return (res['target_replica_uid'], res['target_replica_generation'], |
584 | - res['source_replica_generation']) |
585 | + res['source_replica_generation'], res['source_transaction_id']) |
586 | |
587 | - def record_sync_info(self, source_replica_uid, source_replica_generation): |
588 | + def record_sync_info(self, source_replica_uid, source_replica_generation, |
589 | + source_transaction_id): |
590 | self._ensure_connection() |
591 | self._request_json('PUT', ['sync-from', source_replica_uid], {}, |
592 | - {'generation': source_replica_generation}) |
593 | + {'generation': source_replica_generation, |
594 | + 'transaction_id': source_transaction_id}) |
595 | |
596 | def _parse_sync_stream(self, data, return_doc_cb): |
597 | parts = data.splitlines() # one at a time |
598 | |
599 | === modified file 'u1db/sync.py' |
600 | --- u1db/sync.py 2012-05-17 13:36:08 +0000 |
601 | +++ u1db/sync.py 2012-05-18 08:52:17 +0000 |
602 | @@ -86,20 +86,20 @@ |
603 | if (cur_gen == start_generation + self.num_inserted |
604 | and self.num_inserted > 0): |
605 | self.sync_target.record_sync_info(self.source._replica_uid, |
606 | - cur_gen) |
607 | + cur_gen, 'T-sid') |
608 | |
609 | def sync(self, callback=None): |
610 | """Synchronize documents between source and target.""" |
611 | sync_target = self.sync_target |
612 | # get target identifier, its current generation, |
613 | # and its last-seen database generation for this source |
614 | - (self.target_replica_uid, target_gen, |
615 | - target_my_gen) = sync_target.get_sync_info(self.source._replica_uid) |
616 | + (self.target_replica_uid, target_gen, target_my_gen, |
617 | + target_my_trans_id) = sync_target.get_sync_info(self.source._replica_uid) |
618 | # what's changed since that generation and this current gen |
619 | my_gen, changes = self.source.whats_changed(target_my_gen) |
620 | |
621 | # this source last-seen database generation for the target |
622 | - target_last_known_gen = self.source._get_sync_generation( |
623 | + target_last_known_gen, target_trans_id = self.source._get_sync_gen_info( |
624 | self.target_replica_uid) |
625 | if not changes and target_last_known_gen == target_gen: |
626 | return my_gen |
627 | @@ -115,7 +115,7 @@ |
628 | self.source._replica_uid, target_last_known_gen, |
629 | return_doc_cb=self._insert_doc_from_target) |
630 | # record target synced-up-to generation including applying what we sent |
631 | - self.source._set_sync_generation(self.target_replica_uid, new_gen) |
632 | + self.source._set_sync_info(self.target_replica_uid, new_gen, 'T-sid') |
633 | |
634 | # if gapless record current reached generation with target |
635 | self._record_sync_info_with_the_target(my_gen) |
636 | |
637 | === modified file 'u1db/tests/c_backend_wrapper.pyx' |
638 | --- u1db/tests/c_backend_wrapper.pyx 2012-05-17 15:13:42 +0000 |
639 | +++ u1db/tests/c_backend_wrapper.pyx 2012-05-18 08:52:17 +0000 |
640 | @@ -156,9 +156,10 @@ |
641 | ctypedef struct u1db_sync_target: |
642 | int (*get_sync_info)(u1db_sync_target *st, |
643 | char *source_replica_uid, |
644 | - const_char_ptr *st_replica_uid, int *st_gen, int *source_gen) nogil |
645 | + const_char_ptr *st_replica_uid, int *st_gen, int *source_gen, |
646 | + char **source_trans_id) nogil |
647 | int (*record_sync_info)(u1db_sync_target *st, |
648 | - char *source_replica_uid, int source_gen) nogil |
649 | + char *source_replica_uid, int source_gen, char *trans_id) nogil |
650 | int (*sync_exchange)(u1db_sync_target *st, |
651 | char *source_replica_uid, int n_docs, |
652 | u1db_document **docs, int *generations, |
653 | @@ -191,10 +192,10 @@ |
654 | char *content, int has_conflicts) |
655 | int u1db__generate_hex_uuid(char *) |
656 | |
657 | - int u1db__get_sync_generation(u1database *db, char *replica_uid, |
658 | - int *generation) |
659 | - int u1db__set_sync_generation(u1database *db, char *replica_uid, |
660 | - int generation) |
661 | + int u1db__get_sync_gen_info(u1database *db, char *replica_uid, |
662 | + int *generation, char **trans_id) |
663 | + int u1db__set_sync_info(u1database *db, char *replica_uid, int generation, |
664 | + char *trans_id) |
665 | int u1db__sync_get_machine_info(u1database *db, char *other_replica_uid, |
666 | int *other_db_rev, char **my_replica_uid, |
667 | int *my_db_rev) |
668 | @@ -665,22 +666,27 @@ |
669 | def get_sync_info(self, source_replica_uid): |
670 | cdef const_char_ptr st_replica_uid = NULL |
671 | cdef int st_gen = 0, source_gen = 0, status |
672 | + cdef char *trans_id = NULL |
673 | |
674 | self._check() |
675 | assert self._st.get_sync_info != NULL, "get_sync_info is NULL?" |
676 | with nogil: |
677 | status = self._st.get_sync_info(self._st, source_replica_uid, |
678 | - &st_replica_uid, &st_gen, &source_gen) |
679 | + &st_replica_uid, &st_gen, &source_gen, &trans_id) |
680 | handle_status("get_sync_info", status) |
681 | - return (safe_str(st_replica_uid), st_gen, source_gen) |
682 | + res_trans_id = None |
683 | + if trans_id != NULL: |
684 | + res_trans_id = trans_id |
685 | + free(trans_id) |
686 | + return (safe_str(st_replica_uid), st_gen, source_gen, res_trans_id) |
687 | |
688 | - def record_sync_info(self, source_replica_uid, source_gen): |
689 | + def record_sync_info(self, source_replica_uid, source_gen, source_trans_id): |
690 | cdef int status |
691 | self._check() |
692 | assert self._st.record_sync_info != NULL, "record_sync_info is NULL?" |
693 | with nogil: |
694 | status = self._st.record_sync_info(self._st, source_replica_uid, |
695 | - source_gen) |
696 | + source_gen, source_trans_id) |
697 | handle_status("record_sync_info", status) |
698 | |
699 | def _get_sync_exchange(self, source_replica_uid, source_gen): |
700 | @@ -968,16 +974,22 @@ |
701 | u1db__get_generation(self._db, &generation)) |
702 | return generation |
703 | |
704 | - def _get_sync_generation(self, replica_uid): |
705 | - cdef int generation |
706 | - |
707 | - handle_status("_get_sync_generation", |
708 | - u1db__get_sync_generation(self._db, replica_uid, &generation)) |
709 | - return generation |
710 | - |
711 | - def _set_sync_generation(self, replica_uid, generation): |
712 | - handle_status("_set_sync_generation", |
713 | - u1db__set_sync_generation(self._db, replica_uid, generation)) |
714 | + def _get_sync_gen_info(self, replica_uid): |
715 | + cdef int generation, status |
716 | + cdef char *trans_id = NULL |
717 | + |
718 | + status = u1db__get_sync_gen_info(self._db, replica_uid, &generation, |
719 | + &trans_id) |
720 | + handle_status("_get_sync_gen_info", status) |
721 | + raw_trans_id = None |
722 | + if trans_id != NULL: |
723 | + raw_trans_id = trans_id |
724 | + free(trans_id) |
725 | + return generation, raw_trans_id |
726 | + |
727 | + def _set_sync_info(self, replica_uid, generation, trans_id): |
728 | + handle_status("_set_sync_info", |
729 | + u1db__set_sync_info(self._db, replica_uid, generation, trans_id)) |
730 | |
731 | def _sync_exchange(self, docs_info, from_replica_uid, from_machine_rev, |
732 | last_known_rev): |
733 | |
734 | === modified file 'u1db/tests/test_backends.py' |
735 | --- u1db/tests/test_backends.py 2012-05-17 14:44:25 +0000 |
736 | +++ u1db/tests/test_backends.py 2012-05-18 08:52:17 +0000 |
737 | @@ -296,19 +296,19 @@ |
738 | |
739 | def test_put_doc_if_newer_replica_uid(self): |
740 | doc1 = self.db.create_doc(simple_doc) |
741 | - self.db._set_sync_generation('other', 1) |
742 | + self.db._set_sync_info('other', 1, 'T-sid') |
743 | doc2 = self.make_document(doc1.doc_id, doc1.rev + '|other:1', |
744 | nested_doc) |
745 | self.assertEqual('inserted', |
746 | self.db._put_doc_if_newer(doc2, save_conflict=False, |
747 | replica_uid='other', replica_gen=2)[0]) |
748 | - self.assertEqual(2, self.db._get_sync_generation('other')) |
749 | + self.assertEqual(2, self.db._get_sync_gen_info('other')[0]) |
750 | # Compare to the old rev, should be superseded |
751 | doc2 = self.make_document(doc1.doc_id, doc1.rev, nested_doc) |
752 | self.assertEqual('superseded', |
753 | self.db._put_doc_if_newer(doc2, save_conflict=False, |
754 | replica_uid='other', replica_gen=3)[0]) |
755 | - self.assertEqual(3, self.db._get_sync_generation('other')) |
756 | + self.assertEqual(3, self.db._get_sync_gen_info('other')[0]) |
757 | # A conflict that isn't saved still records the sync gen, because we |
758 | # don't need to see it again |
759 | doc2 = self.make_document(doc1.doc_id, doc1.rev + '|fourth:1', |
760 | @@ -316,12 +316,13 @@ |
761 | self.assertEqual('conflicted', |
762 | self.db._put_doc_if_newer(doc2, save_conflict=False, |
763 | replica_uid='other', replica_gen=4)[0]) |
764 | - self.assertEqual(4, self.db._get_sync_generation('other')) |
765 | + self.assertEqual(4, self.db._get_sync_gen_info('other')[0]) |
766 | |
767 | - def test__get_sync_generation(self): |
768 | - self.assertEqual(0, self.db._get_sync_generation('other-db')) |
769 | - self.db._set_sync_generation('other-db', 2) |
770 | - self.assertEqual(2, self.db._get_sync_generation('other-db')) |
771 | + def test__get_sync_gen_info(self): |
772 | + self.assertEqual((0, ''), self.db._get_sync_gen_info('other-db')) |
773 | + self.db._set_sync_info('other-db', 2, 'T-transaction') |
774 | + self.assertEqual((2, 'T-transaction'), |
775 | + self.db._get_sync_gen_info('other-db')) |
776 | |
777 | def test_put_updates_transaction_log(self): |
778 | doc = self.db.create_doc(simple_doc) |
779 | @@ -568,7 +569,7 @@ |
780 | |
781 | def test_put_doc_if_newer_replica_uid(self): |
782 | doc1 = self.db.create_doc(simple_doc) |
783 | - self.db._set_sync_generation('other', 1) |
784 | + self.db._set_sync_info('other', 1, 'T-sid') |
785 | doc2 = self.make_document(doc1.doc_id, doc1.rev + '|other:1', |
786 | nested_doc) |
787 | self.db._put_doc_if_newer(doc2, save_conflict=True, |
788 | @@ -579,7 +580,7 @@ |
789 | self.assertEqual('conflicted', |
790 | self.db._put_doc_if_newer(doc2, save_conflict=True, |
791 | replica_uid='other', replica_gen=3)[0]) |
792 | - self.assertEqual(3, self.db._get_sync_generation('other')) |
793 | + self.assertEqual(3, self.db._get_sync_gen_info('other')[0]) |
794 | |
795 | def test_put_refuses_to_update_conflicted(self): |
796 | doc1 = self.db.create_doc(simple_doc) |
797 | |
798 | === modified file 'u1db/tests/test_c_backend.py' |
799 | --- u1db/tests/test_c_backend.py 2012-05-17 13:30:51 +0000 |
800 | +++ u1db/tests/test_c_backend.py 2012-05-18 08:52:17 +0000 |
801 | @@ -201,7 +201,8 @@ |
802 | exc.insert_doc_from_source(doc, 10) |
803 | self.assertGetDoc(self.db, 'doc-id', 'replica:1', tests.simple_doc, |
804 | False) |
805 | - self.assertEqual(10, self.db._get_sync_generation('source-uid')) |
806 | + self.assertEqual((10, 'T-sid'), |
807 | + self.db._get_sync_gen_info('source-uid')) |
808 | self.assertEqual(['doc-id'], exc.get_seen_ids()) |
809 | |
810 | def test_sync_exchange_conflicted_doc(self): |
811 | |
812 | === modified file 'u1db/tests/test_http_app.py' |
813 | --- u1db/tests/test_http_app.py 2012-05-17 13:36:08 +0000 |
814 | +++ u1db/tests/test_http_app.py 2012-05-18 08:52:17 +0000 |
815 | @@ -664,24 +664,26 @@ |
816 | simplejson.loads(resp.body)) |
817 | |
818 | def test_get_sync_info(self): |
819 | - self.db0._set_sync_generation('other-id', 1) |
820 | + self.db0._set_sync_info('other-id', 1, 'T-transid') |
821 | resp = self.app.get('/db0/sync-from/other-id') |
822 | self.assertEqual(200, resp.status) |
823 | self.assertEqual('application/json', resp.header('content-type')) |
824 | self.assertEqual(dict(target_replica_uid='db0', |
825 | target_replica_generation=0, |
826 | source_replica_uid='other-id', |
827 | - source_replica_generation=1), |
828 | + source_replica_generation=1, |
829 | + source_transaction_id='T-transid'), |
830 | simplejson.loads(resp.body)) |
831 | |
832 | def test_record_sync_info(self): |
833 | resp = self.app.put('/db0/sync-from/other-id', |
834 | - params='{"generation": 2}', |
835 | - headers={'content-type': 'application/json'}) |
836 | + params='{"generation": 2, "transaction_id": "T-transid"}', |
837 | + headers={'content-type': 'application/json'}) |
838 | self.assertEqual(200, resp.status) |
839 | self.assertEqual('application/json', resp.header('content-type')) |
840 | self.assertEqual({'ok': True}, simplejson.loads(resp.body)) |
841 | - self.assertEqual(self.db0._get_sync_generation('other-id'), 2) |
842 | + self.assertEqual((2, 'T-transid'), |
843 | + self.db0._get_sync_gen_info('other-id')) |
844 | |
845 | def test_sync_exchange_send(self): |
846 | entries = { |
847 | @@ -692,16 +694,15 @@ |
848 | } |
849 | |
850 | gens = [] |
851 | - _do_set_sync_generation = self.db0._do_set_sync_generation |
852 | - def set_sync_generation_witness(other_uid, other_gen): |
853 | + _do_set_sync_info = self.db0._do_set_sync_info |
854 | + def set_sync_generation_witness(other_uid, other_gen, other_trans_id): |
855 | gens.append((other_uid, other_gen)) |
856 | - _do_set_sync_generation(other_uid, other_gen) |
857 | + _do_set_sync_info(other_uid, other_gen, other_trans_id) |
858 | self.assertGetDoc(self.db0, entries[other_gen]['id'], |
859 | entries[other_gen]['rev'], |
860 | entries[other_gen]['content'], False) |
861 | |
862 | - self.patch(self.db0, '_do_set_sync_generation', |
863 | - set_sync_generation_witness) |
864 | + self.patch(self.db0, '_do_set_sync_info', set_sync_generation_witness) |
865 | |
866 | args = dict(last_known_generation=0) |
867 | body = ("[\r\n" + |
868 | |
869 | === modified file 'u1db/tests/test_https.py' |
870 | --- u1db/tests/test_https.py 2012-05-17 15:13:31 +0000 |
871 | +++ u1db/tests/test_https.py 2012-05-18 08:52:17 +0000 |
872 | @@ -83,8 +83,8 @@ |
873 | db = self.request_state._create_database('test') |
874 | self.patch(http_client, 'CA_CERTS', self.cacert_pem) |
875 | remote_target = self.getSyncTarget('localhost', 'test') |
876 | - remote_target.record_sync_info('other-id', 2) |
877 | - self.assertEqual(db._get_sync_generation('other-id'), 2) |
878 | + remote_target.record_sync_info('other-id', 2, 'T-id') |
879 | + self.assertEqual((2, 'T-id'), db._get_sync_gen_info('other-id')) |
880 | |
881 | def test_cannot_verify_cert(self): |
882 | if not sys.platform.startswith('linux'): |
883 | |
884 | === modified file 'u1db/tests/test_remote_sync_target.py' |
885 | --- u1db/tests/test_remote_sync_target.py 2012-05-17 13:36:08 +0000 |
886 | +++ u1db/tests/test_remote_sync_target.py 2012-05-18 08:52:17 +0000 |
887 | @@ -164,17 +164,17 @@ |
888 | def test_get_sync_info(self): |
889 | self.startServer() |
890 | db = self.request_state._create_database('test') |
891 | - db._set_sync_generation('other-id', 1) |
892 | + db._set_sync_info('other-id', 1, 'T-transid') |
893 | remote_target = self.getSyncTarget('test') |
894 | - self.assertEqual(('test', 0, 1), |
895 | + self.assertEqual(('test', 0, 1, 'T-transid'), |
896 | remote_target.get_sync_info('other-id')) |
897 | |
898 | def test_record_sync_info(self): |
899 | self.startServer() |
900 | db = self.request_state._create_database('test') |
901 | remote_target = self.getSyncTarget('test') |
902 | - remote_target.record_sync_info('other-id', 2) |
903 | - self.assertEqual(db._get_sync_generation('other-id'), 2) |
904 | + remote_target.record_sync_info('other-id', 2, 'T-transid') |
905 | + self.assertEqual((2, 'T-transid'), db._get_sync_gen_info('other-id')) |
906 | |
907 | def test_sync_exchange_send(self): |
908 | self.startServer() |
909 | @@ -222,7 +222,7 @@ |
910 | return_doc_cb=receive_doc) |
911 | self.assertGetDoc(db, 'doc-here', 'replica:1', '{"value": "here"}', |
912 | False) |
913 | - self.assertEqual(10, db._get_sync_generation('replica')) |
914 | + self.assertEqual((10, 'T-sid'), db._get_sync_gen_info('replica')) |
915 | self.assertEqual([], other_changes) |
916 | # retry |
917 | trigger_ids = [] |
918 | @@ -232,7 +232,7 @@ |
919 | return_doc_cb=receive_doc) |
920 | self.assertGetDoc(db, 'doc-here2', 'replica:1', '{"value": "here2"}', |
921 | False) |
922 | - self.assertEqual(11, db._get_sync_generation('replica')) |
923 | + self.assertEqual((11, 'T-sid'), db._get_sync_gen_info('replica')) |
924 | self.assertEqual(2, new_gen) |
925 | # bounced back to us |
926 | self.assertEqual([('doc-here', 'replica:1', '{"value": "here"}', 1)], |
927 | |
928 | === modified file 'u1db/tests/test_sync.py' |
929 | --- u1db/tests/test_sync.py 2012-05-17 14:44:25 +0000 |
930 | +++ u1db/tests/test_sync.py 2012-05-18 08:52:17 +0000 |
931 | @@ -141,17 +141,18 @@ |
932 | self.assertIsNot(None, self.st) |
933 | |
934 | def test_get_sync_info(self): |
935 | - self.assertEqual(('test', 0, 0), self.st.get_sync_info('other')) |
936 | + self.assertEqual(('test', 0, 0, ''), self.st.get_sync_info('other')) |
937 | |
938 | def test_create_doc_updates_sync_info(self): |
939 | - self.assertEqual(('test', 0, 0), self.st.get_sync_info('other')) |
940 | + self.assertEqual(('test', 0, 0, ''), self.st.get_sync_info('other')) |
941 | doc = self.db.create_doc(simple_doc) |
942 | - self.assertEqual(('test', 1, 0), self.st.get_sync_info('other')) |
943 | + self.assertEqual(('test', 1, 0, ''), self.st.get_sync_info('other')) |
944 | |
945 | def test_record_sync_info(self): |
946 | - self.assertEqual(('test', 0, 0), self.st.get_sync_info('replica')) |
947 | - self.st.record_sync_info('replica', 10) |
948 | - self.assertEqual(('test', 0, 10), self.st.get_sync_info('replica')) |
949 | + self.assertEqual(('test', 0, 0, ''), self.st.get_sync_info('replica')) |
950 | + self.st.record_sync_info('replica', 10, 'T-transid') |
951 | + self.assertEqual(('test', 0, 10, 'T-transid'), |
952 | + self.st.get_sync_info('replica')) |
953 | |
954 | def test_sync_exchange(self): |
955 | docs_by_gen = [ |
956 | @@ -162,7 +163,7 @@ |
957 | self.assertGetDoc(self.db, 'doc-id', 'replica:1', simple_doc, False) |
958 | self.assertTransactionLog(['doc-id'], self.db) |
959 | self.assertEqual(([], 1), (self.other_changes, new_gen)) |
960 | - self.assertEqual(10, self.st.get_sync_info('replica')[-1]) |
961 | + self.assertEqual(10, self.st.get_sync_info('replica')[2]) |
962 | |
963 | def test_sync_exchange_deleted(self): |
964 | doc = self.db.create_doc('{}') |
965 | @@ -175,7 +176,7 @@ |
966 | self.assertGetDoc(self.db, doc.doc_id, edit_rev, None, False) |
967 | self.assertTransactionLog([doc.doc_id, doc.doc_id], self.db) |
968 | self.assertEqual(([], 2), (self.other_changes, new_gen)) |
969 | - self.assertEqual(10, self.st.get_sync_info('replica')[-1]) |
970 | + self.assertEqual(10, self.st.get_sync_info('replica')[2]) |
971 | |
972 | def test_sync_exchange_push_many(self): |
973 | docs_by_gen = [ |
974 | @@ -188,7 +189,7 @@ |
975 | self.assertGetDoc(self.db, 'doc-id2', 'replica:1', nested_doc, False) |
976 | self.assertTransactionLog(['doc-id', 'doc-id2'], self.db) |
977 | self.assertEqual(([], 2), (self.other_changes, new_gen)) |
978 | - self.assertEqual(11, self.st.get_sync_info('replica')[-1]) |
979 | + self.assertEqual(11, self.st.get_sync_info('replica')[2]) |
980 | |
981 | def test_sync_exchange_refuses_conflicts(self): |
982 | doc = self.db.create_doc(simple_doc) |
983 | @@ -345,7 +346,7 @@ |
984 | self.assertGetDoc(self.db, doc.doc_id, doc.rev, simple_doc, False) |
985 | self.assertTransactionLog([doc.doc_id], self.db) |
986 | self.assertEqual(([], 1), (self.other_changes, new_gen)) |
987 | - self.assertEqual(10, self.st.get_sync_info(db2._replica_uid)[-1]) |
988 | + self.assertEqual(10, self.st.get_sync_info(db2._replica_uid)[2]) |
989 | |
990 | def test__set_trace_hook(self): |
991 | called = [] |
992 | @@ -353,7 +354,7 @@ |
993 | called.append(state) |
994 | self.set_trace_hook(cb) |
995 | self.st.sync_exchange([], 'replica', 0, self.receive_doc) |
996 | - self.st.record_sync_info('replica', 0) |
997 | + self.st.record_sync_info('replica', 0, 'T-sid') |
998 | self.assertEqual(['before whats_changed', |
999 | 'after whats_changed', |
1000 | 'before get_docs', |
1001 | @@ -410,8 +411,8 @@ |
1002 | |
1003 | def test_sync_tracks_db_generation_of_other(self): |
1004 | self.assertEqual(0, self.sync(self.db1, self.db2)) |
1005 | - self.assertEqual(0, self.db1._get_sync_generation('test2')) |
1006 | - self.assertEqual(0, self.db2._get_sync_generation('test1')) |
1007 | + self.assertEqual((0, ''), self.db1._get_sync_gen_info('test2')) |
1008 | + self.assertEqual((0, ''), self.db2._get_sync_gen_info('test1')) |
1009 | self.assertLastExchangeLog(self.db2, |
1010 | {'receive': {'docs': [], 'last_known_gen': 0}, |
1011 | 'return': {'docs': [], 'last_gen': 0}}) |
1012 | @@ -420,8 +421,8 @@ |
1013 | doc = self.db1.create_doc(simple_doc) |
1014 | self.assertEqual(1, self.sync(self.db1, self.db2)) |
1015 | self.assertGetDoc(self.db2, doc.doc_id, doc.rev, simple_doc, False) |
1016 | - self.assertEqual(1, self.db1._get_sync_generation('test2')) |
1017 | - self.assertEqual(1, self.db2._get_sync_generation('test1')) |
1018 | + self.assertEqual(1, self.db1._get_sync_gen_info('test2')[0]) |
1019 | + self.assertEqual(1, self.db2._get_sync_gen_info('test1')[0]) |
1020 | self.assertLastExchangeLog(self.db2, |
1021 | {'receive': {'docs': [(doc.doc_id, doc.rev)], |
1022 | 'source_uid': 'test1', |
1023 | @@ -433,8 +434,8 @@ |
1024 | self.db1.create_index('test-idx', ['key']) |
1025 | self.assertEqual(0, self.sync(self.db1, self.db2)) |
1026 | self.assertGetDoc(self.db1, doc.doc_id, doc.rev, simple_doc, False) |
1027 | - self.assertEqual(1, self.db1._get_sync_generation('test2')) |
1028 | - self.assertEqual(1, self.db2._get_sync_generation('test1')) |
1029 | + self.assertEqual(1, self.db1._get_sync_gen_info('test2')[0]) |
1030 | + self.assertEqual(1, self.db2._get_sync_gen_info('test1')[0]) |
1031 | self.assertLastExchangeLog(self.db2, |
1032 | {'receive': {'docs': [], 'last_known_gen': 0}, |
1033 | 'return': {'docs': [(doc.doc_id, doc.rev)], |
1034 | @@ -459,11 +460,11 @@ |
1035 | {'receive': {'docs': [], 'last_known_gen': 0}, |
1036 | 'return': {'docs': [(doc.doc_id, doc.rev)], |
1037 | 'last_gen': 1}}) |
1038 | - self.assertEqual(1, self.db1._get_sync_generation('test2')) |
1039 | + self.assertEqual(1, self.db1._get_sync_gen_info('test2')[0]) |
1040 | # c2 should not have gotten a '_record_sync_info' call, because the |
1041 | # local database had been updated more than just by the messages |
1042 | # returned from c2. |
1043 | - self.assertEqual(0, self.db2._get_sync_generation('test1')) |
1044 | + self.assertEqual((0, ''), self.db2._get_sync_gen_info('test1')) |
1045 | |
1046 | def test_sync_doesnt_update_other_if_nothing_pulled(self): |
1047 | doc = self.db1.create_doc(simple_doc) |
1048 | @@ -474,7 +475,7 @@ |
1049 | self.assertEqual(1, self.sync(self.db1, self.db2, |
1050 | trace_hook=no_record_sync_info)) |
1051 | self.assertEqual(1, |
1052 | - self.db2._get_sync_generation(self.db1._replica_uid)) |
1053 | + self.db2._get_sync_gen_info(self.db1._replica_uid)[0]) |
1054 | |
1055 | def test_sync_ignores_convergence(self): |
1056 | doc = self.db1.create_doc(simple_doc) |
1057 | @@ -707,20 +708,20 @@ |
1058 | self.assertEqual(2, len(self.db2._get_transaction_log())) |
1059 | progress1 = [] |
1060 | progress2 = [] |
1061 | - _do_set_sync_generation1 = self.db1._do_set_sync_generation |
1062 | - def set_sync_generation_witness1(other_uid, other_gen): |
1063 | + _do_set_sync_info = self.db1._do_set_sync_info |
1064 | + def set_sync_generation_witness1(other_uid, other_gen, trans_id): |
1065 | progress1.append((other_uid, other_gen, |
1066 | [d for d, t in self.db1._get_transaction_log()[2:]])) |
1067 | - _do_set_sync_generation1(other_uid, other_gen) |
1068 | - self.patch(self.db1, '_do_set_sync_generation', |
1069 | + _do_set_sync_info(other_uid, other_gen, trans_id) |
1070 | + self.patch(self.db1, '_do_set_sync_info', |
1071 | set_sync_generation_witness1) |
1072 | |
1073 | - _do_set_sync_generation2 = self.db2._do_set_sync_generation |
1074 | - def set_sync_generation_witness2(other_uid, other_gen): |
1075 | + _do_set_sync_info2 = self.db2._do_set_sync_info |
1076 | + def set_sync_generation_witness2(other_uid, other_gen, trans_id): |
1077 | progress2.append((other_uid, other_gen, |
1078 | [d for d, t in self.db2._get_transaction_log()[2:]])) |
1079 | - _do_set_sync_generation2(other_uid, other_gen) |
1080 | - self.patch(self.db2, '_do_set_sync_generation', |
1081 | + _do_set_sync_info2(other_uid, other_gen, trans_id) |
1082 | + self.patch(self.db2, '_do_set_sync_info', |
1083 | set_sync_generation_witness2) |
1084 | |
1085 | db2_url = self.getURL('test2') |
Looks good