implementing plugin session monitoring API (#3452)
[oweals/gnunet.git] / src / datastore / gnunet-datastore.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010, 2013 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 3, 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/gnunet-datastore.c
23  * @brief tool to manipulate datastores
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_datastore_service.h"
29
30
31 /**
32  * Name of the second configuration file.
33  */
34 static char *alternative_cfg;
35
36 /**
37  * Global return value.
38  */
39 static int ret;
40
41 /**
42  * Our offset on 'get'.
43  */
44 static uint64_t offset;
45
46 /**
47  * First UID ever returned.
48  */
49 static uint64_t first_uid;
50
51 /**
52  * Configuration for the source database.
53  */
54 static struct GNUNET_CONFIGURATION_Handle *scfg;
55
56 /**
57  * Handle for database source.
58  */
59 static struct GNUNET_DATASTORE_Handle *db_src;
60
61 /**
62  * Handle for database destination.
63  */
64 static struct GNUNET_DATASTORE_Handle *db_dst;
65
66 /**
67  * Current operation.
68  */
69 static struct GNUNET_DATASTORE_QueueEntry *qe;
70
71
72 static void
73 do_shutdown (void *cls,
74              const struct GNUNET_SCHEDULER_TaskContext *tc)
75 {
76   if (NULL != qe)
77     GNUNET_DATASTORE_cancel (qe);
78   GNUNET_DATASTORE_disconnect (db_src, GNUNET_NO);
79   GNUNET_DATASTORE_disconnect (db_dst, GNUNET_NO);
80   GNUNET_CONFIGURATION_destroy (scfg);
81 }
82
83
84 /**
85  * Perform next GET operation.
86  */
87 static void
88 do_get (void);
89
90
91 /**
92  * Continuation called to notify client about result of the
93  * operation.
94  *
95  * @param cls closure
96  * @param success GNUNET_SYSERR on failure (including timeout/queue drop)
97  *                GNUNET_NO if content was already there
98  *                GNUNET_YES (or other positive value) on success
99  * @param min_expiration minimum expiration time required for 0-priority content to be stored
100  *                by the datacache at this time, zero for unknown, forever if we have no
101  *                space for 0-priority content
102  * @param msg NULL on success, otherwise an error message
103  */
104 static void
105 do_finish (void *cls,
106            int32_t success,
107            struct GNUNET_TIME_Absolute min_expiration,
108            const char *msg)
109 {
110   qe = NULL;
111   if (GNUNET_SYSERR == success)
112   {
113     fprintf (stderr,
114              _("Failed to store item: %s, aborting\n"),
115              msg);
116     ret = 1;
117     GNUNET_SCHEDULER_shutdown ();
118     return;
119   }
120   do_get ();
121 }
122
123
124 /**
125  * Process a datum that was stored in the datastore.
126  *
127  * @param cls closure
128  * @param key key for the content
129  * @param size number of bytes in data
130  * @param data content stored
131  * @param type type of the content
132  * @param priority priority of the content
133  * @param anonymity anonymity-level for the content
134  * @param expiration expiration time for the content
135  * @param uid unique identifier for the datum;
136  *        maybe 0 if no unique identifier is available
137  */
138 static void
139 do_put (void *cls,
140         const struct GNUNET_HashCode *key,
141         size_t size, const void *data,
142         enum GNUNET_BLOCK_Type type,
143         uint32_t priority,
144         uint32_t anonymity,
145         struct GNUNET_TIME_Absolute
146         expiration, uint64_t uid)
147 {
148   qe = NULL;
149   if ( (0 != offset) &&
150        (uid == first_uid) )
151   {
152     GNUNET_SCHEDULER_shutdown ();
153     return;
154   }
155   if (0 == offset)
156     first_uid = uid;
157   qe = GNUNET_DATASTORE_put (db_dst, 0,
158                              key, size, data, type,
159                              priority, anonymity,
160                              0 /* FIXME: replication is lost... */,
161                              expiration,
162                              0, 1, GNUNET_TIME_UNIT_FOREVER_REL,
163                              &do_finish, NULL);
164 }
165
166
167 /**
168  * Perform next GET operation.
169  */
170 static void
171 do_get ()
172 {
173   qe = GNUNET_DATASTORE_get_key (db_src,
174                                  offset,
175                                  NULL, GNUNET_BLOCK_TYPE_ANY,
176                                  0, 1,
177                                  GNUNET_TIME_UNIT_FOREVER_REL,
178                                  &do_put, NULL);
179 }
180
181
182
183 /**
184  * Main function that will be run by the scheduler.
185  *
186  * @param cls closure
187  * @param args remaining command-line arguments
188  * @param cfgfile name of the configuration file used
189  * @param cfg configuration -- for destination datastore
190  */
191 static void
192 run (void *cls, char *const *args, const char *cfgfile,
193      const struct GNUNET_CONFIGURATION_Handle *cfg)
194 {
195   if (NULL == alternative_cfg)
196     return; /* nothing to be done */
197   if (0 == strcmp (cfgfile, alternative_cfg))
198   {
199     fprintf (stderr,
200              _("Cannot use the same configuration for source and destination\n"));
201     ret = 1;
202     return;
203   }
204   scfg = GNUNET_CONFIGURATION_create ();
205   if (GNUNET_OK !=
206       GNUNET_CONFIGURATION_load (scfg,
207                                  alternative_cfg))
208   {
209     GNUNET_CONFIGURATION_destroy (scfg);
210     ret = 1;
211     return;
212   }
213   db_src = GNUNET_DATASTORE_connect (scfg);
214   if (NULL == db_src)
215   {
216     GNUNET_CONFIGURATION_destroy (scfg);
217     ret = 1;
218     return;
219   }
220   db_dst = GNUNET_DATASTORE_connect (cfg);
221   if (NULL == db_dst)
222   {
223     GNUNET_DATASTORE_disconnect (db_src, GNUNET_NO);
224     GNUNET_CONFIGURATION_destroy (scfg);
225     ret = 1;
226     return;
227   }
228   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
229                                 &do_shutdown, NULL);
230   do_get ();
231 }
232
233
234 /**
235  * The main function to manipulate datastores.
236  *
237  * @param argc number of arguments from the command line
238  * @param argv command line arguments
239  * @return 0 ok, 1 on error
240  */
241 int
242 main (int argc, char *const *argv)
243 {
244   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
245     { 's', "sourcecfg", "FILENAME",
246       gettext_noop ("specifies the configuration to use to access an alternative datastore; will merge that datastore into our current datastore"),
247       1, &GNUNET_GETOPT_set_filename, &alternative_cfg },
248     GNUNET_GETOPT_OPTION_END
249   };
250   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
251     return 2;
252
253   if (GNUNET_OK !=
254       GNUNET_PROGRAM_run (argc, argv, "gnunet-datastore",
255                           gettext_noop ("Manipulate GNUnet datastore"),
256                           options, &run, NULL))
257     ret = 1;
258   GNUNET_free ((void*) argv);
259   return ret;
260 }
261
262 /* end of gnunet-datastore.c */