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;
118 * Pointer to the currently actively running request,
119 * NULL if none is running.
121 static struct DatastoreRequestQueue *drq_running;
125 * Run the next DS request in our queue, we're done with the current
133 * Wrapper for the datastore get operation. Makes sure to trigger the
134 * next datastore operation in the queue once the operation is
137 * @param cls our 'struct DatastoreRequestQueue*'
138 * @param key key for the content
139 * @param size number of bytes in data
140 * @param data content stored
141 * @param type type of the content
142 * @param priority priority of the content
143 * @param anonymity anonymity-level for the content
144 * @param expiration expiration time for the content
145 * @param uid unique identifier for the datum;
146 * maybe 0 if no unique identifier is available
149 get_iterator (void *cls,
150 const GNUNET_HashCode * key,
153 enum GNUNET_BLOCK_Type type,
156 struct GNUNET_TIME_Absolute
160 struct DatastoreRequestQueue *gc = cls;
162 if (gc->iter == NULL)
164 /* stop the iteration */
166 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
167 "Iteration terminated\n");
170 GNUNET_DATASTORE_get_next (dsh, GNUNET_NO);
176 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
177 "Iteration produced %u-byte result for `%s'\n",
181 gc->iter (gc->iter_cls,
182 key, size, data, type,
183 priority, anonymity, expiration, uid);
188 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
189 "Iteration completed\n");
191 GNUNET_assert (gc == drq_running);
200 * A datastore request can be run right now. Run it.
202 * @param cls closure (of type "struct DatastoreRequestQueue*")
203 * @param tc task context, unused
206 run_next_request (void *cls,
207 const struct GNUNET_SCHEDULER_TaskContext *tc)
209 struct DatastoreRequestQueue *gc = cls;
211 gc->task = GNUNET_SCHEDULER_NO_TASK;
213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
214 "Running datastore request for `%s' of type %u\n",
215 GNUNET_h2s (&gc->key),
218 GNUNET_DATASTORE_get (dsh,
221 42 /* FIXME */, 64 /* FIXME */,
222 GNUNET_TIME_absolute_get_remaining(gc->timeout),
229 * Run the next DS request in our queue, we're done with the current
235 struct DatastoreRequestQueue *e;
237 GNUNET_free_non_null (drq_running);
242 GNUNET_CONTAINER_DLL_remove (drq_head, drq_tail, e);
244 GNUNET_SCHEDULER_cancel (sched, e->task);
245 e->task = GNUNET_SCHEDULER_add_now (sched,
252 * A datastore request had to be timed out.
254 * @param cls closure (unused)
255 * @param tc task context, unused
258 timeout_ds_request (void *cls,
259 const struct GNUNET_SCHEDULER_TaskContext *tc)
261 struct DatastoreRequestQueue *e = cls;
264 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
265 "Datastore request timed out in queue before transmission\n");
267 e->task = GNUNET_SCHEDULER_NO_TASK;
268 GNUNET_CONTAINER_DLL_remove (drq_head, drq_tail, e);
270 e->iter (e->iter_cls,
271 NULL, 0, NULL, 0, 0, 0,
272 GNUNET_TIME_UNIT_ZERO_ABS, 0);
278 * Task run during shutdown.
284 shutdown_task (void *cls,
285 const struct GNUNET_SCHEDULER_TaskContext *tc)
287 struct DatastoreRequestQueue *drq;
290 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
291 "DRQ shutdown initiated\n");
293 GNUNET_assert (NULL != dsh);
294 while (NULL != (drq = drq_head))
296 drq_head = drq->next;
297 GNUNET_SCHEDULER_cancel (sched, drq->task);
298 if (drq->iter != NULL)
299 drq->iter (drq->iter_cls,
300 NULL, 0, NULL, 0, 0, 0,
301 GNUNET_TIME_UNIT_ZERO_ABS, 0);
305 if (drq_running != NULL)
307 if (drq_running->task != GNUNET_SCHEDULER_NO_TASK)
309 GNUNET_SCHEDULER_cancel (sched,
312 if (drq_running->iter != NULL)
314 drq_running->iter (drq_running->iter_cls,
315 NULL, 0, NULL, 0, 0, 0,
316 GNUNET_TIME_UNIT_ZERO_ABS, 0);
318 GNUNET_free (drq_running);
325 * Iterate over the results for a particular key
326 * in the datastore. The iterator will only be called
327 * once initially; if the first call did contain a
328 * result, further results can be obtained by calling
329 * "GNUNET_DATASTORE_get_next" with the given argument.
331 * @param key maybe NULL (to match all entries)
332 * @param type desired type, 0 for any
333 * @param iter function to call on each matching value;
334 * will be called once with a NULL value at the end
335 * @param iter_cls closure for iter
336 * @param timeout how long to wait at most for a response
337 * @param immediate should this be queued immediately at
338 * the head of the queue (irrespecitive of the timeout)?
340 struct DatastoreRequestQueue *
341 GNUNET_FS_drq_get (const GNUNET_HashCode * key,
342 enum GNUNET_BLOCK_Type type,
343 GNUNET_DATASTORE_Iterator iter,
345 struct GNUNET_TIME_Relative timeout,
348 struct DatastoreRequestQueue *e;
349 struct DatastoreRequestQueue *bef;
352 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
353 "DRQ receives request for `%s' of type %u\n",
357 e = GNUNET_malloc (sizeof (struct DatastoreRequestQueue));
358 e->timeout = GNUNET_TIME_relative_to_absolute (timeout);
359 e->forced_head = immediate;
363 e->iter_cls = iter_cls;
364 e->timeout = GNUNET_TIME_relative_to_absolute (timeout);
365 if (GNUNET_YES == immediate)
367 /* local request, highest prio, put at head of queue
368 regardless of deadline */
374 while ( (NULL != bef) &&
375 (e->timeout.value < bef->timeout.value) &&
376 (GNUNET_YES != e->forced_head) )
379 GNUNET_CONTAINER_DLL_insert_after (drq_head, drq_tail, bef, e);
380 e->task = GNUNET_SCHEDULER_add_delayed (sched,
384 if (drq_running == NULL)
391 * Cancel the given operation.
393 * @param drq the queued operation (must not have been
397 GNUNET_FS_drq_get_cancel (struct DatastoreRequestQueue *drq)
400 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
401 "DRQ receives request cancellation request\n");
403 if (drq == drq_running)
405 /* 'DATASTORE_get' has already been started (and this call might
406 actually be be legal since it is possible that the client has
407 not yet received any calls to its the iterator; so we need to
408 cancel somehow; we do this by zeroing the 'iter' field, which
409 stops the iteration */
410 drq_running->iter = NULL;
414 GNUNET_CONTAINER_DLL_remove (drq_head, drq_tail, drq);
415 GNUNET_SCHEDULER_cancel (sched, drq->task);
422 * Function called to trigger obtaining the next result
423 * from the datastore.
425 * @param more GNUNET_YES to get more results, GNUNET_NO to abort
426 * iteration (with a final call to "iter" with key/data == NULL).
429 GNUNET_FS_drq_get_next (int more)
432 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
433 "DRQ receives request for next result (more is %d)\n",
436 GNUNET_DATASTORE_get_next (dsh, more);
441 * Closure for 'drq_remove_cont'.
445 struct GNUNET_DATASTORE_Handle *rmdsh;
446 GNUNET_DATASTORE_ContinuationWithStatus cont;
452 drq_remove_cont (void *cls,
456 struct RemoveContext *rc = cls;
458 rc->cont (rc->cont_cls,
466 * Explicitly remove some content from the database.
467 * The "cont"inuation will be called with status
468 * "GNUNET_OK" if content was removed, "GNUNET_NO"
469 * if no matching entry was found and "GNUNET_SYSERR"
470 * on all other types of errors.
472 * @param key key for the value
473 * @param size number of bytes in data
474 * @param data content stored
475 * @param cont continuation to call when done
476 * @param cont_cls closure for cont
477 * @param timeout how long to wait at most for a response
480 GNUNET_FS_drq_remove (const GNUNET_HashCode *key,
481 uint32_t size, const void *data,
482 GNUNET_DATASTORE_ContinuationWithStatus cont,
484 struct GNUNET_TIME_Relative timeout)
486 struct GNUNET_DATASTORE_Handle *rmdsh;
487 struct RemoveContext *rc;
494 _("Failed to connect to datastore"));
497 rc = GNUNET_malloc (sizeof (struct RemoveContext));
499 rc->cont_cls = cont_cls;
501 GNUNET_DATASTORE_remove (rmdsh, key, size, data,
510 * Setup datastore request queues.
512 * @param s scheduler to use
513 * @param c configuration to use
514 * @return GNUNET_OK on success
517 GNUNET_FS_drq_init (struct GNUNET_SCHEDULER_Handle *s,
518 const struct GNUNET_CONFIGURATION_Handle *c)
522 dsh = GNUNET_DATASTORE_connect (cfg,
526 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
527 _("Failed to connect to `%s' service.\n"),
529 return GNUNET_SYSERR;
531 GNUNET_SCHEDULER_add_delayed (sched,
532 GNUNET_TIME_UNIT_FOREVER_REL,
539 /* end of gnunet-service-fs_drq.c */