Merge lp:~jameinel/u1db/sync_info_999574 into lp:u1db

Proposed by John A Meinel
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
Reviewer Review Type Date Requested Status
Eric Casteleijn (community) Approve
Review via email: mp+106334@code.launchpad.net

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_generation and _set_sync_generation code. Because it is no longer just setting a generation counter, I wanted to change the api names.

I'm not very happy with the new names "_get_sync_gen_info()" and "_set_sync_info()". I was hoping to have the Database names be clearly distinct from the SyncTarget names (currently get_sync_info() and record_sync_info()). I would be ok with _get_sync_info() but it means that the difference is only in an underscore.

Calling it _get_sync_generation_and_transaction_id() is just not reasonable. The db table is currently called 'sync_log'. Maybe "_get_sync_state()" ? We don't want _get_sync_log because we aren't storing history. And possibly the table should be renamed as well.

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.

To post a comment you must log in.
Revision history for this message
Eric Casteleijn (thisfred) wrote :

Looks good

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-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')

Subscribers

People subscribed via source and target branches