arg
[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  * Context for each zero-anonymity iterator.
39  */
40 struct PutOperator
41 {
42
43   /**
44    * Request to datastore for DHT PUTs (or NULL).
45    */
46   struct GNUNET_DATASTORE_QueueEntry *dht_qe;
47
48   /**
49    * Type we request from the datastore.
50    */
51   enum GNUNET_BLOCK_Type dht_put_type;
52
53   /**
54    * ID of task that collects blocks for DHT PUTs.
55    */
56   GNUNET_SCHEDULER_TaskIdentifier dht_task;
57   
58   /**
59    * How many entires with zero anonymity of our type do we currently
60    * estimate to have in the database?
61    */
62   uint64_t zero_anonymity_count_estimate;
63
64   /**
65    * Current offset when iterating the database.
66    */
67   uint64_t current_offset;
68 };
69
70
71 /**
72  * ANY-terminated list of our operators (one per type
73  * of block that we're putting into the DHT).
74  */
75 static struct PutOperator operators[] = 
76   {
77     { NULL, GNUNET_BLOCK_TYPE_FS_KBLOCK, 0, 0, 0 },
78     { NULL, GNUNET_BLOCK_TYPE_FS_SBLOCK, 0, 0, 0 },
79     { NULL, GNUNET_BLOCK_TYPE_FS_NBLOCK, 0, 0, 0 },
80     { NULL, GNUNET_BLOCK_TYPE_ANY, 0, 0, 0 }
81   };
82
83
84 /**
85  * Task that is run periodically to obtain blocks for DHT PUTs.
86  * 
87  * @param cls type of blocks to gather
88  * @param tc scheduler context (unused)
89  */
90 static void
91 gather_dht_put_blocks (void *cls,
92                        const struct GNUNET_SCHEDULER_TaskContext *tc);
93
94
95 /**
96  * Task that is run periodically to obtain blocks for DHT PUTs.
97  * 
98  * @param cls type of blocks to gather
99  * @param tc scheduler context (unused)
100  */
101 static void
102 delay_dht_put_blocks (void *cls,
103                       const struct GNUNET_SCHEDULER_TaskContext *tc)
104 {
105   struct PutOperator *po = cls;
106   struct GNUNET_TIME_Relative delay;
107
108   po->dht_task = GNUNET_SCHEDULER_NO_TASK;
109   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
110     return;
111   if (po->zero_anonymity_count_estimate > 0)
112     {
113       delay = GNUNET_TIME_relative_divide (GNUNET_DHT_DEFAULT_REPUBLISH_FREQUENCY,
114                                            po->zero_anonymity_count_estimate);
115       delay = GNUNET_TIME_relative_min (delay,
116                                         MAX_DHT_PUT_FREQ);
117     }
118   else
119     {
120       /* if we have NO zero-anonymity content yet, wait 5 minutes for some to
121          (hopefully) appear */
122       delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5);
123     }
124   po->dht_task = GNUNET_SCHEDULER_add_delayed (delay,
125                                                &gather_dht_put_blocks,
126                                                po);
127 }
128
129
130 /**
131  * Store content in DHT.
132  *
133  * @param cls closure
134  * @param key key for the content
135  * @param size number of bytes in data
136  * @param data content stored
137  * @param type type of the content
138  * @param priority priority of the content
139  * @param anonymity anonymity-level for the content
140  * @param expiration expiration time for the content
141  * @param uid unique identifier for the datum;
142  *        maybe 0 if no unique identifier is available
143  */
144 static void
145 process_dht_put_content (void *cls,
146                          const GNUNET_HashCode * key,
147                          size_t size,
148                          const void *data,
149                          enum GNUNET_BLOCK_Type type,
150                          uint32_t priority,
151                          uint32_t anonymity,
152                          struct GNUNET_TIME_Absolute
153                          expiration, uint64_t uid)
154
155   struct PutOperator *po = cls;
156
157   po->dht_qe = NULL;
158   if (key == NULL)
159     {
160       po->zero_anonymity_count_estimate = po->current_offset - 1;
161       po->current_offset = 0;
162       po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_blocks,
163                                                po);
164       return;
165     }
166   po->zero_anonymity_count_estimate = GNUNET_MAX (po->current_offset,
167                                                   po->zero_anonymity_count_estimate);
168 #if DEBUG_FS
169   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
170               "Retrieved block `%s' of type %u for DHT PUT\n",
171               GNUNET_h2s (key),
172               type);
173 #endif
174   GNUNET_DHT_put (GSF_dht,
175                   key,
176                   DEFAULT_PUT_REPLICATION,
177                   GNUNET_DHT_RO_NONE,
178                   type,
179                   size,
180                   data,
181                   expiration,
182                   GNUNET_TIME_UNIT_FOREVER_REL,
183                   &delay_dht_put_blocks,
184                   po);
185 }
186
187
188 /**
189  * Task that is run periodically to obtain blocks for DHT PUTs.
190  * 
191  * @param cls type of blocks to gather
192  * @param tc scheduler context (unused)
193  */
194 static void
195 gather_dht_put_blocks (void *cls,
196                        const struct GNUNET_SCHEDULER_TaskContext *tc)
197 {
198   struct PutOperator *po = cls;
199
200   po->dht_task = GNUNET_SCHEDULER_NO_TASK;
201   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
202     return;
203   po->dht_qe = GNUNET_DATASTORE_get_zero_anonymity (GSF_dsh, 
204                                                     po->current_offset++,
205                                                     0, UINT_MAX,
206                                                     GNUNET_TIME_UNIT_FOREVER_REL,
207                                                     po->dht_put_type,
208                                                     &process_dht_put_content, po);
209   if (NULL == po->dht_qe)
210     po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_blocks,
211                                              po);
212 }
213
214
215 /**
216  * Setup the module.
217  */
218 void
219 GSF_put_init_ ()
220 {
221   unsigned int i;
222
223   i = 0;
224   while (operators[i].dht_put_type != GNUNET_BLOCK_TYPE_ANY)
225     {
226       operators[i].dht_task = GNUNET_SCHEDULER_add_now (&gather_dht_put_blocks, &operators[i]);
227       i++;
228     }
229 }
230
231
232 /**
233  * Shutdown the module.
234  */
235 void
236 GSF_put_done_ ()
237 {
238   struct PutOperator *po;
239   unsigned int i;
240
241   i = 0;
242   while ((po = &operators[i])->dht_put_type != GNUNET_BLOCK_TYPE_ANY)
243     {
244       if (GNUNET_SCHEDULER_NO_TASK != po->dht_task)
245         {
246           GNUNET_SCHEDULER_cancel (po->dht_task);
247           po->dht_task = GNUNET_SCHEDULER_NO_TASK;
248         }
249       if (NULL != po->dht_qe)
250         {
251           GNUNET_DATASTORE_cancel (po->dht_qe);
252           po->dht_qe = NULL;
253         }
254       i++;
255     }
256 }
257
258 /* end of gnunet-service-fs_put.c */