die strtok_r
[oweals/gnunet.git] / src / fs / gnunet-service-fs_pe.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_pe.c
23  * @brief API to manage query plan
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet-service-fs_cp.h"
28 #include "gnunet-service-fs_pe.h"
29
30 /**
31  * Hash map from peer identities to GNUNET_CONTAINER_Heap's with
32  * pending requests as entries.
33  */
34 static struct GNUNET_CONTAINER_MultiHashMap *plans;
35
36
37 /**
38  * Get the size of the request queue for the given peer.
39  *
40  * @param cp connected peer to query 
41  * @return number of entries in this peer's request queue
42  */
43 static struct GNUNET_CONTAINER_Heap *
44 get_heap (const struct GSF_ConnectedPeer *cp)
45 {
46   struct GNUNET_CONTAINER_Heap *h;
47   struct GNUNET_PeerIdentity id;
48
49   GSF_connected_peer_get_identity_ (cp, &id);
50   return GNUNET_CONTAINER_multihashmap_get (plans,
51                                             &id.hashPubKey);
52 }
53
54
55 /**
56  * Create a new query plan entry.
57  *
58  * @param cp peer with the entry
59  * @param pr request with the entry
60  * @param weight determines position of the entry in the cp queue,
61  *        lower weights are earlier in the queue
62  */
63 void
64 GSF_plan_add_ (const struct GSF_ConnectedPeer *cp,
65                struct GSF_PendingRequest *pr,
66                GNUNET_CONTAINER_HeapCostType weight)
67 {
68   struct GNUNET_PeerIdentity id;
69   struct GNUNET_CONTAINER_Heap *h;
70   struct GSF_PendingRequest *pr;
71
72   GSF_connected_peer_get_identity_ (cp, &id);
73   h = GNUNET_CONTAINER_multihashmap_get (plans,
74                                          &id.hashPubKey);
75   if (NULL == h)
76     {
77       h = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
78       GNUNET_CONTAINER_multihashmap_put (plans,
79                                          &id.hashPubKey,
80                                          h,
81                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
82     }
83   GNUNET_CONTAINER_heap_insert (h,
84                                 pr,
85                                 weight);
86 }
87
88
89 /**
90  * Notify the plan about a peer being no longer available;
91  * destroy all entries associated with this peer.
92  *
93  * @param cp connected peer 
94  */
95 void
96 GSF_plan_notify_peer_disconnect_ (const struct GSF_ConnectedPeer *cp)
97 {
98   struct GNUNET_PeerIdentity id;
99   struct GNUNET_CONTAINER_Heap *h;
100   struct GSF_PendingRequest *pr;
101
102   GSF_connected_peer_get_identity_ (cp, &id);
103   h = GNUNET_CONTAINER_multihashmap_get (plans,
104                                          &id.hashPubKey);
105   GNUNET_CONTAINER_multihashmap_remove (plans,
106                                         &id.hashPubKey,
107                                         h);
108   GNUNET_CONTAINER_heap_destroy (h);
109 }
110
111
112 /**
113  * Closure for 'find_request'.
114  */
115 struct FindRequestClosure
116 {
117   /**
118    * Place to store the node that was found (NULL for none).
119    */
120   struct GNUNET_CONTAINER_HeapNode *node;
121
122   /**
123    * Value we're looking for
124    */
125   const struct GSF_PendingRequest *pr;
126 };
127
128
129 /**
130  * Find a heap node where the value matches the
131  * pending request given in the closure.
132  *
133  * @param cls the 'struct FindRequestClosure'
134  * @param node heap structure we're looking for on a match
135  * @param element the pending request stored in the heap
136  * @param cost weight of the request
137  * @return GNUNET_YES to continue looking
138  */
139 static int
140 find_request (void *cls,
141               struct GNUNET_CONTAINER_HeapNode *node,
142               void *element,
143               GNUNET_CONTAINER_HeapCostType cost)
144 {
145   struct FindRequestClosure *frc = cls;
146   struct GSF_PendingRequest *pr = element;
147
148   if (pr == frc->pr)
149     {
150       frc->node = node;
151       return GNUNET_NO;
152     }
153   return GNUNET_YES;
154 }
155
156
157 /**
158  * Remove the given request from all heaps. * 
159  *
160  * @param cls 'struct GSF_PendingRequest' to purge
161  * @param key identity of the peer we're currently looking at (unused)
162  * @param value request heap for the given peer to search for the 'cls'
163  * @return GNUNET_OK (continue iteration)
164  */
165 static int
166 remove_request (void *cls,
167                 const GNUNET_HashCode *key,
168                 void *value)
169 {
170   const struct GSF_PendingRequest *pr = cls;
171   struct GNUNET_CONTAINER_Heap *h = value;
172   struct FindRequestClosure frc;
173
174   frc.pr = pr;
175   do
176     {
177       frc.node = NULL;
178       GNUNET_CONTAINER_heap_iterate (h, &find_request, &frc);
179       if (frc.node != NULL)
180         GNUNET_CONTAINER_heap_remove_node (h, frc.node);
181     }
182   while (NULL != frc.node);
183   return GNUNET_OK;
184 }
185
186
187 /**
188  * Notify the plan about a request being done; destroy all entries
189  * associated with this request.  Note that this implementation is
190  * currently terribly inefficient (O(n)) and could instead be done in
191  * O(1).  But for now, I first want to see it work correctly...
192  *
193  * @param pr request that is done
194  */
195 void
196 GSF_plan_notify_request_done_ (const struct GSF_PendingRequest *pr)
197 {
198   GNUNET_CONTAINER_multihashmap_iterate (plans,
199                                          &remove_request,
200                                          (void*) pr);
201 }
202
203
204 /**
205  * Get the lowest-weight entry for the respective peer
206  * from the plan.  Removes the entry from the plan's queue.
207  *
208  * @param cp connected peer to query for the next request
209  * @return NULL if the queue for this peer is empty
210  */
211 struct GSF_PendingRequest *
212 GSF_plan_get_ (const struct GSF_ConnectedPeer *cp)
213 {
214   struct GNUNET_CONTAINER_Heap *h;
215   struct GSF_PendingRequest *pr;
216
217   h = get_heap (cp);
218   if (NULL == h)
219     return NULL;
220   return GNUNET_CONTAINER_heap_remove_root (h);
221 }
222
223
224 /**
225  * Get the size of the request queue for the given peer.
226  *
227  * @param cp connected peer to query 
228  * @return number of entries in this peer's request queue
229  */
230 unsigned int
231 GSF_plan_size_ (const struct GSF_ConnectedPeer *cp)
232 {
233   struct GNUNET_CONTAINER_Heap *h;
234
235   h = get_heap (cp);
236   if (NULL == h)
237     return 0;
238   return GNUNET_CONTAINER_heap_get_size (h);
239 }
240
241
242
243 /**
244  * Initialize plan subsystem.
245  */
246 void
247 GSF_plan_init ()
248 {
249   plans = GNUNET_CONTAINER_multihashmap_create (256);
250 }
251
252
253 /**
254  * Shutdown plan subsystem.
255  */
256 void
257 GSF_plan_done ()
258 {
259   GNUNET_assert (0 == 
260                  GNUNET_CONTAINER_multihashmap_get_size (plans));
261   GNUNET_CONTAINER_multihashmap_destroy (plans);
262 }
263
264
265
266 /* end of gnunet-service-fs_pe.h */