gnunet-service-testbed_cache.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2008--2013 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file testbed/gnunet-service-testbed_cache.c
  18. * @brief testbed cache implementation
  19. * @author Sree Harsha Totakura
  20. */
  21. #include "gnunet-service-testbed.h"
  22. /**
  23. * Redefine LOG with a changed log component string
  24. */
  25. #ifdef LOG
  26. #undef LOG
  27. #endif
  28. #define LOG(kind,...) \
  29. GNUNET_log_from (kind, "testbed-cache", __VA_ARGS__)
  30. /**
  31. * Cache entry
  32. */
  33. struct CacheEntry
  34. {
  35. /**
  36. * DLL next ptr for least recently used cache entries
  37. */
  38. struct CacheEntry *next;
  39. /**
  40. * DLL prev ptr for least recently used cache entries
  41. */
  42. struct CacheEntry *prev;
  43. /**
  44. * The HELLO message
  45. */
  46. struct GNUNET_MessageHeader *hello;
  47. /**
  48. * The id of the peer this entry corresponds to
  49. */
  50. unsigned int peer_id;
  51. };
  52. /**
  53. * Hashmap to maintain cache
  54. */
  55. static struct GNUNET_CONTAINER_MultiHashMap32 *cache;
  56. /**
  57. * DLL head for least recently used cache entries; least recently used
  58. * cache items are at the head. The cache enties are added to this queue when
  59. * their demand becomes zero. They are removed from the queue when they are
  60. * needed by any operation.
  61. */
  62. static struct CacheEntry *cache_head;
  63. /**
  64. * DLL tail for least recently used cache entries; recently used cache
  65. * items are at the tail.The cache enties are added to this queue when
  66. * their demand becomes zero. They are removed from the queue when they are
  67. * needed by any operation.
  68. */
  69. static struct CacheEntry *cache_tail;
  70. /**
  71. * Maximum number of elements to cache
  72. */
  73. static unsigned int cache_size;
  74. /**
  75. * Looks up in the cache and returns the entry
  76. *
  77. * @param peer_id the peer identity of the peer whose corresponding entry has to
  78. * be looked up
  79. * @return the HELLO message; NULL if not found
  80. */
  81. static struct CacheEntry *
  82. cache_lookup (unsigned int peer_id)
  83. {
  84. struct CacheEntry *entry;
  85. GNUNET_assert (NULL != cache);
  86. entry = GNUNET_CONTAINER_multihashmap32_get (cache, peer_id);
  87. if (NULL == entry)
  88. return NULL;
  89. GNUNET_CONTAINER_DLL_remove (cache_head, cache_tail, entry);
  90. GNUNET_CONTAINER_DLL_insert_tail (cache_head, cache_tail, entry);
  91. return entry;
  92. }
  93. /**
  94. * Free the resources occupied by a cache entry
  95. *
  96. * @param entry the cache entry to free
  97. */
  98. static void
  99. free_entry (struct CacheEntry *entry)
  100. {
  101. GNUNET_CONTAINER_DLL_remove (cache_head, cache_tail, entry);
  102. GNUNET_free_non_null (entry->hello);
  103. GNUNET_free (entry);
  104. }
  105. /**
  106. * Creates a new cache entry and then puts it into the cache's hashtable.
  107. *
  108. * @param peer_id the index of the peer to tag the newly created entry
  109. * @return the newly created entry
  110. */
  111. static struct CacheEntry *
  112. add_entry (unsigned int peer_id)
  113. {
  114. struct CacheEntry *entry;
  115. GNUNET_assert (NULL != cache);
  116. if (cache_size == GNUNET_CONTAINER_multihashmap32_size (cache))
  117. {
  118. /* remove the LRU head */
  119. entry = cache_head;
  120. GNUNET_assert (GNUNET_OK ==
  121. GNUNET_CONTAINER_multihashmap32_remove (cache, (uint32_t)
  122. entry->peer_id,
  123. entry));
  124. free_entry (entry);
  125. }
  126. entry = GNUNET_new (struct CacheEntry);
  127. entry->peer_id = peer_id;
  128. GNUNET_assert (GNUNET_OK ==
  129. GNUNET_CONTAINER_multihashmap32_put (cache,
  130. (uint32_t) peer_id,
  131. entry,
  132. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
  133. GNUNET_CONTAINER_DLL_insert_tail (cache_head, cache_tail, entry);
  134. return entry;
  135. }
  136. /**
  137. * Iterator over hash map entries.
  138. *
  139. * @param cls closure
  140. * @param key current key
  141. * @param value value in the hash map
  142. * @return GNUNET_YES if we should continue to
  143. * iterate,
  144. * GNUNET_NO if not.
  145. */
  146. static int
  147. cache_clear_iterator (void *cls, uint32_t key, void *value)
  148. {
  149. struct CacheEntry *entry = value;
  150. GNUNET_assert (NULL != entry);
  151. GNUNET_assert (GNUNET_YES ==
  152. GNUNET_CONTAINER_multihashmap32_remove (cache, key, value));
  153. free_entry (entry);
  154. return GNUNET_YES;
  155. }
  156. /**
  157. * Clear cache
  158. */
  159. void
  160. GST_cache_clear ()
  161. {
  162. if (NULL != cache)
  163. {
  164. GNUNET_CONTAINER_multihashmap32_iterate (cache, &cache_clear_iterator, NULL);
  165. GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (cache));
  166. GNUNET_CONTAINER_multihashmap32_destroy (cache);
  167. cache = NULL;
  168. }
  169. cache_size = 0;
  170. cache_head = NULL;
  171. cache_tail = NULL;
  172. }
  173. /**
  174. * Initializes the cache
  175. *
  176. * @param size the size of the cache
  177. */
  178. void
  179. GST_cache_init (unsigned int size)
  180. {
  181. if (0 == size)
  182. return;
  183. cache_size = size;
  184. cache = GNUNET_CONTAINER_multihashmap32_create (cache_size);
  185. }
  186. /**
  187. * Looks up in the hello cache and returns the HELLO of the given peer
  188. *
  189. * @param peer_id the index of the peer whose HELLO has to be looked up
  190. * @return the HELLO message; NULL if not found
  191. */
  192. const struct GNUNET_MessageHeader *
  193. GST_cache_lookup_hello (const unsigned int peer_id)
  194. {
  195. struct CacheEntry *entry;
  196. LOG_DEBUG ("Looking up HELLO for peer %u\n", peer_id);
  197. if (NULL == cache)
  198. {
  199. LOG_DEBUG ("Caching disabled\n");
  200. return NULL;
  201. }
  202. entry = cache_lookup (peer_id);
  203. if (NULL == entry)
  204. return NULL;
  205. if (NULL != entry->hello)
  206. LOG_DEBUG ("HELLO found for peer %u\n", peer_id);
  207. return entry->hello;
  208. }
  209. /**
  210. * Caches the HELLO of the given peer. Updates the HELLO if it was already
  211. * cached before
  212. *
  213. * @param peer_id the peer identity of the peer whose HELLO has to be cached
  214. * @param hello the HELLO message
  215. */
  216. void
  217. GST_cache_add_hello (const unsigned int peer_id,
  218. const struct GNUNET_MessageHeader *hello)
  219. {
  220. struct CacheEntry *entry;
  221. if (NULL == cache)
  222. return;
  223. entry = cache_lookup (peer_id);
  224. if (NULL == entry)
  225. entry = add_entry (peer_id);
  226. GNUNET_free_non_null (entry->hello);
  227. entry->hello = GNUNET_copy_message (hello);
  228. }
  229. /* end of gnunet-service-testbed_hc.c */