GNUnet 0.28.1-dev.6-1-gcf4da5b7a
 
Loading...
Searching...
No Matches
plugin_datacache_postgres.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet
3 Copyright (C) 2006, 2009, 2010, 2012, 2015, 2017, 2018, 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
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_pq_lib.h"
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "datacache-postgres", __VA_ARGS__)
32
36#define OVERHEAD (sizeof(struct GNUNET_HashCode) + 24)
37
41struct Plugin
42{
47
52
56 unsigned int num_items;
57
61 bool ready;
62
63};
64
65
73static void
74reconnect_setup (void *cls,
75 struct GNUNET_PQ_Context *pq)
76{
77 struct Plugin *plugin = cls;
80 "SELECT expiration_time,type,ro,value,trunc,path"
81 " FROM datacache.gn180dc"
82 " WHERE key=$1 AND type=$2 AND expiration_time >= $3"
83 " ORDER BY expiration_time DESC"),
85 "SELECT expiration_time,type,ro,value,trunc,path"
86 " FROM datacache.gn180dc"
87 " WHERE key=$1 AND expiration_time >= $2"
88 " ORDER BY expiration_time DESC"),
90 "SELECT LENGTH(value) AS len,oid,key"
91 " FROM datacache.gn180dc"
92 " WHERE expiration_time < $1"
93 " ORDER BY expiration_time ASC LIMIT 1"),
95 "SELECT LENGTH(value) AS len,oid,key"
96 " FROM datacache.gn180dc"
97 " ORDER BY prox ASC, expiration_time ASC LIMIT 1"),
98 GNUNET_PQ_make_prepare ("get_closest",
99 "(SELECT expiration_time,type,ro,value,trunc,path,key"
100 " FROM datacache.gn180dc"
101 " WHERE key >= $1"
102 " AND expiration_time >= $2"
103 " AND ( (type = $3) OR ( 0 = $3) )"
104 " ORDER BY key ASC"
105 " LIMIT $4)"
106 " UNION "
107 "(SELECT expiration_time,type,ro,value,trunc,path,key"
108 " FROM datacache.gn180dc"
109 " WHERE key <= $1"
110 " AND expiration_time >= $2"
111 " AND ( (type = $3) OR ( 0 = $3) )"
112 " ORDER BY key DESC"
113 " LIMIT $4)"),
114 GNUNET_PQ_make_prepare ("delrow",
115 "DELETE FROM datacache.gn180dc"
116 " WHERE oid=$1"),
118 "INSERT INTO datacache.gn180dc"
119 " (type, ro, prox, expiration_time, key, value, trunc, path) "
120 "VALUES ($1, $2, $3, $4, $5, $6, $7, $8)"),
122 };
123
124 if (GNUNET_OK !=
126 "datacache-"))
127 {
128 plugin->ready = false;
129 return;
130 }
131 if (GNUNET_OK !=
133 ps))
134 {
135 plugin->ready = false;
136 return;
137 }
138 plugin->ready = true;
139}
140
141
150{
151 plugin->dbh = GNUNET_PQ_init (plugin->env->cfg,
152 "datacache-postgres",
154 plugin);
155 if (NULL == plugin->dbh)
156 return GNUNET_SYSERR;
157 if (! plugin->ready)
158 return GNUNET_NO;
159 return GNUNET_OK;
160}
161
162
171static ssize_t
173 uint32_t prox,
174 const struct GNUNET_DATACACHE_Block *block)
175{
176 struct Plugin *plugin = cls;
177 uint32_t type32 = (uint32_t) block->type;
178 uint32_t ro32 = (uint32_t) block->type;
179 struct GNUNET_PQ_QueryParam params[] = {
186 block->data_size),
188 (0 == block->put_path_length)
191 block->put_path,
192 block->put_path_length
193 * sizeof(struct GNUNET_DHT_PathElement)),
195 };
197
199 "put",
200 params);
201 if (0 > ret)
202 return -1;
203 plugin->num_items++;
204 return block->data_size + OVERHEAD;
205}
206
207
228
229
239static void
240handle_results (void *cls,
241 PGresult *result,
242 unsigned int num_results)
243{
244 struct HandleResultContext *hrc = cls;
245
246 for (unsigned int i = 0; i < num_results; i++)
247 {
248 uint32_t type32;
249 uint32_t bro32;
250 void *data;
251 struct GNUNET_DATACACHE_Block block;
252 void *path = NULL;
253 size_t path_size = 0;
254 struct GNUNET_PQ_ResultSpec rs[] = {
255 GNUNET_PQ_result_spec_absolute_time ("expiration_time",
256 &block.expiration_time),
258 &type32),
260 &bro32),
262 &data,
263 &block.data_size),
265 &block.trunc_peer),
268 &path,
269 &path_size),
270 NULL),
272 };
273
274 if (GNUNET_YES !=
276 rs,
277 i))
278 {
279 GNUNET_break (0);
280 return;
281 }
282 if (0 != (path_size % sizeof(struct GNUNET_DHT_PathElement)))
283 {
284 GNUNET_break (0);
285 path_size = 0;
286 path = NULL;
287 }
288 block.data = data;
289 block.put_path = path;
290 block.put_path_length
291 = path_size / sizeof (struct GNUNET_DHT_PathElement);
292 block.type = (enum GNUNET_BLOCK_Type) type32;
293 block.ro = (enum GNUNET_DHT_RouteOption) bro32;
294 block.key = *hrc->key;
296 "Found result of size %u bytes and type %u in database\n",
297 (unsigned int) block.data_size,
298 (unsigned int) block.type);
299 if ( (NULL != hrc->iter) &&
300 (GNUNET_SYSERR ==
301 hrc->iter (hrc->iter_cls,
302 &block)) )
303 {
305 "Ending iteration (client error)\n");
307 return;
308 }
310 }
311}
312
313
325static unsigned int
327 const struct GNUNET_HashCode *key,
330 void *iter_cls)
331{
332 struct Plugin *plugin = cls;
333 uint32_t type32 = (uint32_t) type;
334 struct GNUNET_TIME_Absolute now = { 0 };
335 struct GNUNET_PQ_QueryParam paramk[] = {
339 };
340 struct GNUNET_PQ_QueryParam paramkt[] = {
345 };
347 struct HandleResultContext hr_ctx;
348
350 hr_ctx.iter = iter;
351 hr_ctx.iter_cls = iter_cls;
352 hr_ctx.key = key;
354 (0 == type) ? "getk" : "getkt",
355 (0 == type) ? paramk : paramkt,
357 &hr_ctx);
358 if (res < 0)
359 return 0;
360 return res;
361}
362
363
373{
374 struct Plugin *plugin = cls;
375 struct GNUNET_PQ_QueryParam pempty[] = {
377 };
378 uint32_t size;
379 uint64_t oid;
380 struct GNUNET_HashCode key;
381 struct GNUNET_PQ_ResultSpec rs[] = {
383 &size),
385 &oid),
387 &key),
389 };
391 struct GNUNET_TIME_Absolute now;
393 {
394 struct GNUNET_PQ_QueryParam xparam[] = {
397 };
398
400 "getex",
401 xparam,
402 rs);
403 }
404 if (0 >= res)
406 "getm",
407 pempty,
408 rs);
409 if (0 > res)
410 return GNUNET_SYSERR;
412 {
413 /* no result */
415 "Ending iteration (no more results)\n");
416 return 0;
417 }
418 {
419 struct GNUNET_PQ_QueryParam dparam[] = {
422 };
424 "delrow",
425 dparam);
426 }
427 if (0 > res)
428 {
430 return GNUNET_SYSERR;
431 }
432 plugin->num_items--;
433 plugin->env->delete_notify (plugin->env->cls,
434 &key,
435 size + OVERHEAD);
437 return GNUNET_OK;
438}
439
440
456
457
467static void
469 PGresult *result,
470 unsigned int num_results)
471{
472 struct ExtractResultContext *erc = cls;
473
474 if (NULL == erc->iter)
475 return;
476 for (unsigned int i = 0; i < num_results; i++)
477 {
478 uint32_t type32;
479 uint32_t bro32;
480 struct GNUNET_DATACACHE_Block block;
481 void *data;
482 void *path;
483 size_t path_size;
484 struct GNUNET_PQ_ResultSpec rs[] = {
485 GNUNET_PQ_result_spec_absolute_time ("expiration_time",
486 &block.expiration_time),
488 &type32),
490 &bro32),
492 &data,
493 &block.data_size),
495 &block.trunc_peer),
497 &path,
498 &path_size),
500 &block.key),
502 };
503
504 if (GNUNET_YES !=
506 rs,
507 i))
508 {
509 GNUNET_break (0);
510 return;
511 }
512 if (0 != (path_size % sizeof(struct GNUNET_DHT_PathElement)))
513 {
514 GNUNET_break (0);
515 path_size = 0;
516 path = NULL;
517 }
518 block.type = (enum GNUNET_BLOCK_Type) type32;
519 block.ro = (enum GNUNET_DHT_RouteOption) bro32;
520 block.data = data;
521 block.put_path = path;
522 block.put_path_length = path_size / sizeof (struct GNUNET_DHT_PathElement);
524 "Found result of size %u bytes and type %u in database\n",
525 (unsigned int) block.data_size,
526 (unsigned int) block.type);
527 if ( (NULL != erc->iter) &&
528 (GNUNET_SYSERR ==
529 erc->iter (erc->iter_cls,
530 &block)) )
531 {
533 "Ending iteration (client error)\n");
535 break;
536 }
538 }
539}
540
541
556static unsigned int
558 const struct GNUNET_HashCode *key,
560 unsigned int num_results,
562 void *iter_cls)
563{
564 struct Plugin *plugin = cls;
565 uint32_t num_results32 = (uint32_t) num_results;
566 uint32_t type32 = (uint32_t) type;
567 struct GNUNET_TIME_Absolute now;
569 struct ExtractResultContext erc;
570
571 erc.iter = iter;
572 erc.iter_cls = iter_cls;
574 {
575 struct GNUNET_PQ_QueryParam params[] = {
579 GNUNET_PQ_query_param_uint32 (&num_results32),
581 };
583 "get_closest",
584 params,
586 &erc);
587 }
588 if (0 > res)
589 {
591 "Ending iteration (postgres error)\n");
592 return 0;
593 }
595 {
596 /* no result */
598 "Ending iteration (no more results)\n");
599 return 0;
600 }
601 return res;
602}
603
604
605void *
607
614void *
616{
619 struct Plugin *plugin;
620
621 plugin = GNUNET_new (struct Plugin);
622 plugin->env = env;
623
625 {
627 return NULL;
628 }
629
631 api->cls = plugin;
632 api->get = &postgres_plugin_get;
633 api->put = &postgres_plugin_put;
634 api->del = &postgres_plugin_del;
635 api->get_closest = &postgres_plugin_get_closest;
637 "Postgres datacache running\n");
638 return api;
639}
640
641
642void *
644
651void *
653{
655 struct Plugin *plugin = api->cls;
656
659 "datacache-drop"));
663 return NULL;
664}
665
666
667/* end of plugin_datacache_postgres.c */
struct GNUNET_MQ_Envelope * env
Definition 005.c:1
static int ret
Final status code.
Definition gnunet-arm.c:93
static struct GNUNET_TESTING_PluginFunctions * plugin
Plugin to dynamically load a test case.
static struct GNUNET_PEERSTORE_Handle * ps
Handle to the PEERSTORE service.
static char * data
The data to insert into the dht.
struct GNUNET_HashCode key
The key used in the DHT.
static char * res
Currently read line or NULL on EOF.
static uint32_t type
Type string converted to DNS type value.
static int result
Global testing status.
API for database backends for the datacache.
GNUNET_DB_QueryStatus
Status code returned from functions running database commands.
@ GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
The transaction succeeded, but yielded zero results.
GNUNET_BLOCK_Type
WARNING: This header is generated! In order to add DHT block types, you must register them in GANA,...
helper functions for Postgres DB interactions
struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_fixed_size(const void *ptr, size_t ptr_size)
Generate query parameter for a buffer ptr of ptr_size bytes.
struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_uint64(const uint64_t *x)
Generate query parameter for an uint64_t in host byte order.
#define GNUNET_PQ_query_param_auto_from_type(x)
Generate fixed-size query parameter with size determined by variable type.
enum GNUNET_DB_QueryStatus GNUNET_PQ_eval_prepared_multi_select(struct GNUNET_PQ_Context *db, const char *statement_name, const struct GNUNET_PQ_QueryParam *params, GNUNET_PQ_PostgresResultHandler rh, void *rh_cls)
Execute a named prepared statement that is a SELECT statement which may return multiple results in co...
Definition pq_eval.c:165
struct GNUNET_PQ_ResultSpec GNUNET_PQ_result_spec_uint32(const char *name, uint32_t *u32)
uint32_t expected.
struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_null(void)
Generate query parameter to create a NULL value.
enum GNUNET_DB_QueryStatus GNUNET_PQ_eval_prepared_singleton_select(struct GNUNET_PQ_Context *db, const char *statement_name, const struct GNUNET_PQ_QueryParam *params, struct GNUNET_PQ_ResultSpec *rs)
Execute a named prepared statement that is a SELECT statement which must return a single result in co...
Definition pq_eval.c:199
struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_absolute_time(const struct GNUNET_TIME_Absolute *x)
Generate query parameter for an absolute time value.
#define GNUNET_PQ_result_spec_auto_from_type(name, dst)
We expect a fixed-size result, with size determined by the type of * dst
enum GNUNET_GenericReturnValue GNUNET_PQ_prepare_statements(struct GNUNET_PQ_Context *db, const struct GNUNET_PQ_PreparedStatement *ps)
Request creation of prepared statements ps from Postgres.
Definition pq_prepare.c:77
struct GNUNET_PQ_ResultSpec GNUNET_PQ_result_spec_uint64(const char *name, uint64_t *u64)
uint64_t expected.
void GNUNET_PQ_disconnect(struct GNUNET_PQ_Context *db)
Disconnect from the database, destroying the prepared statements and releasing other associated resou...
Definition pq_connect.c:788
struct GNUNET_PQ_ResultSpec GNUNET_PQ_result_spec_allow_null(struct GNUNET_PQ_ResultSpec rs, bool *is_null)
Allow NULL value to be found in the database for the given value.
struct GNUNET_PQ_ResultSpec GNUNET_PQ_result_spec_absolute_time(const char *name, struct GNUNET_TIME_Absolute *at)
Absolute time expected.
struct GNUNET_PQ_PreparedStatement GNUNET_PQ_make_prepare(const char *name, const char *sql)
Create a struct GNUNET_PQ_PreparedStatement.
Definition pq_prepare.c:30
#define GNUNET_PQ_query_param_end
End of query parameter specification.
struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_uint32(const uint32_t *x)
Generate query parameter for an uint32_t in host byte order.
struct GNUNET_PQ_Context * GNUNET_PQ_init(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, GNUNET_PQ_ReconnectCallback rc, void *rc_cls)
Connect to a postgres database using the configuration option "CONFIG" in section.
struct GNUNET_PQ_ResultSpec GNUNET_PQ_result_spec_variable_size(const char *name, void **dst, size_t *sptr)
Variable-size result expected.
void GNUNET_PQ_cleanup_result(struct GNUNET_PQ_ResultSpec *rs)
Free all memory that was allocated in rs during GNUNET_PQ_extract_result().
Definition pq.c:142
#define GNUNET_PQ_PREPARED_STATEMENT_END
Terminator for prepared statement list.
enum GNUNET_GenericReturnValue GNUNET_PQ_extract_result(PGresult *result, struct GNUNET_PQ_ResultSpec *rs, int row)
Extract results from a query result according to the given specification.
Definition pq.c:152
uint32_t oid
enum GNUNET_DB_QueryStatus GNUNET_PQ_eval_prepared_non_select(struct GNUNET_PQ_Context *db, const char *statement_name, const struct GNUNET_PQ_QueryParam *params)
Execute a named prepared statement that is NOT a SELECT statement in connection using the given param...
Definition pq_eval.c:135
enum GNUNET_GenericReturnValue GNUNET_PQ_exec_sql(struct GNUNET_PQ_Context *db, const char *buf)
Execute SQL statements from buf against db.
Definition pq_connect.c:388
#define GNUNET_PQ_result_spec_end
End of result parameter specification.
enum GNUNET_GenericReturnValue GNUNET_PQ_run_sql(struct GNUNET_PQ_Context *db, const char *load_suffix)
Within the db context, run all the SQL files in the load path where the name starts with the load_suf...
Definition pq_connect.c:486
enum GNUNET_GenericReturnValue(* GNUNET_DATACACHE_Iterator)(void *cls, const struct GNUNET_DATACACHE_Block *block)
An iterator over a set of items stored in the datacache.
GNUNET_DHT_RouteOption
Options for routing.
GNUNET_GenericReturnValue
Named constants for return values.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition time.c:111
static unsigned int size
Size of the "table".
Definition peer.c:68
#define OVERHEAD
Per-entry overhead estimate.
void * libgnunet_plugin_datacache_postgres_init(void *cls)
Entry point for the plugin.
static ssize_t postgres_plugin_put(void *cls, uint32_t prox, const struct GNUNET_DATACACHE_Block *block)
Store an item in the datastore.
static enum GNUNET_GenericReturnValue postgres_plugin_del(void *cls)
Delete the entry with the lowest expiration value from the datacache right now.
static enum GNUNET_GenericReturnValue init_connection(struct Plugin *plugin)
Get a database handle.
static unsigned int postgres_plugin_get(void *cls, const struct GNUNET_HashCode *key, enum GNUNET_BLOCK_Type type, GNUNET_DATACACHE_Iterator iter, void *iter_cls)
Iterate over the results for a particular key in the datastore.
void * libgnunet_plugin_datacache_postgres_done(void *cls)
Exit point from the plugin.
static unsigned int postgres_plugin_get_closest(void *cls, const struct GNUNET_HashCode *key, enum GNUNET_BLOCK_Type type, unsigned int num_results, GNUNET_DATACACHE_Iterator iter, void *iter_cls)
Iterate over the results that are "close" to a particular key in the datacache.
static void extract_result_cb(void *cls, PGresult *result, unsigned int num_results)
Function to be called with the results of a SELECT statement that has returned num_results results.
#define LOG(kind,...)
static void reconnect_setup(void *cls, struct GNUNET_PQ_Context *pq)
Function called whenever we reconnect to the DB.
static void handle_results(void *cls, PGresult *result, unsigned int num_results)
Function to be called with the results of a SELECT statement that has returned num_results results.
Closure for extract_result_cb.
void * iter_cls
Closure for iter.
GNUNET_DATACACHE_Iterator iter
Function to call for each result found.
void * cls
Closure for all of the callbacks.
Information about a block stored in the datacache.
const struct GNUNET_DHT_PathElement * put_path
PUT path taken by the block, array of peer identities.
enum GNUNET_BLOCK_Type type
Type of the block.
const void * data
Actual block data.
enum GNUNET_DHT_RouteOption ro
Options for routing for the block.
struct GNUNET_PeerIdentity trunc_peer
If the path was truncated, this is the peer ID at which the path was truncated.
struct GNUNET_HashCode key
Key of the block.
size_t data_size
Number of bytes in data.
unsigned int put_path_length
Length of the put_path array.
struct GNUNET_TIME_Absolute expiration_time
When does the block expire?
The datastore service will pass a pointer to a struct of this type as the first and only argument to ...
void * cls
Closure to use for callbacks.
struct returned by the initialization function of the plugin
void * cls
Closure to pass to all plugin functions.
A (signed) path tracking a block's flow through the DHT is represented by an array of path elements,...
A 512-bit hashcode.
Handle to Postgres database.
Definition pq.h:36
Information needed to prepare a list of SQL statements using GNUNET_PQ_prepare_statements().
Description of a DB query parameter.
Description of a DB result cell.
void * cls
Closure to pass to start_testcase.
Time for absolute times used by GNUnet, in microseconds.
Closure for handle_results.
void * iter_cls
Closure for iter.
const struct GNUNET_HashCode * key
Key used.
GNUNET_DATACACHE_Iterator iter
Function to call on each result, may be NULL.
Handle for a plugin.
Definition block.c:38
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
Definition block.c:47
unsigned int num_items
Number of key-value pairs in the database.
bool ready
Set to true if the DB is ready for action.
struct GNUNET_DATACACHE_PluginEnvironment * env
Our execution environment.
struct GNUNET_PQ_Context * dbh
Native Postgres database handle.