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