2 This file is part of GNUnet.
3 (C) 2009, 2010 Christian Grothoff (and other contributing authors)
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 2, 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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file fs/gnunet-service-fs_drq.c
23 * @brief queueing of requests to the datastore service
24 * @author Christian Grothoff
27 #include "gnunet-service-fs_drq.h"
29 #define DEBUG_DRQ GNUNET_NO
32 * Signature of a function that is called whenever a datastore
33 * request can be processed (or an entry put on the queue times out).
36 * @param ok GNUNET_OK if DS is ready, GNUNET_SYSERR on timeout
38 typedef void (*RequestFunction)(void *cls,
43 * Doubly-linked list of our requests for the datastore.
45 struct DatastoreRequestQueue
49 * This is a doubly-linked list.
51 struct DatastoreRequestQueue *next;
54 * This is a doubly-linked list.
56 struct DatastoreRequestQueue *prev;
59 * Function to call for each entry.
61 GNUNET_DATASTORE_Iterator iter;
69 * Key we are doing the 'get' for.
74 * Timeout for this operation.
76 struct GNUNET_TIME_Absolute timeout;
79 * ID of task used for signaling timeout.
81 GNUNET_SCHEDULER_TaskIdentifier task;
84 * Datastore entry type we are doing the 'get' for.
86 enum GNUNET_BLOCK_Type type;
89 * Is this request at the head of the queue irrespective of its
99 static struct GNUNET_SCHEDULER_Handle *sched;
104 static const struct GNUNET_CONFIGURATION_Handle *cfg;
107 * Head of request queue for the datastore, sorted by timeout.
109 static struct DatastoreRequestQueue *drq_head;
112 * Tail of request queue for the datastore.
114 static struct DatastoreRequestQueue *drq_tail;
117 * Our connection to the datastore.
119 static struct GNUNET_DATASTORE_Handle *dsh;
122 * Pointer to the currently actively running request,
123 * NULL if none is running.
125 static struct DatastoreRequestQueue *drq_running;
129 * Run the next DS request in our queue, we're done with the current
137 * Wrapper for the datastore get operation. Makes sure to trigger the
138 * next datastore operation in the queue once the operation is
141 * @param cls our 'struct DatastoreRequestQueue*'
142 * @param key key for the content
143 * @param size number of bytes in data
144 * @param data content stored
145 * @param type type of the content
146 * @param priority priority of the content
147 * @param anonymity anonymity-level for the content
148 * @param expiration expiration time for the content
149 * @param uid unique identifier for the datum;
150 * maybe 0 if no unique identifier is available
153 get_iterator (void *cls,
154 const GNUNET_HashCode * key,
157 enum GNUNET_BLOCK_Type type,
160 struct GNUNET_TIME_Absolute
164 struct DatastoreRequestQueue *gc = cls;
166 if (gc->iter == NULL)
168 /* stop the iteration */
170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
171 "Iteration terminated\n");
174 GNUNET_DATASTORE_get_next (dsh, GNUNET_NO);
180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
181 "Iteration produced %u-byte result for `%s'\n",
185 gc->iter (gc->iter_cls,
186 key, size, data, type,
187 priority, anonymity, expiration, uid);
192 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
193 "Iteration completed\n");
195 GNUNET_assert (gc == drq_running);
204 * A datastore request can be run right now. Run it.
206 * @param cls closure (of type "struct DatastoreRequestQueue*")
207 * @param tc task context, unused
210 run_next_request (void *cls,
211 const struct GNUNET_SCHEDULER_TaskContext *tc)
213 struct DatastoreRequestQueue *gc = cls;
215 gc->task = GNUNET_SCHEDULER_NO_TASK;
217 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
218 "Running datastore request for `%s' of type %u\n",
219 GNUNET_h2s (&gc->key),
222 GNUNET_DATASTORE_get (dsh,
225 42 /* FIXME */, 64 /* FIXME */,
226 GNUNET_TIME_absolute_get_remaining(gc->timeout),
233 * Run the next DS request in our queue, we're done with the current
239 struct DatastoreRequestQueue *e;
241 GNUNET_free_non_null (drq_running);
246 GNUNET_CONTAINER_DLL_remove (drq_head, drq_tail, e);
248 GNUNET_SCHEDULER_cancel (sched, e->task);
249 e->task = GNUNET_SCHEDULER_add_now (sched,
256 * A datastore request had to be timed out.
258 * @param cls closure (unused)
259 * @param tc task context, unused
262 timeout_ds_request (void *cls,
263 const struct GNUNET_SCHEDULER_TaskContext *tc)
265 struct DatastoreRequestQueue *e = cls;
268 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
269 "Datastore request timed out in queue before transmission\n");
271 e->task = GNUNET_SCHEDULER_NO_TASK;
272 GNUNET_CONTAINER_DLL_remove (drq_head, drq_tail, e);
274 e->iter (e->iter_cls,
275 NULL, 0, NULL, 0, 0, 0,
276 GNUNET_TIME_UNIT_ZERO_ABS, 0);
282 * Task run during shutdown.
288 shutdown_task (void *cls,
289 const struct GNUNET_SCHEDULER_TaskContext *tc)
291 struct DatastoreRequestQueue *drq;
294 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
295 "DRQ shutdown initiated\n");
297 GNUNET_assert (NULL != dsh);
298 GNUNET_DATASTORE_disconnect (dsh,
301 while (NULL != (drq = drq_head))
303 drq_head = drq->next;
304 GNUNET_SCHEDULER_cancel (sched, drq->task);
305 if (drq->iter != NULL)
306 drq->iter (drq->iter_cls,
307 NULL, 0, NULL, 0, 0, 0,
308 GNUNET_TIME_UNIT_ZERO_ABS, 0);
312 if (drq_running != NULL)
314 if (drq_running->task != GNUNET_SCHEDULER_NO_TASK)
316 GNUNET_SCHEDULER_cancel (sched,
319 if (drq_running->iter != NULL)
321 drq_running->iter (drq_running->iter_cls,
322 NULL, 0, NULL, 0, 0, 0,
323 GNUNET_TIME_UNIT_ZERO_ABS, 0);
325 GNUNET_free (drq_running);
332 * Iterate over the results for a particular key
333 * in the datastore. The iterator will only be called
334 * once initially; if the first call did contain a
335 * result, further results can be obtained by calling
336 * "GNUNET_DATASTORE_get_next" with the given argument.
338 * @param key maybe NULL (to match all entries)
339 * @param type desired type, 0 for any
340 * @param iter function to call on each matching value;
341 * will be called once with a NULL value at the end
342 * @param iter_cls closure for iter
343 * @param timeout how long to wait at most for a response
344 * @param immediate should this be queued immediately at
345 * the head of the queue (irrespecitive of the timeout)?
347 struct DatastoreRequestQueue *
348 GNUNET_FS_drq_get (const GNUNET_HashCode * key,
349 enum GNUNET_BLOCK_Type type,
350 GNUNET_DATASTORE_Iterator iter,
352 struct GNUNET_TIME_Relative timeout,
355 struct DatastoreRequestQueue *e;
356 struct DatastoreRequestQueue *bef;
359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
360 "DRQ receives request for `%s' of type %u\n",
364 e = GNUNET_malloc (sizeof (struct DatastoreRequestQueue));
365 e->timeout = GNUNET_TIME_relative_to_absolute (timeout);
366 e->forced_head = immediate;
370 e->iter_cls = iter_cls;
371 e->timeout = GNUNET_TIME_relative_to_absolute (timeout);
372 if (GNUNET_YES == immediate)
374 /* local request, highest prio, put at head of queue
375 regardless of deadline */
381 while ( (NULL != bef) &&
382 (e->timeout.value < bef->timeout.value) &&
383 (GNUNET_YES != e->forced_head) )
386 GNUNET_CONTAINER_DLL_insert_after (drq_head, drq_tail, bef, e);
387 e->task = GNUNET_SCHEDULER_add_delayed (sched,
391 if (drq_running == NULL)
398 * Cancel the given operation.
400 * @param drq the queued operation (must not have been
404 GNUNET_FS_drq_get_cancel (struct DatastoreRequestQueue *drq)
407 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
408 "DRQ receives request cancellation request\n");
410 if (drq == drq_running)
412 /* 'DATASTORE_get' has already been started (and this call might
413 actually be be legal since it is possible that the client has
414 not yet received any calls to its the iterator; so we need to
415 cancel somehow; we do this by zeroing the 'iter' field, which
416 stops the iteration */
417 drq_running->iter = NULL;
421 GNUNET_CONTAINER_DLL_remove (drq_head, drq_tail, drq);
422 GNUNET_SCHEDULER_cancel (sched, drq->task);
429 * Function called to trigger obtaining the next result
430 * from the datastore.
432 * @param more GNUNET_YES to get more results, GNUNET_NO to abort
433 * iteration (with a final call to "iter" with key/data == NULL).
436 GNUNET_FS_drq_get_next (int more)
439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
440 "DRQ receives request for next result (more is %d)\n",
443 GNUNET_DATASTORE_get_next (dsh, more);
448 * Closure for 'drq_remove_cont'.
452 struct GNUNET_DATASTORE_Handle *rmdsh;
453 GNUNET_DATASTORE_ContinuationWithStatus cont;
459 drq_remove_cont (void *cls,
463 struct RemoveContext *rc = cls;
465 rc->cont (rc->cont_cls,
468 GNUNET_DATASTORE_disconnect (rc->rmdsh, GNUNET_NO);
474 * Explicitly remove some content from the database.
475 * The "cont"inuation will be called with status
476 * "GNUNET_OK" if content was removed, "GNUNET_NO"
477 * if no matching entry was found and "GNUNET_SYSERR"
478 * on all other types of errors.
480 * @param key key for the value
481 * @param size number of bytes in data
482 * @param data content stored
483 * @param cont continuation to call when done
484 * @param cont_cls closure for cont
485 * @param timeout how long to wait at most for a response
488 GNUNET_FS_drq_remove (const GNUNET_HashCode *key,
489 uint32_t size, const void *data,
490 GNUNET_DATASTORE_ContinuationWithStatus cont,
492 struct GNUNET_TIME_Relative timeout)
494 struct GNUNET_DATASTORE_Handle *rmdsh;
495 struct RemoveContext *rc;
497 rmdsh = GNUNET_DATASTORE_connect (cfg,
504 _("Failed to connect to datastore"));
507 rc = GNUNET_malloc (sizeof (struct RemoveContext));
509 rc->cont_cls = cont_cls;
511 GNUNET_DATASTORE_remove (rmdsh, key, size, data,
520 * Setup datastore request queues.
522 * @param s scheduler to use
523 * @param c configuration to use
524 * @return GNUNET_OK on success
527 GNUNET_FS_drq_init (struct GNUNET_SCHEDULER_Handle *s,
528 const struct GNUNET_CONFIGURATION_Handle *c)
532 dsh = GNUNET_DATASTORE_connect (cfg,
536 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
537 _("Failed to connect to `%s' service.\n"),
539 return GNUNET_SYSERR;
541 GNUNET_SCHEDULER_add_delayed (sched,
542 GNUNET_TIME_UNIT_FOREVER_REL,
549 /* end of gnunet-service-fs_drq.c */