indentation
[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   {NULL, GNUNET_BLOCK_TYPE_FS_KBLOCK, 0, 0, 0},
77   {NULL, GNUNET_BLOCK_TYPE_FS_SBLOCK, 0, 0, 0},
78   {NULL, GNUNET_BLOCK_TYPE_FS_NBLOCK, 0, 0, 0},
79   {NULL, GNUNET_BLOCK_TYPE_ANY, 0, 0, 0}
80 };
81
82
83 /**
84  * Task that is run periodically to obtain blocks for DHT PUTs.
85  * 
86  * @param cls type of blocks to gather
87  * @param tc scheduler context (unused)
88  */
89 static void
90 gather_dht_put_blocks (void *cls,
91                        const struct GNUNET_SCHEDULER_TaskContext *tc);
92
93
94 /**
95  * Task that is run periodically to obtain blocks for DHT PUTs.
96  * 
97  * @param cls type of blocks to gather
98  * @param tc scheduler context (unused)
99  */
100 static void
101 delay_dht_put_blocks (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
102 {
103   struct PutOperator *po = cls;
104   struct GNUNET_TIME_Relative delay;
105
106   po->dht_task = GNUNET_SCHEDULER_NO_TASK;
107   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
108     return;
109   if (po->zero_anonymity_count_estimate > 0)
110   {
111     delay = GNUNET_TIME_relative_divide (GNUNET_DHT_DEFAULT_REPUBLISH_FREQUENCY,
112                                          po->zero_anonymity_count_estimate);
113     delay = GNUNET_TIME_relative_min (delay, MAX_DHT_PUT_FREQ);
114   }
115   else
116   {
117     /* if we have NO zero-anonymity content yet, wait 5 minutes for some to
118      * (hopefully) appear */
119     delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5);
120   }
121   po->dht_task = GNUNET_SCHEDULER_add_delayed (delay,
122                                                &gather_dht_put_blocks, po);
123 }
124
125
126 /**
127  * Store content in DHT.
128  *
129  * @param cls closure
130  * @param key key for the content
131  * @param size number of bytes in data
132  * @param data content stored
133  * @param type type of the content
134  * @param priority priority of the content
135  * @param anonymity anonymity-level for the content
136  * @param expiration expiration time for the content
137  * @param uid unique identifier for the datum;
138  *        maybe 0 if no unique identifier is available
139  */
140 static void
141 process_dht_put_content (void *cls,
142                          const GNUNET_HashCode * key,
143                          size_t size,
144                          const void *data,
145                          enum GNUNET_BLOCK_Type type,
146                          uint32_t priority,
147                          uint32_t anonymity,
148                          struct GNUNET_TIME_Absolute expiration, uint64_t uid)
149 {
150   struct PutOperator *po = cls;
151
152   po->dht_qe = NULL;
153   if (key == NULL)
154   {
155     po->zero_anonymity_count_estimate = po->current_offset - 1;
156     po->current_offset = 0;
157     po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_blocks, po);
158     return;
159   }
160   po->zero_anonymity_count_estimate = GNUNET_MAX (po->current_offset,
161                                                   po->zero_anonymity_count_estimate);
162 #if DEBUG_FS
163   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
164               "Retrieved block `%s' of type %u for DHT PUT\n",
165               GNUNET_h2s (key), type);
166 #endif
167   GNUNET_DHT_put (GSF_dht,
168                   key,
169                   DEFAULT_PUT_REPLICATION,
170                   GNUNET_DHT_RO_NONE,
171                   type,
172                   size,
173                   data,
174                   expiration,
175                   GNUNET_TIME_UNIT_FOREVER_REL, &delay_dht_put_blocks, po);
176 }
177
178
179 /**
180  * Task that is run periodically to obtain blocks for DHT PUTs.
181  * 
182  * @param cls type of blocks to gather
183  * @param tc scheduler context (unused)
184  */
185 static void
186 gather_dht_put_blocks (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
187 {
188   struct PutOperator *po = cls;
189
190   po->dht_task = GNUNET_SCHEDULER_NO_TASK;
191   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
192     return;
193   po->dht_qe = GNUNET_DATASTORE_get_zero_anonymity (GSF_dsh,
194                                                     po->current_offset++,
195                                                     0, UINT_MAX,
196                                                     GNUNET_TIME_UNIT_FOREVER_REL,
197                                                     po->dht_put_type,
198                                                     &process_dht_put_content,
199                                                     po);
200   if (NULL == po->dht_qe)
201     po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_blocks, po);
202 }
203
204
205 /**
206  * Setup the module.
207  */
208 void
209 GSF_put_init_ ()
210 {
211   unsigned int i;
212
213   i = 0;
214   while (operators[i].dht_put_type != GNUNET_BLOCK_TYPE_ANY)
215   {
216     operators[i].dht_task =
217         GNUNET_SCHEDULER_add_now (&gather_dht_put_blocks, &operators[i]);
218     i++;
219   }
220 }
221
222
223 /**
224  * Shutdown the module.
225  */
226 void
227 GSF_put_done_ ()
228 {
229   struct PutOperator *po;
230   unsigned int i;
231
232   i = 0;
233   while ((po = &operators[i])->dht_put_type != GNUNET_BLOCK_TYPE_ANY)
234   {
235     if (GNUNET_SCHEDULER_NO_TASK != po->dht_task)
236     {
237       GNUNET_SCHEDULER_cancel (po->dht_task);
238       po->dht_task = GNUNET_SCHEDULER_NO_TASK;
239     }
240     if (NULL != po->dht_qe)
241     {
242       GNUNET_DATASTORE_cancel (po->dht_qe);
243       po->dht_qe = NULL;
244     }
245     i++;
246   }
247 }
248
249 /* end of gnunet-service-fs_put.c */