GNUnet  0.11.x
plugin_namecache_postgres.c
Go to the documentation of this file.
1 /*
2  * This file is part of GNUnet
3  * Copyright (C) 2009-2013, 2016, 2017 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"
29 #include "gnunet_gnsrecord_lib.h"
30 #include "gnunet_pq_lib.h"
31 #include "namecache.h"
32 
33 
34 #define LOG(kind, ...) GNUNET_log_from (kind, "namecache-postgres", __VA_ARGS__)
35 
36 
40 struct Plugin
41 {
42  const struct GNUNET_CONFIGURATION_Handle *cfg;
43 
47  struct GNUNET_PQ_Context *dbh;
48 };
49 
50 
59 static int
61 {
62  struct GNUNET_PQ_ExecuteStatement es_temporary =
63  GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS ns096blocks ("
64  " query BYTEA NOT NULL DEFAULT '',"
65  " block BYTEA NOT NULL DEFAULT '',"
66  " expiration_time BIGINT NOT NULL DEFAULT 0"
67  ")");
68  struct GNUNET_PQ_ExecuteStatement es_default =
69  GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS ns096blocks ("
70  " query BYTEA NOT NULL DEFAULT '',"
71  " block BYTEA NOT NULL DEFAULT '',"
72  " expiration_time BIGINT NOT NULL DEFAULT 0"
73  ")");
74  const struct GNUNET_PQ_ExecuteStatement *cr;
75 
76  if (GNUNET_YES ==
78  "namecache-postgres",
79  "TEMPORARY_TABLE"))
80  {
81  cr = &es_temporary;
82  }
83  else
84  {
85  cr = &es_default;
86  }
87  {
88  struct GNUNET_PQ_ExecuteStatement es[] = {
89  *cr,
91  "CREATE INDEX ir_query_hash ON ns096blocks (query,expiration_time)"),
93  "CREATE INDEX ir_block_expiration ON ns096blocks (expiration_time)"),
95  };
96  struct GNUNET_PQ_PreparedStatement ps[] = {
97  GNUNET_PQ_make_prepare ("cache_block",
98  "INSERT INTO ns096blocks (query, block, expiration_time) VALUES "
99  "($1, $2, $3)", 3),
100  GNUNET_PQ_make_prepare ("expire_blocks",
101  "DELETE FROM ns096blocks WHERE expiration_time<$1",
102  1),
103  GNUNET_PQ_make_prepare ("delete_block",
104  "DELETE FROM ns096blocks WHERE query=$1 AND expiration_time<=$2",
105  2),
106  GNUNET_PQ_make_prepare ("lookup_block",
107  "SELECT block FROM ns096blocks WHERE query=$1"
108  " ORDER BY expiration_time DESC LIMIT 1", 1),
110  };
111 
112  plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg,
113  "namecache-postgres",
114  NULL,
115  es,
116  ps);
117  }
118  if (NULL == plugin->dbh)
119  return GNUNET_SYSERR;
120  return GNUNET_OK;
121 }
122 
123 
129 static void
131 {
133  struct GNUNET_PQ_QueryParam params[] = {
136  };
138 
140  "expire_blocks",
141  params);
143 }
144 
145 
153 static void
155  const struct GNUNET_HashCode *query,
156  struct GNUNET_TIME_Absolute expiration_time)
157 {
158  struct GNUNET_PQ_QueryParam params[] = {
160  GNUNET_PQ_query_param_absolute_time (&expiration_time),
162  };
164 
166  "delete_block",
167  params);
169 }
170 
171 
179 static int
181  const struct GNUNET_GNSRECORD_Block *block)
182 {
183  struct Plugin *plugin = cls;
184  struct GNUNET_HashCode query;
185  size_t block_size = GNUNET_GNSRECORD_block_get_size (block);
186  struct GNUNET_TIME_Absolute exp;
188  struct GNUNET_PQ_QueryParam params[] = {
190  GNUNET_PQ_query_param_fixed_size (block, block_size),
193  };
195 
198  &query);
199  if (block_size > 64 * 65536)
200  {
201  GNUNET_break (0);
202  return GNUNET_SYSERR;
203  }
204  delete_old_block (plugin,
205  &query,
206  exp);
207 
209  "cache_block",
210  params);
211  if (0 > res)
212  return GNUNET_SYSERR;
213  return GNUNET_OK;
214 }
215 
216 
227 static int
229  const struct GNUNET_HashCode *query,
231  void *iter_cls)
232 {
233  struct Plugin *plugin = cls;
234  size_t bsize;
235  struct GNUNET_GNSRECORD_Block *block;
236  struct GNUNET_PQ_QueryParam params[] = {
239  };
240  struct GNUNET_PQ_ResultSpec rs[] = {
242  (void **) &block,
243  &bsize),
245  };
247 
249  "lookup_block",
250  params,
251  rs);
252  if (0 > res)
253  {
255  "Failing lookup block in namecache (postgres error)\n");
256  return GNUNET_SYSERR;
257  }
259  {
260  /* no result */
262  "Ending iteration (no more results)\n");
263  return GNUNET_NO;
264  }
265  if ((bsize < sizeof(*block)))
266  {
267  GNUNET_break (0);
269  "Failing lookup (corrupt block)\n");
271  return GNUNET_SYSERR;
272  }
273  iter (iter_cls,
274  block);
276  return GNUNET_OK;
277 }
278 
279 
286 static void
288 {
289  GNUNET_PQ_disconnect (plugin->dbh);
290  plugin->dbh = NULL;
291 }
292 
293 
300 void *
302 {
303  static struct Plugin plugin;
304  const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
306 
307  if (NULL != plugin.cfg)
308  return NULL; /* can only initialize once! */
309  memset (&plugin, 0, sizeof(struct Plugin));
310  plugin.cfg = cfg;
311  if (GNUNET_OK != database_setup (&plugin))
312  {
313  database_shutdown (&plugin);
314  return NULL;
315  }
317  api->cls = &plugin;
321  "Postgres namecache plugin running\n");
322  return api;
323 }
324 
325 
332 void *
334 {
336  struct Plugin *plugin = api->cls;
337 
338  database_shutdown (plugin);
339  plugin->cfg = NULL;
340  GNUNET_free (api);
342  "Postgres namecache plugin is finished\n");
343  return NULL;
344 }
345 
346 
347 /* end of plugin_namecache_postgres.c */
void(* GNUNET_NAMECACHE_BlockCallback)(void *cls, const struct GNUNET_GNSRECORD_Block *block)
Function called for matching blocks.
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 * cls
Closure to pass to all plugin functions.
static int namecache_postgres_lookup_block(void *cls, const struct GNUNET_HashCode *query, GNUNET_NAMECACHE_BlockCallback iter, void *iter_cls)
Get the block for a particular zone and label in the datastore.
static void database_shutdown(struct Plugin *plugin)
Shutdown database connection and associate data structures.
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
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().
const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Description of a DB result cell.
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_new(type)
Allocate a struct or union of the given type.
static void delete_old_block(struct Plugin *plugin, const struct GNUNET_HashCode *query, struct GNUNET_TIME_Absolute expiration_time)
Delete older block in the datastore.
A hard error occurred, retrying will not help.
Definition: gnunet_db_lib.h:39
static int namecache_postgres_cache_block(void *cls, const struct GNUNET_GNSRECORD_Block *block)
Cache a block in the datastore.
#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
int(* cache_block)(void *cls, const struct GNUNET_GNSRECORD_Block *block)
Cache a block in the datastore.
void * cls
Closure for conv and cleaner.
#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
void * libgnunet_plugin_namecache_postgres_done(void *cls)
Exit point from the plugin.
struct GNUNET_PQ_ResultSpec GNUNET_PQ_result_spec_variable_size(const char *name, void **dst, size_t *sptr)
Variable-size result expected.
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
size_t GNUNET_GNSRECORD_block_get_size(const struct GNUNET_GNSRECORD_Block *block)
Returns the length of this block in bytes.
int(* lookup_block)(void *cls, const struct GNUNET_HashCode *query, GNUNET_NAMECACHE_BlockCallback iter, void *iter_cls)
Get the block for a particular zone and label in the datastore.
#define LOG(kind,...)
#define GNUNET_PQ_query_param_auto_from_type(x)
Generate fixed-size query parameter with size determined by variable type.
void * libgnunet_plugin_namecache_postgres_init(void *cls)
Entry point for the plugin.
static unsigned int bsize
A 512-bit hashcode.
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:118
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_PREPARED_STATEMENT_END
Terminator for prepared statement list.
helper functions for Postgres DB interactions
void * iter_cls
Iterator cls.
static int database_setup(struct Plugin *plugin)
Initialize the database connections and associated data structures (create tables and indices as need...
struct returned by the initialization function of the plugin
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
static void namecache_postgres_expire_blocks(struct Plugin *plugin)
Removes any expired block.
configuration data
Definition: configuration.c:84
Handle for a plugin.
Definition: block.c:37
struct GNUNET_PQ_Context * dbh
Native Postgres database handle.
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.
enum GNUNET_GenericReturnValue GNUNET_GNSRECORD_query_from_block(const struct GNUNET_GNSRECORD_Block *block, struct GNUNET_HashCode *query)
Builds the query hash from a block.
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
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
The transaction succeeded, but yielded zero results.
Definition: gnunet_db_lib.h:53
int GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
struct GNUNET_TIME_Absolute GNUNET_GNSRECORD_block_get_expiration(const struct GNUNET_GNSRECORD_Block *block)
Returns the expiration of a block.
GNUNET_PEERSTORE_Processor iter
Iterator.
common internal definitions for namecache service
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
#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