aboutsummaryrefslogtreecommitdiff
path: root/src/namestore/plugin_namestore_postgres.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/namestore/plugin_namestore_postgres.c')
-rw-r--r--src/namestore/plugin_namestore_postgres.c796
1 files changed, 0 insertions, 796 deletions
diff --git a/src/namestore/plugin_namestore_postgres.c b/src/namestore/plugin_namestore_postgres.c
deleted file mode 100644
index de819f196..000000000
--- a/src/namestore/plugin_namestore_postgres.c
+++ /dev/null
@@ -1,796 +0,0 @@
1/*
2 * This file is part of GNUnet
3 * Copyright (C) 2009-2013, 2016-2018 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/**
22 * @file namestore/plugin_namestore_postgres.c
23 * @brief postgres-based namestore backend
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_namestore_plugin.h"
28#include "gnunet_namestore_service.h"
29#include "gnunet_gnsrecord_lib.h"
30#include "gnunet_pq_lib.h"
31#include "namestore.h"
32
33
34#define LOG(kind, ...) GNUNET_log_from (kind, "namestore-postgres", __VA_ARGS__)
35
36
37/**
38 * Context for all functions in this plugin.
39 */
40struct Plugin
41{
42 /**
43 * Our configuration.
44 */
45 const struct GNUNET_CONFIGURATION_Handle *cfg;
46
47 /**
48 * Postgres database handle.
49 */
50 struct GNUNET_PQ_Context *dbh;
51
52 /**
53 * Database is prepared and ready
54 */
55 bool ready;
56};
57
58
59/**
60 * Initialize the database connections and associated data structures (create
61 * tables and indices as needed as well).
62 *
63 * @param cls the plugin context (state for this module)
64 * @return #GNUNET_OK on success
65 */
66static enum GNUNET_GenericReturnValue
67namestore_postgres_create_tables (void *cls)
68{
69 struct Plugin *plugin = cls;
70 struct GNUNET_PQ_Context *dbh;
71
72 dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
73 "namestore-postgres",
74 "namestore-",
75 NULL,
76 NULL);
77 if (NULL == dbh)
78 return GNUNET_SYSERR;
79 GNUNET_PQ_disconnect (dbh);
80 return GNUNET_OK;
81}
82
83
84/**
85 * Drop existing namestore tables.
86 *
87 * @param cls the plugin context (state for this module)
88 * @return #GNUNET_OK on success
89 */
90static enum GNUNET_GenericReturnValue
91namestore_postgres_drop_tables (void *cls)
92{
93 struct Plugin *plugin = cls;
94 struct GNUNET_PQ_Context *dbh;
95 enum GNUNET_GenericReturnValue ret;
96
97 dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
98 "namestore-postgres",
99 NULL,
100 NULL,
101 NULL);
102 if (NULL == dbh)
103 {
104 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
105 "Failed to connect to database\n");
106 return GNUNET_SYSERR;
107 }
108 ret = GNUNET_PQ_exec_sql (dbh,
109 "namestore-drop");
110 GNUNET_PQ_disconnect (dbh);
111 return ret;
112}
113
114
115static enum GNUNET_GenericReturnValue
116database_prepare (struct Plugin *plugin)
117{
118 enum GNUNET_GenericReturnValue ret;
119
120 if (plugin->ready)
121 return GNUNET_OK;
122 {
123 struct GNUNET_PQ_PreparedStatement ps[] = {
124 GNUNET_PQ_make_prepare ("store_records",
125 "INSERT INTO namestore.ns098records"
126 " (zone_private_key, pkey, rvalue, record_count, record_data, label)"
127 " VALUES ($1, $2, $3, $4, $5, $6)"
128 " ON CONFLICT ON CONSTRAINT zl"
129 " DO UPDATE"
130 " SET pkey=$2,rvalue=$3,record_count=$4,record_data=$5"
131 " WHERE ns098records.zone_private_key = $1"
132 " AND ns098records.label = $6"),
133 GNUNET_PQ_make_prepare ("delete_records",
134 "DELETE FROM namestore.ns098records "
135 "WHERE zone_private_key=$1 AND label=$2"),
136 GNUNET_PQ_make_prepare ("zone_to_name",
137 "SELECT seq,record_count,record_data,label FROM namestore.ns098records"
138 " WHERE zone_private_key=$1 AND pkey=$2"),
139 GNUNET_PQ_make_prepare ("iterate_zone",
140 "SELECT seq,record_count,record_data,label FROM namestore.ns098records "
141 "WHERE zone_private_key=$1 AND seq > $2 ORDER BY seq ASC LIMIT $3"),
142 GNUNET_PQ_make_prepare ("iterate_all_zones",
143 "SELECT seq,record_count,record_data,label,zone_private_key"
144 " FROM namestore.ns098records WHERE seq > $1 ORDER BY seq ASC LIMIT $2"),
145 GNUNET_PQ_make_prepare ("lookup_label",
146 "SELECT seq,record_count,record_data,label "
147 "FROM namestore.ns098records WHERE zone_private_key=$1 AND label=$2"),
148 GNUNET_PQ_make_prepare ("edit_set",
149 "SELECT seq,record_count,record_data,label "
150 "FROM namestore.ns098records WHERE zone_private_key=$1 AND label=$2 FOR UPDATE NOWAIT"),
151 GNUNET_PQ_PREPARED_STATEMENT_END
152 };
153
154 ret = GNUNET_PQ_prepare_statements (plugin->dbh,
155 ps);
156 }
157 if (GNUNET_OK != ret)
158 return ret;
159 plugin->ready = true;
160 return GNUNET_OK;
161}
162
163
164/**
165 * Initialize the database connections and associated
166 * data structures (create tables and indices
167 * as needed as well).
168 *
169 * @param plugin the plugin context (state for this module)
170 * @return #GNUNET_OK on success
171 */
172static enum GNUNET_GenericReturnValue
173database_connect (struct Plugin *plugin)
174{
175 struct GNUNET_PQ_ExecuteStatement ess[] = {
176 GNUNET_PQ_make_try_execute ("SET synchronous_commit TO off"),
177 GNUNET_PQ_EXECUTE_STATEMENT_END
178 };
179 struct GNUNET_PQ_ExecuteStatement *es;
180
181 if (GNUNET_YES ==
182 GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg,
183 "namestore-postgres",
184 "ASYNC_COMMIT"))
185 es = &ess[0];
186 else
187 es = &ess[1];
188
189 if (GNUNET_YES ==
190 GNUNET_CONFIGURATION_get_value_yesno (plugin->cfg,
191 "namestore-postgres",
192 "INIT_ON_CONNECT"))
193 {
194 if (GNUNET_OK !=
195 namestore_postgres_create_tables (plugin))
196 {
197 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
198 "Failed to create tables\n");
199 return GNUNET_SYSERR;
200 }
201 }
202 plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
203 "namestore-postgres",
204 NULL,
205 es,
206 NULL);
207 if (NULL == plugin->dbh)
208 return GNUNET_SYSERR;
209 return GNUNET_OK;
210}
211
212
213/**
214 * Store a record in the datastore. Removes any existing record in the
215 * same zone with the same name.
216 *
217 * @param cls closure (internal context for the plugin)
218 * @param zone_key private key of the zone
219 * @param label name that is being mapped (at most 255 characters long)
220 * @param rd_count number of entries in @a rd array
221 * @param rd array of records with data to store
222 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
223 */
224static enum GNUNET_GenericReturnValue
225namestore_postgres_store_records (void *cls,
226 const struct
227 GNUNET_IDENTITY_PrivateKey *zone_key,
228 const char *label,
229 unsigned int rd_count,
230 const struct GNUNET_GNSRECORD_Data *rd)
231{
232 struct Plugin *plugin = cls;
233 struct GNUNET_IDENTITY_PublicKey pkey;
234 uint64_t rvalue;
235 uint32_t rd_count32 = (uint32_t) rd_count;
236 ssize_t data_size;
237
238 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
239 memset (&pkey,
240 0,
241 sizeof(pkey));
242 for (unsigned int i = 0; i < rd_count; i++)
243 if (GNUNET_YES ==
244 GNUNET_GNSRECORD_is_zonekey_type (rd[i].record_type))
245 {
246 GNUNET_break (GNUNET_OK ==
247 GNUNET_GNSRECORD_identity_from_data (rd[i].data,
248 rd[i].data_size,
249 rd[i].record_type,
250 &pkey));
251 break;
252 }
253 rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
254 UINT64_MAX);
255 data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
256 rd);
257 if (data_size < 0)
258 {
259 GNUNET_break (0);
260 return GNUNET_SYSERR;
261 }
262 if (data_size >= UINT16_MAX)
263 {
264 GNUNET_break (0);
265 return GNUNET_SYSERR;
266 }
267 /* if record set is empty, delete existing records */
268 if (0 == rd_count)
269 {
270 struct GNUNET_PQ_QueryParam params[] = {
271 GNUNET_PQ_query_param_auto_from_type (zone_key),
272 GNUNET_PQ_query_param_string (label),
273 GNUNET_PQ_query_param_end
274 };
275 enum GNUNET_DB_QueryStatus res;
276
277 res = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
278 "delete_records",
279 params);
280 if ((GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != res) &&
281 (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != res))
282 {
283 GNUNET_break (0);
284 return GNUNET_SYSERR;
285 }
286 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
287 "postgres",
288 "Record deleted\n");
289 return GNUNET_OK;
290 }
291 /* otherwise, UPSERT (i.e. UPDATE if exists, otherwise INSERT) */
292 {
293 char data[data_size];
294 struct GNUNET_PQ_QueryParam params[] = {
295 GNUNET_PQ_query_param_auto_from_type (zone_key),
296 GNUNET_PQ_query_param_auto_from_type (&pkey),
297 GNUNET_PQ_query_param_uint64 (&rvalue),
298 GNUNET_PQ_query_param_uint32 (&rd_count32),
299 GNUNET_PQ_query_param_fixed_size (data, data_size),
300 GNUNET_PQ_query_param_string (label),
301 GNUNET_PQ_query_param_end
302 };
303 enum GNUNET_DB_QueryStatus res;
304 ssize_t ret;
305
306 ret = GNUNET_GNSRECORD_records_serialize (rd_count,
307 rd,
308 data_size,
309 data);
310 if ((ret < 0) ||
311 (data_size != ret))
312 {
313 GNUNET_break (0);
314 return GNUNET_SYSERR;
315 }
316
317 res = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
318 "store_records",
319 params);
320 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != res)
321 return GNUNET_SYSERR;
322 }
323 return GNUNET_OK;
324}
325
326
327/**
328 * Closure for #parse_result_call_iterator.
329 */
330struct ParserContext
331{
332 /**
333 * Function to call for each result.
334 */
335 GNUNET_NAMESTORE_RecordIterator iter;
336
337 /**
338 * Closure for @e iter.
339 */
340 void *iter_cls;
341
342 /**
343 * Zone key, NULL if part of record.
344 */
345 const struct GNUNET_IDENTITY_PrivateKey *zone_key;
346
347 /**
348 * Number of results still to return (counted down by
349 * number of results given to iterator).
350 */
351 uint64_t limit;
352};
353
354
355/**
356 * A statement has been run. We should evaluate the result, and if possible
357 * call the @a iter in @a cls with the result.
358 *
359 * @param cls closure of type `struct ParserContext *`
360 * @param res the postgres result
361 * @param num_results the number of results in @a result
362 */
363static void
364parse_result_call_iterator (void *cls,
365 PGresult *res,
366 unsigned int num_results)
367{
368 struct ParserContext *pc = cls;
369
370 if (NULL == pc->iter)
371 return; /* no need to do more work */
372 LOG (GNUNET_ERROR_TYPE_DEBUG,
373 "Got %d results from PQ.\n", num_results);
374 for (unsigned int i = 0; i < num_results; i++)
375 {
376 uint64_t serial;
377 void *data;
378 size_t data_size;
379 uint32_t record_count;
380 char *label;
381 struct GNUNET_IDENTITY_PrivateKey zk;
382 struct GNUNET_PQ_ResultSpec rs_with_zone[] = {
383 GNUNET_PQ_result_spec_uint64 ("seq", &serial),
384 GNUNET_PQ_result_spec_uint32 ("record_count", &record_count),
385 GNUNET_PQ_result_spec_variable_size ("record_data", &data, &data_size),
386 GNUNET_PQ_result_spec_string ("label", &label),
387 GNUNET_PQ_result_spec_auto_from_type ("zone_private_key", &zk),
388 GNUNET_PQ_result_spec_end
389 };
390 struct GNUNET_PQ_ResultSpec rs_without_zone[] = {
391 GNUNET_PQ_result_spec_uint64 ("seq", &serial),
392 GNUNET_PQ_result_spec_uint32 ("record_count", &record_count),
393 GNUNET_PQ_result_spec_variable_size ("record_data", &data, &data_size),
394 GNUNET_PQ_result_spec_string ("label", &label),
395 GNUNET_PQ_result_spec_end
396 };
397 struct GNUNET_PQ_ResultSpec *rs;
398
399 rs = (NULL == pc->zone_key) ? rs_with_zone : rs_without_zone;
400 if (GNUNET_YES !=
401 GNUNET_PQ_extract_result (res,
402 rs,
403 i))
404 {
405 GNUNET_break (0);
406 return;
407 }
408
409 if (record_count > 64 * 1024)
410 {
411 /* sanity check, don't stack allocate far too much just
412 because database might contain a large value here */
413 GNUNET_break (0);
414 GNUNET_PQ_cleanup_result (rs);
415 return;
416 }
417
418 {
419 struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (record_count)];
420
421 GNUNET_assert (0 != serial);
422 if (GNUNET_OK !=
423 GNUNET_GNSRECORD_records_deserialize (data_size,
424 data,
425 record_count,
426 rd))
427 {
428 GNUNET_break (0);
429 GNUNET_PQ_cleanup_result (rs);
430 return;
431 }
432 pc->iter (pc->iter_cls,
433 serial,
434 (NULL == pc->zone_key) ? &zk : pc->zone_key,
435 label,
436 record_count,
437 rd);
438 }
439 GNUNET_PQ_cleanup_result (rs);
440 }
441 pc->limit -= num_results;
442}
443
444
445/**
446 * Lookup records in the datastore for which we are the authority.
447 *
448 * @param cls closure (internal context for the plugin)
449 * @param zone private key of the zone
450 * @param label name of the record in the zone
451 * @param iter function to call with the result
452 * @param iter_cls closure for @a iter
453 * @param method the method to use "lookup_record" or "edit_set"
454 * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
455 */
456static enum GNUNET_GenericReturnValue
457lookup_records (void *cls,
458 const struct
459 GNUNET_IDENTITY_PrivateKey *zone,
460 const char *label,
461 GNUNET_NAMESTORE_RecordIterator iter,
462 void *iter_cls,
463 const char*method)
464{
465 struct Plugin *plugin = cls;
466 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
467 struct GNUNET_PQ_QueryParam params[] = {
468 GNUNET_PQ_query_param_auto_from_type (zone),
469 GNUNET_PQ_query_param_string (label),
470 GNUNET_PQ_query_param_end
471 };
472 struct ParserContext pc;
473 enum GNUNET_DB_QueryStatus res;
474
475 if (NULL == zone)
476 {
477 GNUNET_break (0);
478 return GNUNET_SYSERR;
479 }
480 pc.iter = iter;
481 pc.iter_cls = iter_cls;
482 pc.zone_key = zone;
483 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
484 method,
485 params,
486 &parse_result_call_iterator,
487 &pc);
488 if (res < 0)
489 return GNUNET_SYSERR;
490 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == res)
491 return GNUNET_NO;
492 return GNUNET_OK;
493}
494
495
496/**
497 * Lookup records in the datastore for which we are the authority.
498 *
499 * @param cls closure (internal context for the plugin)
500 * @param zone private key of the zone
501 * @param label name of the record in the zone
502 * @param iter function to call with the result
503 * @param iter_cls closure for @a iter
504 * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
505 */
506static enum GNUNET_GenericReturnValue
507namestore_postgres_lookup_records (void *cls,
508 const struct
509 GNUNET_IDENTITY_PrivateKey *zone,
510 const char *label,
511 GNUNET_NAMESTORE_RecordIterator iter,
512 void *iter_cls)
513{
514 return lookup_records (cls, zone, label, iter, iter_cls, "lookup_label");
515}
516
517
518/**
519 * Edit records in the datastore for which we are the authority.
520 *
521 * @param cls closure (internal context for the plugin)
522 * @param zone private key of the zone
523 * @param label name of the record in the zone
524 * @param iter function to call with the result
525 * @param iter_cls closure for @a iter
526 * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR
527 */
528static int
529namestore_postgres_edit_records (void *cls,
530 const struct
531 GNUNET_IDENTITY_PrivateKey *zone,
532 const char *label,
533 GNUNET_NAMESTORE_RecordIterator iter,
534 void *iter_cls)
535{
536 return lookup_records (cls, zone, label, iter, iter_cls, "edit_set");
537}
538
539
540/**
541 * Iterate over the results for a particular key and zone in the
542 * datastore. Will return at most one result to the iterator.
543 *
544 * @param cls closure (internal context for the plugin)
545 * @param zone hash of public key of the zone, NULL to iterate over all zones
546 * @param serial serial number to exclude in the list of all matching records
547 * @param limit maximum number of results to fetch
548 * @param iter function to call with the result
549 * @param iter_cls closure for @a iter
550 * @return #GNUNET_OK on success, #GNUNET_NO if there were no more results, #GNUNET_SYSERR on error
551 */
552static enum GNUNET_GenericReturnValue
553namestore_postgres_iterate_records (void *cls,
554 const struct
555 GNUNET_IDENTITY_PrivateKey *zone,
556 uint64_t serial,
557 uint64_t limit,
558 GNUNET_NAMESTORE_RecordIterator iter,
559 void *iter_cls)
560{
561 struct Plugin *plugin = cls;
562 enum GNUNET_DB_QueryStatus res;
563 struct ParserContext pc;
564
565 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
566 pc.iter = iter;
567 pc.iter_cls = iter_cls;
568 pc.zone_key = zone;
569 pc.limit = limit;
570 if (NULL == zone)
571 {
572 struct GNUNET_PQ_QueryParam params_without_zone[] = {
573 GNUNET_PQ_query_param_uint64 (&serial),
574 GNUNET_PQ_query_param_uint64 (&limit),
575 GNUNET_PQ_query_param_end
576 };
577
578 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
579 "iterate_all_zones",
580 params_without_zone,
581 &parse_result_call_iterator,
582 &pc);
583 }
584 else
585 {
586 struct GNUNET_PQ_QueryParam params_with_zone[] = {
587 GNUNET_PQ_query_param_auto_from_type (zone),
588 GNUNET_PQ_query_param_uint64 (&serial),
589 GNUNET_PQ_query_param_uint64 (&limit),
590 GNUNET_PQ_query_param_end
591 };
592
593 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
594 "iterate_zone",
595 params_with_zone,
596 &parse_result_call_iterator,
597 &pc);
598 }
599 if (res < 0)
600 return GNUNET_SYSERR;
601
602 if ((GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == res) ||
603 (pc.limit > 0))
604 return GNUNET_NO;
605 return GNUNET_OK;
606}
607
608
609/**
610 * Look for an existing PKEY delegation record for a given public key.
611 * Returns at most one result to the iterator.
612 *
613 * @param cls closure (internal context for the plugin)
614 * @param zone private key of the zone to look up in, never NULL
615 * @param value_zone public key of the target zone (value), never NULL
616 * @param iter function to call with the result
617 * @param iter_cls closure for @a iter
618 * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
619 */
620static enum GNUNET_GenericReturnValue
621namestore_postgres_zone_to_name (void *cls,
622 const struct
623 GNUNET_IDENTITY_PrivateKey *zone,
624 const struct
625 GNUNET_IDENTITY_PublicKey *value_zone,
626 GNUNET_NAMESTORE_RecordIterator iter,
627 void *iter_cls)
628{
629 struct Plugin *plugin = cls;
630 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
631 struct GNUNET_PQ_QueryParam params[] = {
632 GNUNET_PQ_query_param_auto_from_type (zone),
633 GNUNET_PQ_query_param_auto_from_type (value_zone),
634 GNUNET_PQ_query_param_end
635 };
636 enum GNUNET_DB_QueryStatus res;
637 struct ParserContext pc;
638
639 pc.iter = iter;
640 pc.iter_cls = iter_cls;
641 pc.zone_key = zone;
642 res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
643 "zone_to_name",
644 params,
645 &parse_result_call_iterator,
646 &pc);
647 if (res < 0)
648 return GNUNET_SYSERR;
649 return GNUNET_OK;
650}
651
652
653/**
654 * Begin a transaction for a client.
655 *
656 * @param cls closure (internal context for the plugin)
657 * @param emsg error message set of return code is #GNUNET_SYSERR
658 * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started.
659 */
660static enum GNUNET_GenericReturnValue
661namestore_postgres_transaction_begin (void *cls,
662 char **emsg)
663{
664 struct Plugin *plugin = cls;
665 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
666 struct GNUNET_PQ_ExecuteStatement es[] = {
667 GNUNET_PQ_make_execute ("BEGIN"),
668 GNUNET_PQ_EXECUTE_STATEMENT_END
669 };
670
671 return GNUNET_PQ_exec_statements (plugin->dbh, es);
672}
673
674
675/**
676 * Commit a transaction for a client.
677 * This releases the lock on the database.
678 *
679 * @param cls closure (internal context for the plugin)
680 * @param emsg error message set of return code is #GNUNET_SYSERR
681 * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started.
682 */
683static enum GNUNET_GenericReturnValue
684namestore_postgres_transaction_rollback (void *cls,
685 char **emsg)
686{
687 struct Plugin *plugin = cls;
688 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
689 struct GNUNET_PQ_ExecuteStatement es[] = {
690 GNUNET_PQ_make_execute ("ROLLBACK"),
691 GNUNET_PQ_EXECUTE_STATEMENT_END
692 };
693
694 return GNUNET_PQ_exec_statements (plugin->dbh, es);
695}
696
697
698/**
699 * Roll back a transaction for a client.
700 * This releases the lock on the database.
701 *
702 * @param cls closure (internal context for the plugin)
703 * @param emsg error message set of return code is #GNUNET_SYSERR
704 * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started.
705 */
706static enum GNUNET_GenericReturnValue
707namestore_postgres_transaction_commit (void *cls,
708 char **emsg)
709{
710 struct Plugin *plugin = cls;
711 GNUNET_assert (GNUNET_OK == database_prepare (plugin));
712 struct GNUNET_PQ_ExecuteStatement es[] = {
713 GNUNET_PQ_make_execute ("COMMIT"),
714 GNUNET_PQ_EXECUTE_STATEMENT_END
715 };
716
717 return GNUNET_PQ_exec_statements (plugin->dbh, es);
718}
719
720
721/**
722 * Shutdown database connection and associate data
723 * structures.
724 *
725 * @param plugin the plugin context (state for this module)
726 */
727static void
728database_shutdown (struct Plugin *plugin)
729{
730 GNUNET_PQ_disconnect (plugin->dbh);
731 plugin->dbh = NULL;
732}
733
734
735/**
736 * Entry point for the plugin.
737 *
738 * @param cls the `struct GNUNET_NAMESTORE_PluginEnvironment*`
739 * @return NULL on error, othrewise the plugin context
740 */
741void *
742libgnunet_plugin_namestore_postgres_init (void *cls)
743{
744 struct Plugin *plugin;
745 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
746 struct GNUNET_NAMESTORE_PluginFunctions *api;
747
748 plugin = GNUNET_new (struct Plugin);
749 plugin->cfg = cfg;
750 if (GNUNET_OK != database_connect (plugin))
751 {
752 database_shutdown (plugin);
753 GNUNET_free (plugin);
754 return NULL;
755 }
756 api = GNUNET_new (struct GNUNET_NAMESTORE_PluginFunctions);
757 api->cls = plugin;
758 api->create_tables = &namestore_postgres_create_tables;
759 api->drop_tables = &namestore_postgres_drop_tables;
760 api->store_records = &namestore_postgres_store_records;
761 api->iterate_records = &namestore_postgres_iterate_records;
762 api->zone_to_name = &namestore_postgres_zone_to_name;
763 api->lookup_records = &namestore_postgres_lookup_records;
764 api->transaction_begin = &namestore_postgres_transaction_begin;
765 api->transaction_commit = &namestore_postgres_transaction_commit;
766 api->transaction_rollback = &namestore_postgres_transaction_rollback;
767 api->edit_records = &namestore_postgres_edit_records;
768 LOG (GNUNET_ERROR_TYPE_INFO,
769 "Postgres namestore plugin running\n");
770 return api;
771}
772
773
774/**
775 * Exit point from the plugin.
776 *
777 * @param cls the plugin context (as returned by "init")
778 * @return always NULL
779 */
780void *
781libgnunet_plugin_namestore_postgres_done (void *cls)
782{
783 struct GNUNET_NAMESTORE_PluginFunctions *api = cls;
784 struct Plugin *plugin = api->cls;
785
786 database_shutdown (plugin);
787 plugin->cfg = NULL;
788 GNUNET_free (plugin);
789 GNUNET_free (api);
790 LOG (GNUNET_ERROR_TYPE_DEBUG,
791 "Postgres namestore plugin is finished\n");
792 return NULL;
793}
794
795
796/* end of plugin_namestore_postgres.c */