GNUnet  0.11.x
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 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 
41 struct Plugin
42 {
47 
52 
56  unsigned int num_items;
57 };
58 
59 
66 static int
68 {
69  struct GNUNET_PQ_ExecuteStatement es[] = {
70  GNUNET_PQ_make_try_execute ("CREATE TEMPORARY SEQUENCE IF NOT EXISTS gn011dc_oid_seq"),
71  GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS gn011dc ("
72  " oid OID NOT NULL DEFAULT nextval('gn011dc_oid_seq'),"
73  " type INTEGER NOT NULL,"
74  " prox INTEGER NOT NULL,"
75  " discard_time BIGINT NOT NULL,"
76  " key BYTEA NOT NULL,"
77  " value BYTEA NOT NULL,"
78  " path BYTEA DEFAULT NULL)"),
80  "ALTER SEQUENCE gnu011dc_oid_seq OWNED BY gn011dc.oid"),
82  "CREATE INDEX IF NOT EXISTS idx_oid ON gn011dc (oid)"),
84  "CREATE INDEX IF NOT EXISTS idx_key ON gn011dc (key)"),
86  "CREATE INDEX IF NOT EXISTS idx_dt ON gn011dc (discard_time)"),
88  "ALTER TABLE gn011dc ALTER value SET STORAGE EXTERNAL"),
89  GNUNET_PQ_make_execute ("ALTER TABLE gn011dc ALTER key SET STORAGE PLAIN"),
91  };
92  struct GNUNET_PQ_PreparedStatement ps[] = {
93  GNUNET_PQ_make_prepare ("getkt",
94  "SELECT discard_time,type,value,path FROM gn011dc "
95  "WHERE key=$1 AND type=$2 AND discard_time >= $3",
96  3),
97  GNUNET_PQ_make_prepare ("getk",
98  "SELECT discard_time,type,value,path FROM gn011dc "
99  "WHERE key=$1 AND discard_time >= $2",
100  2),
101  GNUNET_PQ_make_prepare ("getex",
102  "SELECT length(value) AS len,oid,key FROM gn011dc"
103  " WHERE discard_time < $1"
104  " ORDER BY discard_time ASC LIMIT 1",
105  1),
106  GNUNET_PQ_make_prepare ("getm",
107  "SELECT length(value) AS len,oid,key FROM gn011dc"
108  " ORDER BY prox ASC, discard_time ASC LIMIT 1",
109  0),
110  GNUNET_PQ_make_prepare ("get_random",
111  "SELECT discard_time,type,value,path,key FROM gn011dc"
112  " WHERE discard_time >= $1"
113  " ORDER BY key ASC LIMIT 1 OFFSET $2",
114  2),
115  GNUNET_PQ_make_prepare ("get_closest",
116  "SELECT discard_time,type,value,path,key FROM gn011dc "
117  "WHERE key>=$1 AND discard_time >= $2 ORDER BY key ASC LIMIT $3",
118  3),
119  GNUNET_PQ_make_prepare ("delrow",
120  "DELETE FROM gn011dc WHERE oid=$1",
121  1),
122  GNUNET_PQ_make_prepare ("put",
123  "INSERT INTO gn011dc (type, prox, discard_time, key, value, path) "
124  "VALUES ($1, $2, $3, $4, $5, $6)",
125  6),
127  };
128 
129  plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->env->cfg,
130  "datacache-postgres",
131  NULL,
132  es,
133  ps);
134  if (NULL == plugin->dbh)
135  return GNUNET_SYSERR;
136  return GNUNET_OK;
137 }
138 
139 
154 static ssize_t
156  const struct GNUNET_HashCode *key,
157  uint32_t prox,
158  size_t data_size,
159  const char *data,
160  enum GNUNET_BLOCK_Type type,
161  struct GNUNET_TIME_Absolute discard_time,
162  unsigned int path_info_len,
163  const struct GNUNET_PeerIdentity *path_info)
164 {
165  struct Plugin *plugin = cls;
166  uint32_t type32 = (uint32_t) type;
167  struct GNUNET_PQ_QueryParam params[] = {
170  GNUNET_PQ_query_param_absolute_time (&discard_time),
172  GNUNET_PQ_query_param_fixed_size (data, data_size),
174  path_info_len * sizeof(struct
177  };
179 
181  "put",
182  params);
183  if (0 > ret)
184  return -1;
185  plugin->num_items++;
186  return data_size + OVERHEAD;
187 }
188 
189 
194 {
199 
203  void *iter_cls;
204 
208  const struct GNUNET_HashCode *key;
209 };
210 
211 
221 static void
222 handle_results (void *cls,
223  PGresult *result,
224  unsigned int num_results)
225 {
226  struct HandleResultContext *hrc = cls;
227 
228  for (unsigned int i = 0; i < num_results; i++)
229  {
230  struct GNUNET_TIME_Absolute expiration_time;
231  uint32_t type;
232  void *data;
233  size_t data_size;
234  struct GNUNET_PeerIdentity *path;
235  size_t path_len;
236  struct GNUNET_PQ_ResultSpec rs[] = {
237  GNUNET_PQ_result_spec_absolute_time ("discard_time",
238  &expiration_time),
240  &type),
242  &data,
243  &data_size),
245  (void **) &path,
246  &path_len),
248  };
249 
250  if (GNUNET_YES !=
251  GNUNET_PQ_extract_result (result,
252  rs,
253  i))
254  {
255  GNUNET_break (0);
256  return;
257  }
258  if (0 != (path_len % sizeof(struct GNUNET_PeerIdentity)))
259  {
260  GNUNET_break (0);
261  path_len = 0;
262  }
263  path_len %= sizeof(struct GNUNET_PeerIdentity);
265  "Found result of size %u bytes and type %u in database\n",
266  (unsigned int) data_size,
267  (unsigned int) type);
268  if ((NULL != hrc->iter) &&
269  (GNUNET_SYSERR ==
270  hrc->iter (hrc->iter_cls,
271  hrc->key,
272  data_size,
273  data,
274  (enum GNUNET_BLOCK_Type) type,
275  expiration_time,
276  path_len,
277  path)))
278  {
280  "Ending iteration (client error)\n");
282  return;
283  }
285  }
286 }
287 
288 
300 static unsigned int
302  const struct GNUNET_HashCode *key,
303  enum GNUNET_BLOCK_Type type,
305  void *iter_cls)
306 {
307  struct Plugin *plugin = cls;
308  uint32_t type32 = (uint32_t) type;
309  struct GNUNET_TIME_Absolute now;
310  struct GNUNET_PQ_QueryParam paramk[] = {
314  };
315  struct GNUNET_PQ_QueryParam paramkt[] = {
320  };
322  struct HandleResultContext hr_ctx;
323 
324  now = GNUNET_TIME_absolute_get ();
325  hr_ctx.iter = iter;
326  hr_ctx.iter_cls = iter_cls;
327  hr_ctx.key = key;
329  (0 == type) ? "getk" : "getkt",
330  (0 == type) ? paramk : paramkt,
332  &hr_ctx);
333  if (res < 0)
334  return 0;
335  return res;
336 }
337 
338 
346 static int
348 {
349  struct Plugin *plugin = cls;
350  struct GNUNET_PQ_QueryParam pempty[] = {
352  };
353  uint32_t size;
354  uint32_t oid;
355  struct GNUNET_HashCode key;
356  struct GNUNET_PQ_ResultSpec rs[] = {
358  &size),
360  &oid),
362  &key),
364  };
366  struct GNUNET_PQ_QueryParam dparam[] = {
369  };
370  struct GNUNET_TIME_Absolute now;
371  struct GNUNET_PQ_QueryParam xparam[] = {
374  };
375 
376  now = GNUNET_TIME_absolute_get ();
378  "getex",
379  xparam,
380  rs);
381  if (0 >= res)
383  "getm",
384  pempty,
385  rs);
386  if (0 > res)
387  return GNUNET_SYSERR;
389  {
390  /* no result */
392  "Ending iteration (no more results)\n");
393  return 0;
394  }
396  "delrow",
397  dparam);
398  if (0 > res)
399  {
401  return GNUNET_SYSERR;
402  }
403  plugin->num_items--;
404  plugin->env->delete_notify (plugin->env->cls,
405  &key,
406  size + OVERHEAD);
408  return GNUNET_OK;
409 }
410 
411 
420 static unsigned int
423  void *iter_cls)
424 {
425  struct Plugin *plugin = cls;
426  uint32_t off;
427  struct GNUNET_TIME_Absolute now;
428  struct GNUNET_TIME_Absolute expiration_time;
429  size_t data_size;
430  void *data;
431  size_t path_len;
432  struct GNUNET_PeerIdentity *path;
433  struct GNUNET_HashCode key;
434  uint32_t type;
436  struct GNUNET_PQ_QueryParam params[] = {
440  };
441  struct GNUNET_PQ_ResultSpec rs[] = {
442  GNUNET_PQ_result_spec_absolute_time ("discard_time",
443  &expiration_time),
445  &type),
447  &data,
448  &data_size),
450  (void **) &path,
451  &path_len),
453  &key),
455  };
456 
457  if (0 == plugin->num_items)
458  return 0;
459  if (NULL == iter)
460  return 1;
461  now = GNUNET_TIME_absolute_get ();
463  plugin->num_items);
465  "get_random",
466  params,
467  rs);
468  if (0 > res)
469  {
470  GNUNET_break (0);
471  return 0;
472  }
474  {
475  GNUNET_break (0);
476  return 0;
477  }
478  if (0 != (path_len % sizeof(struct GNUNET_PeerIdentity)))
479  {
480  GNUNET_break (0);
481  path_len = 0;
482  }
483  path_len %= sizeof(struct GNUNET_PeerIdentity);
485  "Found random value with key %s of size %u bytes and type %u in database\n",
486  GNUNET_h2s (&key),
487  (unsigned int) data_size,
488  (unsigned int) type);
489  (void) iter (iter_cls,
490  &key,
491  data_size,
492  data,
493  (enum GNUNET_BLOCK_Type) type,
494  expiration_time,
495  path_len,
496  path);
498  return 1;
499 }
500 
501 
506 {
511 
515  void *iter_cls;
516 };
517 
518 
528 static void
529 extract_result_cb (void *cls,
530  PGresult *result,
531  unsigned int num_results)
532 {
533  struct ExtractResultContext *erc = cls;
534 
535  if (NULL == erc->iter)
536  return;
537  for (unsigned int i = 0; i < num_results; i++)
538  {
539  struct GNUNET_TIME_Absolute expiration_time;
540  uint32_t type;
541  void *data;
542  size_t data_size;
543  struct GNUNET_PeerIdentity *path;
544  size_t path_len;
545  struct GNUNET_HashCode key;
546  struct GNUNET_PQ_ResultSpec rs[] = {
548  &expiration_time),
550  &type),
552  &data,
553  &data_size),
555  (void **) &path,
556  &path_len),
558  &key),
560  };
561 
562  if (GNUNET_YES !=
563  GNUNET_PQ_extract_result (result,
564  rs,
565  i))
566  {
567  GNUNET_break (0);
568  return;
569  }
570  if (0 != (path_len % sizeof(struct GNUNET_PeerIdentity)))
571  {
572  GNUNET_break (0);
573  path_len = 0;
574  }
575  path_len %= sizeof(struct GNUNET_PeerIdentity);
577  "Found result of size %u bytes and type %u in database\n",
578  (unsigned int) data_size,
579  (unsigned int) type);
580  if (GNUNET_SYSERR ==
581  erc->iter (erc->iter_cls,
582  &key,
583  data_size,
584  data,
585  (enum GNUNET_BLOCK_Type) type,
586  expiration_time,
587  path_len,
588  path))
589  {
591  "Ending iteration (client error)\n");
593  break;
594  }
596  }
597 }
598 
599 
613 static unsigned int
615  const struct GNUNET_HashCode *key,
616  unsigned int num_results,
618  void *iter_cls)
619 {
620  struct Plugin *plugin = cls;
621  uint32_t num_results32 = (uint32_t) num_results;
622  struct GNUNET_TIME_Absolute now;
623  struct GNUNET_PQ_QueryParam params[] = {
626  GNUNET_PQ_query_param_uint32 (&num_results32),
628  };
630  struct ExtractResultContext erc;
631 
632  erc.iter = iter;
633  erc.iter_cls = iter_cls;
634  now = GNUNET_TIME_absolute_get ();
636  "get_closest",
637  params,
639  &erc);
640  if (0 > res)
641  {
643  "Ending iteration (postgres error)\n");
644  return 0;
645  }
647  {
648  /* no result */
650  "Ending iteration (no more results)\n");
651  return 0;
652  }
653  return res;
654 }
655 
656 
663 void *
665 {
668  struct Plugin *plugin;
669 
670  plugin = GNUNET_new (struct Plugin);
671  plugin->env = env;
672 
673  if (GNUNET_OK != init_connection (plugin))
674  {
675  GNUNET_free (plugin);
676  return NULL;
677  }
678 
680  api->cls = plugin;
681  api->get = &postgres_plugin_get;
682  api->put = &postgres_plugin_put;
683  api->del = &postgres_plugin_del;
687  "Postgres datacache running\n");
688  return api;
689 }
690 
691 
698 void *
700 {
702  struct Plugin *plugin = api->cls;
703 
704  GNUNET_PQ_disconnect (plugin->dbh);
705  GNUNET_free (plugin);
706  GNUNET_free (api);
707  return NULL;
708 }
709 
710 
711 /* end of plugin_datacache_postgres.c */
void * cls
Closure to pass to all plugin functions.
static unsigned int postgres_plugin_get_random(void *cls, GNUNET_DATACACHE_Iterator iter, void *iter_cls)
Obtain a random key-value pair from the datacache.
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:516
void * iter_cls
Closure for iter.
ssize_t(* put)(void *cls, const struct GNUNET_HashCode *key, uint32_t xor_distance, size_t size, const char *data, enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute discard_time, unsigned int path_info_len, const struct GNUNET_PeerIdentity *path_info)
Store an item in the datastore.
int(* del)(void *cls)
Delete the entry with the lowest expiration value from the datacache right now.
static int postgres_plugin_del(void *cls)
Delete the entry with the lowest expiration value from the datacache right now.
struct GNUNET_PQ_ExecuteStatement GNUNET_PQ_make_execute(const char *sql)
Create a struct GNUNET_PQ_ExecuteStatement where errors are fatal.
Definition: pq_exec.c:36
void * iter_cls
Closure for iter.
GNUNET_BLOCK_Type
Blocks in the datastore and the datacache must have a unique type.
const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration to use.
#define LOG(kind,...)
void * libgnunet_plugin_datacache_postgres_init(void *cls)
Entry point for the plugin.
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:209
static size_t data_size
Number of bytes in data.
Definition: gnunet-abd.c:187
uint32_t GNUNET_CRYPTO_random_u32(enum GNUNET_CRYPTO_Quality mode, uint32_t i)
Produce a random value.
Information needed to run a list of SQL statements using GNUNET_PQ_exec_statements().
Information needed to prepare a list of SQL statements using GNUNET_PQ_prepare_statements().
char * key
TLS key.
Description of a DB result cell.
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
Closure for handle_results.
struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_absolute_time(const struct GNUNET_TIME_Absolute *x)
Generate query parameter for an absolute time value.
const char * GNUNET_h2s(const struct GNUNET_HashCode *hc)
Convert a hash value to a string (for printing debug messages).
#define GNUNET_new(type)
Allocate a struct or union of the given type.
Closure for extract_result_cb.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
struct GNUNET_BLOCK_PluginFunctions * api
Plugin API.
Definition: block.c:47
static unsigned int postgres_plugin_get_closest(void *cls, const struct GNUNET_HashCode *key, 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.
GNUNET_DATACACHE_DeleteNotifyCallback delete_notify
Function to call whenever the plugin needs to discard content that it was asked to store...
#define OVERHEAD
Per-entry overhead estimate.
#define GNUNET_PQ_result_spec_end
End of result parameter specification.
#define GNUNET_PQ_query_param_end
End of query parameter specification.
Definition: gnunet_pq_lib.h:97
struct GNUNET_PQ_ResultSpec GNUNET_PQ_result_spec_variable_size(const char *name, void **dst, size_t *sptr)
Variable-size result expected.
struct GNUNET_PQ_ResultSpec GNUNET_PQ_result_spec_uint32(const char *name, uint32_t *u32)
uint32_t expected.
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...
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:258
struct GNUNET_PQ_ResultSpec GNUNET_PQ_result_spec_absolute_time(const char *name, struct GNUNET_TIME_Absolute *at)
Absolute time expected.
struct GNUNET_DATACACHE_PluginEnvironment * env
Our execution environment.
unsigned int(* get_closest)(void *cls, const struct GNUNET_HashCode *key, 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.
#define GNUNET_PQ_query_param_auto_from_type(x)
Generate fixed-size query parameter with size determined by variable type.
Randomness for IVs etc.
static ssize_t postgres_plugin_put(void *cls, const struct GNUNET_HashCode *key, uint32_t prox, size_t data_size, const char *data, enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute discard_time, unsigned int path_info_len, const struct GNUNET_PeerIdentity *path_info)
Store an item in the datastore.
struct returned by the initialization function of the plugin
static int result
Global testing status.
struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_uint32(const uint32_t *x)
Generate query parameter for an uint32_t in host byte order.
A 512-bit hashcode.
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...
void * libgnunet_plugin_datacache_postgres_done(void *cls)
Exit point from the plugin.
static int res
static char * plugin
Solver plugin name as string.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:86
struct GNUNET_PQ_Context * GNUNET_PQ_connect_with_cfg(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *load_path_suffix, const struct GNUNET_PQ_ExecuteStatement *es, const struct GNUNET_PQ_PreparedStatement *ps)
Connect to a postgres database using the configuration option "CONFIG" in section.
Definition: pq_connect.c:469
#define GNUNET_PQ_result_spec_auto_from_type(name, dst)
We expect a fixed-size result, with size determined by the type of * dst
#define GNUNET_PQ_PREPARED_STATEMENT_END
Terminator for prepared statement list.
helper functions for Postgres DB interactions
void * iter_cls
Iterator cls.
GNUNET_DATACACHE_Iterator iter
Function to call on each result, may be NULL.
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:164
The identity of the host (wraps the signing key of the peer).
unsigned long long size
Size of all values we&#39;re storing.
Handle for a plugin.
Definition: block.c:37
struct GNUNET_PQ_Context * dbh
Native Postgres database handle.
GNUNET_DATACACHE_Iterator iter
Function to call for each result found.
Description of a DB query parameter.
Definition: gnunet_pq_lib.h:64
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.
#define GNUNET_PQ_EXECUTE_STATEMENT_END
Terminator for executable statement list.
int(* GNUNET_DATACACHE_Iterator)(void *cls, const struct GNUNET_HashCode *key, size_t data_size, const char *data, enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute exp, unsigned int path_info_len, const struct GNUNET_PeerIdentity *path_info)
An iterator over a set of items stored in the datacache.
void * cls
Closure to use for callbacks.
enum GNUNET_TESTBED_UnderlayLinkModelType type
the type of this model
Time for absolute times used by GNUnet, in microseconds.
GNUNET_DB_QueryStatus
Status code returned from functions running database commands.
Definition: gnunet_db_lib.h:34
unsigned int num_items
Number of key-value pairs in the database.
unsigned int(* get_random)(void *cls, GNUNET_DATACACHE_Iterator iter, void *iter_cls)
Return a random value from the datastore.
struct GNUNET_PQ_ExecuteStatement GNUNET_PQ_make_try_execute(const char *sql)
Create a struct GNUNET_PQ_ExecuteStatement where errors should be tolerated.
Definition: pq_exec.c:55
static int init_connection(struct Plugin *plugin)
Get a database handle.
The transaction succeeded, but yielded zero results.
Definition: gnunet_db_lib.h:53
uint32_t data
The data value.
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.
The datastore service will pass a pointer to a struct of this type as the first and only argument to ...
GNUNET_PEERSTORE_Processor iter
Iterator.
const struct GNUNET_HashCode * key
Key used.
Handle to Postgres database.
Definition: pq.h:34
struct GNUNET_PQ_PreparedStatement GNUNET_PQ_make_prepare(const char *name, const char *sql, unsigned int num_args)
Create a struct GNUNET_PQ_PreparedStatement.
Definition: pq_prepare.c:38
int 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:127
unsigned int(* 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.
#define GNUNET_free(ptr)
Wrapper around free.
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:117