uncrustify as demanded.
[oweals/gnunet.git] / src / datacache / datacache.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2015 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 /**
21  * @file datacache/datacache.c
22  * @brief datacache API implementation
23  * @author Christian Grothoff
24  */
25 #include "platform.h"
26 #include "gnunet_util_lib.h"
27 #include "gnunet_datacache_lib.h"
28 #include "gnunet_statistics_service.h"
29 #include "gnunet_datacache_plugin.h"
30
31
32 #define LOG(kind, ...) GNUNET_log_from(kind, "datacache", __VA_ARGS__)
33
34 #define LOG_STRERROR_FILE(kind, op, fn) \
35   GNUNET_log_from_strerror_file(kind, "datacache", op, fn)
36
37 /**
38  * Internal state of the datacache library.
39  */
40 struct GNUNET_DATACACHE_Handle {
41   /**
42    * Bloomfilter to quickly tell if we don't have the content.
43    */
44   struct GNUNET_CONTAINER_BloomFilter *filter;
45
46   /**
47    * Our configuration.
48    */
49   const struct GNUNET_CONFIGURATION_Handle *cfg;
50
51   /**
52    * Opaque handle for the statistics service.
53    */
54   struct GNUNET_STATISTICS_Handle *stats;
55
56   /**
57    * Configuration section to use.
58    */
59   char *section;
60
61   /**
62    * API of the transport as returned by the plugin's
63    * initialization function.
64    */
65   struct GNUNET_DATACACHE_PluginFunctions *api;
66
67   /**
68    * Short name for the plugin (i.e. "sqlite").
69    */
70   char *short_name;
71
72   /**
73    * Name of the library (i.e. "gnunet_plugin_datacache_sqlite").
74    */
75   char *lib_name;
76
77   /**
78    * Name for the bloom filter file.
79    */
80   char *bloom_name;
81
82   /**
83    * Environment provided to our plugin.
84    */
85   struct GNUNET_DATACACHE_PluginEnvironment env;
86
87   /**
88    * How much space is in use right now?
89    */
90   unsigned long long utilization;
91 };
92
93
94 /**
95  * Function called by plugins to notify the datacache
96  * about content deletions.
97  *
98  * @param cls closure
99  * @param key key of the content that was deleted
100  * @param size number of bytes that were made available
101  */
102 static void
103 env_delete_notify(void *cls, const struct GNUNET_HashCode *key, size_t size)
104 {
105   struct GNUNET_DATACACHE_Handle *h = cls;
106
107   LOG(GNUNET_ERROR_TYPE_DEBUG,
108       "Content under key `%s' discarded\n",
109       GNUNET_h2s(key));
110   GNUNET_assert(h->utilization >= size);
111   h->utilization -= size;
112   GNUNET_CONTAINER_bloomfilter_remove(h->filter, key);
113   GNUNET_STATISTICS_update(h->stats,
114                            gettext_noop("# bytes stored"),
115                            -(long long)size,
116                            GNUNET_NO);
117   GNUNET_STATISTICS_update(h->stats,
118                            gettext_noop("# items stored"),
119                            -1,
120                            GNUNET_NO);
121 }
122
123
124 /**
125  * Create a data cache.
126  *
127  * @param cfg configuration to use
128  * @param section section in the configuration that contains our options
129  * @return handle to use to access the service
130  */
131 struct GNUNET_DATACACHE_Handle *
132 GNUNET_DATACACHE_create(const struct GNUNET_CONFIGURATION_Handle *cfg,
133                         const char *section)
134 {
135   unsigned int bf_size;
136   unsigned long long quota;
137   struct GNUNET_DATACACHE_Handle *ret;
138   char *libname;
139   char *name;
140
141   if (GNUNET_OK !=
142       GNUNET_CONFIGURATION_get_value_size(cfg, section, "QUOTA", &quota))
143     {
144       GNUNET_log_config_missing(GNUNET_ERROR_TYPE_ERROR, section, "QUOTA");
145       return NULL;
146     }
147   if (GNUNET_OK !=
148       GNUNET_CONFIGURATION_get_value_string(cfg, section, "DATABASE", &name))
149     {
150       GNUNET_log_config_missing(GNUNET_ERROR_TYPE_ERROR, section, "DATABASE");
151       return NULL;
152     }
153   bf_size = quota / 32; /* 8 bit per entry, 1 bit per 32 kb in DB */
154
155   ret = GNUNET_new(struct GNUNET_DATACACHE_Handle);
156
157   if (GNUNET_YES !=
158       GNUNET_CONFIGURATION_get_value_yesno(cfg, section, "DISABLE_BF"))
159     {
160       if (GNUNET_YES !=
161           GNUNET_CONFIGURATION_get_value_yesno(cfg, section, "DISABLE_BF_RC"))
162         {
163           ret->bloom_name = GNUNET_DISK_mktemp("gnunet-datacachebloom");
164         }
165       if (NULL != ret->bloom_name)
166         {
167           ret->filter = GNUNET_CONTAINER_bloomfilter_load(
168             ret->bloom_name,
169             quota / 1024, /* 8 bit per entry in DB, expect 1k entries */
170             5);
171         }
172       if (NULL == ret->filter)
173         {
174           ret->filter =
175             GNUNET_CONTAINER_bloomfilter_init(NULL,
176                                               bf_size,
177                                               5); /* approx. 3% false positives at max use */
178         }
179     }
180   ret->stats = GNUNET_STATISTICS_create("datacache", cfg);
181   ret->section = GNUNET_strdup(section);
182   ret->env.cfg = cfg;
183   ret->env.delete_notify = &env_delete_notify;
184   ret->env.section = ret->section;
185   ret->env.cls = ret;
186   ret->env.delete_notify = &env_delete_notify;
187   ret->env.quota = quota;
188   LOG(GNUNET_ERROR_TYPE_INFO, _("Loading `%s' datacache plugin\n"), name);
189   GNUNET_asprintf(&libname, "libgnunet_plugin_datacache_%s", name);
190   ret->short_name = name;
191   ret->lib_name = libname;
192   ret->api = GNUNET_PLUGIN_load(libname, &ret->env);
193   if (ret->api == NULL)
194     {
195       LOG(GNUNET_ERROR_TYPE_ERROR,
196           _("Failed to load datacache plugin for `%s'\n"),
197           name);
198       GNUNET_DATACACHE_destroy(ret);
199       return NULL;
200     }
201   return ret;
202 }
203
204
205 /**
206  * Destroy a data cache (and free associated resources).
207  *
208  * @param h handle to the datastore
209  */
210 void
211 GNUNET_DATACACHE_destroy(struct GNUNET_DATACACHE_Handle *h)
212 {
213   if (NULL != h->filter)
214     GNUNET_CONTAINER_bloomfilter_free(h->filter);
215   if (NULL != h->api)
216     GNUNET_break(NULL == GNUNET_PLUGIN_unload(h->lib_name, h->api));
217   GNUNET_free(h->lib_name);
218   GNUNET_free(h->short_name);
219   GNUNET_free(h->section);
220   if (NULL != h->bloom_name)
221     {
222       if (0 != unlink(h->bloom_name))
223         GNUNET_log_from_strerror_file(GNUNET_ERROR_TYPE_WARNING,
224                                       "datacache",
225                                       "unlink",
226                                       h->bloom_name);
227       GNUNET_free(h->bloom_name);
228     }
229   GNUNET_STATISTICS_destroy(h->stats, GNUNET_NO);
230   GNUNET_free(h);
231 }
232
233
234 /**
235  * Store an item in the datastore.
236  *
237  * @param h handle to the datacache
238  * @param key key to store data under
239  * @param xor_distance distance of @a key to our PID
240  * @param data_size number of bytes in @a data
241  * @param data data to store
242  * @param type type of the value
243  * @param discard_time when to discard the value in any case
244  * @param path_info_len number of entries in @a path_info
245  * @param path_info a path through the network
246  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error, #GNUNET_NO if duplicate
247  */
248 int
249 GNUNET_DATACACHE_put(struct GNUNET_DATACACHE_Handle *h,
250                      const struct GNUNET_HashCode *key,
251                      uint32_t xor_distance,
252                      size_t data_size,
253                      const char *data,
254                      enum GNUNET_BLOCK_Type type,
255                      struct GNUNET_TIME_Absolute discard_time,
256                      unsigned int path_info_len,
257                      const struct GNUNET_PeerIdentity *path_info)
258 {
259   ssize_t used;
260
261   used = h->api->put(h->api->cls,
262                      key,
263                      xor_distance,
264                      data_size,
265                      data,
266                      type,
267                      discard_time,
268                      path_info_len,
269                      path_info);
270   if (-1 == used)
271     {
272       GNUNET_break(0);
273       return GNUNET_SYSERR;
274     }
275   if (0 == used)
276     {
277       /* duplicate */
278       return GNUNET_NO;
279     }
280   LOG(GNUNET_ERROR_TYPE_DEBUG,
281       "Stored data under key `%s' in cache\n",
282       GNUNET_h2s(key));
283   if (NULL != h->filter)
284     GNUNET_CONTAINER_bloomfilter_add(h->filter, key);
285   GNUNET_STATISTICS_update(h->stats,
286                            gettext_noop("# bytes stored"),
287                            used,
288                            GNUNET_NO);
289   GNUNET_STATISTICS_update(h->stats,
290                            gettext_noop("# items stored"),
291                            1,
292                            GNUNET_NO);
293   while (h->utilization + used > h->env.quota)
294     GNUNET_assert(GNUNET_OK == h->api->del(h->api->cls));
295   h->utilization += used;
296   return GNUNET_OK;
297 }
298
299
300 /**
301  * Iterate over the results for a particular key
302  * in the datacache.
303  *
304  * @param h handle to the datacache
305  * @param key what to look up
306  * @param type entries of which type are relevant?
307  * @param iter maybe NULL (to just count)
308  * @param iter_cls closure for @a iter
309  * @return the number of results found
310  */
311 unsigned int
312 GNUNET_DATACACHE_get(struct GNUNET_DATACACHE_Handle *h,
313                      const struct GNUNET_HashCode *key,
314                      enum GNUNET_BLOCK_Type type,
315                      GNUNET_DATACACHE_Iterator iter,
316                      void *iter_cls)
317 {
318   GNUNET_STATISTICS_update(h->stats,
319                            gettext_noop("# requests received"),
320                            1,
321                            GNUNET_NO);
322   LOG(GNUNET_ERROR_TYPE_DEBUG,
323       "Processing request for key `%s'\n",
324       GNUNET_h2s(key));
325   if ((NULL != h->filter) &&
326       (GNUNET_OK != GNUNET_CONTAINER_bloomfilter_test(h->filter, key)))
327     {
328       GNUNET_STATISTICS_update(h->stats,
329                                gettext_noop(
330                                  "# requests filtered by bloom filter"),
331                                1,
332                                GNUNET_NO);
333       LOG(GNUNET_ERROR_TYPE_DEBUG,
334           "Bloomfilter filters request for key `%s'\n",
335           GNUNET_h2s(key));
336       return 0; /* can not be present */
337     }
338   return h->api->get(h->api->cls, key, type, iter, iter_cls);
339 }
340
341
342 /**
343  * Obtain a random element from the datacache.
344  *
345  * @param h handle to the datacache
346  * @param iter maybe NULL (to just count)
347  * @param iter_cls closure for @a iter
348  * @return the number of results found (zero or 1)
349  */
350 unsigned int
351 GNUNET_DATACACHE_get_random(struct GNUNET_DATACACHE_Handle *h,
352                             GNUNET_DATACACHE_Iterator iter,
353                             void *iter_cls)
354 {
355   GNUNET_STATISTICS_update(h->stats,
356                            gettext_noop(
357                              "# requests for random value received"),
358                            1,
359                            GNUNET_NO);
360   LOG(GNUNET_ERROR_TYPE_DEBUG, "Processing request for random value\n");
361   return h->api->get_random(h->api->cls, iter, iter_cls);
362 }
363
364
365 /**
366  * Iterate over the results that are "close" to a particular key in
367  * the datacache.  "close" is defined as numerically larger than @a
368  * key (when interpreted as a circular address space), with small
369  * distance.
370  *
371  * @param h handle to the datacache
372  * @param key area of the keyspace to look into
373  * @param num_results number of results that should be returned to @a iter
374  * @param iter maybe NULL (to just count)
375  * @param iter_cls closure for @a iter
376  * @return the number of results found
377  */
378 unsigned int
379 GNUNET_DATACACHE_get_closest(struct GNUNET_DATACACHE_Handle *h,
380                              const struct GNUNET_HashCode *key,
381                              unsigned int num_results,
382                              GNUNET_DATACACHE_Iterator iter,
383                              void *iter_cls)
384 {
385   GNUNET_STATISTICS_update(h->stats,
386                            gettext_noop(
387                              "# proximity search requests received"),
388                            1,
389                            GNUNET_NO);
390   LOG(GNUNET_ERROR_TYPE_DEBUG,
391       "Processing proximity search at `%s'\n",
392       GNUNET_h2s(key));
393   return h->api->get_closest(h->api->cls, key, num_results, iter, iter_cls);
394 }
395
396
397 /* end of datacache.c */