2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 2015 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.
21 * @file dht/gnunet-service-dht_datacache.c
22 * @brief GNUnet DHT service's datacache integration
23 * @author Christian Grothoff
24 * @author Nathan Evans
27 #include "gnunet_datacache_lib.h"
28 #include "gnunet-service-dht_datacache.h"
29 #include "gnunet-service-dht_routing.h"
30 #include "gnunet-service-dht.h"
32 #define LOG(kind,...) GNUNET_log_from (kind, "dht-dhtcache",__VA_ARGS__)
35 * How many "closest" results to we return for migration when
38 #define NUM_CLOSEST 42
41 * Handle to the datacache service (for inserting/retrieving data)
43 static struct GNUNET_DATACACHE_Handle *datacache;
47 * Handle a datum we've received from another peer. Cache if
50 * @param expiration when will the reply expire
51 * @param key the query this reply is for
52 * @param put_path_length number of peers in @a put_path
53 * @param put_path path the reply took on put
54 * @param type type of the reply
55 * @param data_size number of bytes in @a data
56 * @param data application payload data
59 GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration,
60 const struct GNUNET_HashCode *key,
61 unsigned int put_path_length,
62 const struct GNUNET_PeerIdentity *put_path,
63 enum GNUNET_BLOCK_Type type,
69 if (NULL == datacache)
71 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
72 _("%s request received, but have no datacache!\n"), "PUT");
75 if (data_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
80 /* Put size is actual data size plus struct overhead plus path length (if any) */
81 GNUNET_STATISTICS_update (GDS_stats,
82 gettext_noop ("# ITEMS stored in datacache"), 1,
84 r = GNUNET_DATACACHE_put (datacache,
92 LOG (GNUNET_ERROR_TYPE_DEBUG,
93 "DATACACHE PUT for key %s [%u] completed (%d) after %u hops\n",
102 * Context containing information about a GET request.
104 struct GetRequestContext
107 * extended query (see gnunet_block_lib.h).
112 * Bloomfilter to filter out duplicate replies (updated)
114 struct GNUNET_CONTAINER_BloomFilter **reply_bf;
117 * The key this request was about
119 struct GNUNET_HashCode key;
122 * Number of bytes in xquery.
127 * Mutator value for the @e reply_bf, see gnunet_block_lib.h
129 uint32_t reply_bf_mutator;
132 * Return value to give back.
134 enum GNUNET_BLOCK_EvaluationResult eval;
137 * Function to call on results.
139 GDS_DATACACHE_GetCallback gc;
150 * Iterator for local get request results,
152 * @param cls closure for iterator, a `struct GetRequestContext`
153 * @param exp when does this value expire?
154 * @param key the key this data is stored under
155 * @param data_size the size of the data identified by key
156 * @param data the actual data
157 * @param type the type of the @a data
158 * @param put_path_length number of peers in @a put_path
159 * @param put_path path the reply took on put
160 * @return #GNUNET_OK to continue iteration, anything else
164 datacache_get_iterator (void *cls,
165 const struct GNUNET_HashCode *key,
168 enum GNUNET_BLOCK_Type type,
169 struct GNUNET_TIME_Absolute exp,
170 unsigned int put_path_length,
171 const struct GNUNET_PeerIdentity *put_path)
173 struct GetRequestContext *ctx = cls;
174 enum GNUNET_BLOCK_EvaluationResult eval;
177 = GNUNET_BLOCK_evaluate (GDS_block_context,
179 GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO,
182 ctx->reply_bf_mutator,
187 LOG (GNUNET_ERROR_TYPE_DEBUG,
188 "Found reply for query %s in datacache, evaluation result is %d\n",
194 case GNUNET_BLOCK_EVALUATION_OK_MORE:
195 case GNUNET_BLOCK_EVALUATION_OK_LAST:
196 /* forward to local clients */
197 GNUNET_STATISTICS_update (GDS_stats,
199 ("# Good RESULTS found in datacache"), 1,
201 ctx->gc (ctx->gc_cls,
205 put_path_length, put_path,
209 case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
210 GNUNET_STATISTICS_update (GDS_stats,
211 gettext_noop ("# Duplicate RESULTS found in datacache"),
215 case GNUNET_BLOCK_EVALUATION_RESULT_INVALID:
216 GNUNET_STATISTICS_update (GDS_stats,
217 gettext_noop ("# Invalid RESULTS found in datacache"),
221 case GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT:
222 GNUNET_STATISTICS_update (GDS_stats,
223 gettext_noop ("# Irrelevant RESULTS found in datacache"),
227 case GNUNET_BLOCK_EVALUATION_REQUEST_VALID:
230 case GNUNET_BLOCK_EVALUATION_REQUEST_INVALID:
232 return GNUNET_SYSERR;
233 case GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED:
234 GNUNET_STATISTICS_update (GDS_stats,
235 gettext_noop ("# Unsupported RESULTS found in datacache"),
238 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
239 _("Unsupported block type (%u) in local response!\n"),
243 return (eval == GNUNET_BLOCK_EVALUATION_OK_LAST) ? GNUNET_NO : GNUNET_OK;
248 * Handle a GET request we've received from another peer.
250 * @param key the query
251 * @param type requested data type
252 * @param xquery extended query
253 * @param xquery_size number of bytes in @a xquery
254 * @param reply_bf where the reply bf is (to be) stored, possibly updated, can be NULL
255 * @param reply_bf_mutator mutation value for @a reply_bf
256 * @param gc function to call on the results
257 * @param gc_cls closure for @a gc
258 * @return evaluation result for the local replies
260 enum GNUNET_BLOCK_EvaluationResult
261 GDS_DATACACHE_handle_get (const struct GNUNET_HashCode *key,
262 enum GNUNET_BLOCK_Type type,
265 struct GNUNET_CONTAINER_BloomFilter **reply_bf,
266 uint32_t reply_bf_mutator,
267 GDS_DATACACHE_GetCallback gc,
270 struct GetRequestContext ctx;
273 if (NULL == datacache)
274 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
275 GNUNET_STATISTICS_update (GDS_stats,
276 gettext_noop ("# GET requests given to datacache"),
279 ctx.eval = GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
282 ctx.xquery_size = xquery_size;
283 ctx.reply_bf = reply_bf;
284 ctx.reply_bf_mutator = reply_bf_mutator;
287 r = GNUNET_DATACACHE_get (datacache,
290 &datacache_get_iterator,
292 LOG (GNUNET_ERROR_TYPE_DEBUG,
293 "DATACACHE GET for key %s completed (%d). %u results found.\n",
302 * Function called with a random element from the datacache.
303 * Stores the key in the closure.
305 * @param cls a `struct GNUNET_HashCode *`, where to store the @a key
306 * @param key key for the content
307 * @param data_size number of bytes in @a data
308 * @param data content stored
309 * @param type type of the content
310 * @param exp when will the content expire?
311 * @param path_info_len number of entries in @a path_info
312 * @param path_info a path through the network
313 * @return #GNUNET_OK to continue iterating, #GNUNET_SYSERR to abort
316 datacache_random_iterator (void *cls,
317 const struct GNUNET_HashCode *key,
320 enum GNUNET_BLOCK_Type type,
321 struct GNUNET_TIME_Absolute exp,
322 unsigned int path_info_len,
323 const struct GNUNET_PeerIdentity *path_info)
325 struct GNUNET_HashCode *dest = cls;
328 return GNUNET_OK; /* should actually not matter which we return */
333 * Obtain a random key from the datacache.
334 * Used by Whanau for load-balancing.
336 * @param[out] key where to store the key of a random element,
337 * randomized by PRNG if datacache is empty
338 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the datacache is empty
341 GDS_DATACACHE_get_random_key (struct GNUNET_HashCode *key)
344 GNUNET_DATACACHE_get_random (datacache,
345 &datacache_random_iterator,
348 /* randomize key in this case */
349 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE,
351 return GNUNET_SYSERR;
358 * Closure for #datacache_get_successors_iterator().
363 * Function to call on the result
365 GDS_DATACACHE_SuccessorCallback cb;
375 * Iterator for local get request results,
377 * @param cls closure with the `struct GNUNET_HashCode *` with the trail ID
378 * @param key the key this data is stored under
379 * @param size the size of the data identified by key
380 * @param data the actual data
381 * @param type the type of the data
382 * @param exp when does this value expire?
383 * @param put_path_length number of peers in @a put_path
384 * @param put_path path the reply took on put
385 * @return #GNUNET_OK to continue iteration, anything else
389 datacache_get_successors_iterator (void *cls,
390 const struct GNUNET_HashCode *key,
393 enum GNUNET_BLOCK_Type type,
394 struct GNUNET_TIME_Absolute exp,
395 unsigned int put_path_length,
396 const struct GNUNET_PeerIdentity *put_path)
398 const struct SuccContext *sc = cls;
400 /* NOTE: The datacache currently does not store the RO from
401 the original 'put', so we don't know the 'correct' option
402 at this point anymore. Thus, we conservatively assume
403 that recording is desired (for now). */
405 GNUNET_DHT_RO_RECORD_ROUTE,
408 put_path_length, put_path,
417 * Handle a request for data close to a key that we have received from
420 * @param key the location at which the peer is looking for data that is close
421 * @param cb function to call with the result
422 * @param cb_cls closure for @a cb
425 GDS_DATACACHE_get_successors (const struct GNUNET_HashCode *key,
426 GDS_DATACACHE_SuccessorCallback cb,
429 struct SuccContext sc;
433 (void) GNUNET_DATACACHE_get_closest (datacache,
436 &datacache_get_successors_iterator,
442 * Initialize datacache subsystem.
445 GDS_DATACACHE_init ()
447 datacache = GNUNET_DATACACHE_create (GDS_cfg, "dhtcache");
452 * Shutdown datacache subsystem.
455 GDS_DATACACHE_done ()
457 if (NULL != datacache)
459 GNUNET_DATACACHE_destroy (datacache);
465 /* end of gnunet-service-dht_datacache.c */