[datastore] Return and update replication
[oweals/gnunet.git] / src / datastore / gnunet-datastore.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2010, 2013 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, 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 {
75   if (NULL != qe)
76     GNUNET_DATASTORE_cancel (qe);
77   GNUNET_DATASTORE_disconnect (db_src, GNUNET_NO);
78   GNUNET_DATASTORE_disconnect (db_dst, GNUNET_NO);
79   GNUNET_CONFIGURATION_destroy (scfg);
80 }
81
82
83 /**
84  * Perform next GET operation.
85  */
86 static void
87 do_get (void);
88
89
90 /**
91  * Continuation called to notify client about result of the
92  * operation.
93  *
94  * @param cls closure
95  * @param success GNUNET_SYSERR on failure (including timeout/queue drop)
96  *                GNUNET_NO if content was already there
97  *                GNUNET_YES (or other positive value) on success
98  * @param min_expiration minimum expiration time required for 0-priority content to be stored
99  *                by the datacache at this time, zero for unknown, forever if we have no
100  *                space for 0-priority content
101  * @param msg NULL on success, otherwise an error message
102  */
103 static void
104 do_finish (void *cls,
105            int32_t success,
106            struct GNUNET_TIME_Absolute min_expiration,
107            const char *msg)
108 {
109   qe = NULL;
110   if (GNUNET_SYSERR == success)
111   {
112     fprintf (stderr,
113              _("Failed to store item: %s, aborting\n"),
114              msg);
115     ret = 1;
116     GNUNET_SCHEDULER_shutdown ();
117     return;
118   }
119   do_get ();
120 }
121
122
123 /**
124  * Process a datum that was stored in the datastore.
125  *
126  * @param cls closure
127  * @param key key for the content
128  * @param size number of bytes in data
129  * @param data content stored
130  * @param type type of the content
131  * @param priority priority of the content
132  * @param anonymity anonymity-level for the content
133  * @param replication replication-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,
142         const void *data,
143         enum GNUNET_BLOCK_Type type,
144         uint32_t priority,
145         uint32_t anonymity,
146         uint32_t replication,
147         struct GNUNET_TIME_Absolute
148         expiration,
149         uint64_t uid)
150 {
151   qe = NULL;
152   if ( (0 != offset) &&
153        (uid == first_uid) )
154   {
155     GNUNET_SCHEDULER_shutdown ();
156     return;
157   }
158   if (0 == offset)
159     first_uid = uid;
160   qe = GNUNET_DATASTORE_put (db_dst,
161                              0,
162                              key,
163                              size,
164                              data,
165                              type,
166                              priority,
167                              anonymity,
168                              replication,
169                              expiration,
170                              0,
171                              1,
172                              &do_finish,
173                              NULL);
174 }
175
176
177 /**
178  * Perform next GET operation.
179  */
180 static void
181 do_get ()
182 {
183   qe = GNUNET_DATASTORE_get_key (db_src,
184                                  0, false,
185                                  NULL, GNUNET_BLOCK_TYPE_ANY,
186                                  0, 1,
187                                  &do_put, NULL);
188 }
189
190
191
192 /**
193  * Main function that will be run by the scheduler.
194  *
195  * @param cls closure
196  * @param args remaining command-line arguments
197  * @param cfgfile name of the configuration file used
198  * @param cfg configuration -- for destination datastore
199  */
200 static void
201 run (void *cls, char *const *args, const char *cfgfile,
202      const struct GNUNET_CONFIGURATION_Handle *cfg)
203 {
204   if (NULL == alternative_cfg)
205     return; /* nothing to be done */
206   if (0 == strcmp (cfgfile, alternative_cfg))
207   {
208     fprintf (stderr,
209              _("Cannot use the same configuration for source and destination\n"));
210     ret = 1;
211     return;
212   }
213   scfg = GNUNET_CONFIGURATION_create ();
214   if (GNUNET_OK !=
215       GNUNET_CONFIGURATION_load (scfg,
216                                  alternative_cfg))
217   {
218     GNUNET_CONFIGURATION_destroy (scfg);
219     ret = 1;
220     return;
221   }
222   db_src = GNUNET_DATASTORE_connect (scfg);
223   if (NULL == db_src)
224   {
225     GNUNET_CONFIGURATION_destroy (scfg);
226     ret = 1;
227     return;
228   }
229   db_dst = GNUNET_DATASTORE_connect (cfg);
230   if (NULL == db_dst)
231   {
232     GNUNET_DATASTORE_disconnect (db_src, GNUNET_NO);
233     GNUNET_CONFIGURATION_destroy (scfg);
234     ret = 1;
235     return;
236   }
237   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
238   do_get ();
239 }
240
241
242 /**
243  * The main function to manipulate datastores.
244  *
245  * @param argc number of arguments from the command line
246  * @param argv command line arguments
247  * @return 0 ok, 1 on error
248  */
249 int
250 main (int argc, char *const *argv)
251 {
252   struct GNUNET_GETOPT_CommandLineOption options[] = {
253     GNUNET_GETOPT_OPTION_FILENAME ('s',
254                                    "sourcecfg",
255                                    "FILENAME",
256                                    gettext_noop ("specifies the configuration to use to access an alternative datastore; will merge that datastore into our current datastore"),
257                                        &alternative_cfg),
258     GNUNET_GETOPT_OPTION_END
259   };
260   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
261     return 2;
262
263   if (GNUNET_OK !=
264       GNUNET_PROGRAM_run (argc, argv, "gnunet-datastore",
265                           gettext_noop ("Manipulate GNUnet datastore"),
266                           options, &run, NULL))
267     ret = 1;
268   GNUNET_free ((void*) argv);
269   return ret;
270 }
271
272 /* end of gnunet-datastore.c */