aboutsummaryrefslogtreecommitdiff
path: root/src/namestore/test_namestore_api_edit_records.c
diff options
context:
space:
mode:
authorMartin Schanzenbach <schanzen@gnunet.org>2022-09-23 16:39:21 +0900
committerMartin Schanzenbach <schanzen@gnunet.org>2022-09-23 16:39:21 +0900
commite0e36b6feba6cbcbbb3516d3a9de4d6fd0199825 (patch)
tree77429f5da157e6c002cdb0d31dfb44da0cc48123 /src/namestore/test_namestore_api_edit_records.c
parent7678d77b1cb0dcfd8887016d35b27fbedb136050 (diff)
downloadgnunet-e0e36b6feba6cbcbbb3516d3a9de4d6fd0199825.tar.gz
gnunet-e0e36b6feba6cbcbbb3516d3a9de4d6fd0199825.zip
NAMESTORE: Towards proper transactional locks
Diffstat (limited to 'src/namestore/test_namestore_api_edit_records.c')
-rw-r--r--src/namestore/test_namestore_api_edit_records.c404
1 files changed, 404 insertions, 0 deletions
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
38static struct GNUNET_NAMESTORE_Handle *nsh;
39
40static struct GNUNET_NAMESTORE_Handle *nsh2;
41
42static struct GNUNET_SCHEDULER_Task *endbadly_task;
43
44static struct GNUNET_IDENTITY_PrivateKey privkey;
45
46static struct GNUNET_IDENTITY_PublicKey pubkey;
47
48static int res;
49
50static int removed;
51
52static struct GNUNET_NAMESTORE_QueueEntry *nsqe;
53
54static int nonce = 0;
55
56static void
57cleanup ()
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 */
73static void
74endbadly (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
86static void
87end (void *cls)
88{
89 cleanup ();
90 res = 0;
91}
92
93static void
94lookup_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
104static void
105fail_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
113static void
114remove_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
138static void
139fail_cb_lock (void *cls);
140
141static void
142edit_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
168static void
169commit_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
207static void
208fail_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
227static void
228begin_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
248static void
249edit_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
263static void
264begin_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
282static void
283preload_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
313static void
314run (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
381int
382main (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 */