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