diff options
author | Martin Schanzenbach <schanzen@gnunet.org> | 2022-09-23 16:39:21 +0900 |
---|---|---|
committer | Martin Schanzenbach <schanzen@gnunet.org> | 2022-09-23 16:39:21 +0900 |
commit | e0e36b6feba6cbcbbb3516d3a9de4d6fd0199825 (patch) | |
tree | 77429f5da157e6c002cdb0d31dfb44da0cc48123 | |
parent | 7678d77b1cb0dcfd8887016d35b27fbedb136050 (diff) | |
download | gnunet-e0e36b6feba6cbcbbb3516d3a9de4d6fd0199825.tar.gz gnunet-e0e36b6feba6cbcbbb3516d3a9de4d6fd0199825.zip |
NAMESTORE: Towards proper transactional locks
-rw-r--r-- | src/include/gnunet_namestore_service.h | 10 | ||||
-rw-r--r-- | src/namestore/Makefile.am | 12 | ||||
-rw-r--r-- | src/namestore/gnunet-service-namestore.c | 6 | ||||
-rw-r--r-- | src/namestore/plugin_namestore_postgres.c | 26 | ||||
-rw-r--r-- | src/namestore/test_namestore_api_edit_records.c | 404 | ||||
-rw-r--r-- | src/namestore/test_namestore_api_postgres.conf | 2 | ||||
-rw-r--r-- | src/namestore/test_namestore_api_tx_rollback.c | 268 | ||||
-rw-r--r-- | src/pq/pq.c | 4 | ||||
-rw-r--r-- | src/pq/pq_exec.c | 4 |
9 files changed, 715 insertions, 21 deletions
diff --git a/src/include/gnunet_namestore_service.h b/src/include/gnunet_namestore_service.h index 68aeebef8..0788bc8b4 100644 --- a/src/include/gnunet_namestore_service.h +++ b/src/include/gnunet_namestore_service.h | |||
@@ -453,6 +453,16 @@ GNUNET_NAMESTORE_transaction_commit (struct GNUNET_NAMESTORE_Handle *h, | |||
453 | cont, | 453 | cont, |
454 | void *cont_cls); | 454 | void *cont_cls); |
455 | 455 | ||
456 | struct GNUNET_NAMESTORE_QueueEntry * | ||
457 | GNUNET_NAMESTORE_records_edit ( | ||
458 | struct GNUNET_NAMESTORE_Handle *h, | ||
459 | const struct GNUNET_IDENTITY_PrivateKey *pkey, | ||
460 | const char *label, | ||
461 | GNUNET_SCHEDULER_TaskCallback error_cb, | ||
462 | void *error_cb_cls, | ||
463 | GNUNET_NAMESTORE_RecordMonitor rm, | ||
464 | void *rm_cls); | ||
465 | |||
456 | #if 0 /* keep Emacsens' auto-indent happy */ | 466 | #if 0 /* keep Emacsens' auto-indent happy */ |
457 | { | 467 | { |
458 | #endif | 468 | #endif |
diff --git a/src/namestore/Makefile.am b/src/namestore/Makefile.am index e3c1825d3..b71896894 100644 --- a/src/namestore/Makefile.am +++ b/src/namestore/Makefile.am | |||
@@ -58,7 +58,8 @@ POSTGRES_TESTS = test_plugin_namestore_postgres \ | |||
58 | test_namestore_api_monitoring_existing_postgres \ | 58 | test_namestore_api_monitoring_existing_postgres \ |
59 | test_namestore_api_zone_to_name_postgres \ | 59 | test_namestore_api_zone_to_name_postgres \ |
60 | perf_namestore_api_zone_iteration_postgres \ | 60 | perf_namestore_api_zone_iteration_postgres \ |
61 | test_namestore_api_tx_rollback_postgres | 61 | test_namestore_api_tx_rollback_postgres \ |
62 | test_namestore_api_edit_records_postgres | ||
62 | endif | 63 | endif |
63 | 64 | ||
64 | if HAVE_SQLITE | 65 | if HAVE_SQLITE |
@@ -442,7 +443,14 @@ test_namestore_api_tx_rollback_postgres_LDADD = \ | |||
442 | $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ | 443 | $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ |
443 | $(top_builddir)/src/util/libgnunetutil.la | 444 | $(top_builddir)/src/util/libgnunetutil.la |
444 | 445 | ||
445 | 446 | test_namestore_api_edit_records_postgres_SOURCES = \ | |
447 | test_namestore_api_edit_records.c | ||
448 | test_namestore_api_edit_records_postgres_LDADD = \ | ||
449 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
450 | $(top_builddir)/src/identity/libgnunetidentity.la \ | ||
451 | libgnunetnamestore.la \ | ||
452 | $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ | ||
453 | $(top_builddir)/src/util/libgnunetutil.la | ||
446 | 454 | ||
447 | test_namestore_api_zone_iteration_sqlite_SOURCES = \ | 455 | test_namestore_api_zone_iteration_sqlite_SOURCES = \ |
448 | test_namestore_api_zone_iteration.c | 456 | test_namestore_api_zone_iteration.c |
diff --git a/src/namestore/gnunet-service-namestore.c b/src/namestore/gnunet-service-namestore.c index 100f155fa..c1d7b8753 100644 --- a/src/namestore/gnunet-service-namestore.c +++ b/src/namestore/gnunet-service-namestore.c | |||
@@ -1428,7 +1428,7 @@ handle_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg) | |||
1428 | rlc.res_rd = NULL; | 1428 | rlc.res_rd = NULL; |
1429 | rlc.rd_ser_len = 0; | 1429 | rlc.rd_ser_len = 0; |
1430 | rlc.nick = get_nick_record (nc, &ll_msg->zone); | 1430 | rlc.nick = get_nick_record (nc, &ll_msg->zone); |
1431 | if (GNUNET_YES == ntohl (ll_msg->is_edit_request)) | 1431 | if (GNUNET_YES != ntohl (ll_msg->is_edit_request)) |
1432 | res = nc->GSN_database->lookup_records (nc->GSN_database->cls, | 1432 | res = nc->GSN_database->lookup_records (nc->GSN_database->cls, |
1433 | &ll_msg->zone, | 1433 | &ll_msg->zone, |
1434 | conv_name, | 1434 | conv_name, |
@@ -1451,7 +1451,9 @@ handle_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg) | |||
1451 | llr_msg->rd_count = htons (rlc.res_rd_count); | 1451 | llr_msg->rd_count = htons (rlc.res_rd_count); |
1452 | llr_msg->rd_len = htons (rlc.rd_ser_len); | 1452 | llr_msg->rd_len = htons (rlc.rd_ser_len); |
1453 | res_name = (char *) &llr_msg[1]; | 1453 | res_name = (char *) &llr_msg[1]; |
1454 | if ((GNUNET_YES == rlc.found) && (GNUNET_OK == res)) | 1454 | if (GNUNET_OK != res) |
1455 | llr_msg->found = htons (GNUNET_SYSERR); | ||
1456 | else if (GNUNET_YES == rlc.found) | ||
1455 | llr_msg->found = htons (GNUNET_YES); | 1457 | llr_msg->found = htons (GNUNET_YES); |
1456 | else | 1458 | else |
1457 | llr_msg->found = htons (GNUNET_NO); | 1459 | llr_msg->found = htons (GNUNET_NO); |
diff --git a/src/namestore/plugin_namestore_postgres.c b/src/namestore/plugin_namestore_postgres.c index 2d4c5d089..510d24496 100644 --- a/src/namestore/plugin_namestore_postgres.c +++ b/src/namestore/plugin_namestore_postgres.c | |||
@@ -153,7 +153,7 @@ database_setup (struct Plugin *plugin) | |||
153 | 2), | 153 | 2), |
154 | GNUNET_PQ_make_prepare ("edit_set", | 154 | GNUNET_PQ_make_prepare ("edit_set", |
155 | "SELECT seq,record_count,record_data,label " | 155 | "SELECT seq,record_count,record_data,label " |
156 | "FROM ns098records WHERE zone_private_key=$1 AND label=$2 FOR UPDATE", | 156 | "FROM ns098records WHERE zone_private_key=$1 AND label=$2 FOR UPDATE NOWAIT", |
157 | 2), | 157 | 2), |
158 | GNUNET_PQ_PREPARED_STATEMENT_END | 158 | GNUNET_PQ_PREPARED_STATEMENT_END |
159 | }; | 159 | }; |
@@ -328,6 +328,8 @@ parse_result_call_iterator (void *cls, | |||
328 | 328 | ||
329 | if (NULL == pc->iter) | 329 | if (NULL == pc->iter) |
330 | return; /* no need to do more work */ | 330 | return; /* no need to do more work */ |
331 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
332 | "Got %d results from PQ.\n", num_results); | ||
331 | for (unsigned int i = 0; i < num_results; i++) | 333 | for (unsigned int i = 0; i < num_results; i++) |
332 | { | 334 | { |
333 | uint64_t serial; | 335 | uint64_t serial; |
@@ -412,12 +414,12 @@ parse_result_call_iterator (void *cls, | |||
412 | */ | 414 | */ |
413 | static int | 415 | static int |
414 | lookup_records (void *cls, | 416 | lookup_records (void *cls, |
415 | const struct | 417 | const struct |
416 | GNUNET_IDENTITY_PrivateKey *zone, | 418 | GNUNET_IDENTITY_PrivateKey *zone, |
417 | const char *label, | 419 | const char *label, |
418 | GNUNET_NAMESTORE_RecordIterator iter, | 420 | GNUNET_NAMESTORE_RecordIterator iter, |
419 | void *iter_cls, | 421 | void *iter_cls, |
420 | const char* method) | 422 | const char*method) |
421 | { | 423 | { |
422 | struct Plugin *plugin = cls; | 424 | struct Plugin *plugin = cls; |
423 | struct GNUNET_PQ_QueryParam params[] = { | 425 | struct GNUNET_PQ_QueryParam params[] = { |
@@ -481,11 +483,11 @@ namestore_postgres_lookup_records (void *cls, | |||
481 | */ | 483 | */ |
482 | static int | 484 | static int |
483 | namestore_postgres_edit_records (void *cls, | 485 | namestore_postgres_edit_records (void *cls, |
484 | const struct | 486 | const struct |
485 | GNUNET_IDENTITY_PrivateKey *zone, | 487 | GNUNET_IDENTITY_PrivateKey *zone, |
486 | const char *label, | 488 | const char *label, |
487 | GNUNET_NAMESTORE_RecordIterator iter, | 489 | GNUNET_NAMESTORE_RecordIterator iter, |
488 | void *iter_cls) | 490 | void *iter_cls) |
489 | { | 491 | { |
490 | return lookup_records (cls, zone, label, iter, iter_cls, "edit_set"); | 492 | return lookup_records (cls, zone, label, iter, iter_cls, "edit_set"); |
491 | } | 493 | } |
diff --git a/src/namestore/test_namestore_api_edit_records.c b/src/namestore/test_namestore_api_edit_records.c new file mode 100644 index 000000000..c1c64ee9c --- /dev/null +++ b/src/namestore/test_namestore_api_edit_records.c | |||
@@ -0,0 +1,404 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file namestore/test_namestore_api_edit_records.c | ||
22 | * @brief testcase for namestore_api.c: Multiple clients work with record set. | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_namestore_service.h" | ||
26 | #include "gnunet_testing_lib.h" | ||
27 | #include "gnunet_dnsparser_lib.h" | ||
28 | |||
29 | #define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT | ||
30 | |||
31 | #define TEST_RECORD_DATALEN 123 | ||
32 | |||
33 | #define TEST_RECORD_DATA 'a' | ||
34 | |||
35 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100) | ||
36 | |||
37 | |||
38 | static struct GNUNET_NAMESTORE_Handle *nsh; | ||
39 | |||
40 | static struct GNUNET_NAMESTORE_Handle *nsh2; | ||
41 | |||
42 | static struct GNUNET_SCHEDULER_Task *endbadly_task; | ||
43 | |||
44 | static struct GNUNET_IDENTITY_PrivateKey privkey; | ||
45 | |||
46 | static struct GNUNET_IDENTITY_PublicKey pubkey; | ||
47 | |||
48 | static int res; | ||
49 | |||
50 | static int removed; | ||
51 | |||
52 | static struct GNUNET_NAMESTORE_QueueEntry *nsqe; | ||
53 | |||
54 | static int nonce = 0; | ||
55 | |||
56 | static void | ||
57 | cleanup () | ||
58 | { | ||
59 | if (NULL != nsh) | ||
60 | { | ||
61 | GNUNET_NAMESTORE_disconnect (nsh); | ||
62 | nsh = NULL; | ||
63 | } | ||
64 | GNUNET_SCHEDULER_shutdown (); | ||
65 | } | ||
66 | |||
67 | |||
68 | /** | ||
69 | * Re-establish the connection to the service. | ||
70 | * | ||
71 | * @param cls handle to use to re-connect. | ||
72 | */ | ||
73 | static void | ||
74 | endbadly (void *cls) | ||
75 | { | ||
76 | if (NULL != nsqe) | ||
77 | { | ||
78 | GNUNET_NAMESTORE_cancel (nsqe); | ||
79 | nsqe = NULL; | ||
80 | } | ||
81 | cleanup (); | ||
82 | res = 1; | ||
83 | } | ||
84 | |||
85 | |||
86 | static void | ||
87 | end (void *cls) | ||
88 | { | ||
89 | cleanup (); | ||
90 | res = 0; | ||
91 | } | ||
92 | |||
93 | static void | ||
94 | lookup_it (void *cls, | ||
95 | const struct GNUNET_IDENTITY_PrivateKey *zone, | ||
96 | const char *label, | ||
97 | unsigned int rd_count, | ||
98 | const struct GNUNET_GNSRECORD_Data *rd) | ||
99 | { | ||
100 | GNUNET_assert (0 == rd_count); | ||
101 | GNUNET_SCHEDULER_add_now (&end, NULL); | ||
102 | } | ||
103 | |||
104 | static void | ||
105 | fail_cb (void *cls) | ||
106 | { | ||
107 | if (endbadly_task != NULL) | ||
108 | GNUNET_SCHEDULER_cancel (endbadly_task); | ||
109 | endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL); | ||
110 | return; | ||
111 | } | ||
112 | |||
113 | static void | ||
114 | remove_cont (void *cls, | ||
115 | int32_t success, | ||
116 | const char *emsg) | ||
117 | { | ||
118 | nsqe = NULL; | ||
119 | if (GNUNET_YES != success) | ||
120 | { | ||
121 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
122 | _ ("Unable to roll back: `%s'\n"), | ||
123 | emsg); | ||
124 | if (NULL != endbadly_task) | ||
125 | GNUNET_SCHEDULER_cancel (endbadly_task); | ||
126 | endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, | ||
127 | NULL); | ||
128 | return; | ||
129 | } | ||
130 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
131 | "Rolled back, perform lookup\n"); | ||
132 | removed = GNUNET_YES; | ||
133 | if (NULL != endbadly_task) | ||
134 | GNUNET_SCHEDULER_cancel (endbadly_task); | ||
135 | GNUNET_SCHEDULER_add_now (&end, NULL); | ||
136 | } | ||
137 | |||
138 | static void | ||
139 | fail_cb_lock (void *cls); | ||
140 | |||
141 | static void | ||
142 | edit_cont_b (void *cls, | ||
143 | const struct GNUNET_IDENTITY_PrivateKey *zone, | ||
144 | const char *label, | ||
145 | unsigned int rd_count, | ||
146 | const struct GNUNET_GNSRECORD_Data *rd) | ||
147 | { | ||
148 | const char *name = cls; | ||
149 | /** | ||
150 | * We should probably never get here right at first. | ||
151 | * We may want to change the blocking of nsh2 so that we do get this | ||
152 | * eventually instead of the error callback above when locked. | ||
153 | */ | ||
154 | if (0 == nonce) | ||
155 | { | ||
156 | if (endbadly_task != NULL) | ||
157 | GNUNET_SCHEDULER_cancel (endbadly_task); | ||
158 | endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL); | ||
159 | return; | ||
160 | |||
161 | } | ||
162 | /* Abort transaction for B */ | ||
163 | nsqe = GNUNET_NAMESTORE_transaction_rollback (nsh2, remove_cont, | ||
164 | (void *) name); | ||
165 | } | ||
166 | |||
167 | |||
168 | static void | ||
169 | commit_cont_a (void *cls, | ||
170 | int32_t success, | ||
171 | const char *emsg) | ||
172 | { | ||
173 | const char *name = cls; | ||
174 | |||
175 | GNUNET_assert (NULL != cls); | ||
176 | nsqe = NULL; | ||
177 | if (GNUNET_SYSERR == success) | ||
178 | { | ||
179 | GNUNET_break (0); | ||
180 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
181 | "Namestore could not store record: `%s'\n", | ||
182 | emsg); | ||
183 | if (endbadly_task != NULL) | ||
184 | GNUNET_SCHEDULER_cancel (endbadly_task); | ||
185 | endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL); | ||
186 | return; | ||
187 | } | ||
188 | |||
189 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
190 | "Name store added record for `%s': %s\n", | ||
191 | name, | ||
192 | (success == GNUNET_OK) ? "SUCCESS" : "FAIL"); | ||
193 | /** | ||
194 | * Try again for B | ||
195 | */ | ||
196 | nsqe = GNUNET_NAMESTORE_records_edit (nsh2, | ||
197 | &privkey, | ||
198 | name, | ||
199 | &fail_cb_lock, | ||
200 | (void *) name, | ||
201 | &edit_cont_b, | ||
202 | (void *) name); | ||
203 | |||
204 | GNUNET_assert (NULL != nsqe); | ||
205 | } | ||
206 | |||
207 | static void | ||
208 | fail_cb_lock (void *cls) | ||
209 | { | ||
210 | const char *name = cls; | ||
211 | if (1 == nonce) | ||
212 | { | ||
213 | if (endbadly_task != NULL) | ||
214 | GNUNET_SCHEDULER_cancel (endbadly_task); | ||
215 | endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL); | ||
216 | return; | ||
217 | } | ||
218 | nonce = 1; | ||
219 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
220 | "Failed to aquire additional lock\n"); | ||
221 | /* Now, we stop the transaction for B */ | ||
222 | nsqe = GNUNET_NAMESTORE_transaction_commit (nsh, commit_cont_a, | ||
223 | (void *) name); | ||
224 | } | ||
225 | |||
226 | |||
227 | static void | ||
228 | begin_cont_b (void *cls, | ||
229 | int32_t success, | ||
230 | const char *emsg) | ||
231 | { | ||
232 | const char *name = cls; | ||
233 | |||
234 | GNUNET_assert (success == GNUNET_YES); | ||
235 | /** Now, we expect this to "hang" let's see how this behaves in practice. */ | ||
236 | nsqe = GNUNET_NAMESTORE_records_edit (nsh2, | ||
237 | &privkey, | ||
238 | name, | ||
239 | &fail_cb_lock, | ||
240 | (void *) name, | ||
241 | &edit_cont_b, | ||
242 | (void *) name); | ||
243 | |||
244 | GNUNET_assert (NULL != nsqe); | ||
245 | } | ||
246 | |||
247 | |||
248 | static void | ||
249 | edit_cont (void *cls, | ||
250 | const struct GNUNET_IDENTITY_PrivateKey *zone, | ||
251 | const char *label, | ||
252 | unsigned int rd_count, | ||
253 | const struct GNUNET_GNSRECORD_Data *rd) | ||
254 | { | ||
255 | const char *name = cls; | ||
256 | |||
257 | GNUNET_assert (1 == rd_count); | ||
258 | /* Now, we start a transaction for B */ | ||
259 | nsqe = GNUNET_NAMESTORE_transaction_begin (nsh2, begin_cont_b, (void *) name); | ||
260 | } | ||
261 | |||
262 | |||
263 | static void | ||
264 | begin_cont (void *cls, | ||
265 | int32_t success, | ||
266 | const char *emsg) | ||
267 | { | ||
268 | const char *name = cls; | ||
269 | |||
270 | GNUNET_assert (success == GNUNET_YES); | ||
271 | nsqe = GNUNET_NAMESTORE_records_edit (nsh, | ||
272 | &privkey, | ||
273 | name, | ||
274 | &fail_cb, | ||
275 | (void *) name, | ||
276 | &edit_cont, | ||
277 | (void *) name); | ||
278 | |||
279 | GNUNET_assert (NULL != nsqe); | ||
280 | } | ||
281 | |||
282 | static void | ||
283 | preload_cont (void *cls, | ||
284 | int32_t success, | ||
285 | const char *emsg) | ||
286 | { | ||
287 | const char *name = cls; | ||
288 | |||
289 | GNUNET_assert (NULL != cls); | ||
290 | nsqe = NULL; | ||
291 | if (GNUNET_SYSERR == success) | ||
292 | { | ||
293 | GNUNET_break (0); | ||
294 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
295 | "Namestore could not store record: `%s'\n", | ||
296 | emsg); | ||
297 | if (endbadly_task != NULL) | ||
298 | GNUNET_SCHEDULER_cancel (endbadly_task); | ||
299 | endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL); | ||
300 | return; | ||
301 | } | ||
302 | |||
303 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
304 | "Name store added record for `%s': %s\n", | ||
305 | name, | ||
306 | (success == GNUNET_OK) ? "SUCCESS" : "FAIL"); | ||
307 | /* We start transaction for A */ | ||
308 | nsqe = GNUNET_NAMESTORE_transaction_begin (nsh, begin_cont, (void *) name); | ||
309 | |||
310 | } | ||
311 | |||
312 | |||
313 | static void | ||
314 | run (void *cls, | ||
315 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
316 | struct GNUNET_TESTING_Peer *peer) | ||
317 | { | ||
318 | struct GNUNET_GNSRECORD_Data rd; | ||
319 | const char *name = "dummy"; | ||
320 | |||
321 | endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, | ||
322 | &endbadly, | ||
323 | NULL); | ||
324 | nsh = GNUNET_NAMESTORE_connect (cfg); | ||
325 | nsh2 = GNUNET_NAMESTORE_connect (cfg); | ||
326 | GNUNET_break (NULL != nsh); | ||
327 | GNUNET_break (NULL != nsh2); | ||
328 | |||
329 | privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY); | ||
330 | GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key); | ||
331 | GNUNET_IDENTITY_key_get_public (&privkey, | ||
332 | &pubkey); | ||
333 | |||
334 | removed = GNUNET_NO; | ||
335 | |||
336 | rd.expiration_time = GNUNET_TIME_absolute_get ().abs_value_us; | ||
337 | rd.record_type = TEST_RECORD_TYPE; | ||
338 | rd.data_size = TEST_RECORD_DATALEN; | ||
339 | rd.data = GNUNET_malloc (TEST_RECORD_DATALEN); | ||
340 | rd.flags = 0; | ||
341 | memset ((char *) rd.data, | ||
342 | 'a', | ||
343 | TEST_RECORD_DATALEN); | ||
344 | nsqe = GNUNET_NAMESTORE_records_store (nsh, | ||
345 | &privkey, | ||
346 | name, | ||
347 | 1, | ||
348 | &rd, | ||
349 | &preload_cont, | ||
350 | (void *) name); | ||
351 | GNUNET_assert (NULL != nsqe); | ||
352 | GNUNET_free_nz ((void *) rd.data); | ||
353 | |||
354 | /*nsqe = GNUNET_NAMESTORE_transaction_commit (nsh, commit_cont); | ||
355 | nsqe = GNUNET_NAMESTORE_transaction_rollback (nsh, rollback_cont); Must also happen on disconnect | ||
356 | nsqe = GNUNET_NAMESTORE_records_edit (nsh, | ||
357 | &privkey, | ||
358 | name, | ||
359 | 1, | ||
360 | &rd, | ||
361 | &edit_cont, | ||
362 | (void *) name); | ||
363 | nsqe = GNUNET_NAMESTORE_records_insert_bulk (nsh, | ||
364 | count, | ||
365 | &rd, | ||
366 | & | ||
367 | nsqe = GNUNET_NAMESTORE_records_store (nsh, | ||
368 | &privkey, | ||
369 | name, | ||
370 | 1, | ||
371 | &rd, | ||
372 | &put_cont, | ||
373 | (void *) name);*/ | ||
374 | GNUNET_assert (NULL != nsqe); | ||
375 | } | ||
376 | |||
377 | |||
378 | #include "test_common.c" | ||
379 | |||
380 | |||
381 | int | ||
382 | main (int argc, char *argv[]) | ||
383 | { | ||
384 | const char *plugin_name; | ||
385 | char *cfg_name; | ||
386 | |||
387 | SETUP_CFG (plugin_name, cfg_name); | ||
388 | res = 1; | ||
389 | if (0 != | ||
390 | GNUNET_TESTING_peer_run ("test-namestore-api-remove", | ||
391 | cfg_name, | ||
392 | &run, | ||
393 | NULL)) | ||
394 | { | ||
395 | res = 1; | ||
396 | } | ||
397 | GNUNET_DISK_purge_cfg_dir (cfg_name, | ||
398 | "GNUNET_TEST_HOME"); | ||
399 | GNUNET_free (cfg_name); | ||
400 | return res; | ||
401 | } | ||
402 | |||
403 | |||
404 | /* end of test_namestore_api_remove.c */ | ||
diff --git a/src/namestore/test_namestore_api_postgres.conf b/src/namestore/test_namestore_api_postgres.conf index 93ef935b5..c648a6ab9 100644 --- a/src/namestore/test_namestore_api_postgres.conf +++ b/src/namestore/test_namestore_api_postgres.conf | |||
@@ -6,4 +6,4 @@ DATABASE = postgres | |||
6 | 6 | ||
7 | [namestore-postgres] | 7 | [namestore-postgres] |
8 | CONFIG = connect_timeout=10 dbname=gnunetcheck | 8 | CONFIG = connect_timeout=10 dbname=gnunetcheck |
9 | TEMPORARY_TABLE = YES | 9 | TEMPORARY_TABLE = NO |
diff --git a/src/namestore/test_namestore_api_tx_rollback.c b/src/namestore/test_namestore_api_tx_rollback.c new file mode 100644 index 000000000..ccfd8d701 --- /dev/null +++ b/src/namestore/test_namestore_api_tx_rollback.c | |||
@@ -0,0 +1,268 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2022 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file namestore/test_namestore_api_tx_rollback.c | ||
22 | * @brief testcase for namestore_api_tx_rollback.c to: rollback changes in TX | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_namestore_service.h" | ||
26 | #include "gnunet_testing_lib.h" | ||
27 | #include "gnunet_dnsparser_lib.h" | ||
28 | |||
29 | #define TEST_RECORD_TYPE GNUNET_DNSPARSER_TYPE_TXT | ||
30 | |||
31 | #define TEST_RECORD_DATALEN 123 | ||
32 | |||
33 | #define TEST_RECORD_DATA 'a' | ||
34 | |||
35 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100) | ||
36 | |||
37 | |||
38 | static struct GNUNET_NAMESTORE_Handle *nsh; | ||
39 | |||
40 | static struct GNUNET_SCHEDULER_Task *endbadly_task; | ||
41 | |||
42 | static struct GNUNET_IDENTITY_PrivateKey privkey; | ||
43 | |||
44 | static struct GNUNET_IDENTITY_PublicKey pubkey; | ||
45 | |||
46 | static int res; | ||
47 | |||
48 | static int removed; | ||
49 | |||
50 | static struct GNUNET_NAMESTORE_QueueEntry *nsqe; | ||
51 | |||
52 | |||
53 | static void | ||
54 | cleanup () | ||
55 | { | ||
56 | if (NULL != nsh) | ||
57 | { | ||
58 | GNUNET_NAMESTORE_disconnect (nsh); | ||
59 | nsh = NULL; | ||
60 | } | ||
61 | GNUNET_SCHEDULER_shutdown (); | ||
62 | } | ||
63 | |||
64 | |||
65 | /** | ||
66 | * Re-establish the connection to the service. | ||
67 | * | ||
68 | * @param cls handle to use to re-connect. | ||
69 | */ | ||
70 | static void | ||
71 | endbadly (void *cls) | ||
72 | { | ||
73 | if (NULL != nsqe) | ||
74 | { | ||
75 | GNUNET_NAMESTORE_cancel (nsqe); | ||
76 | nsqe = NULL; | ||
77 | } | ||
78 | cleanup (); | ||
79 | res = 1; | ||
80 | } | ||
81 | |||
82 | |||
83 | static void | ||
84 | end (void *cls) | ||
85 | { | ||
86 | cleanup (); | ||
87 | res = 0; | ||
88 | } | ||
89 | |||
90 | static void | ||
91 | lookup_it (void *cls, | ||
92 | const struct GNUNET_IDENTITY_PrivateKey *zone, | ||
93 | const char *label, | ||
94 | unsigned int rd_count, | ||
95 | const struct GNUNET_GNSRECORD_Data *rd) | ||
96 | { | ||
97 | GNUNET_assert (0 == rd_count); | ||
98 | GNUNET_SCHEDULER_add_now (&end, NULL); | ||
99 | } | ||
100 | |||
101 | static void | ||
102 | fail_cb (void *cls) | ||
103 | { | ||
104 | GNUNET_assert (0); | ||
105 | } | ||
106 | |||
107 | static void | ||
108 | remove_cont (void *cls, | ||
109 | int32_t success, | ||
110 | const char *emsg) | ||
111 | { | ||
112 | nsqe = NULL; | ||
113 | if (GNUNET_YES != success) | ||
114 | { | ||
115 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
116 | _ ("Unable to roll back: `%s'\n"), | ||
117 | emsg); | ||
118 | if (NULL != endbadly_task) | ||
119 | GNUNET_SCHEDULER_cancel (endbadly_task); | ||
120 | endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, | ||
121 | NULL); | ||
122 | return; | ||
123 | } | ||
124 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
125 | "Rolled back, perform lookup\n"); | ||
126 | removed = GNUNET_YES; | ||
127 | if (NULL != endbadly_task) | ||
128 | GNUNET_SCHEDULER_cancel (endbadly_task); | ||
129 | /* FIXME not actually doing lookup here */ | ||
130 | nsqe = GNUNET_NAMESTORE_records_lookup (nsh, | ||
131 | &privkey, | ||
132 | (char*) cls, | ||
133 | &fail_cb, | ||
134 | NULL, | ||
135 | &lookup_it, | ||
136 | NULL); | ||
137 | } | ||
138 | |||
139 | |||
140 | static void | ||
141 | put_cont (void *cls, | ||
142 | int32_t success, | ||
143 | const char *emsg) | ||
144 | { | ||
145 | const char *name = cls; | ||
146 | |||
147 | GNUNET_assert (NULL != cls); | ||
148 | nsqe = NULL; | ||
149 | if (GNUNET_SYSERR == success) | ||
150 | { | ||
151 | GNUNET_break (0); | ||
152 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
153 | "Namestore could not store record: `%s'\n", | ||
154 | emsg); | ||
155 | if (endbadly_task != NULL) | ||
156 | GNUNET_SCHEDULER_cancel (endbadly_task); | ||
157 | endbadly_task = GNUNET_SCHEDULER_add_now (&endbadly, NULL); | ||
158 | return; | ||
159 | } | ||
160 | |||
161 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
162 | "Name store added record for `%s': %s\n", | ||
163 | name, | ||
164 | (success == GNUNET_OK) ? "SUCCESS" : "FAIL"); | ||
165 | nsqe = GNUNET_NAMESTORE_transaction_rollback (nsh, remove_cont, | ||
166 | (void *) name); | ||
167 | } | ||
168 | |||
169 | static void | ||
170 | begin_cont (void *cls, | ||
171 | int32_t success, | ||
172 | const char *emsg) | ||
173 | { | ||
174 | struct GNUNET_GNSRECORD_Data rd; | ||
175 | const char *name = cls; | ||
176 | |||
177 | GNUNET_assert (success == GNUNET_YES); | ||
178 | privkey.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY); | ||
179 | GNUNET_CRYPTO_ecdsa_key_create (&privkey.ecdsa_key); | ||
180 | GNUNET_IDENTITY_key_get_public (&privkey, | ||
181 | &pubkey); | ||
182 | |||
183 | removed = GNUNET_NO; | ||
184 | |||
185 | rd.expiration_time = GNUNET_TIME_absolute_get ().abs_value_us; | ||
186 | rd.record_type = TEST_RECORD_TYPE; | ||
187 | rd.data_size = TEST_RECORD_DATALEN; | ||
188 | rd.data = GNUNET_malloc (TEST_RECORD_DATALEN); | ||
189 | rd.flags = 0; | ||
190 | memset ((char *) rd.data, | ||
191 | 'a', | ||
192 | TEST_RECORD_DATALEN); | ||
193 | nsqe = GNUNET_NAMESTORE_records_store (nsh, | ||
194 | &privkey, | ||
195 | name, | ||
196 | 1, | ||
197 | &rd, | ||
198 | &put_cont, | ||
199 | (void *) name); | ||
200 | GNUNET_assert (NULL != nsqe); | ||
201 | GNUNET_free_nz ((void *) rd.data); | ||
202 | } | ||
203 | |||
204 | static void | ||
205 | run (void *cls, | ||
206 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
207 | struct GNUNET_TESTING_Peer *peer) | ||
208 | { | ||
209 | struct GNUNET_GNSRECORD_Data rd; | ||
210 | const char *name = "dummy"; | ||
211 | |||
212 | endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, | ||
213 | &endbadly, | ||
214 | NULL); | ||
215 | nsh = GNUNET_NAMESTORE_connect (cfg); | ||
216 | GNUNET_break (NULL != nsh); | ||
217 | nsqe = GNUNET_NAMESTORE_transaction_begin (nsh, begin_cont, (void *) name); | ||
218 | /*nsqe = GNUNET_NAMESTORE_transaction_commit (nsh, commit_cont); | ||
219 | nsqe = GNUNET_NAMESTORE_transaction_rollback (nsh, rollback_cont); Must also happen on disconnect | ||
220 | nsqe = GNUNET_NAMESTORE_records_edit (nsh, | ||
221 | &privkey, | ||
222 | name, | ||
223 | 1, | ||
224 | &rd, | ||
225 | &edit_cont, | ||
226 | (void *) name); | ||
227 | nsqe = GNUNET_NAMESTORE_records_insert_bulk (nsh, | ||
228 | count, | ||
229 | &rd, | ||
230 | & | ||
231 | nsqe = GNUNET_NAMESTORE_records_store (nsh, | ||
232 | &privkey, | ||
233 | name, | ||
234 | 1, | ||
235 | &rd, | ||
236 | &put_cont, | ||
237 | (void *) name);*/ | ||
238 | GNUNET_assert (NULL != nsqe); | ||
239 | } | ||
240 | |||
241 | |||
242 | #include "test_common.c" | ||
243 | |||
244 | |||
245 | int | ||
246 | main (int argc, char *argv[]) | ||
247 | { | ||
248 | const char *plugin_name; | ||
249 | char *cfg_name; | ||
250 | |||
251 | SETUP_CFG (plugin_name, cfg_name); | ||
252 | res = 1; | ||
253 | if (0 != | ||
254 | GNUNET_TESTING_peer_run ("test-namestore-api-remove", | ||
255 | cfg_name, | ||
256 | &run, | ||
257 | NULL)) | ||
258 | { | ||
259 | res = 1; | ||
260 | } | ||
261 | GNUNET_DISK_purge_cfg_dir (cfg_name, | ||
262 | "GNUNET_TEST_HOME"); | ||
263 | GNUNET_free (cfg_name); | ||
264 | return res; | ||
265 | } | ||
266 | |||
267 | |||
268 | /* end of test_namestore_api_remove.c */ | ||
diff --git a/src/pq/pq.c b/src/pq/pq.c index 130ff355f..c8deb8193 100644 --- a/src/pq/pq.c +++ b/src/pq/pq.c | |||
@@ -97,9 +97,9 @@ GNUNET_PQ_exec_prepared (struct GNUNET_PQ_Context *db, | |||
97 | 1); | 97 | 1); |
98 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, | 98 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, |
99 | "pq", | 99 | "pq", |
100 | "Execution of prepared SQL statement `%s' finished (%d)\n", | 100 | "Execution of prepared SQL statement `%s' finished (%s)\n", |
101 | name, | 101 | name, |
102 | PGRES_COMMAND_OK == PQresultStatus (res)); | 102 | PQresStatus (PQresultStatus (res))); |
103 | if ( (PGRES_COMMAND_OK != PQresultStatus (res)) && | 103 | if ( (PGRES_COMMAND_OK != PQresultStatus (res)) && |
104 | (CONNECTION_OK != (status = PQstatus (db->conn))) ) | 104 | (CONNECTION_OK != (status = PQstatus (db->conn))) ) |
105 | { | 105 | { |
diff --git a/src/pq/pq_exec.c b/src/pq/pq_exec.c index dcde331b6..62dd577ad 100644 --- a/src/pq/pq_exec.c +++ b/src/pq/pq_exec.c | |||
@@ -87,10 +87,10 @@ GNUNET_PQ_exec_statements (struct GNUNET_PQ_Context *db, | |||
87 | result = PQexec (db->conn, | 87 | result = PQexec (db->conn, |
88 | es[i].sql); | 88 | es[i].sql); |
89 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 89 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
90 | "Running statement `%s' on %p finished (%d)\n", | 90 | "Running statement `%s' on %p finished (%s)\n", |
91 | es[i].sql, | 91 | es[i].sql, |
92 | db, | 92 | db, |
93 | PGRES_COMMAND_OK == PQresultStatus (result)); | 93 | PQresStatus (PQresultStatus (result))); |
94 | if ((GNUNET_NO == es[i].ignore_errors) && | 94 | if ((GNUNET_NO == es[i].ignore_errors) && |
95 | (PGRES_COMMAND_OK != PQresultStatus (result))) | 95 | (PGRES_COMMAND_OK != PQresultStatus (result))) |
96 | { | 96 | { |