fix
[oweals/gnunet.git] / src / fs / gnunet-service-fs_put.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011 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 fs/gnunet-service-fs_put.c
23  * @brief API to PUT zero-anonymity index data from our datastore into the DHT
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet-service-fs.h"
28 #include "gnunet-service-fs_put.h"
29
30
31 /**
32  * How often do we at most PUT content into the DHT?
33  */
34 #define MAX_DHT_PUT_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
35
36
37 /**
38  * Request to datastore for DHT PUTs (or NULL).
39  */
40 static struct GNUNET_DATASTORE_QueueEntry *dht_qe;
41
42 /**
43  * Type we will request for the next DHT PUT round from the datastore.
44  */
45 static enum GNUNET_BLOCK_Type dht_put_type = GNUNET_BLOCK_TYPE_FS_KBLOCK;
46
47 /**
48  * ID of task that collects blocks for DHT PUTs.
49  */
50 static GNUNET_SCHEDULER_TaskIdentifier dht_task;
51
52 /**
53  * How many entires with zero anonymity do we currently estimate
54  * to have in the database?
55  */
56 static unsigned int zero_anonymity_count_estimate;
57
58
59 /**
60  * Task that is run periodically to obtain blocks for DHT PUTs.
61  * 
62  * @param cls type of blocks to gather
63  * @param tc scheduler context (unused)
64  */
65 static void
66 gather_dht_put_blocks (void *cls,
67                        const struct GNUNET_SCHEDULER_TaskContext *tc);
68
69
70
71 /**
72  * If the DHT PUT gathering task is not currently running, consider
73  * (re)scheduling it with the appropriate delay.
74  */
75 static void
76 consider_dht_put_gathering (void *cls)
77 {
78   struct GNUNET_TIME_Relative delay;
79
80   if (GSF_dsh == NULL)
81     return;
82   if (dht_qe != NULL)
83     return;
84   if (dht_task != GNUNET_SCHEDULER_NO_TASK)
85     return;
86   if (zero_anonymity_count_estimate > 0)
87     {
88       delay = GNUNET_TIME_relative_divide (GNUNET_DHT_DEFAULT_REPUBLISH_FREQUENCY,
89                                            zero_anonymity_count_estimate);
90       delay = GNUNET_TIME_relative_min (delay,
91                                         MAX_DHT_PUT_FREQ);
92     }
93   else
94     {
95       /* if we have NO zero-anonymity content yet, wait 5 minutes for some to
96          (hopefully) appear */
97       delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5);
98     }
99   dht_task = GNUNET_SCHEDULER_add_delayed (delay,
100                                            &gather_dht_put_blocks,
101                                            cls);
102 }
103
104
105 /**
106  * Function called upon completion of the DHT PUT operation.
107  */
108 static void
109 dht_put_continuation (void *cls,
110                       const struct GNUNET_SCHEDULER_TaskContext *tc)
111 {
112   GNUNET_DATASTORE_iterate_get_next (GSF_dsh);
113 }
114
115
116 /**
117  * Store content in DHT.
118  *
119  * @param cls closure
120  * @param key key for the content
121  * @param size number of bytes in data
122  * @param data content stored
123  * @param type type of the content
124  * @param priority priority of the content
125  * @param anonymity anonymity-level for the content
126  * @param expiration expiration time for the content
127  * @param uid unique identifier for the datum;
128  *        maybe 0 if no unique identifier is available
129  */
130 static void
131 process_dht_put_content (void *cls,
132                          const GNUNET_HashCode * key,
133                          size_t size,
134                          const void *data,
135                          enum GNUNET_BLOCK_Type type,
136                          uint32_t priority,
137                          uint32_t anonymity,
138                          struct GNUNET_TIME_Absolute
139                          expiration, uint64_t uid)
140
141   static unsigned int counter;
142   static GNUNET_HashCode last_vhash;
143   static GNUNET_HashCode vhash;
144
145   if (key == NULL)
146     {
147       dht_qe = NULL;
148       consider_dht_put_gathering (cls);
149       return;
150     }
151   /* slightly funky code to estimate the total number of values with zero
152      anonymity from the maximum observed length of a monotonically increasing 
153      sequence of hashes over the contents */
154   GNUNET_CRYPTO_hash (data, size, &vhash);
155   if (GNUNET_CRYPTO_hash_cmp (&vhash, &last_vhash) <= 0)
156     {
157       if (zero_anonymity_count_estimate > 0)
158         zero_anonymity_count_estimate /= 2;
159       counter = 0;
160     }
161   last_vhash = vhash;
162   if (counter < 31)
163     counter++;
164   if (zero_anonymity_count_estimate < (1 << counter))
165     zero_anonymity_count_estimate = (1 << counter);
166 #if DEBUG_FS
167   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
168               "Retrieved block `%s' of type %u for DHT PUT\n",
169               GNUNET_h2s (key),
170               type);
171 #endif
172   GNUNET_DHT_put (GSF_dht,
173                   key,
174                   DEFAULT_PUT_REPLICATION,
175                   GNUNET_DHT_RO_NONE,
176                   type,
177                   size,
178                   data,
179                   expiration,
180                   GNUNET_TIME_UNIT_FOREVER_REL,
181                   &dht_put_continuation,
182                   cls);
183 }
184
185
186 /**
187  * Task that is run periodically to obtain blocks for DHT PUTs.
188  * 
189  * @param cls type of blocks to gather
190  * @param tc scheduler context (unused)
191  */
192 static void
193 gather_dht_put_blocks (void *cls,
194                        const struct GNUNET_SCHEDULER_TaskContext *tc)
195 {
196   dht_task = GNUNET_SCHEDULER_NO_TASK;
197   if (GSF_dsh == NULL)
198     return;
199   if (dht_put_type == GNUNET_BLOCK_TYPE_FS_ONDEMAND)
200     dht_put_type = GNUNET_BLOCK_TYPE_FS_KBLOCK;
201   dht_qe = GNUNET_DATASTORE_iterate_zero_anonymity (GSF_dsh, 
202                                                     0, UINT_MAX,
203                                                     GNUNET_TIME_UNIT_FOREVER_REL,
204                                                     dht_put_type++,
205                                                     &process_dht_put_content, NULL);
206   GNUNET_assert (dht_qe != NULL);
207 }
208
209
210 /**
211  * Setup the module.
212  */
213 void
214 GSF_put_init_ ()
215 {
216   dht_task = GNUNET_SCHEDULER_add_now (&gather_dht_put_blocks, NULL);
217 }
218
219
220 /**
221  * Shutdown the module.
222  */
223 void
224 GSF_put_done_ ()
225 {
226   if (GNUNET_SCHEDULER_NO_TASK != dht_task)
227     {
228       GNUNET_SCHEDULER_cancel (dht_task);
229       dht_task = GNUNET_SCHEDULER_NO_TASK;
230     }
231   if (NULL != dht_qe)
232     {
233       GNUNET_DATASTORE_cancel (dht_qe);
234       dht_qe = NULL;
235     }
236 }
237
238 /* end of gnunet-service-fs_put.c */