2 * This file is part of GNUnet
3 * Copyright (C) 2016 GNUnet e.V.
5 * GNUnet is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; either version 3, or (at your
8 * option) any later version.
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 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNUnet; see the file COPYING. If not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
22 * @file psycstore/plugin_psycstore_postgres.c
23 * @brief PostgresQL-based psycstore backend
24 * @author Daniel Golle
25 * @author Gabor X Toth
26 * @author Christian Grothoff
27 * @author Christophe Genevey
28 * @author Jeffrey Burdges
32 #include "gnunet_psycstore_plugin.h"
33 #include "gnunet_psycstore_service.h"
34 #include "gnunet_multicast_service.h"
35 #include "gnunet_crypto_lib.h"
36 #include "gnunet_psyc_util_lib.h"
37 #include "psycstore.h"
38 #include "gnunet_pq_lib.h"
41 * After how many ms "busy" should a DB operation fail for good? A
42 * low value makes sure that we are more responsive to requests
43 * (especially PUTs). A high value guarantees a higher success rate
44 * (SELECTs in iterate can take several seconds despite LIMIT=1).
46 * The default value of 1s should ensure that users do not experience
47 * huge latencies while at the same time allowing operations to
48 * succeed with reasonable probability.
50 #define BUSY_TIMEOUT_MS 1000
52 #define DEBUG_PSYCSTORE GNUNET_EXTRA_LOGGING
54 #define LOG(kind,...) GNUNET_log_from (kind, "psycstore-postgres", __VA_ARGS__)
58 TRANSACTION_STATE_MODIFY,
59 TRANSACTION_STATE_SYNC,
63 * Context for all functions in this plugin.
68 const struct GNUNET_CONFIGURATION_Handle *cfg;
71 * Native Postgres database handle.
75 enum Transactions transaction;
82 * Initialize the database connections and associated
83 * data structures (create tables and indices
86 * @param plugin the plugin context (state for this module)
87 * @return #GNUNET_OK on success
90 database_setup (struct Plugin *plugin)
92 struct GNUNET_PQ_ExecuteStatement es[] = {
93 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS channels (\n"
95 " pub_key BYTEA NOT NULL CHECK (LENGTH(pub_key)=32),\n"
96 " max_state_message_id BIGINT,\n"
97 " state_hash_message_id BIGINT,\n"
101 GNUNET_PQ_make_execute ("CREATE UNIQUE INDEX IF NOT EXISTS channel_pub_key_idx \n"
102 " ON channels (pub_key)"),
103 GNUNET_PQ_make_execute ("CREATE OR REPLACE FUNCTION get_chan_id(BYTEA) RETURNS INTEGER AS \n"
104 " 'SELECT id FROM channels WHERE pub_key=$1;' LANGUAGE SQL STABLE \n"
105 "RETURNS NULL ON NULL INPUT"),
106 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS slaves (\n"
108 " pub_key BYTEA NOT NULL CHECK (LENGTH(pub_key)=32),\n"
112 GNUNET_PQ_make_execute ("CREATE UNIQUE INDEX IF NOT EXISTS slaves_pub_key_idx \n"
113 " ON slaves (pub_key)"),
114 GNUNET_PQ_make_execute ("CREATE OR REPLACE FUNCTION get_slave_id(BYTEA) RETURNS INTEGER AS \n"
115 " 'SELECT id FROM slaves WHERE pub_key=$1;' LANGUAGE SQL STABLE \n"
116 "RETURNS NULL ON NULL INPUT"),
117 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS membership (\n"
118 " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
119 " slave_id BIGINT NOT NULL REFERENCES slaves(id),\n"
120 " did_join INT NOT NULL,\n"
121 " announced_at BIGINT NOT NULL,\n"
122 " effective_since BIGINT NOT NULL,\n"
123 " group_generation BIGINT NOT NULL\n"
126 GNUNET_PQ_make_execute ("CREATE INDEX IF NOT EXISTS idx_membership_channel_id_slave_id "
127 "ON membership (channel_id, slave_id)"),
128 /** @todo messages table: add method_name column */
129 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS messages (\n"
130 " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
131 " hop_counter INT NOT NULL,\n"
132 " signature BYTEA CHECK (LENGTH(signature)=64),\n"
133 " purpose BYTEA CHECK (LENGTH(purpose)=8),\n"
134 " fragment_id BIGINT NOT NULL,\n"
135 " fragment_offset BIGINT NOT NULL,\n"
136 " message_id BIGINT NOT NULL,\n"
137 " group_generation BIGINT NOT NULL,\n"
138 " multicast_flags INT NOT NULL,\n"
139 " psycstore_flags INT NOT NULL,\n"
141 " PRIMARY KEY (channel_id, fragment_id),\n"
142 " UNIQUE (channel_id, message_id, fragment_offset)\n"
145 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS state (\n"
146 " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
147 " name TEXT NOT NULL,\n"
148 " value_current BYTEA,\n"
149 " value_signed BYTEA,\n"
150 " PRIMARY KEY (channel_id, name)\n"
153 GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS state_sync (\n"
154 " channel_id BIGINT NOT NULL REFERENCES channels(id),\n"
155 " name TEXT NOT NULL,\n"
157 " PRIMARY KEY (channel_id, name)\n"
160 GNUNET_PQ_EXECUTE_STATEMENT_END
163 /* Open database and precompile statements */
164 plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
165 "psycstore-postgres");
166 if (NULL == plugin->dbh)
167 return GNUNET_SYSERR;
169 GNUNET_PQ_exec_statements (plugin->dbh,
172 PQfinish (plugin->dbh);
174 return GNUNET_SYSERR;
177 /* Prepare statements */
179 struct GNUNET_PQ_PreparedStatement ps[] = {
180 GNUNET_PQ_make_prepare ("transaction_begin",
182 GNUNET_PQ_make_prepare ("transaction_commit",
184 GNUNET_PQ_make_prepare ("transaction_rollback",
186 GNUNET_PQ_make_prepare ("insert_channel_key",
187 "INSERT INTO channels (pub_key) VALUES ($1)"
188 " ON CONFLICT DO NOTHING", 1),
189 GNUNET_PQ_make_prepare ("insert_slave_key",
190 "INSERT INTO slaves (pub_key) VALUES ($1)"
191 " ON CONFLICT DO NOTHING", 1),
192 GNUNET_PQ_make_prepare ("insert_membership",
193 "INSERT INTO membership\n"
194 " (channel_id, slave_id, did_join, announced_at,\n"
195 " effective_since, group_generation)\n"
196 "VALUES (get_chan_id($1),\n"
197 " get_slave_id($2),\n"
198 " $3, $4, $5, $6)", 6),
199 GNUNET_PQ_make_prepare ("select_membership",
200 "SELECT did_join FROM membership\n"
201 "WHERE channel_id = get_chan_id($1)\n"
202 " AND slave_id = get_slave_id($2)\n"
203 " AND effective_since <= $3 AND did_join = 1\n"
204 "ORDER BY announced_at DESC LIMIT 1", 3),
205 GNUNET_PQ_make_prepare ("insert_fragment",
206 "INSERT INTO messages\n"
207 " (channel_id, hop_counter, signature, purpose,\n"
208 " fragment_id, fragment_offset, message_id,\n"
209 " group_generation, multicast_flags, psycstore_flags, data)\n"
210 "VALUES (get_chan_id($1),\n"
211 " $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)"
212 "ON CONFLICT DO NOTHING", 11),
213 GNUNET_PQ_make_prepare ("update_message_flags",
215 "SET psycstore_flags = psycstore_flags | $1\n"
216 "WHERE channel_id = get_chan_id($2) \n"
217 " AND message_id = $3 AND fragment_offset = 0", 3),
218 GNUNET_PQ_make_prepare ("select_fragments",
219 "SELECT hop_counter, signature, purpose, fragment_id,\n"
220 " fragment_offset, message_id, group_generation,\n"
221 " multicast_flags, psycstore_flags, data\n"
223 "WHERE channel_id = get_chan_id($1) \n"
224 " AND $2 <= fragment_id AND fragment_id <= $3", 3),
225 /** @todo select_messages: add method_prefix filter */
226 GNUNET_PQ_make_prepare ("select_messages",
227 "SELECT hop_counter, signature, purpose, fragment_id,\n"
228 " fragment_offset, message_id, group_generation,\n"
229 " multicast_flags, psycstore_flags, data\n"
231 "WHERE channel_id = get_chan_id($1) \n"
232 " AND $2 <= message_id AND message_id <= $3\n"
234 /** @todo select_latest_messages: add method_prefix filter */
235 GNUNET_PQ_make_prepare ("select_latest_fragments",
236 "SELECT rev.hop_counter AS hop_counter,\n"
237 " rev.signature AS signature,\n"
238 " rev.purpose AS purpose,\n"
239 " rev.fragment_id AS fragment_id,\n"
240 " rev.fragment_offset AS fragment_offset,\n"
241 " rev.message_id AS message_id,\n"
242 " rev.group_generation AS group_generation,\n"
243 " rev.multicast_flags AS multicast_flags,\n"
244 " rev.psycstore_flags AS psycstore_flags,\n"
245 " rev.data AS data\n"
247 " (SELECT hop_counter, signature, purpose, fragment_id,\n"
248 " fragment_offset, message_id, group_generation,\n"
249 " multicast_flags, psycstore_flags, data \n"
251 " WHERE channel_id = get_chan_id($1) \n"
252 " ORDER BY fragment_id DESC\n"
253 " LIMIT $2) AS rev\n"
254 " ORDER BY rev.fragment_id;", 2),
255 GNUNET_PQ_make_prepare ("select_latest_messages",
256 "SELECT hop_counter, signature, purpose, fragment_id,\n"
257 " fragment_offset, message_id, group_generation,\n"
258 " multicast_flags, psycstore_flags, data\n"
260 "WHERE channel_id = get_chan_id($1)\n"
261 " AND message_id IN\n"
262 " (SELECT message_id\n"
264 " WHERE channel_id = get_chan_id($2) \n"
265 " GROUP BY message_id\n"
266 " ORDER BY message_id\n"
268 "ORDER BY fragment_id", 3),
269 GNUNET_PQ_make_prepare ("select_message_fragment",
270 "SELECT hop_counter, signature, purpose, fragment_id,\n"
271 " fragment_offset, message_id, group_generation,\n"
272 " multicast_flags, psycstore_flags, data\n"
274 "WHERE channel_id = get_chan_id($1) \n"
275 " AND message_id = $2 AND fragment_offset = $3", 3),
276 GNUNET_PQ_make_prepare ("select_counters_message",
277 "SELECT fragment_id, message_id, group_generation\n"
279 "WHERE channel_id = get_chan_id($1)\n"
280 "ORDER BY fragment_id DESC LIMIT 1", 1),
281 GNUNET_PQ_make_prepare ("select_counters_state",
282 "SELECT max_state_message_id\n"
284 "WHERE pub_key = $1 AND max_state_message_id IS NOT NULL", 1),
285 GNUNET_PQ_make_prepare ("update_max_state_message_id",
287 "SET max_state_message_id = $1\n"
288 "WHERE pub_key = $2", 2),
290 GNUNET_PQ_make_prepare ("update_state_hash_message_id",
292 "SET state_hash_message_id = $1\n"
293 "WHERE pub_key = $2", 2),
294 GNUNET_PQ_make_prepare ("insert_state_current",
295 "INSERT INTO state\n"
296 " (channel_id, name, value_current, value_signed)\n"
297 "SELECT new.channel_id, new.name,\n"
298 " new.value_current, old.value_signed\n"
299 "FROM (SELECT get_chan_id($1) AS channel_id,\n"
300 " $2::TEXT AS name, $3::BYTEA AS value_current) AS new\n"
301 "LEFT JOIN (SELECT channel_id, name, value_signed\n"
302 " FROM state) AS old\n"
303 "ON new.channel_id = old.channel_id AND new.name = old.name\n"
304 "ON CONFLICT (channel_id, name)\n"
305 " DO UPDATE SET value_current = EXCLUDED.value_current,\n"
306 " value_signed = EXCLUDED.value_signed", 3),
307 GNUNET_PQ_make_prepare ("delete_state_empty",
308 "DELETE FROM state\n"
309 "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = $1)\n"
310 " AND (value_current IS NULL OR length(value_current) = 0)\n"
311 " AND (value_signed IS NULL OR length(value_signed) = 0)", 1),
312 GNUNET_PQ_make_prepare ("update_state_signed",
314 "SET value_signed = value_current\n"
315 "WHERE channel_id = get_chan_id($1) ", 1),
316 GNUNET_PQ_make_prepare ("delete_state",
317 "DELETE FROM state\n"
318 "WHERE channel_id = get_chan_id($1) ", 1),
319 GNUNET_PQ_make_prepare ("insert_state_sync",
320 "INSERT INTO state_sync (channel_id, name, value)\n"
321 "VALUES (get_chan_id($1), $2, $3)", 3),
322 GNUNET_PQ_make_prepare ("insert_state_from_sync",
323 "INSERT INTO state\n"
324 " (channel_id, name, value_current, value_signed)\n"
325 "SELECT channel_id, name, value, value\n"
327 "WHERE channel_id = get_chan_id($1)", 1),
328 GNUNET_PQ_make_prepare ("delete_state_sync",
329 "DELETE FROM state_sync\n"
330 "WHERE channel_id = get_chan_id($1)", 1),
331 GNUNET_PQ_make_prepare ("select_state_one",
332 "SELECT value_current\n"
334 "WHERE channel_id = get_chan_id($1)\n"
335 " AND name = $2", 2),
336 GNUNET_PQ_make_prepare ("select_state_prefix",
337 "SELECT name, value_current\n"
339 "WHERE channel_id = get_chan_id($1)\n"
340 " AND (name = $2 OR substr(name, 1, $3) = $4)", 4),
341 GNUNET_PQ_make_prepare ("select_state_signed",
342 "SELECT name, value_signed\n"
344 "WHERE channel_id = get_chan_id($1)\n"
345 " AND value_signed IS NOT NULL", 1),
346 GNUNET_PQ_PREPARED_STATEMENT_END
350 GNUNET_PQ_prepare_statements (plugin->dbh,
353 PQfinish (plugin->dbh);
355 return GNUNET_SYSERR;
364 * Shutdown database connection and associate data
366 * @param plugin the plugin context (state for this module)
369 database_shutdown (struct Plugin *plugin)
371 PQfinish (plugin->dbh);
377 * Execute a prepared statement with a @a channel_key argument.
379 * @param plugin Plugin handle.
380 * @param stmt Statement to execute.
381 * @param channel_key Public key of the channel.
383 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
386 exec_channel (struct Plugin *plugin, const char *stmt,
387 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
389 struct GNUNET_PQ_QueryParam params[] = {
390 GNUNET_PQ_query_param_auto_from_type (channel_key),
391 GNUNET_PQ_query_param_end
394 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
395 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, stmt, params))
396 return GNUNET_SYSERR;
403 * Begin a transaction.
406 transaction_begin (struct Plugin *plugin, enum Transactions transaction)
408 struct GNUNET_PQ_QueryParam params[] = {
409 GNUNET_PQ_query_param_end
412 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
413 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "transaction_begin", params))
414 return GNUNET_SYSERR;
416 plugin->transaction = transaction;
422 * Commit current transaction.
425 transaction_commit (struct Plugin *plugin)
427 struct GNUNET_PQ_QueryParam params[] = {
428 GNUNET_PQ_query_param_end
431 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
432 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "transaction_commit", params))
433 return GNUNET_SYSERR;
435 plugin->transaction = TRANSACTION_NONE;
441 * Roll back current transaction.
444 transaction_rollback (struct Plugin *plugin)
446 struct GNUNET_PQ_QueryParam params[] = {
447 GNUNET_PQ_query_param_end
450 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
451 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "transaction_rollback", params))
452 return GNUNET_SYSERR;
454 plugin->transaction = TRANSACTION_NONE;
460 channel_key_store (struct Plugin *plugin,
461 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
463 struct GNUNET_PQ_QueryParam params[] = {
464 GNUNET_PQ_query_param_auto_from_type (channel_key),
465 GNUNET_PQ_query_param_end
468 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
469 GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
470 "insert_channel_key",
472 return GNUNET_SYSERR;
479 slave_key_store (struct Plugin *plugin,
480 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key)
482 struct GNUNET_PQ_QueryParam params[] = {
483 GNUNET_PQ_query_param_auto_from_type (slave_key),
484 GNUNET_PQ_query_param_end
487 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
488 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "insert_slave_key", params))
489 return GNUNET_SYSERR;
496 * Store join/leave events for a PSYC channel in order to be able to answer
497 * membership test queries later.
499 * @see GNUNET_PSYCSTORE_membership_store()
501 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
504 postgres_membership_store (void *cls,
505 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
506 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
508 uint64_t announced_at,
509 uint64_t effective_since,
510 uint64_t group_generation)
512 struct Plugin *plugin = cls;
513 uint32_t idid_join = (uint32_t) did_join;
515 GNUNET_assert (TRANSACTION_NONE == plugin->transaction);
517 if ( (announced_at > INT64_MAX) ||
518 (effective_since > INT64_MAX) ||
519 (group_generation > INT64_MAX) )
522 return GNUNET_SYSERR;
526 channel_key_store (plugin, channel_key)) ||
528 slave_key_store (plugin, slave_key)) )
529 return GNUNET_SYSERR;
531 struct GNUNET_PQ_QueryParam params[] = {
532 GNUNET_PQ_query_param_auto_from_type (channel_key),
533 GNUNET_PQ_query_param_auto_from_type (slave_key),
534 GNUNET_PQ_query_param_uint32 (&idid_join),
535 GNUNET_PQ_query_param_uint64 (&announced_at),
536 GNUNET_PQ_query_param_uint64 (&effective_since),
537 GNUNET_PQ_query_param_uint64 (&group_generation),
538 GNUNET_PQ_query_param_end
541 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
542 GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
545 return GNUNET_SYSERR;
551 * Test if a member was admitted to the channel at the given message ID.
553 * @see GNUNET_PSYCSTORE_membership_test()
555 * @return #GNUNET_YES if the member was admitted, #GNUNET_NO if not,
556 * #GNUNET_SYSERR if there was en error.
559 membership_test (void *cls,
560 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
561 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
564 struct Plugin *plugin = cls;
566 uint32_t did_join = 0;
568 struct GNUNET_PQ_QueryParam params_select[] = {
569 GNUNET_PQ_query_param_auto_from_type (channel_key),
570 GNUNET_PQ_query_param_auto_from_type (slave_key),
571 GNUNET_PQ_query_param_uint64 (&message_id),
572 GNUNET_PQ_query_param_end
575 struct GNUNET_PQ_ResultSpec results_select[] = {
576 GNUNET_PQ_result_spec_uint32 ("did_join", &did_join),
577 GNUNET_PQ_result_spec_end
580 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
581 GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, "select_membership",
582 params_select, results_select))
583 return GNUNET_SYSERR;
589 * Store a message fragment sent to a channel.
591 * @see GNUNET_PSYCSTORE_fragment_store()
593 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
596 fragment_store (void *cls,
597 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
598 const struct GNUNET_MULTICAST_MessageHeader *msg,
599 uint32_t psycstore_flags)
601 struct Plugin *plugin = cls;
603 GNUNET_assert (TRANSACTION_NONE == plugin->transaction);
605 uint64_t fragment_id = GNUNET_ntohll (msg->fragment_id);
607 uint64_t fragment_offset = GNUNET_ntohll (msg->fragment_offset);
608 uint64_t message_id = GNUNET_ntohll (msg->message_id);
609 uint64_t group_generation = GNUNET_ntohll (msg->group_generation);
611 uint32_t hop_counter = ntohl(msg->hop_counter);
612 uint32_t flags = ntohl(msg->flags);
614 if (fragment_id > INT64_MAX || fragment_offset > INT64_MAX ||
615 message_id > INT64_MAX || group_generation > INT64_MAX)
617 LOG(GNUNET_ERROR_TYPE_ERROR,
618 "Tried to store fragment with a field > INT64_MAX: "
619 "%lu, %lu, %lu, %lu\n", fragment_id, fragment_offset,
620 message_id, group_generation);
622 return GNUNET_SYSERR;
625 if (GNUNET_OK != channel_key_store (plugin, channel_key))
626 return GNUNET_SYSERR;
628 struct GNUNET_PQ_QueryParam params_insert[] = {
629 GNUNET_PQ_query_param_auto_from_type (channel_key),
630 GNUNET_PQ_query_param_uint32 (&hop_counter),
631 GNUNET_PQ_query_param_auto_from_type (&msg->signature),
632 GNUNET_PQ_query_param_auto_from_type (&msg->purpose),
633 GNUNET_PQ_query_param_uint64 (&fragment_id),
634 GNUNET_PQ_query_param_uint64 (&fragment_offset),
635 GNUNET_PQ_query_param_uint64 (&message_id),
636 GNUNET_PQ_query_param_uint64 (&group_generation),
637 GNUNET_PQ_query_param_uint32 (&flags),
638 GNUNET_PQ_query_param_uint32 (&psycstore_flags),
639 GNUNET_PQ_query_param_fixed_size (&msg[1], ntohs (msg->header.size) - sizeof (*msg)),
640 GNUNET_PQ_query_param_end
643 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
644 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "insert_fragment", params_insert))
645 return GNUNET_SYSERR;
651 * Set additional flags for a given message.
653 * They are OR'd with any existing flags set.
655 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
658 message_add_flags (void *cls,
659 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
661 uint32_t psycstore_flags)
663 struct Plugin *plugin = cls;
665 struct GNUNET_PQ_QueryParam params_update[] = {
666 GNUNET_PQ_query_param_uint32 (&psycstore_flags),
667 GNUNET_PQ_query_param_auto_from_type (channel_key),
668 GNUNET_PQ_query_param_uint64 (&message_id),
669 GNUNET_PQ_query_param_end
672 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
673 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "update_message_flags", params_update))
674 return GNUNET_SYSERR;
681 * Closure for #fragment_rows.
683 struct FragmentRowsContext {
684 GNUNET_PSYCSTORE_FragmentCallback cb;
687 uint64_t *returned_fragments;
689 /* I preserved this but I do not see the point since
690 * it cannot stop the loop early and gets overwritten ?? */
696 * Callback that retrieves the results of a SELECT statement
697 * reading form the messages table.
699 * Only passed to GNUNET_PQ_eval_prepared_multi_select and
700 * has type GNUNET_PQ_PostgresResultHandler.
703 * @param result the postgres result
704 * @param num_result the number of results in @a result
706 void fragment_rows (void *cls,
708 unsigned int num_results)
710 struct FragmentRowsContext *c = cls;
712 for (unsigned int i=0;i<num_results;i++)
714 uint32_t hop_counter;
715 void *signature = NULL;
716 void *purpose = NULL;
717 size_t signature_size;
719 uint64_t fragment_id;
720 uint64_t fragment_offset;
722 uint64_t group_generation;
727 struct GNUNET_PQ_ResultSpec results[] = {
728 GNUNET_PQ_result_spec_uint32 ("hop_counter", &hop_counter),
729 GNUNET_PQ_result_spec_variable_size ("signature", &signature, &signature_size),
730 GNUNET_PQ_result_spec_variable_size ("purpose", &purpose, &purpose_size),
731 GNUNET_PQ_result_spec_uint64 ("fragment_id", &fragment_id),
732 GNUNET_PQ_result_spec_uint64 ("fragment_offset", &fragment_offset),
733 GNUNET_PQ_result_spec_uint64 ("message_id", &message_id),
734 GNUNET_PQ_result_spec_uint64 ("group_generation", &group_generation),
735 GNUNET_PQ_result_spec_uint32 ("multicast_flags", &msg_flags),
736 GNUNET_PQ_result_spec_uint32 ("psycstore_flags", &flags),
737 GNUNET_PQ_result_spec_variable_size ("data", &buf, &buf_size),
738 GNUNET_PQ_result_spec_end
740 struct GNUNET_MULTICAST_MessageHeader *mp;
742 if (GNUNET_YES != GNUNET_PQ_extract_result (res, results, i))
744 GNUNET_PQ_cleanup_result(results); /* missing previously, a memory leak?? */
745 break; /* nothing more?? */
748 mp = GNUNET_malloc (sizeof (*mp) + buf_size);
750 mp->header.size = htons (sizeof (*mp) + buf_size);
751 mp->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
752 mp->hop_counter = htonl (hop_counter);
753 GNUNET_memcpy (&mp->signature,
754 signature, signature_size);
755 GNUNET_memcpy (&mp->purpose,
756 purpose, purpose_size);
757 mp->fragment_id = GNUNET_htonll (fragment_id);
758 mp->fragment_offset = GNUNET_htonll (fragment_offset);
759 mp->message_id = GNUNET_htonll (message_id);
760 mp->group_generation = GNUNET_htonll (group_generation);
761 mp->flags = htonl(msg_flags);
763 GNUNET_memcpy (&mp[1],
765 GNUNET_PQ_cleanup_result(results);
766 c->ret = c->cb (c->cb_cls, mp, (enum GNUNET_PSYCSTORE_MessageFlags) flags);
767 if (NULL != c->returned_fragments)
768 (*c->returned_fragments)++;
774 fragment_select (struct Plugin *plugin,
776 struct GNUNET_PQ_QueryParam *params,
777 uint64_t *returned_fragments,
778 GNUNET_PSYCSTORE_FragmentCallback cb,
781 /* Stack based closure */
782 struct FragmentRowsContext frc = {
785 .returned_fragments = returned_fragments,
789 if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
791 &fragment_rows, &frc))
792 return GNUNET_SYSERR;
793 return frc.ret; /* GNUNET_OK ?? */
797 * Retrieve a message fragment range by fragment ID.
799 * @see GNUNET_PSYCSTORE_fragment_get()
801 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
804 fragment_get (void *cls,
805 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
806 uint64_t first_fragment_id,
807 uint64_t last_fragment_id,
808 uint64_t *returned_fragments,
809 GNUNET_PSYCSTORE_FragmentCallback cb,
812 struct Plugin *plugin = cls;
813 struct GNUNET_PQ_QueryParam params_select[] = {
814 GNUNET_PQ_query_param_auto_from_type (channel_key),
815 GNUNET_PQ_query_param_uint64 (&first_fragment_id),
816 GNUNET_PQ_query_param_uint64 (&last_fragment_id),
817 GNUNET_PQ_query_param_end
820 *returned_fragments = 0;
821 return fragment_select (plugin,
830 * Retrieve a message fragment range by fragment ID.
832 * @see GNUNET_PSYCSTORE_fragment_get_latest()
834 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
837 fragment_get_latest (void *cls,
838 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
839 uint64_t fragment_limit,
840 uint64_t *returned_fragments,
841 GNUNET_PSYCSTORE_FragmentCallback cb,
844 struct Plugin *plugin = cls;
846 *returned_fragments = 0;
848 struct GNUNET_PQ_QueryParam params_select[] = {
849 GNUNET_PQ_query_param_auto_from_type (channel_key),
850 GNUNET_PQ_query_param_uint64 (&fragment_limit),
851 GNUNET_PQ_query_param_end
854 return fragment_select (plugin,
855 "select_latest_fragments",
863 * Retrieve all fragments of a message ID range.
865 * @see GNUNET_PSYCSTORE_message_get()
867 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
870 message_get (void *cls,
871 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
872 uint64_t first_message_id,
873 uint64_t last_message_id,
874 uint64_t fragment_limit,
875 uint64_t *returned_fragments,
876 GNUNET_PSYCSTORE_FragmentCallback cb,
879 struct Plugin *plugin = cls;
880 struct GNUNET_PQ_QueryParam params_select[] = {
881 GNUNET_PQ_query_param_auto_from_type (channel_key),
882 GNUNET_PQ_query_param_uint64 (&first_message_id),
883 GNUNET_PQ_query_param_uint64 (&last_message_id),
884 GNUNET_PQ_query_param_uint64 (&fragment_limit),
885 GNUNET_PQ_query_param_end
888 if (0 == fragment_limit)
889 fragment_limit = INT64_MAX;
890 *returned_fragments = 0;
891 return fragment_select (plugin,
900 * Retrieve all fragments of the latest messages.
902 * @see GNUNET_PSYCSTORE_message_get_latest()
904 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
907 message_get_latest (void *cls,
908 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
909 uint64_t message_limit,
910 uint64_t *returned_fragments,
911 GNUNET_PSYCSTORE_FragmentCallback cb,
914 struct Plugin *plugin = cls;
915 struct GNUNET_PQ_QueryParam params_select[] = {
916 GNUNET_PQ_query_param_auto_from_type (channel_key),
917 GNUNET_PQ_query_param_auto_from_type (channel_key),
918 GNUNET_PQ_query_param_uint64 (&message_limit),
919 GNUNET_PQ_query_param_end
922 *returned_fragments = 0;
923 return fragment_select (plugin,
924 "select_latest_messages",
932 * Retrieve a fragment of message specified by its message ID and fragment
935 * @see GNUNET_PSYCSTORE_message_get_fragment()
937 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
940 message_get_fragment (void *cls,
941 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
943 uint64_t fragment_offset,
944 GNUNET_PSYCSTORE_FragmentCallback cb,
947 struct Plugin *plugin = cls;
948 const char *stmt = "select_message_fragment";
950 struct GNUNET_PQ_QueryParam params_select[] = {
951 GNUNET_PQ_query_param_auto_from_type (channel_key),
952 GNUNET_PQ_query_param_uint64 (&message_id),
953 GNUNET_PQ_query_param_uint64 (&fragment_offset),
954 GNUNET_PQ_query_param_end
957 /* Stack based closure */
958 struct FragmentRowsContext frc = {
961 .returned_fragments = NULL,
965 if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
967 &fragment_rows, &frc))
968 return GNUNET_SYSERR;
969 return frc.ret; /* GNUNET_OK ?? */
973 * Retrieve the max. values of message counters for a channel.
975 * @see GNUNET_PSYCSTORE_counters_get()
977 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
980 counters_message_get (void *cls,
981 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
982 uint64_t *max_fragment_id,
983 uint64_t *max_message_id,
984 uint64_t *max_group_generation)
986 struct Plugin *plugin = cls;
988 const char *stmt = "select_counters_message";
990 struct GNUNET_PQ_QueryParam params_select[] = {
991 GNUNET_PQ_query_param_auto_from_type (channel_key),
992 GNUNET_PQ_query_param_end
995 struct GNUNET_PQ_ResultSpec results_select[] = {
996 GNUNET_PQ_result_spec_uint64 ("fragment_id", max_fragment_id),
997 GNUNET_PQ_result_spec_uint64 ("message_id", max_message_id),
998 GNUNET_PQ_result_spec_uint64 ("group_generation", max_group_generation),
999 GNUNET_PQ_result_spec_end
1002 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
1003 GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, stmt,
1004 params_select, results_select))
1005 return GNUNET_SYSERR;
1011 * Retrieve the max. values of state counters for a channel.
1013 * @see GNUNET_PSYCSTORE_counters_get()
1015 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1018 counters_state_get (void *cls,
1019 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1020 uint64_t *max_state_message_id)
1022 struct Plugin *plugin = cls;
1024 const char *stmt = "select_counters_state";
1026 struct GNUNET_PQ_QueryParam params_select[] = {
1027 GNUNET_PQ_query_param_auto_from_type (channel_key),
1028 GNUNET_PQ_query_param_end
1031 struct GNUNET_PQ_ResultSpec results_select[] = {
1032 GNUNET_PQ_result_spec_uint64 ("max_state_message_id", max_state_message_id),
1033 GNUNET_PQ_result_spec_end
1036 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
1037 GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, stmt,
1038 params_select, results_select))
1039 return GNUNET_SYSERR;
1046 * Assign a value to a state variable.
1048 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1051 state_assign (struct Plugin *plugin, const char *stmt,
1052 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1053 const char *name, const void *value, size_t value_size)
1055 struct GNUNET_PQ_QueryParam params[] = {
1056 GNUNET_PQ_query_param_auto_from_type (channel_key),
1057 GNUNET_PQ_query_param_string (name),
1058 GNUNET_PQ_query_param_fixed_size (value, value_size),
1059 GNUNET_PQ_query_param_end
1062 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
1063 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, stmt, params))
1064 return GNUNET_SYSERR;
1071 update_message_id (struct Plugin *plugin,
1073 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1074 uint64_t message_id)
1076 struct GNUNET_PQ_QueryParam params[] = {
1077 GNUNET_PQ_query_param_uint64 (&message_id),
1078 GNUNET_PQ_query_param_auto_from_type (channel_key),
1079 GNUNET_PQ_query_param_end
1082 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
1083 GNUNET_PQ_eval_prepared_non_select (plugin->dbh, stmt, params))
1084 return GNUNET_SYSERR;
1091 * Begin modifying current state.
1094 state_modify_begin (void *cls,
1095 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1096 uint64_t message_id, uint64_t state_delta)
1098 struct Plugin *plugin = cls;
1100 if (state_delta > 0)
1103 * We can only apply state modifiers in the current message if modifiers in
1104 * the previous stateful message (message_id - state_delta) were already
1108 uint64_t max_state_message_id = 0;
1109 int ret = counters_state_get (plugin, channel_key, &max_state_message_id);
1113 case GNUNET_NO: // no state yet
1121 if (max_state_message_id < message_id - state_delta)
1122 return GNUNET_NO; /* some stateful messages not yet applied */
1123 else if (message_id - state_delta < max_state_message_id)
1124 return GNUNET_NO; /* changes already applied */
1127 if (TRANSACTION_NONE != plugin->transaction)
1129 /** @todo FIXME: wait for other transaction to finish */
1130 return GNUNET_SYSERR;
1132 return transaction_begin (plugin, TRANSACTION_STATE_MODIFY);
1137 * Set the current value of state variable.
1139 * @see GNUNET_PSYCSTORE_state_modify()
1141 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1144 state_modify_op (void *cls,
1145 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1146 enum GNUNET_PSYC_Operator op,
1147 const char *name, const void *value, size_t value_size)
1149 struct Plugin *plugin = cls;
1150 GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction);
1154 case GNUNET_PSYC_OP_ASSIGN:
1155 return state_assign (plugin, "insert_state_current",
1156 channel_key, name, value, value_size);
1158 default: /** @todo implement more state operations */
1160 return GNUNET_SYSERR;
1166 * End modifying current state.
1169 state_modify_end (void *cls,
1170 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1171 uint64_t message_id)
1173 struct Plugin *plugin = cls;
1174 GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction);
1177 GNUNET_OK == exec_channel (plugin, "delete_state_empty", channel_key)
1178 && GNUNET_OK == update_message_id (plugin,
1179 "update_max_state_message_id",
1180 channel_key, message_id)
1181 && GNUNET_OK == transaction_commit (plugin)
1182 ? GNUNET_OK : GNUNET_SYSERR;
1187 * Begin state synchronization.
1190 state_sync_begin (void *cls,
1191 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
1193 struct Plugin *plugin = cls;
1194 return exec_channel (plugin, "delete_state_sync", channel_key);
1199 * Assign current value of a state variable.
1201 * @see GNUNET_PSYCSTORE_state_modify()
1203 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1206 state_sync_assign (void *cls,
1207 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1208 const char *name, const void *value, size_t value_size)
1210 struct Plugin *plugin = cls;
1211 return state_assign (plugin, "insert_state_sync",
1212 channel_key, name, value, value_size);
1217 * End modifying current state.
1220 state_sync_end (void *cls,
1221 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1222 uint64_t max_state_message_id,
1223 uint64_t state_hash_message_id)
1225 struct Plugin *plugin = cls;
1226 int ret = GNUNET_SYSERR;
1228 if (TRANSACTION_NONE != plugin->transaction)
1230 /** @todo FIXME: wait for other transaction to finish */
1231 return GNUNET_SYSERR;
1234 GNUNET_OK == transaction_begin (plugin, TRANSACTION_STATE_SYNC)
1235 && GNUNET_OK == exec_channel (plugin, "delete_state", channel_key)
1236 && GNUNET_OK == exec_channel (plugin, "insert_state_from_sync",
1238 && GNUNET_OK == exec_channel (plugin, "delete_state_sync",
1240 && GNUNET_OK == update_message_id (plugin,
1241 "update_state_hash_message_id",
1242 channel_key, state_hash_message_id)
1243 && GNUNET_OK == update_message_id (plugin,
1244 "update_max_state_message_id",
1245 channel_key, max_state_message_id)
1246 && GNUNET_OK == transaction_commit (plugin)
1248 : transaction_rollback (plugin);
1254 * Delete the whole state.
1256 * @see GNUNET_PSYCSTORE_state_reset()
1258 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1261 state_reset (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
1263 struct Plugin *plugin = cls;
1264 return exec_channel (plugin, "delete_state", channel_key);
1269 * Update signed values of state variables in the state store.
1271 * @see GNUNET_PSYCSTORE_state_hash_update()
1273 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1276 state_update_signed (void *cls,
1277 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key)
1279 struct Plugin *plugin = cls;
1280 return exec_channel (plugin, "update_state_signed", channel_key);
1285 * Retrieve a state variable by name.
1287 * @see GNUNET_PSYCSTORE_state_get()
1289 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1292 state_get (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1293 const char *name, GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls)
1295 struct Plugin *plugin = cls;
1297 const char *stmt = "select_state_one";
1299 struct GNUNET_PQ_QueryParam params_select[] = {
1300 GNUNET_PQ_query_param_auto_from_type (channel_key),
1301 GNUNET_PQ_query_param_string (name),
1302 GNUNET_PQ_query_param_end
1305 void *value_current = NULL;
1306 size_t value_size = 0;
1308 struct GNUNET_PQ_ResultSpec results_select[] = {
1309 GNUNET_PQ_result_spec_variable_size ("value_current", &value_current, &value_size),
1310 GNUNET_PQ_result_spec_end
1313 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
1314 GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, stmt,
1315 params_select, results_select))
1316 return GNUNET_SYSERR;
1318 return cb (cb_cls, name, value_current,
1325 * Closure for #get_state_cb.
1327 struct GetStateContext {
1328 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key;
1329 // const char *name,
1330 GNUNET_PSYCSTORE_StateCallback cb;
1333 const char *value_id;
1335 /* I preserved this but I do not see the point since
1336 * it cannot stop the loop early and gets overwritten ?? */
1342 * Callback that retrieves the results of a SELECT statement
1343 * reading form the state table.
1345 * Only passed to GNUNET_PQ_eval_prepared_multi_select and
1346 * has type GNUNET_PQ_PostgresResultHandler.
1348 * @param cls closure
1349 * @param result the postgres result
1350 * @param num_result the number of results in @a result
1353 get_state_cb (void *cls,
1355 unsigned int num_results)
1357 struct GetStateContext *c = cls;
1359 for (unsigned int i=0;i<num_results;i++)
1363 size_t value_size = 0;
1365 struct GNUNET_PQ_ResultSpec results[] = {
1366 GNUNET_PQ_result_spec_string ("name", &name),
1367 GNUNET_PQ_result_spec_variable_size (c->value_id, &value, &value_size),
1368 GNUNET_PQ_result_spec_end
1371 if (GNUNET_YES != GNUNET_PQ_extract_result (res, results, i))
1373 GNUNET_PQ_cleanup_result(results); /* previously invoked via PQclear?? */
1374 break; /* nothing more?? */
1377 c->ret = c->cb (c->cb_cls, (const char *) name, value, value_size);
1378 GNUNET_PQ_cleanup_result(results);
1383 * Retrieve all state variables for a channel with the given prefix.
1385 * @see GNUNET_PSYCSTORE_state_get_prefix()
1387 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1390 state_get_prefix (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1391 const char *name, GNUNET_PSYCSTORE_StateCallback cb,
1394 struct Plugin *plugin = cls;
1396 const char *stmt = "select_state_prefix";
1398 uint32_t name_len = (uint32_t) strlen (name);
1400 struct GNUNET_PQ_QueryParam params_select[] = {
1401 GNUNET_PQ_query_param_auto_from_type (channel_key),
1402 GNUNET_PQ_query_param_string (name),
1403 GNUNET_PQ_query_param_uint32 (&name_len),
1404 GNUNET_PQ_query_param_string (name),
1405 GNUNET_PQ_query_param_end
1408 struct GetStateContext gsc = {
1411 .value_id = "value_current",
1415 if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
1416 stmt, params_select,
1417 &get_state_cb, &gsc))
1418 return GNUNET_SYSERR;
1419 return gsc.ret; /* GNUNET_OK ?? */
1424 * Retrieve all signed state variables for a channel.
1426 * @see GNUNET_PSYCSTORE_state_get_signed()
1428 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
1431 state_get_signed (void *cls,
1432 const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1433 GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls)
1435 struct Plugin *plugin = cls;
1437 const char *stmt = "select_state_signed";
1439 struct GNUNET_PQ_QueryParam params_select[] = {
1440 GNUNET_PQ_query_param_auto_from_type (channel_key),
1441 GNUNET_PQ_query_param_end
1444 struct GetStateContext gsc = {
1447 .value_id = "value_signed",
1451 if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
1452 stmt, params_select,
1453 &get_state_cb, &gsc))
1454 return GNUNET_SYSERR;
1455 return gsc.ret; /* GNUNET_OK ?? */
1460 * Entry point for the plugin.
1462 * @param cls The struct GNUNET_CONFIGURATION_Handle.
1463 * @return NULL on error, otherwise the plugin context
1466 libgnunet_plugin_psycstore_postgres_init (void *cls)
1468 static struct Plugin plugin;
1469 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1470 struct GNUNET_PSYCSTORE_PluginFunctions *api;
1472 if (NULL != plugin.cfg)
1473 return NULL; /* can only initialize once! */
1474 memset (&plugin, 0, sizeof (struct Plugin));
1476 if (GNUNET_OK != database_setup (&plugin))
1478 database_shutdown (&plugin);
1481 api = GNUNET_new (struct GNUNET_PSYCSTORE_PluginFunctions);
1483 api->membership_store = &postgres_membership_store;
1484 api->membership_test = &membership_test;
1485 api->fragment_store = &fragment_store;
1486 api->message_add_flags = &message_add_flags;
1487 api->fragment_get = &fragment_get;
1488 api->fragment_get_latest = &fragment_get_latest;
1489 api->message_get = &message_get;
1490 api->message_get_latest = &message_get_latest;
1491 api->message_get_fragment = &message_get_fragment;
1492 api->counters_message_get = &counters_message_get;
1493 api->counters_state_get = &counters_state_get;
1494 api->state_modify_begin = &state_modify_begin;
1495 api->state_modify_op = &state_modify_op;
1496 api->state_modify_end = &state_modify_end;
1497 api->state_sync_begin = &state_sync_begin;
1498 api->state_sync_assign = &state_sync_assign;
1499 api->state_sync_end = &state_sync_end;
1500 api->state_reset = &state_reset;
1501 api->state_update_signed = &state_update_signed;
1502 api->state_get = &state_get;
1503 api->state_get_prefix = &state_get_prefix;
1504 api->state_get_signed = &state_get_signed;
1506 LOG (GNUNET_ERROR_TYPE_INFO, _("Postgres database running\n"));
1512 * Exit point from the plugin.
1514 * @param cls The plugin context (as returned by "init")
1515 * @return Always NULL
1518 libgnunet_plugin_psycstore_postgres_done (void *cls)
1520 struct GNUNET_PSYCSTORE_PluginFunctions *api = cls;
1521 struct Plugin *plugin = api->cls;
1523 database_shutdown (plugin);
1526 LOG (GNUNET_ERROR_TYPE_DEBUG, "Postgres plugin has finished\n");
1530 /* end of plugin_psycstore_postgres.c */