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;
190 h->response_proc = NULL;
191 GNUNET_CLIENT_disconnect (h->client);
192 h->client = GNUNET_CLIENT_connect (h->sched, "datastore", h->cfg);
193 cont (h->response_proc_cls,
195 _("Timeout trying to read response from datastore service"));
198 if ( (ntohs(msg->size) < sizeof(struct StatusMessage)) ||
199 (ntohs(msg->type) != GNUNET_MESSAGE_TYPE_DATASTORE_STATUS) )
202 h->response_proc = NULL;
203 GNUNET_CLIENT_disconnect (h->client);
204 h->client = GNUNET_CLIENT_connect (h->sched, "datastore", h->cfg);
205 cont (h->response_proc_cls,
207 _("Error reading response from datastore service"));
210 sm = (const struct StatusMessage*) msg;
211 status = ntohl(sm->status);
213 if (ntohs(msg->size) > sizeof(struct StatusMessage))
215 emsg = (const char*) &sm[1];
216 if (emsg[ntohs(msg->size) - sizeof(struct StatusMessage) - 1] != '\0')
219 emsg = _("Invalid error message received from datastore service");
222 if ( (status == GNUNET_SYSERR) &&
226 emsg = _("Invalid error message received from datastore service");
228 h->response_proc = NULL;
230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
231 "Received status %d/%s\n",
235 cont (h->response_proc_cls,
242 * Helper function that will initiate the
243 * transmission of a message to the datastore
244 * service. The message must already be prepared
245 * and stored in the buffer at the end of the
246 * handle. The message must be of a type that
247 * expects a "StatusMessage" in response.
249 * @param h handle to the service with prepared message
250 * @param cont function to call with result
251 * @param cont_cls closure
252 * @param timeout timeout for the operation
255 transmit_for_status (struct GNUNET_DATASTORE_Handle *h,
256 GNUNET_DATASTORE_ContinuationWithStatus cont,
258 struct GNUNET_TIME_Relative timeout)
260 const struct GNUNET_MessageHeader *hdr;
263 GNUNET_assert (cont != NULL);
264 hdr = (const struct GNUNET_MessageHeader*) &h[1];
265 msize = ntohs(hdr->size);
267 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
268 "Transmitting %u byte message of type %u to datastore service\n",
272 GNUNET_assert (h->response_proc == NULL);
273 h->response_proc = cont;
274 h->response_proc_cls = cont_cls;
275 h->timeout = GNUNET_TIME_relative_to_absolute (timeout);
276 h->message_size = msize;
278 GNUNET_CLIENT_transmit_and_get_response (h->client,
282 &with_status_response_handler,
286 h->response_proc = NULL;
290 _("Not ready to transmit request to datastore service"));
296 * Store an item in the datastore. If the item is already present,
297 * the priorities are summed up and the higher expiration time and
298 * lower anonymity level is used.
300 * @param h handle to the datastore
301 * @param rid reservation ID to use (from "reserve"); use 0 if no
302 * prior reservation was made
303 * @param key key for the value
304 * @param size number of bytes in data
305 * @param data content stored
306 * @param type type of the content
307 * @param priority priority of the content
308 * @param anonymity anonymity-level for the content
309 * @param expiration expiration time for the content
310 * @param timeout timeout for the operation
311 * @param cont continuation to call when done
312 * @param cont_cls closure for cont
315 GNUNET_DATASTORE_put (struct GNUNET_DATASTORE_Handle *h,
317 const GNUNET_HashCode * key,
323 struct GNUNET_TIME_Absolute expiration,
324 struct GNUNET_TIME_Relative timeout,
325 GNUNET_DATASTORE_ContinuationWithStatus cont,
328 struct DataMessage *dm;
332 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
333 "Asked to put %u bytes of data under key `%s'\n",
337 msize = sizeof(struct DataMessage) + size;
338 GNUNET_assert (msize <= GNUNET_SERVER_MAX_MESSAGE_SIZE);
339 dm = (struct DataMessage*) &h[1];
340 dm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_PUT);
341 dm->header.size = htons(msize);
342 dm->rid = htonl(rid);
343 dm->size = htonl(size);
344 dm->type = htonl(type);
345 dm->priority = htonl(priority);
346 dm->anonymity = htonl(anonymity);
347 dm->uid = GNUNET_htonll(0);
348 dm->expiration = GNUNET_TIME_absolute_hton(expiration);
350 memcpy (&dm[1], data, size);
351 transmit_for_status (h, cont, cont_cls, timeout);
356 * Reserve space in the datastore. This function should be used
357 * to avoid "out of space" failures during a longer sequence of "put"
358 * operations (for example, when a file is being inserted).
360 * @param h handle to the datastore
361 * @param amount how much space (in bytes) should be reserved (for content only)
362 * @param entries how many entries will be created (to calculate per-entry overhead)
363 * @param cont continuation to call when done; "success" will be set to
364 * a positive reservation value if space could be reserved.
365 * @param cont_cls closure for cont
366 * @param timeout how long to wait at most for a response
369 GNUNET_DATASTORE_reserve (struct GNUNET_DATASTORE_Handle *h,
372 GNUNET_DATASTORE_ContinuationWithStatus cont,
374 struct GNUNET_TIME_Relative timeout)
376 struct ReserveMessage *rm;
378 rm = (struct ReserveMessage*) &h[1];
379 rm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_RESERVE);
380 rm->header.size = htons(sizeof (struct ReserveMessage));
381 rm->entries = htonl(entries);
382 rm->amount = GNUNET_htonll(amount);
383 transmit_for_status (h, cont, cont_cls, timeout);
388 * Signal that all of the data for which a reservation was made has
389 * been stored and that whatever excess space might have been reserved
390 * can now be released.
392 * @param h handle to the datastore
393 * @param rid reservation ID (value of "success" in original continuation
394 * from the "reserve" function).
395 * @param cont continuation to call when done
396 * @param cont_cls closure for cont
397 * @param timeout how long to wait at most for a response
400 GNUNET_DATASTORE_release_reserve (struct GNUNET_DATASTORE_Handle *h,
402 GNUNET_DATASTORE_ContinuationWithStatus cont,
404 struct GNUNET_TIME_Relative timeout)
406 struct ReleaseReserveMessage *rrm;
408 rrm = (struct ReleaseReserveMessage*) &h[1];
409 rrm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_RELEASE_RESERVE);
410 rrm->header.size = htons(sizeof (struct ReleaseReserveMessage));
411 rrm->rid = htonl(rid);
412 transmit_for_status (h, cont, cont_cls, timeout);
417 * Update a value in the datastore.
419 * @param h handle to the datastore
420 * @param uid identifier for the value
421 * @param priority how much to increase the priority of the value
422 * @param expiration new expiration value should be MAX of existing and this argument
423 * @param cont continuation to call when done
424 * @param cont_cls closure for cont
425 * @param timeout how long to wait at most for a response
428 GNUNET_DATASTORE_update (struct GNUNET_DATASTORE_Handle *h,
429 unsigned long long uid,
431 struct GNUNET_TIME_Absolute expiration,
432 GNUNET_DATASTORE_ContinuationWithStatus cont,
434 struct GNUNET_TIME_Relative timeout)
436 struct UpdateMessage *um;
438 um = (struct UpdateMessage*) &h[1];
439 um->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_UPDATE);
440 um->header.size = htons(sizeof (struct UpdateMessage));
441 um->priority = htonl(priority);
442 um->expiration = GNUNET_TIME_absolute_hton(expiration);
443 um->uid = GNUNET_htonll(uid);
444 transmit_for_status (h, cont, cont_cls, timeout);
451 * Type of a function to call when we receive a message
452 * from the service. This specific function is used
453 * to handle messages of type "struct DataMessage".
456 * @param msg message received, NULL on timeout or fatal error
459 with_result_response_handler (void *cls,
461 GNUNET_MessageHeader * msg)
463 struct GNUNET_DATASTORE_Handle *h = cls;
464 GNUNET_DATASTORE_Iterator cont = h->response_proc;
465 const struct DataMessage *dm;
471 h->response_proc = NULL;
472 GNUNET_CLIENT_disconnect (h->client);
473 h->client = GNUNET_CLIENT_connect (h->sched, "datastore", h->cfg);
474 cont (h->response_proc_cls,
475 NULL, 0, NULL, 0, 0, 0,
476 GNUNET_TIME_UNIT_ZERO_ABS, 0);
479 if (ntohs(msg->type) == GNUNET_MESSAGE_TYPE_DATASTORE_DATA_END)
481 GNUNET_break (ntohs(msg->size) == sizeof(struct GNUNET_MessageHeader));
482 h->response_proc = NULL;
484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
485 "Received end of result set\n");
487 cont (h->response_proc_cls,
488 NULL, 0, NULL, 0, 0, 0,
489 GNUNET_TIME_UNIT_ZERO_ABS, 0);
492 if ( (ntohs(msg->size) < sizeof(struct DataMessage)) ||
493 (ntohs(msg->type) != GNUNET_MESSAGE_TYPE_DATASTORE_DATA) )
496 GNUNET_CLIENT_disconnect (h->client);
497 h->client = GNUNET_CLIENT_connect (h->sched, "datastore", h->cfg);
498 h->response_proc = NULL;
499 cont (h->response_proc_cls,
500 NULL, 0, NULL, 0, 0, 0,
501 GNUNET_TIME_UNIT_ZERO_ABS, 0);
504 dm = (const struct DataMessage*) msg;
505 msize = ntohl(dm->size);
506 if (ntohs(msg->size) != msize + sizeof(struct DataMessage))
509 GNUNET_CLIENT_disconnect (h->client);
510 h->client = GNUNET_CLIENT_connect (h->sched, "datastore", h->cfg);
511 h->response_proc = NULL;
512 cont (h->response_proc_cls,
513 NULL, 0, NULL, 0, 0, 0,
514 GNUNET_TIME_UNIT_ZERO_ABS, 0);
518 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
519 "Received result %llu with type %u and size %u with key %s\n",
520 (unsigned long long) GNUNET_ntohll(dm->uid),
523 GNUNET_h2s(&dm->key));
525 cont (h->response_proc_cls,
531 ntohl(dm->anonymity),
532 GNUNET_TIME_absolute_ntoh(dm->expiration),
533 GNUNET_ntohll(dm->uid));
538 * Function called to trigger obtaining the next result
539 * from the datastore.
541 * @param h handle to the datastore
542 * @param more GNUNET_YES to get moxre results, GNUNET_NO to abort
543 * iteration (with a final call to "iter" with key/data == NULL).
546 GNUNET_DATASTORE_get_next (struct GNUNET_DATASTORE_Handle *h,
549 GNUNET_DATASTORE_Iterator cont;
551 if (GNUNET_YES == more)
553 GNUNET_CLIENT_receive (h->client,
554 &with_result_response_handler,
556 GNUNET_TIME_absolute_get_remaining (h->timeout));
559 cont = h->response_proc;
560 h->response_proc = NULL;
561 GNUNET_CLIENT_disconnect (h->client);
562 h->client = GNUNET_CLIENT_connect (h->sched, "datastore", h->cfg);
563 cont (h->response_proc_cls,
564 NULL, 0, NULL, 0, 0, 0,
565 GNUNET_TIME_UNIT_ZERO_ABS, 0);
570 * Helper function that will initiate the transmission of a message to
571 * the datastore service. The message must already be prepared and
572 * stored in the buffer at the end of the handle. The message must be
573 * of a type that expects a "DataMessage" in response.
575 * @param h handle to the service with prepared message
576 * @param cont function to call with result
577 * @param cont_cls closure
578 * @param timeout timeout for the operation
581 transmit_for_result (struct GNUNET_DATASTORE_Handle *h,
582 GNUNET_DATASTORE_Iterator cont,
584 struct GNUNET_TIME_Relative timeout)
586 const struct GNUNET_MessageHeader *hdr;
589 GNUNET_assert (cont != NULL);
590 hdr = (const struct GNUNET_MessageHeader*) &h[1];
591 msize = ntohs(hdr->size);
593 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
594 "Transmitting %u byte message of type %u to datastore service\n",
598 GNUNET_assert (h->response_proc == NULL);
599 h->response_proc = cont;
600 h->response_proc_cls = cont_cls;
601 h->timeout = GNUNET_TIME_relative_to_absolute (timeout);
602 h->message_size = msize;
604 GNUNET_CLIENT_transmit_and_get_response (h->client,
608 &with_result_response_handler,
612 h->response_proc = NULL;
614 cont (h->response_proc_cls,
615 NULL, 0, NULL, 0, 0, 0,
616 GNUNET_TIME_UNIT_ZERO_ABS, 0);
622 * Iterate over the results for a particular key
625 * @param h handle to the datastore
626 * @param key maybe NULL (to match all entries)
627 * @param type desired type, 0 for any
628 * @param iter function to call on each matching value;
629 * will be called once with a NULL value at the end
630 * @param iter_cls closure for iter
631 * @param timeout how long to wait at most for a response
634 GNUNET_DATASTORE_get (struct GNUNET_DATASTORE_Handle *h,
635 const GNUNET_HashCode * key,
637 GNUNET_DATASTORE_Iterator iter, void *iter_cls,
638 struct GNUNET_TIME_Relative timeout)
640 struct GetMessage *gm;
643 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
644 "Asked to look for data under key `%s'\n",
647 gm = (struct GetMessage*) &h[1];
648 gm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_GET);
649 gm->type = htonl(type);
652 gm->header.size = htons(sizeof (struct GetMessage));
657 gm->header.size = htons(sizeof (struct GetMessage) - sizeof(GNUNET_HashCode));
659 transmit_for_result (h, iter, iter_cls, timeout);
664 * Get a random value from the datastore.
666 * @param h handle to the datastore
667 * @param iter function to call on a random value; it
668 * will be called exactly once; if no values
669 * are available, the value will be NULL.
670 * @param iter_cls closure for iter
671 * @param timeout how long to wait at most for a response
674 GNUNET_DATASTORE_get_random (struct GNUNET_DATASTORE_Handle *h,
675 GNUNET_DATASTORE_Iterator iter, void *iter_cls,
676 struct GNUNET_TIME_Relative timeout)
678 struct GNUNET_MessageHeader *m;
680 m = (struct GNUNET_MessageHeader*) &h[1];
681 m->type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_GET_RANDOM);
682 m->size = htons(sizeof (struct GNUNET_MessageHeader));
683 transmit_for_result (h, iter, iter_cls, timeout);
688 * Explicitly remove some content from the database.
690 * @param h handle to the datastore
691 * @param key key for the value
692 * @param size number of bytes in data
693 * @param data content stored
694 * @param cont continuation to call when done
695 * @param cont_cls closure for cont
696 * @param timeout how long to wait at most for a response
699 GNUNET_DATASTORE_remove (struct GNUNET_DATASTORE_Handle *h,
700 const GNUNET_HashCode * key,
701 uint32_t size, const void *data,
702 GNUNET_DATASTORE_ContinuationWithStatus cont,
704 struct GNUNET_TIME_Relative timeout)
706 struct DataMessage *dm;
709 msize = sizeof(struct DataMessage) + size;
710 GNUNET_assert (msize <= GNUNET_SERVER_MAX_MESSAGE_SIZE);
711 dm = (struct DataMessage*) &h[1];
712 dm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_REMOVE);
713 dm->header.size = htons(msize);
715 dm->size = htonl(size);
717 dm->priority = htonl(0);
718 dm->anonymity = htonl(0);
719 dm->uid = GNUNET_htonll(0);
720 dm->expiration = GNUNET_TIME_absolute_hton(GNUNET_TIME_UNIT_ZERO_ABS);
722 memcpy (&dm[1], data, size);
723 transmit_for_status (h, cont, cont_cls, timeout);
727 /* end of datastore_api.c */