2 This file is part of GNUnet
3 (C) 2004, 2005, 2006, 2007, 2009 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 datastore/datastore_api.c
23 * @brief Management for the datastore for files stored on a GNUnet node
24 * @author Christian Grothoff
27 #include "gnunet_arm_service.h"
28 #include "gnunet_datastore_service.h"
29 #include "datastore.h"
32 * Handle to the datastore service. Followed
33 * by 65536 bytes used for storing messages.
35 struct GNUNET_DATASTORE_Handle
41 const struct GNUNET_CONFIGURATION_Handle *cfg;
46 struct GNUNET_SCHEDULER_Handle *sched;
49 * Current connection to the datastore service.
51 struct GNUNET_CLIENT_Connection *client;
54 * Current response processor (NULL if we are not waiting for a
55 * response). The specific type depends on the kind of message we
61 * Closure for response_proc.
63 void *response_proc_cls;
66 * Timeout for the current operation.
68 struct GNUNET_TIME_Absolute timeout;
71 * Number of bytes in the message following
72 * this struct, 0 if we have no request pending.
81 * Connect to the datastore service.
83 * @param cfg configuration to use
84 * @param sched scheduler to use
85 * @return handle to use to access the service
87 struct GNUNET_DATASTORE_Handle *GNUNET_DATASTORE_connect (const struct
88 GNUNET_CONFIGURATION_Handle
91 GNUNET_SCHEDULER_Handle
94 struct GNUNET_CLIENT_Connection *c;
95 struct GNUNET_DATASTORE_Handle *h;
97 c = GNUNET_CLIENT_connect (sched, "datastore", cfg);
99 return NULL; /* oops */
100 GNUNET_ARM_start_services (cfg, sched, "datastore", NULL);
101 h = GNUNET_malloc (sizeof(struct GNUNET_DATASTORE_Handle) +
102 GNUNET_SERVER_MAX_MESSAGE_SIZE);
111 * Transmit DROP message to datastore service.
114 transmit_drop (void *cls,
115 size_t size, void *buf)
117 struct GNUNET_DATASTORE_Handle *h = cls;
118 struct GNUNET_MessageHeader *hdr;
122 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
123 _("Failed to transmit request to drop database.\n"));
124 GNUNET_DATASTORE_disconnect (h, GNUNET_NO);
127 GNUNET_assert (size >= sizeof(struct GNUNET_MessageHeader));
129 hdr->size = htons(sizeof(struct GNUNET_MessageHeader));
130 hdr->type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_DROP);
131 GNUNET_DATASTORE_disconnect (h, GNUNET_NO);
132 return sizeof(struct GNUNET_MessageHeader);
137 * Disconnect from the datastore service (and free
138 * associated resources).
140 * @param h handle to the datastore
141 * @param drop set to GNUNET_YES to delete all data in datastore (!)
143 void GNUNET_DATASTORE_disconnect (struct GNUNET_DATASTORE_Handle *h,
146 GNUNET_assert (0 == h->message_size);
147 GNUNET_assert (NULL == h->response_proc);
148 if ( (GNUNET_YES == drop) &&
149 (h->client != NULL) )
152 GNUNET_CLIENT_notify_transmit_ready (h->client,
153 sizeof(struct GNUNET_MessageHeader),
154 GNUNET_TIME_UNIT_MINUTES,
161 if (h->client != NULL)
162 GNUNET_CLIENT_disconnect (h->client);
163 GNUNET_ARM_stop_services (h->cfg, h->sched, "datastore", NULL);
169 * Type of a function to call when we receive a message
170 * from the service. This specific function is used
171 * to handle messages of type "struct StatusMessage".
174 * @param msg message received, NULL on timeout or fatal error
177 with_status_response_handler (void *cls,
179 GNUNET_MessageHeader * msg)
181 struct GNUNET_DATASTORE_Handle *h = cls;
182 GNUNET_DATASTORE_ContinuationWithStatus cont = h->response_proc;
183 const struct StatusMessage *sm;
189 h->response_proc = NULL;
190 GNUNET_CLIENT_disconnect (h->client);
191 h->client = GNUNET_CLIENT_connect (h->sched, "datastore", h->cfg);
192 cont (h->response_proc_cls,
194 _("Timeout trying to read response from datastore service"));
197 if ( (ntohs(msg->size) < sizeof(struct StatusMessage)) ||
198 (ntohs(msg->type) != GNUNET_MESSAGE_TYPE_DATASTORE_STATUS) )
201 h->response_proc = NULL;
202 GNUNET_CLIENT_disconnect (h->client);
203 h->client = GNUNET_CLIENT_connect (h->sched, "datastore", h->cfg);
204 cont (h->response_proc_cls,
206 _("Error reading response from datastore service"));
209 sm = (const struct StatusMessage*) msg;
210 status = ntohl(sm->status);
212 if (ntohs(msg->size) > sizeof(struct StatusMessage))
214 emsg = (const char*) &sm[1];
215 if (emsg[ntohs(msg->size) - sizeof(struct StatusMessage) - 1] != '\0')
218 emsg = _("Invalid error message received from datastore service");
221 if ( (status == GNUNET_SYSERR) &&
225 emsg = _("Invalid error message received from datastore service");
227 h->response_proc = NULL;
229 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
230 "Received status %d/%s\n",
234 cont (h->response_proc_cls,
241 * Helper function that will initiate the
242 * transmission of a message to the datastore
243 * service. The message must already be prepared
244 * and stored in the buffer at the end of the
245 * handle. The message must be of a type that
246 * expects a "StatusMessage" in response.
248 * @param h handle to the service with prepared message
249 * @param cont function to call with result
250 * @param cont_cls closure
251 * @param timeout timeout for the operation
254 transmit_for_status (struct GNUNET_DATASTORE_Handle *h,
255 GNUNET_DATASTORE_ContinuationWithStatus cont,
257 struct GNUNET_TIME_Relative timeout)
259 const struct GNUNET_MessageHeader *hdr;
262 GNUNET_assert (cont != NULL);
263 hdr = (const struct GNUNET_MessageHeader*) &h[1];
264 msize = ntohs(hdr->size);
266 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
267 "Transmitting %u byte message of type %u to datastore service\n",
271 GNUNET_assert (h->response_proc == NULL);
272 h->response_proc = cont;
273 h->response_proc_cls = cont_cls;
274 h->timeout = GNUNET_TIME_relative_to_absolute (timeout);
275 h->message_size = msize;
277 GNUNET_CLIENT_transmit_and_get_response (h->client,
281 &with_status_response_handler,
285 h->response_proc = NULL;
289 _("Not ready to transmit request to datastore service"));
295 * Store an item in the datastore. If the item is already present,
296 * the priorities are summed up and the higher expiration time and
297 * lower anonymity level is used.
299 * @param h handle to the datastore
300 * @param rid reservation ID to use (from "reserve"); use 0 if no
301 * prior reservation was made
302 * @param key key for the value
303 * @param size number of bytes in data
304 * @param data content stored
305 * @param type type of the content
306 * @param priority priority of the content
307 * @param anonymity anonymity-level for the content
308 * @param expiration expiration time for the content
309 * @param timeout timeout for the operation
310 * @param cont continuation to call when done
311 * @param cont_cls closure for cont
314 GNUNET_DATASTORE_put (struct GNUNET_DATASTORE_Handle *h,
316 const GNUNET_HashCode * key,
322 struct GNUNET_TIME_Absolute expiration,
323 struct GNUNET_TIME_Relative timeout,
324 GNUNET_DATASTORE_ContinuationWithStatus cont,
327 struct DataMessage *dm;
331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
332 "Asked to put %u bytes of data under key `%s'\n",
336 msize = sizeof(struct DataMessage) + size;
337 GNUNET_assert (msize <= GNUNET_SERVER_MAX_MESSAGE_SIZE);
338 dm = (struct DataMessage*) &h[1];
339 dm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_PUT);
340 dm->header.size = htons(msize);
341 dm->rid = htonl(rid);
342 dm->size = htonl(size);
343 dm->type = htonl(type);
344 dm->priority = htonl(priority);
345 dm->anonymity = htonl(anonymity);
346 dm->uid = GNUNET_htonll(0);
347 dm->expiration = GNUNET_TIME_absolute_hton(expiration);
349 memcpy (&dm[1], data, size);
350 transmit_for_status (h, cont, cont_cls, timeout);
355 * Reserve space in the datastore. This function should be used
356 * to avoid "out of space" failures during a longer sequence of "put"
357 * operations (for example, when a file is being inserted).
359 * @param h handle to the datastore
360 * @param amount how much space (in bytes) should be reserved (for content only)
361 * @param entries how many entries will be created (to calculate per-entry overhead)
362 * @param cont continuation to call when done; "success" will be set to
363 * a positive reservation value if space could be reserved.
364 * @param cont_cls closure for cont
365 * @param timeout how long to wait at most for a response
368 GNUNET_DATASTORE_reserve (struct GNUNET_DATASTORE_Handle *h,
371 GNUNET_DATASTORE_ContinuationWithStatus cont,
373 struct GNUNET_TIME_Relative timeout)
375 struct ReserveMessage *rm;
377 rm = (struct ReserveMessage*) &h[1];
378 rm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_RESERVE);
379 rm->header.size = htons(sizeof (struct ReserveMessage));
380 rm->entries = htonl(entries);
381 rm->amount = GNUNET_htonll(amount);
382 transmit_for_status (h, cont, cont_cls, timeout);
387 * Signal that all of the data for which a reservation was made has
388 * been stored and that whatever excess space might have been reserved
389 * can now be released.
391 * @param h handle to the datastore
392 * @param rid reservation ID (value of "success" in original continuation
393 * from the "reserve" function).
394 * @param cont continuation to call when done
395 * @param cont_cls closure for cont
396 * @param timeout how long to wait at most for a response
399 GNUNET_DATASTORE_release_reserve (struct GNUNET_DATASTORE_Handle *h,
401 GNUNET_DATASTORE_ContinuationWithStatus cont,
403 struct GNUNET_TIME_Relative timeout)
405 struct ReleaseReserveMessage *rrm;
407 rrm = (struct ReleaseReserveMessage*) &h[1];
408 rrm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_RELEASE_RESERVE);
409 rrm->header.size = htons(sizeof (struct ReleaseReserveMessage));
410 rrm->rid = htonl(rid);
411 transmit_for_status (h, cont, cont_cls, timeout);
416 * Update a value in the datastore.
418 * @param h handle to the datastore
419 * @param uid identifier for the value
420 * @param priority how much to increase the priority of the value
421 * @param expiration new expiration value should be MAX of existing and this argument
422 * @param cont continuation to call when done
423 * @param cont_cls closure for cont
424 * @param timeout how long to wait at most for a response
427 GNUNET_DATASTORE_update (struct GNUNET_DATASTORE_Handle *h,
428 unsigned long long uid,
430 struct GNUNET_TIME_Absolute expiration,
431 GNUNET_DATASTORE_ContinuationWithStatus cont,
433 struct GNUNET_TIME_Relative timeout)
435 struct UpdateMessage *um;
437 um = (struct UpdateMessage*) &h[1];
438 um->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_UPDATE);
439 um->header.size = htons(sizeof (struct UpdateMessage));
440 um->priority = htonl(priority);
441 um->expiration = GNUNET_TIME_absolute_hton(expiration);
442 um->uid = GNUNET_htonll(uid);
443 transmit_for_status (h, cont, cont_cls, timeout);
450 * Type of a function to call when we receive a message
451 * from the service. This specific function is used
452 * to handle messages of type "struct DataMessage".
455 * @param msg message received, NULL on timeout or fatal error
458 with_result_response_handler (void *cls,
460 GNUNET_MessageHeader * msg)
462 struct GNUNET_DATASTORE_Handle *h = cls;
463 GNUNET_DATASTORE_Iterator cont = h->response_proc;
464 const struct DataMessage *dm;
469 h->response_proc = NULL;
470 GNUNET_CLIENT_disconnect (h->client);
471 h->client = GNUNET_CLIENT_connect (h->sched, "datastore", h->cfg);
472 cont (h->response_proc_cls,
473 NULL, 0, NULL, 0, 0, 0,
474 GNUNET_TIME_UNIT_ZERO_ABS, 0);
477 if (ntohs(msg->type) == GNUNET_MESSAGE_TYPE_DATASTORE_DATA_END)
479 GNUNET_break (ntohs(msg->size) == sizeof(struct GNUNET_MessageHeader));
480 h->response_proc = NULL;
482 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
483 "Received end of result set\n");
485 cont (h->response_proc_cls,
486 NULL, 0, NULL, 0, 0, 0,
487 GNUNET_TIME_UNIT_ZERO_ABS, 0);
490 if ( (ntohs(msg->size) < sizeof(struct DataMessage)) ||
491 (ntohs(msg->type) != GNUNET_MESSAGE_TYPE_DATASTORE_DATA) )
494 GNUNET_CLIENT_disconnect (h->client);
495 h->client = GNUNET_CLIENT_connect (h->sched, "datastore", h->cfg);
496 h->response_proc = NULL;
497 cont (h->response_proc_cls,
498 NULL, 0, NULL, 0, 0, 0,
499 GNUNET_TIME_UNIT_ZERO_ABS, 0);
502 dm = (const struct DataMessage*) msg;
503 msize = ntohl(dm->size);
504 if (ntohs(msg->size) != msize + sizeof(struct DataMessage))
507 GNUNET_CLIENT_disconnect (h->client);
508 h->client = GNUNET_CLIENT_connect (h->sched, "datastore", h->cfg);
509 h->response_proc = NULL;
510 cont (h->response_proc_cls,
511 NULL, 0, NULL, 0, 0, 0,
512 GNUNET_TIME_UNIT_ZERO_ABS, 0);
516 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
517 "Received result %llu with type %u and size %u with key %s\n",
518 (unsigned long long) GNUNET_ntohll(dm->uid),
521 GNUNET_h2s(&dm->key));
523 cont (h->response_proc_cls,
529 ntohl(dm->anonymity),
530 GNUNET_TIME_absolute_ntoh(dm->expiration),
531 GNUNET_ntohll(dm->uid));
536 * Function called to trigger obtaining the next result
537 * from the datastore.
539 * @param h handle to the datastore
540 * @param more GNUNET_YES to get moxre results, GNUNET_NO to abort
541 * iteration (with a final call to "iter" with key/data == NULL).
544 GNUNET_DATASTORE_get_next (struct GNUNET_DATASTORE_Handle *h,
547 GNUNET_DATASTORE_Iterator cont;
549 if (GNUNET_YES == more)
551 GNUNET_CLIENT_receive (h->client,
552 &with_result_response_handler,
554 GNUNET_TIME_absolute_get_remaining (h->timeout));
557 cont = h->response_proc;
558 h->response_proc = NULL;
559 GNUNET_CLIENT_disconnect (h->client);
560 h->client = GNUNET_CLIENT_connect (h->sched, "datastore", h->cfg);
561 cont (h->response_proc_cls,
562 NULL, 0, NULL, 0, 0, 0,
563 GNUNET_TIME_UNIT_ZERO_ABS, 0);
568 * Helper function that will initiate the transmission of a message to
569 * the datastore service. The message must already be prepared and
570 * stored in the buffer at the end of the handle. The message must be
571 * of a type that expects a "DataMessage" in response.
573 * @param h handle to the service with prepared message
574 * @param cont function to call with result
575 * @param cont_cls closure
576 * @param timeout timeout for the operation
579 transmit_for_result (struct GNUNET_DATASTORE_Handle *h,
580 GNUNET_DATASTORE_Iterator cont,
582 struct GNUNET_TIME_Relative timeout)
584 const struct GNUNET_MessageHeader *hdr;
587 GNUNET_assert (cont != NULL);
588 hdr = (const struct GNUNET_MessageHeader*) &h[1];
589 msize = ntohs(hdr->size);
591 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
592 "Transmitting %u byte message of type %u to datastore service\n",
596 GNUNET_assert (h->response_proc == NULL);
597 h->response_proc = cont;
598 h->response_proc_cls = cont_cls;
599 h->timeout = GNUNET_TIME_relative_to_absolute (timeout);
600 h->message_size = msize;
602 GNUNET_CLIENT_transmit_and_get_response (h->client,
606 &with_result_response_handler,
610 h->response_proc = NULL;
612 cont (h->response_proc_cls,
613 NULL, 0, NULL, 0, 0, 0,
614 GNUNET_TIME_UNIT_ZERO_ABS, 0);
620 * Iterate over the results for a particular key
623 * @param h handle to the datastore
624 * @param key maybe NULL (to match all entries)
625 * @param type desired type, 0 for any
626 * @param iter function to call on each matching value;
627 * will be called once with a NULL value at the end
628 * @param iter_cls closure for iter
629 * @param timeout how long to wait at most for a response
632 GNUNET_DATASTORE_get (struct GNUNET_DATASTORE_Handle *h,
633 const GNUNET_HashCode * key,
635 GNUNET_DATASTORE_Iterator iter, void *iter_cls,
636 struct GNUNET_TIME_Relative timeout)
638 struct GetMessage *gm;
641 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
642 "Asked to look for data under key `%s'\n",
645 gm = (struct GetMessage*) &h[1];
646 gm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_GET);
647 gm->type = htonl(type);
650 gm->header.size = htons(sizeof (struct GetMessage));
655 gm->header.size = htons(sizeof (struct GetMessage) - sizeof(GNUNET_HashCode));
657 transmit_for_result (h, iter, iter_cls, timeout);
662 * Get a random value from the datastore.
664 * @param h handle to the datastore
665 * @param iter function to call on a random value; it
666 * will be called exactly once; if no values
667 * are available, the value will be NULL.
668 * @param iter_cls closure for iter
669 * @param timeout how long to wait at most for a response
672 GNUNET_DATASTORE_get_random (struct GNUNET_DATASTORE_Handle *h,
673 GNUNET_DATASTORE_Iterator iter, void *iter_cls,
674 struct GNUNET_TIME_Relative timeout)
676 struct GNUNET_MessageHeader *m;
678 m = (struct GNUNET_MessageHeader*) &h[1];
679 m->type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_GET_RANDOM);
680 m->size = htons(sizeof (struct GNUNET_MessageHeader));
681 transmit_for_result (h, iter, iter_cls, timeout);
686 * Explicitly remove some content from the database.
688 * @param h handle to the datastore
689 * @param key key for the value
690 * @param size number of bytes in data
691 * @param data content stored
692 * @param cont continuation to call when done
693 * @param cont_cls closure for cont
694 * @param timeout how long to wait at most for a response
697 GNUNET_DATASTORE_remove (struct GNUNET_DATASTORE_Handle *h,
698 const GNUNET_HashCode * key,
699 uint32_t size, const void *data,
700 GNUNET_DATASTORE_ContinuationWithStatus cont,
702 struct GNUNET_TIME_Relative timeout)
704 struct DataMessage *dm;
707 msize = sizeof(struct DataMessage) + size;
708 GNUNET_assert (msize <= GNUNET_SERVER_MAX_MESSAGE_SIZE);
709 dm = (struct DataMessage*) &h[1];
710 dm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_REMOVE);
711 dm->header.size = htons(msize);
713 dm->size = htonl(size);
715 dm->priority = htonl(0);
716 dm->anonymity = htonl(0);
717 dm->uid = GNUNET_htonll(0);
718 dm->expiration = GNUNET_TIME_absolute_hton(GNUNET_TIME_UNIT_ZERO_ABS);
720 memcpy (&dm[1], data, size);
721 transmit_for_status (h, cont, cont_cls, timeout);
725 /* end of datastore_api.c */