Merge lp:~jameinel/u1db/put_doc_if_newer_private_999574 into lp:u1db
- put_doc_if_newer_private_999574
- Merge into trunk
Proposed by
John A Meinel
Status: | Merged |
---|---|
Merged at revision: | 295 |
Proposed branch: | lp:~jameinel/u1db/put_doc_if_newer_private_999574 |
Merge into: | lp:u1db |
Prerequisite: | lp:~jameinel/u1db/whats_changed_999574 |
Diff against target: |
396 lines (+77/-44) 13 files modified
include/u1db/u1db_internal.h (+3/-1) src/u1db.c (+15/-7) src/u1db_http_sync_target.c (+12/-6) src/u1db_sync_target.c (+2/-2) u1db/__init__.py (+3/-1) u1db/backends/__init__.py (+2/-2) u1db/backends/sqlite_backend.py (+3/-2) u1db/sync.py (+4/-2) u1db/tests/c_backend_wrapper.pyx (+9/-4) u1db/tests/test_backends.py (+15/-10) u1db/tests/test_c_backend.py (+1/-1) u1db/tests/test_https.py (+2/-2) u1db/tests/test_remote_sync_target.py (+6/-4) |
To merge this branch: | bzr merge lp:~jameinel/u1db/put_doc_if_newer_private_999574 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
John O'Brien (community) | Approve | ||
Review via email: mp+106361@code.launchpad.net |
Commit message
Description of the change
This exposes the transaction_id stuff in put_doc_if_newer. This still is not a complete implementation, as it gets None as the trans_id from the sync code.
However, it is a step further, and should avoid more enormous diffs to review.
To post a comment you must log in.
- 310. By John A Meinel
-
Do the right thing with a const issue for the tmp variable.
- 311. By John A Meinel
-
Catch the other https tests.
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-18 14:08:24 +0000 |
3 | +++ include/u1db/u1db_internal.h 2012-05-18 14:08:24 +0000 |
4 | @@ -182,6 +182,7 @@ |
5 | * this document came from. (Can be NULL) |
6 | * @param replica_gen Generation of the replica. Only meaningful if |
7 | * replica_uid is set. |
8 | + * @param replica_trans_id Transaction id associated with generation. |
9 | * @param state (OUT) Return one of: |
10 | * U1DB_INSERTED The document is newer than what we have |
11 | * U1DB_SUPERSEDED We already have a newer document than what was passed |
12 | @@ -193,7 +194,8 @@ |
13 | */ |
14 | int u1db__put_doc_if_newer(u1database *db, u1db_document *doc, |
15 | int save_conflict, const char *replica_uid, |
16 | - int replica_gen, int *state, int *at_gen); |
17 | + int replica_gen, const char *replica_trans_id, |
18 | + int *state, int *at_gen); |
19 | |
20 | /** |
21 | * Internal API, Get the global database rev. |
22 | |
23 | === modified file 'src/u1db.c' |
24 | --- src/u1db.c 2012-05-18 14:08:24 +0000 |
25 | +++ src/u1db.c 2012-05-18 14:08:24 +0000 |
26 | @@ -723,8 +723,8 @@ |
27 | |
28 | int |
29 | u1db__put_doc_if_newer(u1database *db, u1db_document *doc, int save_conflict, |
30 | - const char *replica_uid, int replica_gen, int *state, |
31 | - int *at_gen) |
32 | + const char *replica_uid, int replica_gen, |
33 | + const char *replica_trans_id, int *state, int *at_gen) |
34 | { |
35 | const char *stored_content = NULL, *stored_doc_rev = NULL; |
36 | int status = U1DB_INVALID_PARAMETER, store = 0; |
37 | @@ -810,7 +810,8 @@ |
38 | (stored_doc_rev != NULL)); |
39 | } |
40 | if (status == U1DB_OK && replica_uid != NULL) { |
41 | - status = u1db__set_sync_info(db, replica_uid, replica_gen, "T-sid"); |
42 | + status = u1db__set_sync_info(db, replica_uid, replica_gen, |
43 | + replica_trans_id); |
44 | } |
45 | if (status == U1DB_OK && at_gen != NULL) { |
46 | status = u1db__get_generation(db, at_gen); |
47 | @@ -1341,16 +1342,23 @@ |
48 | status = SQLITE_OK; |
49 | *generation = 0; |
50 | *trans_id = strdup(""); |
51 | + if (*trans_id == NULL) { |
52 | + status = U1DB_NOMEM; |
53 | + } |
54 | } else if (status == SQLITE_ROW) { |
55 | *generation = sqlite3_column_int(statement, 0); |
56 | // Note: We may want to handle the column containing NULL |
57 | tmp = (const char *)sqlite3_column_text(statement, 1); |
58 | - *trans_id = strdup(tmp); |
59 | + if (tmp == NULL) { |
60 | + *trans_id = NULL; |
61 | + } else { |
62 | + *trans_id = strdup(tmp); |
63 | + if (*trans_id == NULL) { |
64 | + status = U1DB_NOMEM; |
65 | + } |
66 | + } |
67 | status = SQLITE_OK; |
68 | } |
69 | - if (*trans_id == NULL) { |
70 | - status = U1DB_NOMEM; |
71 | - } |
72 | finish: |
73 | sqlite3_finalize(statement); |
74 | return status; |
75 | |
76 | === modified file 'src/u1db_http_sync_target.c' |
77 | --- src/u1db_http_sync_target.c 2012-05-18 14:08:24 +0000 |
78 | +++ src/u1db_http_sync_target.c 2012-05-18 14:08:24 +0000 |
79 | @@ -362,6 +362,7 @@ |
80 | struct _http_state *state; |
81 | struct _http_request req = {0}; |
82 | char *url = NULL; |
83 | + const char *tmp = NULL; |
84 | int status; |
85 | long http_code; |
86 | struct curl_slist *headers = NULL; |
87 | @@ -455,12 +456,17 @@ |
88 | *source_gen = json_object_get_int(obj); |
89 | obj = json_object_object_get(json, "source_transaction_id"); |
90 | if (obj == NULL) { |
91 | - status = U1DB_INVALID_HTTP_RESPONSE; |
92 | - goto finish; |
93 | - } |
94 | - *trans_id = strdup(json_object_get_string(obj)); |
95 | - if (*trans_id == NULL) { |
96 | - status = U1DB_NOMEM; |
97 | + *trans_id = NULL; |
98 | + } else { |
99 | + tmp = json_object_get_string(obj); |
100 | + if (tmp == NULL) { |
101 | + *trans_id = NULL; |
102 | + } else { |
103 | + *trans_id = strdup(tmp); |
104 | + if (*trans_id == NULL) { |
105 | + status = U1DB_NOMEM; |
106 | + } |
107 | + } |
108 | } |
109 | finish: |
110 | if (req.header_buffer != NULL) { |
111 | |
112 | === modified file 'src/u1db_sync_target.c' |
113 | --- src/u1db_sync_target.c 2012-05-18 14:08:24 +0000 |
114 | +++ src/u1db_sync_target.c 2012-05-18 14:08:24 +0000 |
115 | @@ -280,7 +280,7 @@ |
116 | } |
117 | // fprintf(stderr, "Inserting %s from source\n", doc->doc_id); |
118 | status = u1db__put_doc_if_newer(se->db, doc, 0, se->source_replica_uid, |
119 | - source_gen, &insert_state, &at_gen); |
120 | + source_gen, NULL, &insert_state, &at_gen); |
121 | if (insert_state == U1DB_INSERTED || insert_state == U1DB_CONVERGED) { |
122 | lh_table_insert(se->seen_ids, strdup(doc->doc_id), (void *)(intptr_t)at_gen); |
123 | } else { |
124 | @@ -437,7 +437,7 @@ |
125 | state = (struct _return_doc_state *)context; |
126 | |
127 | status = u1db__put_doc_if_newer(state->db, doc, 1, state->target_uid, gen, |
128 | - &insert_state, NULL); |
129 | + NULL, &insert_state, NULL); |
130 | u1db_free_doc(&doc); |
131 | if (status == U1DB_OK) { |
132 | if (insert_state == U1DB_INSERTED || insert_state == U1DB_CONFLICTED) { |
133 | |
134 | === modified file 'u1db/__init__.py' |
135 | --- u1db/__init__.py 2012-05-18 14:08:24 +0000 |
136 | +++ u1db/__init__.py 2012-05-18 14:08:24 +0000 |
137 | @@ -248,7 +248,7 @@ |
138 | raise NotImplementedError(self._set_sync_info) |
139 | |
140 | def _put_doc_if_newer(self, doc, save_conflict, replica_uid=None, |
141 | - replica_gen=None): |
142 | + replica_gen=None, replica_trans_id=None): |
143 | """Insert/update document into the database with a given revision. |
144 | |
145 | This api is used during synchronization operations. |
146 | @@ -273,6 +273,8 @@ |
147 | :param replica_gen: The generation of the replica corresponding to the |
148 | this document. The replica arguments are optional, but are used |
149 | during synchronization. |
150 | + :param replica_trans_id: The transaction_id associated with the |
151 | + generation. |
152 | :return: (state, at_gen) - If we don't have doc_id already, |
153 | or if doc_rev supersedes the existing document revision, |
154 | then the content will be inserted, and state is 'inserted'. |
155 | |
156 | === modified file 'u1db/backends/__init__.py' |
157 | --- u1db/backends/__init__.py 2012-05-18 14:08:24 +0000 |
158 | +++ u1db/backends/__init__.py 2012-05-18 14:08:24 +0000 |
159 | @@ -91,7 +91,7 @@ |
160 | return result |
161 | |
162 | def _put_doc_if_newer(self, doc, save_conflict, replica_uid=None, |
163 | - replica_gen=None): |
164 | + replica_gen=None, replica_trans_id=None): |
165 | cur_doc = self._get_doc(doc.doc_id) |
166 | doc_vcr = VectorClockRev(doc.rev) |
167 | if cur_doc is None: |
168 | @@ -115,7 +115,7 @@ |
169 | if save_conflict: |
170 | self._force_doc_sync_conflict(doc) |
171 | if replica_uid is not None and replica_gen is not None: |
172 | - self._do_set_sync_info(replica_uid, replica_gen, 'T-sid') |
173 | + self._do_set_sync_info(replica_uid, replica_gen, replica_trans_id) |
174 | return state, self._get_generation() |
175 | |
176 | def _ensure_maximal_rev(self, cur_rev, extra_revs): |
177 | |
178 | === modified file 'u1db/backends/sqlite_backend.py' |
179 | --- u1db/backends/sqlite_backend.py 2012-05-18 14:08:24 +0000 |
180 | +++ u1db/backends/sqlite_backend.py 2012-05-18 14:08:24 +0000 |
181 | @@ -438,11 +438,12 @@ |
182 | other_transaction_id)) |
183 | |
184 | def _put_doc_if_newer(self, doc, save_conflict, replica_uid=None, |
185 | - replica_gen=None): |
186 | + replica_gen=None, replica_trans_id=None): |
187 | with self._db_handle: |
188 | return super(SQLiteDatabase, self)._put_doc_if_newer(doc, |
189 | save_conflict=save_conflict, |
190 | - replica_uid=replica_uid, replica_gen=replica_gen) |
191 | + replica_uid=replica_uid, replica_gen=replica_gen, |
192 | + replica_trans_id=replica_trans_id) |
193 | |
194 | def _add_conflict(self, c, doc_id, my_doc_rev, my_content): |
195 | c.execute("INSERT INTO conflicts VALUES (?, ?, ?)", |
196 | |
197 | === modified file 'u1db/sync.py' |
198 | --- u1db/sync.py 2012-05-18 14:08:24 +0000 |
199 | +++ u1db/sync.py 2012-05-18 14:08:24 +0000 |
200 | @@ -53,7 +53,8 @@ |
201 | # Increases self.num_inserted depending whether the document |
202 | # was effectively inserted. |
203 | state, _ = self.source._put_doc_if_newer(doc, save_conflict=True, |
204 | - replica_uid=self.target_replica_uid, replica_gen=replica_gen) |
205 | + replica_uid=self.target_replica_uid, replica_gen=replica_gen, |
206 | + replica_trans_id=None) |
207 | if state == 'inserted': |
208 | self.num_inserted += 1 |
209 | elif state == 'converged': |
210 | @@ -166,7 +167,8 @@ |
211 | :return: None |
212 | """ |
213 | state, at_gen = self._db._put_doc_if_newer(doc, save_conflict=False, |
214 | - replica_uid=self.source_replica_uid, replica_gen=source_gen) |
215 | + replica_uid=self.source_replica_uid, replica_gen=source_gen, |
216 | + replica_trans_id=None) |
217 | if state == 'inserted': |
218 | self.seen_ids[doc.doc_id] = at_gen |
219 | elif state == 'converged': |
220 | |
221 | === modified file 'u1db/tests/c_backend_wrapper.pyx' |
222 | --- u1db/tests/c_backend_wrapper.pyx 2012-05-18 14:08:24 +0000 |
223 | +++ u1db/tests/c_backend_wrapper.pyx 2012-05-18 14:08:24 +0000 |
224 | @@ -78,7 +78,8 @@ |
225 | int u1db_put_doc(u1database *db, u1db_document *doc) |
226 | int u1db__put_doc_if_newer(u1database *db, u1db_document *doc, |
227 | int save_conflict, char *replica_uid, |
228 | - int replica_gen, int *state, int *at_gen) |
229 | + int replica_gen, char *replica_trans_id, |
230 | + int *state, int *at_gen) |
231 | int u1db_resolve_doc(u1database *db, u1db_document *doc, |
232 | int n_revs, const_char_ptr *revs) |
233 | int u1db_delete_doc(u1database *db, u1db_document *doc) |
234 | @@ -868,21 +869,25 @@ |
235 | return doc.rev |
236 | |
237 | def _put_doc_if_newer(self, CDocument doc, save_conflict, replica_uid=None, |
238 | - replica_gen=None): |
239 | - cdef char *c_uid |
240 | + replica_gen=None, replica_trans_id=None): |
241 | + cdef char *c_uid, *c_trans_id |
242 | cdef int gen, state = 0, at_gen = -1 |
243 | |
244 | if replica_uid is None: |
245 | c_uid = NULL |
246 | else: |
247 | c_uid = replica_uid |
248 | + if replica_trans_id is None: |
249 | + c_trans_id = NULL |
250 | + else: |
251 | + c_trans_id = replica_trans_id |
252 | if replica_gen is None: |
253 | gen = 0 |
254 | else: |
255 | gen = replica_gen |
256 | handle_status("Failed to _put_doc_if_newer", |
257 | u1db__put_doc_if_newer(self._db, doc._doc, save_conflict, |
258 | - c_uid, gen, &state, &at_gen)) |
259 | + c_uid, gen, c_trans_id, &state, &at_gen)) |
260 | if state == U1DB_INSERTED: |
261 | return 'inserted', at_gen |
262 | elif state == U1DB_SUPERSEDED: |
263 | |
264 | === modified file 'u1db/tests/test_backends.py' |
265 | --- u1db/tests/test_backends.py 2012-05-18 14:08:24 +0000 |
266 | +++ u1db/tests/test_backends.py 2012-05-18 14:08:24 +0000 |
267 | @@ -301,22 +301,25 @@ |
268 | nested_doc) |
269 | self.assertEqual('inserted', |
270 | self.db._put_doc_if_newer(doc2, save_conflict=False, |
271 | - replica_uid='other', replica_gen=2)[0]) |
272 | - self.assertEqual(2, self.db._get_sync_gen_info('other')[0]) |
273 | + replica_uid='other', replica_gen=2, |
274 | + replica_trans_id='T-id2')[0]) |
275 | + self.assertEqual((2, 'T-id2'), self.db._get_sync_gen_info('other')) |
276 | # Compare to the old rev, should be superseded |
277 | doc2 = self.make_document(doc1.doc_id, doc1.rev, nested_doc) |
278 | self.assertEqual('superseded', |
279 | self.db._put_doc_if_newer(doc2, save_conflict=False, |
280 | - replica_uid='other', replica_gen=3)[0]) |
281 | - self.assertEqual(3, self.db._get_sync_gen_info('other')[0]) |
282 | + replica_uid='other', replica_gen=3, |
283 | + replica_trans_id='T-id3')[0]) |
284 | + self.assertEqual((3, 'T-id3'), self.db._get_sync_gen_info('other')) |
285 | # A conflict that isn't saved still records the sync gen, because we |
286 | # don't need to see it again |
287 | doc2 = self.make_document(doc1.doc_id, doc1.rev + '|fourth:1', |
288 | nested_doc) |
289 | self.assertEqual('conflicted', |
290 | self.db._put_doc_if_newer(doc2, save_conflict=False, |
291 | - replica_uid='other', replica_gen=4)[0]) |
292 | - self.assertEqual(4, self.db._get_sync_gen_info('other')[0]) |
293 | + replica_uid='other', replica_gen=4, |
294 | + replica_trans_id='T-id4')[0]) |
295 | + self.assertEqual((4, 'T-id4'), self.db._get_sync_gen_info('other')) |
296 | |
297 | def test__get_sync_gen_info(self): |
298 | self.assertEqual((0, ''), self.db._get_sync_gen_info('other-db')) |
299 | @@ -579,18 +582,20 @@ |
300 | |
301 | def test_put_doc_if_newer_replica_uid(self): |
302 | doc1 = self.db.create_doc(simple_doc) |
303 | - self.db._set_sync_info('other', 1, 'T-sid') |
304 | + self.db._set_sync_info('other', 1, 'T-id') |
305 | doc2 = self.make_document(doc1.doc_id, doc1.rev + '|other:1', |
306 | nested_doc) |
307 | self.db._put_doc_if_newer(doc2, save_conflict=True, |
308 | - replica_uid='other', replica_gen=2) |
309 | + replica_uid='other', replica_gen=2, |
310 | + replica_trans_id='T-id2') |
311 | # Conflict vs the current update |
312 | doc2 = self.make_document(doc1.doc_id, doc1.rev + '|third:3', |
313 | nested_doc) |
314 | self.assertEqual('conflicted', |
315 | self.db._put_doc_if_newer(doc2, save_conflict=True, |
316 | - replica_uid='other', replica_gen=3)[0]) |
317 | - self.assertEqual(3, self.db._get_sync_gen_info('other')[0]) |
318 | + replica_uid='other', replica_gen=3, |
319 | + replica_trans_id='T-id3')[0]) |
320 | + self.assertEqual((3, 'T-id3'), self.db._get_sync_gen_info('other')) |
321 | |
322 | def test_put_refuses_to_update_conflicted(self): |
323 | doc1 = self.db.create_doc(simple_doc) |
324 | |
325 | === modified file 'u1db/tests/test_c_backend.py' |
326 | --- u1db/tests/test_c_backend.py 2012-05-18 14:08:24 +0000 |
327 | +++ u1db/tests/test_c_backend.py 2012-05-18 14:08:24 +0000 |
328 | @@ -201,7 +201,7 @@ |
329 | exc.insert_doc_from_source(doc, 10) |
330 | self.assertGetDoc(self.db, 'doc-id', 'replica:1', tests.simple_doc, |
331 | False) |
332 | - self.assertEqual((10, 'T-sid'), |
333 | + self.assertEqual((10, None), |
334 | self.db._get_sync_gen_info('source-uid')) |
335 | self.assertEqual(['doc-id'], exc.get_seen_ids()) |
336 | |
337 | |
338 | === modified file 'u1db/tests/test_https.py' |
339 | --- u1db/tests/test_https.py 2012-05-18 14:08:24 +0000 |
340 | +++ u1db/tests/test_https.py 2012-05-18 14:08:24 +0000 |
341 | @@ -96,7 +96,7 @@ |
342 | db = self.request_state._create_database('test') |
343 | remote_target = self.getSyncTarget('localhost', 'test') |
344 | try: |
345 | - remote_target.record_sync_info('other-id', 2) |
346 | + remote_target.record_sync_info('other-id', 2, 'T-id') |
347 | except ssl.SSLError, e: |
348 | self.assertIn("certificate verify failed", str(e)) |
349 | else: |
350 | @@ -111,7 +111,7 @@ |
351 | self.patch(http_client, 'CA_CERTS', self.cacert_pem) |
352 | remote_target = self.getSyncTarget('127.0.0.1', 'test') |
353 | self.assertRaises(http_client.CertificateError, |
354 | - remote_target.record_sync_info, 'other-id', 2) |
355 | + remote_target.record_sync_info, 'other-id', 2, 'T-id') |
356 | |
357 | |
358 | load_tests = tests.load_with_scenarios |
359 | |
360 | === modified file 'u1db/tests/test_remote_sync_target.py' |
361 | --- u1db/tests/test_remote_sync_target.py 2012-05-18 14:08:24 +0000 |
362 | +++ u1db/tests/test_remote_sync_target.py 2012-05-18 14:08:24 +0000 |
363 | @@ -202,11 +202,13 @@ |
364 | _put_doc_if_newer = db._put_doc_if_newer |
365 | trigger_ids = ['doc-here2'] |
366 | def bomb_put_doc_if_newer(doc, save_conflict, |
367 | - replica_uid=None, replica_gen=None): |
368 | + replica_uid=None, replica_gen=None, |
369 | + replica_trans_id=None): |
370 | if doc.doc_id in trigger_ids: |
371 | raise Exception |
372 | return _put_doc_if_newer(doc, save_conflict=save_conflict, |
373 | - replica_uid=replica_uid, replica_gen=replica_gen) |
374 | + replica_uid=replica_uid, replica_gen=replica_gen, |
375 | + replica_trans_id=replica_trans_id) |
376 | self.patch(db, '_put_doc_if_newer', bomb_put_doc_if_newer) |
377 | remote_target = self.getSyncTarget('test') |
378 | other_changes = [] |
379 | @@ -222,7 +224,7 @@ |
380 | return_doc_cb=receive_doc) |
381 | self.assertGetDoc(db, 'doc-here', 'replica:1', '{"value": "here"}', |
382 | False) |
383 | - self.assertEqual((10, 'T-sid'), db._get_sync_gen_info('replica')) |
384 | + self.assertEqual((10, None), db._get_sync_gen_info('replica')) |
385 | self.assertEqual([], other_changes) |
386 | # retry |
387 | trigger_ids = [] |
388 | @@ -232,7 +234,7 @@ |
389 | return_doc_cb=receive_doc) |
390 | self.assertGetDoc(db, 'doc-here2', 'replica:1', '{"value": "here2"}', |
391 | False) |
392 | - self.assertEqual((11, 'T-sid'), db._get_sync_gen_info('replica')) |
393 | + self.assertEqual((11, None), db._get_sync_gen_info('replica')) |
394 | self.assertEqual(2, new_gen) |
395 | # bounced back to us |
396 | self.assertEqual([('doc-here', 'replica:1', '{"value": "here"}', 1)], |
+1 tastes great, less filling.