951cf2651dddfb78403210848e6c26e952344f97
[oweals/gnunet.git] / src / datastore / datastore_api.c
1 /*
2      This file is part of GNUnet
3      (C) 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19 */
20
21 /**
22  * @file datastore/datastore_api.c
23  * @brief Management for the datastore for files stored on a GNUnet node
24  * @author Christian Grothoff
25  */
26
27 #include "platform.h"
28 #include "gnunet_datastore_service.h"
29 #include "datastore.h"
30
31 /**
32  * Handle to the datastore service.  Followed
33  * by 65536 bytes used for storing messages.
34  */
35 struct GNUNET_DATASTORE_Handle
36 {
37
38   /**
39    * Our configuration.
40    */
41   struct GNUNET_CONFIGURATION_Handle *cfg;
42
43   /**
44    * Our scheduler.
45    */
46   struct GNUNET_SCHEDULER_Handle *sched;
47
48   /**
49    * Current connection to the datastore service.
50    */
51   struct GNUNET_CLIENT_Connection *client;
52
53   /**
54    * Current response processor (NULL if we are not waiting for a
55    * response).  The specific type depends on the kind of message we
56    * just transmitted.
57    */
58   void *response_proc;
59   
60   /**
61    * Closure for response_proc.
62    */
63   void *response_proc_cls;
64
65   /**
66    * Timeout for the current operation.
67    */
68   struct GNUNET_TIME_Absolute timeout;
69
70   /**
71    * Number of bytes in the message following
72    * this struct, 0 if we have no request pending.
73    */
74   size_t message_size;
75   
76 };
77
78
79 /**
80  * Connect to the datastore service.
81  *
82  * @param cfg configuration to use
83  * @param sched scheduler to use
84  * @return handle to use to access the service
85  */
86 struct GNUNET_DATASTORE_Handle *GNUNET_DATASTORE_connect (struct
87                                                           GNUNET_CONFIGURATION_Handle
88                                                           *cfg,
89                                                           struct
90                                                           GNUNET_SCHEDULER_Handle
91                                                           *sched)
92 {
93   struct GNUNET_CLIENT_Connection *c;
94   struct GNUNET_DATASTORE_Handle *h;
95   
96   c = GNUNET_CLIENT_connect (sched, "datastore", cfg);
97   if (c == NULL)
98     return NULL; /* oops */
99   h = GNUNET_malloc (sizeof(struct GNUNET_DATASTORE_Handle) + 
100                      GNUNET_SERVER_MAX_MESSAGE_SIZE);
101   h->client = c;
102   h->cfg = cfg;
103   h->sched = sched;
104   return h;
105 }
106
107
108 /**
109  * Transmit DROP message to datastore service.
110  */
111 static size_t
112 transmit_drop (void *cls,
113                size_t size, void *buf)
114 {
115   struct GNUNET_DATASTORE_Handle *h = cls;
116   struct GNUNET_MessageHeader *hdr;
117   
118   if (buf == NULL)
119     {
120       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
121                   _("Failed to transmit request to drop database.\n"));
122       GNUNET_DATASTORE_disconnect (h, GNUNET_NO);
123       return 0;
124     }
125   GNUNET_assert (size >= sizeof(struct GNUNET_MessageHeader));
126   hdr = buf;
127   hdr->size = htons(sizeof(struct GNUNET_MessageHeader));
128   hdr->type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_DROP);
129   GNUNET_DATASTORE_disconnect (h, GNUNET_NO);
130   return sizeof(struct GNUNET_MessageHeader);
131 }
132
133
134 /**
135  * Disconnect from the datastore service (and free
136  * associated resources).
137  *
138  * @param h handle to the datastore
139  * @param drop set to GNUNET_YES to delete all data in datastore (!)
140  */
141 void GNUNET_DATASTORE_disconnect (struct GNUNET_DATASTORE_Handle *h,
142                                   int drop)
143 {
144   GNUNET_assert (0 == h->message_size);
145   GNUNET_assert (NULL == h->response_proc);
146   if ( (GNUNET_YES == drop) &&
147        (h->client != NULL) )
148     {
149       if (NULL != 
150           GNUNET_CLIENT_notify_transmit_ready (h->client,
151                                                sizeof(struct GNUNET_MessageHeader),
152                                                GNUNET_TIME_UNIT_MINUTES,
153                                                &transmit_drop,
154                                                h))
155         return;
156       GNUNET_break (0);
157     }
158   if (h->client != NULL)
159     GNUNET_CLIENT_disconnect (h->client);
160   GNUNET_free (h);
161 }
162
163
164 /**
165  * Type of a function to call when we receive a message
166  * from the service.  This specific function is used
167  * to handle messages of type "struct StatusMessage".
168  *
169  * @param cls closure
170  * @param msg message received, NULL on timeout or fatal error
171  */
172 static void 
173 with_status_response_handler (void *cls,
174                               const struct
175                               GNUNET_MessageHeader * msg)
176 {
177   struct GNUNET_DATASTORE_Handle *h = cls;
178   GNUNET_DATASTORE_ContinuationWithStatus cont = h->response_proc;
179   const struct StatusMessage *sm;
180   const char *emsg;
181   int status;
182
183   if (msg == NULL)
184     {
185       h->response_proc = NULL;
186       GNUNET_CLIENT_disconnect (h->client);
187       h->client = GNUNET_CLIENT_connect (h->sched, "datastore", h->cfg);
188       cont (h->response_proc_cls, 
189             GNUNET_SYSERR,
190             _("Timeout trying to read response from datastore service\n"));       
191       return;
192     }
193   if ( (ntohs(msg->size) < sizeof(struct StatusMessage)) ||
194        (ntohs(msg->type) != GNUNET_MESSAGE_TYPE_DATASTORE_STATUS) ) 
195     {
196       GNUNET_break (0);
197       GNUNET_CLIENT_disconnect (h->client);
198       h->client = GNUNET_CLIENT_connect (h->sched, "datastore", h->cfg);
199       cont (h->response_proc_cls, 
200             GNUNET_SYSERR,
201             _("Error reading response from datastore service\n"));
202       return;
203     }
204   sm = (const struct StatusMessage*) msg;
205   status = ntohl(sm->status);
206   emsg = NULL;
207   if (status == GNUNET_SYSERR)
208     {
209       emsg = (const char*) &sm[1];
210       if ( (ntohs(msg->size) == sizeof(struct StatusMessage)) ||
211            (emsg[ntohs(msg->size) - sizeof(struct StatusMessage) - 1] != '\0') )
212         {
213           GNUNET_break (0);
214           emsg = _("Invalid error message received from datastore service");
215         }
216     }  
217   h->response_proc = NULL;
218   cont (h->response_proc_cls, 
219         status,
220         emsg);
221 }
222
223
224 /**
225  * Transmit message to datastore service and then
226  * read a status message.
227  *
228  * @param cls closure with handle to datastore
229  * @param size number of bytes we can transmit at most
230  * @param buf where to write transmission, NULL on
231  *        timeout
232  * @return number of bytes copied to buf
233  */
234 static size_t
235 transmit_get_status (void *cls,
236                      size_t size,
237                      void *buf)
238 {
239   struct GNUNET_DATASTORE_Handle *h = cls;
240   GNUNET_DATASTORE_ContinuationWithStatus cont = h->response_proc;
241   uint16_t msize;
242
243   h->response_proc = NULL;
244   if (buf == NULL)
245     {
246       h->message_size = 0;
247       cont (h->response_proc_cls, 
248             GNUNET_SYSERR,
249             gettext_noop ("Error transmitting message to datastore service.\n"));
250       return 0;
251     }
252   GNUNET_assert (h->message_size <= size);
253   memcpy (buf, &h[1], h->message_size);
254   h->message_size = 0;
255   GNUNET_CLIENT_receive (h->client,
256                          &with_status_response_handler,
257                          h,
258                          GNUNET_TIME_absolute_get_remaining (h->timeout));
259   return msize;
260 }
261
262
263 /**
264  * Helper function that will initiate the
265  * transmission of a message to the datastore
266  * service.  The message must already be prepared
267  * and stored in the buffer at the end of the
268  * handle.  The message must be of a type that
269  * expects a "StatusMessage" in response.
270  *
271  * @param h handle to the service with prepared message
272  * @param cont function to call with result
273  * @param cont_cls closure
274  * @param timeout timeout for the operation
275  */
276 static void
277 transmit_for_status (struct GNUNET_DATASTORE_Handle *h,
278                      GNUNET_DATASTORE_ContinuationWithStatus cont,
279                      void *cont_cls,
280                      struct GNUNET_TIME_Relative timeout)
281 {
282   const struct GNUNET_MessageHeader *hdr;
283   uint16_t msize;
284
285   hdr = (const struct GNUNET_MessageHeader*) &h[1];
286   msize = ntohs(hdr->size);
287   GNUNET_assert (h->response_proc == NULL);
288   h->response_proc = cont;
289   h->response_proc_cls = cont_cls;
290   h->timeout = GNUNET_TIME_relative_to_absolute (timeout);
291   h->message_size = msize;
292   if (NULL == GNUNET_CLIENT_notify_transmit_ready (h->client,
293                                                    msize,
294                                                    timeout,
295                                                    &transmit_get_status,
296                                                    h))
297     {
298       GNUNET_break (0);
299       h->response_proc = NULL;
300       h->message_size = 0;
301       cont (cont_cls,
302             GNUNET_SYSERR,
303             gettext_noop ("Not ready to transmit request to datastore service"));
304     }
305 }
306
307
308 /**
309  * Store an item in the datastore.  If the item is already present,
310  * the priorities are summed up and the higher expiration time and
311  * lower anonymity level is used.
312  *
313  * @param h handle to the datastore
314  * @param key key for the value
315  * @param size number of bytes in data
316  * @param data content stored
317  * @param type type of the content
318  * @param priority priority of the content
319  * @param anonymity anonymity-level for the content
320  * @param expiration expiration time for the content
321  * @param timeout timeout for the operation
322  * @param cont continuation to call when done
323  * @param cont_cls closure for cont
324  */
325 void
326 GNUNET_DATASTORE_put (struct GNUNET_DATASTORE_Handle *h,
327                       int rid,
328                       const GNUNET_HashCode * key,
329                       uint32_t size,
330                       const void *data,
331                       uint32_t type,
332                       uint32_t priority,
333                       uint32_t anonymity,
334                       struct GNUNET_TIME_Absolute expiration,
335                       struct GNUNET_TIME_Relative timeout,
336                       GNUNET_DATASTORE_ContinuationWithStatus cont,
337                       void *cont_cls)
338 {
339   struct DataMessage *dm;
340   size_t msize;
341
342   msize = sizeof(struct DataMessage) + size;
343   GNUNET_assert (msize <= GNUNET_SERVER_MAX_MESSAGE_SIZE);
344   dm = (struct DataMessage*) &h[1];
345   dm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_PUT);
346   dm->header.size = htons(msize);
347   dm->rid = htonl(rid);
348   dm->size = htonl(size);
349   dm->type = htonl(type);
350   dm->priority = htonl(priority);
351   dm->anonymity = htonl(anonymity);
352   dm->uid = GNUNET_htonll(0);
353   dm->expiration = GNUNET_TIME_absolute_hton(expiration);
354   dm->key = *key;
355   memcpy (&dm[1], data, size);
356   transmit_for_status (h, cont, cont_cls, timeout);
357 }
358
359
360 /**
361  * Reserve space in the datastore.  This function should be used
362  * to avoid "out of space" failures during a longer sequence of "put"
363  * operations (for example, when a file is being inserted).
364  *
365  * @param h handle to the datastore
366  * @param amount how much space (in bytes) should be reserved (for content only)
367  * @param entries how many entries will be created (to calculate per-entry overhead)
368  * @param cont continuation to call when done; "success" will be set to
369  *             a positive reservation value if space could be reserved.
370  * @param cont_cls closure for cont
371  * @param timeout how long to wait at most for a response
372  */
373 void
374 GNUNET_DATASTORE_reserve (struct GNUNET_DATASTORE_Handle *h,
375                           uint64_t amount,
376                           uint64_t entries,
377                           GNUNET_DATASTORE_ContinuationWithStatus cont,
378                           void *cont_cls,
379                           struct GNUNET_TIME_Relative timeout)
380 {
381   struct ReserveMessage *rm;
382
383   rm = (struct ReserveMessage*) &h[1];
384   rm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_RESERVE);
385   rm->header.size = htons(sizeof (struct ReserveMessage));
386   rm->reserved = htonl(0);
387   rm->amount = htonl(amount);
388   rm->entries = htonl(entries);
389   transmit_for_status (h, cont, cont_cls, timeout);
390 }
391
392
393 /**
394  * Signal that all of the data for which a reservation was made has
395  * been stored and that whatever excess space might have been reserved
396  * can now be released.
397  *
398  * @param h handle to the datastore
399  * @param rid reservation ID (value of "success" in original continuation
400  *        from the "reserve" function).
401  * @param cont continuation to call when done
402  * @param cont_cls closure for cont
403  * @param timeout how long to wait at most for a response
404  */
405 void
406 GNUNET_DATASTORE_release_reserve (struct GNUNET_DATASTORE_Handle *h,
407                                   int rid,
408                                   GNUNET_DATASTORE_ContinuationWithStatus cont,
409                                   void *cont_cls,
410                                   struct GNUNET_TIME_Relative timeout)
411 {
412   struct ReleaseReserveMessage *rrm;
413
414   rrm = (struct ReleaseReserveMessage*) &h[1];
415   rrm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_RELEASE_RESERVE);
416   rrm->header.size = htons(sizeof (struct ReleaseReserveMessage));
417   rrm->rid = htonl(rid);
418   transmit_for_status (h, cont, cont_cls, timeout);
419 }
420
421
422 /**
423  * Update a value in the datastore.
424  *
425  * @param h handle to the datastore
426  * @param uid identifier for the value
427  * @param priority how much to increase the priority of the value
428  * @param expiration new expiration value should be MAX of existing and this argument
429  * @param cont continuation to call when done
430  * @param cont_cls closure for cont
431  * @param timeout how long to wait at most for a response
432  */
433 void
434 GNUNET_DATASTORE_update (struct GNUNET_DATASTORE_Handle *h,
435                          unsigned long long uid,
436                          uint32_t priority,
437                          struct GNUNET_TIME_Absolute expiration,
438                          GNUNET_DATASTORE_ContinuationWithStatus cont,
439                          void *cont_cls,
440                          struct GNUNET_TIME_Relative timeout)
441 {
442   struct UpdateMessage *um;
443
444   um = (struct UpdateMessage*) &h[1];
445   um->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_UPDATE);
446   um->header.size = htons(sizeof (struct UpdateMessage));
447   um->priority = htonl(priority);
448   um->expiration = GNUNET_TIME_absolute_hton(expiration);
449   um->uid = GNUNET_htonll(uid);
450   transmit_for_status (h, cont, cont_cls, timeout);
451 }
452
453
454 /**
455  * Iterate over the results for a particular key
456  * in the datastore.
457  *
458  * @param h handle to the datastore
459  * @param key maybe NULL (to match all entries)
460  * @param type desired type, 0 for any
461  * @param iter function to call on each matching value;
462  *        will be called once with a NULL value at the end
463  * @param iter_cls closure for iter
464  * @param timeout how long to wait at most for a response
465  */
466 void
467 GNUNET_DATASTORE_get (struct GNUNET_DATASTORE_Handle *h,
468                       const GNUNET_HashCode * key,
469                       uint32_t type,
470                       GNUNET_DATASTORE_Iterator iter, void *iter_cls,
471                       struct GNUNET_TIME_Relative timeout)
472 {
473   static struct GNUNET_TIME_Absolute zero;
474   iter (iter_cls,
475         NULL, 0, NULL, 0, 0, 0, zero, 0);
476 }
477
478
479 /**
480  * Get a random value from the datastore.
481  *
482  * @param h handle to the datastore
483  * @param iter function to call on a random value; it
484  *        will be called exactly once; if no values
485  *        are available, the value will be NULL.
486  * @param iter_cls closure for iter
487  * @param timeout how long to wait at most for a response
488  */
489 void
490 GNUNET_DATASTORE_get_random (struct GNUNET_DATASTORE_Handle *h,
491                              GNUNET_DATASTORE_Iterator iter, void *iter_cls,
492                              struct GNUNET_TIME_Relative timeout)
493 {
494   static struct GNUNET_TIME_Absolute zero;
495   
496   iter (iter_cls,
497         NULL, 0, NULL, 0, 0, 0, zero, 0);
498 }
499
500
501 /**
502  * Explicitly remove some content from the database.
503  *
504  * @param h handle to the datastore
505  * @param key key for the value
506  * @param size number of bytes in data
507  * @param data content stored
508  * @param cont continuation to call when done
509  * @param cont_cls closure for cont
510  * @param timeout how long to wait at most for a response
511  */
512 void
513 GNUNET_DATASTORE_remove (struct GNUNET_DATASTORE_Handle *h,
514                          const GNUNET_HashCode * key,
515                          uint32_t size, const void *data,
516                          GNUNET_DATASTORE_ContinuationWithStatus cont,
517                          void *cont_cls,
518                          struct GNUNET_TIME_Relative timeout)
519 {
520   struct DataMessage *dm;
521   size_t msize;
522
523   msize = sizeof(struct DataMessage) + size;
524   GNUNET_assert (msize <= GNUNET_SERVER_MAX_MESSAGE_SIZE);
525   dm = (struct DataMessage*) &h[1];
526   dm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_REMOVE);
527   dm->header.size = htons(msize);
528   dm->rid = htonl(0);
529   dm->size = htonl(size);
530   dm->type = htonl(0);
531   dm->priority = htonl(0);
532   dm->anonymity = htonl(0);
533   dm->uid = GNUNET_htonll(0);
534   dm->expiration.value = 0;
535   dm->key = *key;
536   memcpy (&dm[1], data, size);
537   transmit_for_status (h, cont, cont_cls, timeout);
538 }
539
540
541 /* end of datastore_api.c */