- cleanup; move to hashmap32
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed_cache.c
1 /*
2   This file is part of GNUnet.
3   (C) 2008--2013 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 testbed/gnunet-service-testbed_cache.c
23  * @brief testbed cache implementation
24  * @author Sree Harsha Totakura
25  */
26 #include "gnunet-service-testbed.h"
27
28 /**
29  * Redefine LOG with a changed log component string
30  */
31 #ifdef LOG
32 #undef LOG
33 #endif
34 #define LOG(kind,...)                                   \
35   GNUNET_log_from (kind, "testbed-cache", __VA_ARGS__)
36
37
38 /**
39  * Cache entry
40  */
41 struct CacheEntry
42 {
43   /**
44    * DLL next ptr for least recently used cache entries
45    */
46   struct CacheEntry *next;
47
48   /**
49    * DLL prev ptr for least recently used cache entries
50    */
51   struct CacheEntry *prev;
52
53   /**
54    * The HELLO message
55    */
56   struct GNUNET_MessageHeader *hello;
57
58   /**
59    * The id of the peer this entry corresponds to
60    */
61   unsigned int peer_id;
62 };
63
64
65 /**
66  * Hashmap to maintain cache
67  */
68 static struct GNUNET_CONTAINER_MultiHashMap32 *cache;
69
70 /**
71  * DLL head for least recently used cache entries; least recently used
72  * cache items are at the head. The cache enties are added to this queue when
73  * their demand becomes zero. They are removed from the queue when they are
74  * needed by any operation.
75  */
76 static struct CacheEntry *cache_head;
77
78 /**
79  * DLL tail for least recently used cache entries; recently used cache
80  * items are at the tail.The cache enties are added to this queue when
81  * their demand becomes zero. They are removed from the queue when they are
82  * needed by any operation.
83  */
84 static struct CacheEntry *cache_tail;
85
86 /**
87  * Maximum number of elements to cache
88  */
89 static unsigned int cache_size;
90
91
92 /**
93  * Looks up in the cache and returns the entry
94  *
95  * @param key the peer identity of the peer whose corresponding entry has to be
96  *          looked up
97  * @return the HELLO message; NULL if not found
98  */
99 static struct CacheEntry *
100 cache_lookup (unsigned int peer_id)
101 {
102   struct CacheEntry *entry;
103
104   GNUNET_assert (NULL != cache);
105   entry = GNUNET_CONTAINER_multihashmap32_get (cache, peer_id);
106   if (NULL == entry)
107     return NULL;
108   GNUNET_CONTAINER_DLL_remove (cache_head, cache_tail, entry);
109   GNUNET_CONTAINER_DLL_insert_tail (cache_head, cache_tail, entry);
110   return entry;
111 }
112
113
114 /**
115  * Creates a new cache entry and then puts it into the cache's hashtable.
116  *
117  * @param peer_id the index of the peer to tag the newly created entry
118  * @return the newly created entry
119  */
120 static struct CacheEntry *
121 add_entry (unsigned int peer_id)
122 {
123   struct CacheEntry *entry;
124   
125   GNUNET_assert (NULL != cache);
126   if (cache_size == GNUNET_CONTAINER_multihashmap32_size (cache))
127   {
128     /* remove the LRU head */
129     entry = cache_head;
130     GNUNET_assert (GNUNET_OK ==
131                    GNUNET_CONTAINER_multihashmap32_remove (cache, (uint32_t)
132                                                            entry->peer_id,
133                                                            entry));
134   }
135   entry = GNUNET_malloc (sizeof (struct CacheEntry));
136   entry->peer_id = peer_id;
137   GNUNET_assert (GNUNET_OK ==
138                  GNUNET_CONTAINER_multihashmap32_put (cache,
139                                                       (uint32_t) peer_id,
140                                                       entry,
141                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
142   GNUNET_CONTAINER_DLL_insert_tail (cache_head, cache_tail, entry);
143   return entry;
144 }
145
146
147 /**
148  * Iterator over hash map entries.
149  *
150  * @param cls closure
151  * @param key current key
152  * @param value value in the hash map
153  * @return GNUNET_YES if we should continue to
154  *         iterate,
155  *         GNUNET_NO if not.
156  */
157 static int
158 cache_clear_iterator (void *cls, uint32_t key, void *value)
159 {
160   struct CacheEntry *entry = value;
161
162   GNUNET_assert (NULL != entry);
163   GNUNET_assert (GNUNET_YES ==
164                  GNUNET_CONTAINER_multihashmap32_remove (cache, key, value));
165   GNUNET_free_non_null (entry->hello);
166   GNUNET_free (entry);
167   return GNUNET_YES;
168 }
169
170
171 /**
172  * Clear cache
173  */
174 void
175 GST_cache_clear ()
176 {
177   if (NULL != cache)
178   {
179     GNUNET_CONTAINER_multihashmap32_iterate (cache, &cache_clear_iterator, NULL);
180     GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (cache));
181     GNUNET_CONTAINER_multihashmap32_destroy (cache);
182     cache = NULL;
183   }
184   cache_size = 0;
185   cache_head = NULL;
186   cache_tail = NULL;
187 }
188
189
190 /**
191  * Initializes the cache
192  *
193  * @param size the size of the cache
194  */
195 void
196 GST_cache_init (unsigned int size)
197 {
198   if (0 == size)
199     return;
200   cache_size = size;
201   cache = GNUNET_CONTAINER_multihashmap32_create (cache_size);
202 }
203
204
205 /**
206  * Looks up in the hello cache and returns the HELLO of the given peer
207  *
208  * @param peer_id the index of the peer whose HELLO has to be looked up
209  * @return the HELLO message; NULL if not found
210  */
211 const struct GNUNET_MessageHeader *
212 GST_cache_lookup_hello (const unsigned int peer_id)
213 {
214   struct CacheEntry *entry;
215
216   LOG_DEBUG ("Looking up HELLO for peer %u\n", peer_id);
217   if (NULL == cache)
218   {
219     LOG_DEBUG ("Caching disabled\n");
220     return NULL;
221   }
222   entry = cache_lookup (peer_id);
223   if (NULL == entry)
224     return NULL;
225   if (NULL != entry->hello)
226     LOG_DEBUG ("HELLO found for peer %u\n", peer_id);
227   return entry->hello;
228 }
229
230
231 /**
232  * Caches the HELLO of the given peer. Updates the HELLO if it was already
233  * cached before
234  *
235  * @param peer_id the peer identity of the peer whose HELLO has to be cached
236  * @param hello the HELLO message
237  */
238 void
239 GST_cache_add_hello (const unsigned int peer_id,
240                      const struct GNUNET_MessageHeader *hello)
241 {
242   struct CacheEntry *entry;
243
244   if (NULL == cache)
245     return;
246   entry = cache_lookup (peer_id);
247   if (NULL == entry)
248     entry = add_entry (peer_id);
249   GNUNET_free_non_null (entry->hello);
250   entry->hello = GNUNET_copy_message (hello);
251 }
252
253 /* end of gnunet-service-testbed_hc.c */