container_multipeermap.c 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2008, 2012 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 util/container_multipeermap.c
  18. * @brief hash map where the same key may be present multiple times
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "gnunet_util_lib.h"
  23. #define LOG(kind, ...) \
  24. GNUNET_log_from (kind, "util-container-multipeermap", __VA_ARGS__)
  25. /**
  26. * Maximum recursion depth for callbacks of
  27. * #GNUNET_CONTAINER_multihashmap_get_multiple() themselve s
  28. * again calling #GNUNET_CONTAINER_multihashmap_get_multiple().
  29. * Should be totally excessive, but if violated we die.
  30. */
  31. #define NEXT_CACHE_SIZE 16
  32. /**
  33. * An entry in the hash map with the full key.
  34. */
  35. struct BigMapEntry
  36. {
  37. /**
  38. * Value of the entry.
  39. */
  40. void *value;
  41. /**
  42. * If there is a hash collision, we create a linked list.
  43. */
  44. struct BigMapEntry *next;
  45. /**
  46. * Key for the entry.
  47. */
  48. struct GNUNET_PeerIdentity key;
  49. };
  50. /**
  51. * An entry in the hash map with just a pointer to the key.
  52. */
  53. struct SmallMapEntry
  54. {
  55. /**
  56. * Value of the entry.
  57. */
  58. void *value;
  59. /**
  60. * If there is a hash collision, we create a linked list.
  61. */
  62. struct SmallMapEntry *next;
  63. /**
  64. * Key for the entry.
  65. */
  66. const struct GNUNET_PeerIdentity *key;
  67. };
  68. /**
  69. * Entry in the map.
  70. */
  71. union MapEntry
  72. {
  73. /**
  74. * Variant used if map entries only contain a pointer to the key.
  75. */
  76. struct SmallMapEntry *sme;
  77. /**
  78. * Variant used if map entries contain the full key.
  79. */
  80. struct BigMapEntry *bme;
  81. };
  82. /**
  83. * Internal representation of the hash map.
  84. */
  85. struct GNUNET_CONTAINER_MultiPeerMap
  86. {
  87. /**
  88. * All of our buckets.
  89. */
  90. union MapEntry *map;
  91. /**
  92. * Number of entries in the map.
  93. */
  94. unsigned int size;
  95. /**
  96. * Length of the "map" array.
  97. */
  98. unsigned int map_length;
  99. /**
  100. * #GNUNET_NO if the map entries are of type 'struct BigMapEntry',
  101. * #GNUNET_YES if the map entries are of type 'struct SmallMapEntry'.
  102. */
  103. int use_small_entries;
  104. /**
  105. * Counts the destructive modifications (grow, remove)
  106. * to the map, so that iterators can check if they are still valid.
  107. */
  108. unsigned int modification_counter;
  109. /**
  110. * Map entries indicating iteration positions currently
  111. * in use by #GNUNET_CONTAINER_multihashmap_get_multiple().
  112. * Only used up to @e next_cache_off.
  113. */
  114. union MapEntry next_cache[NEXT_CACHE_SIZE];
  115. /**
  116. * Offset of @e next_cache entries in use, must be smaller
  117. * than #NEXT_CACHE_SIZE.
  118. */
  119. unsigned int next_cache_off;
  120. };
  121. /**
  122. * Cursor into a multipeermap.
  123. * Allows to enumerate elements asynchronously.
  124. */
  125. struct GNUNET_CONTAINER_MultiPeerMapIterator
  126. {
  127. /**
  128. * Position in the bucket 'idx'
  129. */
  130. union MapEntry me;
  131. /**
  132. * Current bucket index.
  133. */
  134. unsigned int idx;
  135. /**
  136. * Modification counter as observed on the map when the iterator
  137. * was created.
  138. */
  139. unsigned int modification_counter;
  140. /**
  141. * Map that we are iterating over.
  142. */
  143. const struct GNUNET_CONTAINER_MultiPeerMap *map;
  144. };
  145. /**
  146. * Create a multi hash map.
  147. *
  148. * @param len initial size (map will grow as needed)
  149. * @param do_not_copy_keys GNUNET_NO is always safe and should be used by default;
  150. * GNUNET_YES means that on 'put', the 'key' does not have
  151. * to be copied as the destination of the pointer is
  152. * guaranteed to be life as long as the value is stored in
  153. * the hashmap. This can significantly reduce memory
  154. * consumption, but of course is also a recipie for
  155. * heap corruption if the assumption is not true. Only
  156. * use this if (1) memory use is important in this case and
  157. * (2) you have triple-checked that the invariant holds
  158. * @return NULL on error
  159. */
  160. struct GNUNET_CONTAINER_MultiPeerMap *
  161. GNUNET_CONTAINER_multipeermap_create (unsigned int len, int do_not_copy_keys)
  162. {
  163. struct GNUNET_CONTAINER_MultiPeerMap *map;
  164. GNUNET_assert (len > 0);
  165. map = GNUNET_new (struct GNUNET_CONTAINER_MultiPeerMap);
  166. map->map = GNUNET_malloc_large (len * sizeof(union MapEntry));
  167. if (NULL == map->map)
  168. {
  169. GNUNET_free (map);
  170. return NULL;
  171. }
  172. map->map_length = len;
  173. map->use_small_entries = do_not_copy_keys;
  174. return map;
  175. }
  176. /**
  177. * Destroy a hash map. Will not free any values
  178. * stored in the hash map!
  179. *
  180. * @param map the map
  181. */
  182. void
  183. GNUNET_CONTAINER_multipeermap_destroy (
  184. struct GNUNET_CONTAINER_MultiPeerMap *map)
  185. {
  186. GNUNET_assert (0 == map->next_cache_off);
  187. for (unsigned int i = 0; i < map->map_length; i++)
  188. {
  189. union MapEntry me;
  190. me = map->map[i];
  191. if (map->use_small_entries)
  192. {
  193. struct SmallMapEntry *sme;
  194. struct SmallMapEntry *nxt;
  195. nxt = me.sme;
  196. while (NULL != (sme = nxt))
  197. {
  198. nxt = sme->next;
  199. GNUNET_free (sme);
  200. }
  201. me.sme = NULL;
  202. }
  203. else
  204. {
  205. struct BigMapEntry *bme;
  206. struct BigMapEntry *nxt;
  207. nxt = me.bme;
  208. while (NULL != (bme = nxt))
  209. {
  210. nxt = bme->next;
  211. GNUNET_free (bme);
  212. }
  213. me.bme = NULL;
  214. }
  215. }
  216. GNUNET_free (map->map);
  217. GNUNET_free (map);
  218. }
  219. /**
  220. * Compute the index of the bucket for the given key.
  221. *
  222. * @param map hash map for which to compute the index
  223. * @param key what key should the index be computed for
  224. * @return offset into the "map" array of "map"
  225. */
  226. static unsigned int
  227. idx_of (const struct GNUNET_CONTAINER_MultiPeerMap *map,
  228. const struct GNUNET_PeerIdentity *key)
  229. {
  230. unsigned int kx;
  231. GNUNET_assert (NULL != map);
  232. GNUNET_memcpy (&kx, key, sizeof(kx));
  233. return kx % map->map_length;
  234. }
  235. /**
  236. * Get the number of key-value pairs in the map.
  237. *
  238. * @param map the map
  239. * @return the number of key value pairs
  240. */
  241. unsigned int
  242. GNUNET_CONTAINER_multipeermap_size (
  243. const struct GNUNET_CONTAINER_MultiPeerMap *map)
  244. {
  245. return map->size;
  246. }
  247. /**
  248. * Given a key find a value in the map matching the key.
  249. *
  250. * @param map the map
  251. * @param key what to look for
  252. * @return NULL if no value was found; note that
  253. * this is indistinguishable from values that just
  254. * happen to be NULL; use "contains" to test for
  255. * key-value pairs with value NULL
  256. */
  257. void *
  258. GNUNET_CONTAINER_multipeermap_get (
  259. const struct GNUNET_CONTAINER_MultiPeerMap *map,
  260. const struct GNUNET_PeerIdentity *key)
  261. {
  262. union MapEntry me;
  263. me = map->map[idx_of (map, key)];
  264. if (map->use_small_entries)
  265. {
  266. for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
  267. if (0 == GNUNET_memcmp (key, sme->key))
  268. return sme->value;
  269. }
  270. else
  271. {
  272. for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
  273. if (0 == GNUNET_memcmp (key, &bme->key))
  274. return bme->value;
  275. }
  276. return NULL;
  277. }
  278. /**
  279. * Iterate over all entries in the map.
  280. *
  281. * @param map the map
  282. * @param it function to call on each entry
  283. * @param it_cls extra argument to @a it
  284. * @return the number of key value pairs processed,
  285. * #GNUNET_SYSERR if it aborted iteration
  286. */
  287. int
  288. GNUNET_CONTAINER_multipeermap_iterate (
  289. struct GNUNET_CONTAINER_MultiPeerMap *map,
  290. GNUNET_CONTAINER_PeerMapIterator it,
  291. void *it_cls)
  292. {
  293. int count;
  294. union MapEntry me;
  295. union MapEntry *ce;
  296. struct GNUNET_PeerIdentity kc;
  297. count = 0;
  298. GNUNET_assert (NULL != map);
  299. ce = &map->next_cache[map->next_cache_off];
  300. GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE);
  301. for (unsigned int i = 0; i < map->map_length; i++)
  302. {
  303. me = map->map[i];
  304. if (map->use_small_entries)
  305. {
  306. struct SmallMapEntry *sme;
  307. ce->sme = me.sme;
  308. while (NULL != (sme = ce->sme))
  309. {
  310. ce->sme = sme->next;
  311. if (NULL != it)
  312. {
  313. if (GNUNET_OK != it (it_cls, sme->key, sme->value))
  314. {
  315. GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
  316. return GNUNET_SYSERR;
  317. }
  318. }
  319. count++;
  320. }
  321. }
  322. else
  323. {
  324. struct BigMapEntry *bme;
  325. ce->bme = me.bme;
  326. while (NULL != (bme = ce->bme))
  327. {
  328. ce->bme = bme->next;
  329. if (NULL != it)
  330. {
  331. kc = bme->key;
  332. if (GNUNET_OK != it (it_cls, &kc, bme->value))
  333. {
  334. GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
  335. return GNUNET_SYSERR;
  336. }
  337. }
  338. count++;
  339. }
  340. }
  341. }
  342. GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
  343. return count;
  344. }
  345. /**
  346. * We are about to free() the @a bme, make sure it is not in
  347. * the list of next values for any iterator in the @a map's next_cache.
  348. *
  349. * @param map the map to check
  350. * @param bme the entry that is about to be free'd
  351. */
  352. static void
  353. update_next_cache_bme (struct GNUNET_CONTAINER_MultiPeerMap *map,
  354. const struct BigMapEntry *bme)
  355. {
  356. for (unsigned int i = 0; i < map->next_cache_off; i++)
  357. if (map->next_cache[i].bme == bme)
  358. map->next_cache[i].bme = bme->next;
  359. }
  360. /**
  361. * We are about to free() the @a sme, make sure it is not in
  362. * the list of next values for any iterator in the @a map's next_cache.
  363. *
  364. * @param map the map to check
  365. * @param sme the entry that is about to be free'd
  366. */
  367. static void
  368. update_next_cache_sme (struct GNUNET_CONTAINER_MultiPeerMap *map,
  369. const struct SmallMapEntry *sme)
  370. {
  371. for (unsigned int i = 0; i < map->next_cache_off; i++)
  372. if (map->next_cache[i].sme == sme)
  373. map->next_cache[i].sme = sme->next;
  374. }
  375. /**
  376. * Remove the given key-value pair from the map. Note that if the
  377. * key-value pair is in the map multiple times, only one of the pairs
  378. * will be removed.
  379. *
  380. * @param map the map
  381. * @param key key of the key-value pair
  382. * @param value value of the key-value pair
  383. * @return #GNUNET_YES on success, #GNUNET_NO if the key-value pair
  384. * is not in the map
  385. */
  386. int
  387. GNUNET_CONTAINER_multipeermap_remove (struct GNUNET_CONTAINER_MultiPeerMap *map,
  388. const struct GNUNET_PeerIdentity *key,
  389. const void *value)
  390. {
  391. union MapEntry me;
  392. unsigned int i;
  393. map->modification_counter++;
  394. i = idx_of (map, key);
  395. me = map->map[i];
  396. if (map->use_small_entries)
  397. {
  398. struct SmallMapEntry *p = NULL;
  399. for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
  400. {
  401. if ((0 == GNUNET_memcmp (key, sme->key)) && (value == sme->value))
  402. {
  403. if (NULL == p)
  404. map->map[i].sme = sme->next;
  405. else
  406. p->next = sme->next;
  407. update_next_cache_sme (map, sme);
  408. GNUNET_free (sme);
  409. map->size--;
  410. return GNUNET_YES;
  411. }
  412. p = sme;
  413. }
  414. }
  415. else
  416. {
  417. struct BigMapEntry *p = NULL;
  418. for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
  419. {
  420. if ((0 == GNUNET_memcmp (key, &bme->key)) && (value == bme->value))
  421. {
  422. if (NULL == p)
  423. map->map[i].bme = bme->next;
  424. else
  425. p->next = bme->next;
  426. update_next_cache_bme (map, bme);
  427. GNUNET_free (bme);
  428. map->size--;
  429. return GNUNET_YES;
  430. }
  431. p = bme;
  432. }
  433. }
  434. return GNUNET_NO;
  435. }
  436. /**
  437. * Remove all entries for the given key from the map.
  438. * Note that the values would not be "freed".
  439. *
  440. * @param map the map
  441. * @param key identifies values to be removed
  442. * @return number of values removed
  443. */
  444. int
  445. GNUNET_CONTAINER_multipeermap_remove_all (
  446. struct GNUNET_CONTAINER_MultiPeerMap *map,
  447. const struct GNUNET_PeerIdentity *key)
  448. {
  449. union MapEntry me;
  450. unsigned int i;
  451. int ret;
  452. map->modification_counter++;
  453. ret = 0;
  454. i = idx_of (map, key);
  455. me = map->map[i];
  456. if (map->use_small_entries)
  457. {
  458. struct SmallMapEntry *sme;
  459. struct SmallMapEntry *p;
  460. p = NULL;
  461. sme = me.sme;
  462. while (NULL != sme)
  463. {
  464. if (0 == GNUNET_memcmp (key, sme->key))
  465. {
  466. if (NULL == p)
  467. map->map[i].sme = sme->next;
  468. else
  469. p->next = sme->next;
  470. update_next_cache_sme (map, sme);
  471. GNUNET_free (sme);
  472. map->size--;
  473. if (NULL == p)
  474. sme = map->map[i].sme;
  475. else
  476. sme = p->next;
  477. ret++;
  478. }
  479. else
  480. {
  481. p = sme;
  482. sme = sme->next;
  483. }
  484. }
  485. }
  486. else
  487. {
  488. struct BigMapEntry *bme;
  489. struct BigMapEntry *p;
  490. p = NULL;
  491. bme = me.bme;
  492. while (NULL != bme)
  493. {
  494. if (0 == GNUNET_memcmp (key, &bme->key))
  495. {
  496. if (NULL == p)
  497. map->map[i].bme = bme->next;
  498. else
  499. p->next = bme->next;
  500. update_next_cache_bme (map, bme);
  501. GNUNET_free (bme);
  502. map->size--;
  503. if (NULL == p)
  504. bme = map->map[i].bme;
  505. else
  506. bme = p->next;
  507. ret++;
  508. }
  509. else
  510. {
  511. p = bme;
  512. bme = bme->next;
  513. }
  514. }
  515. }
  516. return ret;
  517. }
  518. /**
  519. * Check if the map contains any value under the given
  520. * key (including values that are NULL).
  521. *
  522. * @param map the map
  523. * @param key the key to test if a value exists for it
  524. * @return #GNUNET_YES if such a value exists,
  525. * #GNUNET_NO if not
  526. */
  527. int
  528. GNUNET_CONTAINER_multipeermap_contains (
  529. const struct GNUNET_CONTAINER_MultiPeerMap *map,
  530. const struct GNUNET_PeerIdentity *key)
  531. {
  532. union MapEntry me;
  533. me = map->map[idx_of (map, key)];
  534. if (map->use_small_entries)
  535. {
  536. for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
  537. if (0 == GNUNET_memcmp (key, sme->key))
  538. return GNUNET_YES;
  539. }
  540. else
  541. {
  542. for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
  543. if (0 == GNUNET_memcmp (key, &bme->key))
  544. return GNUNET_YES;
  545. }
  546. return GNUNET_NO;
  547. }
  548. /**
  549. * Check if the map contains the given value under the given
  550. * key.
  551. *
  552. * @param map the map
  553. * @param key the key to test if a value exists for it
  554. * @param value value to test for
  555. * @return #GNUNET_YES if such a value exists,
  556. * #GNUNET_NO if not
  557. */
  558. int
  559. GNUNET_CONTAINER_multipeermap_contains_value (
  560. const struct GNUNET_CONTAINER_MultiPeerMap *map,
  561. const struct GNUNET_PeerIdentity *key,
  562. const void *value)
  563. {
  564. union MapEntry me;
  565. me = map->map[idx_of (map, key)];
  566. if (map->use_small_entries)
  567. {
  568. for (struct SmallMapEntry *sme = me.sme; NULL != sme; sme = sme->next)
  569. if ((0 == GNUNET_memcmp (key, sme->key)) && (sme->value == value))
  570. return GNUNET_YES;
  571. }
  572. else
  573. {
  574. for (struct BigMapEntry *bme = me.bme; NULL != bme; bme = bme->next)
  575. if ((0 == GNUNET_memcmp (key, &bme->key)) && (bme->value == value))
  576. return GNUNET_YES;
  577. }
  578. return GNUNET_NO;
  579. }
  580. /**
  581. * Grow the given map to a more appropriate size.
  582. *
  583. * @param map the hash map to grow
  584. */
  585. static void
  586. grow (struct GNUNET_CONTAINER_MultiPeerMap *map)
  587. {
  588. union MapEntry *old_map;
  589. union MapEntry *new_map;
  590. unsigned int old_len;
  591. unsigned int new_len;
  592. unsigned int idx;
  593. old_map = map->map;
  594. old_len = map->map_length;
  595. GNUNET_assert (0 != old_len);
  596. new_len = old_len * 2;
  597. if (0 == new_len) /* 2^31 * 2 == 0 */
  598. new_len = old_len; /* never use 0 */
  599. if (new_len == old_len)
  600. return; /* nothing changed */
  601. new_map = GNUNET_malloc_large (new_len * sizeof(union MapEntry));
  602. if (NULL == new_map)
  603. return; /* grow not possible */
  604. map->modification_counter++;
  605. map->map_length = new_len;
  606. map->map = new_map;
  607. for (unsigned int i = 0; i < old_len; i++)
  608. {
  609. if (map->use_small_entries)
  610. {
  611. struct SmallMapEntry *sme;
  612. while (NULL != (sme = old_map[i].sme))
  613. {
  614. old_map[i].sme = sme->next;
  615. idx = idx_of (map, sme->key);
  616. sme->next = new_map[idx].sme;
  617. new_map[idx].sme = sme;
  618. }
  619. }
  620. else
  621. {
  622. struct BigMapEntry *bme;
  623. while (NULL != (bme = old_map[i].bme))
  624. {
  625. old_map[i].bme = bme->next;
  626. idx = idx_of (map, &bme->key);
  627. bme->next = new_map[idx].bme;
  628. new_map[idx].bme = bme;
  629. }
  630. }
  631. }
  632. GNUNET_free (old_map);
  633. }
  634. /**
  635. * Store a key-value pair in the map.
  636. *
  637. * @param map the map
  638. * @param key key to use
  639. * @param value value to use
  640. * @param opt options for put
  641. * @return #GNUNET_OK on success,
  642. * #GNUNET_NO if a value was replaced (with REPLACE)
  643. * #GNUNET_SYSERR if #GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY was the option and the
  644. * value already exists
  645. */
  646. int
  647. GNUNET_CONTAINER_multipeermap_put (struct GNUNET_CONTAINER_MultiPeerMap *map,
  648. const struct GNUNET_PeerIdentity *key,
  649. void *value,
  650. enum GNUNET_CONTAINER_MultiHashMapOption opt)
  651. {
  652. union MapEntry me;
  653. unsigned int i;
  654. i = idx_of (map, key);
  655. if ((opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE) &&
  656. (opt != GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
  657. {
  658. me = map->map[i];
  659. if (map->use_small_entries)
  660. {
  661. struct SmallMapEntry *sme;
  662. for (sme = me.sme; NULL != sme; sme = sme->next)
  663. if (0 == GNUNET_memcmp (key, sme->key))
  664. {
  665. if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
  666. return GNUNET_SYSERR;
  667. sme->value = value;
  668. return GNUNET_NO;
  669. }
  670. }
  671. else
  672. {
  673. struct BigMapEntry *bme;
  674. for (bme = me.bme; NULL != bme; bme = bme->next)
  675. if (0 == GNUNET_memcmp (key, &bme->key))
  676. {
  677. if (opt == GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)
  678. return GNUNET_SYSERR;
  679. bme->value = value;
  680. return GNUNET_NO;
  681. }
  682. }
  683. }
  684. if (map->size / 3 >= map->map_length / 4)
  685. {
  686. grow (map);
  687. i = idx_of (map, key);
  688. }
  689. if (map->use_small_entries)
  690. {
  691. struct SmallMapEntry *sme;
  692. sme = GNUNET_new (struct SmallMapEntry);
  693. sme->key = key;
  694. sme->value = value;
  695. sme->next = map->map[i].sme;
  696. map->map[i].sme = sme;
  697. }
  698. else
  699. {
  700. struct BigMapEntry *bme;
  701. bme = GNUNET_new (struct BigMapEntry);
  702. bme->key = *key;
  703. bme->value = value;
  704. bme->next = map->map[i].bme;
  705. map->map[i].bme = bme;
  706. }
  707. map->size++;
  708. return GNUNET_OK;
  709. }
  710. /**
  711. * Iterate over all entries in the map that match a particular key.
  712. *
  713. * @param map the map
  714. * @param key key that the entries must correspond to
  715. * @param it function to call on each entry
  716. * @param it_cls extra argument to @a it
  717. * @return the number of key value pairs processed,
  718. * #GNUNET_SYSERR if it aborted iteration
  719. */
  720. int
  721. GNUNET_CONTAINER_multipeermap_get_multiple (
  722. struct GNUNET_CONTAINER_MultiPeerMap *map,
  723. const struct GNUNET_PeerIdentity *key,
  724. GNUNET_CONTAINER_PeerMapIterator it,
  725. void *it_cls)
  726. {
  727. int count;
  728. union MapEntry me;
  729. union MapEntry *ce;
  730. ce = &map->next_cache[map->next_cache_off];
  731. GNUNET_assert (++map->next_cache_off < NEXT_CACHE_SIZE);
  732. count = 0;
  733. me = map->map[idx_of (map, key)];
  734. if (map->use_small_entries)
  735. {
  736. struct SmallMapEntry *sme;
  737. ce->sme = me.sme;
  738. while (NULL != (sme = ce->sme))
  739. {
  740. ce->sme = sme->next;
  741. if (0 != GNUNET_memcmp (key, sme->key))
  742. continue;
  743. if ((NULL != it) && (GNUNET_OK != it (it_cls, key, sme->value)))
  744. {
  745. GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
  746. return GNUNET_SYSERR;
  747. }
  748. count++;
  749. }
  750. }
  751. else
  752. {
  753. struct BigMapEntry *bme;
  754. ce->bme = me.bme;
  755. while (NULL != (bme = ce->bme))
  756. {
  757. ce->bme = bme->next;
  758. if (0 != GNUNET_memcmp (key, &bme->key))
  759. continue;
  760. if ((NULL != it) && (GNUNET_OK != it (it_cls, key, bme->value)))
  761. {
  762. GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
  763. return GNUNET_SYSERR;
  764. }
  765. count++;
  766. }
  767. }
  768. GNUNET_assert (--map->next_cache_off < NEXT_CACHE_SIZE);
  769. return count;
  770. }
  771. /**
  772. * @ingroup hashmap
  773. * Call @a it on a random value from the map, or not at all
  774. * if the map is empty. Note that this function has linear
  775. * complexity (in the size of the map).
  776. *
  777. * @param map the map
  778. * @param it function to call on a random entry
  779. * @param it_cls extra argument to @a it
  780. * @return the number of key value pairs processed, zero or one.
  781. */
  782. unsigned int
  783. GNUNET_CONTAINER_multipeermap_get_random (
  784. const struct GNUNET_CONTAINER_MultiPeerMap *map,
  785. GNUNET_CONTAINER_PeerMapIterator it,
  786. void *it_cls)
  787. {
  788. unsigned int off;
  789. union MapEntry me;
  790. if (0 == map->size)
  791. return 0;
  792. if (NULL == it)
  793. return 1;
  794. off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, map->size);
  795. for (unsigned int idx = 0; idx < map->map_length; idx++)
  796. {
  797. me = map->map[idx];
  798. if (map->use_small_entries)
  799. {
  800. struct SmallMapEntry *sme;
  801. struct SmallMapEntry *nxt;
  802. nxt = me.sme;
  803. while (NULL != (sme = nxt))
  804. {
  805. nxt = sme->next;
  806. if (0 == off)
  807. {
  808. if (GNUNET_OK != it (it_cls, sme->key, sme->value))
  809. return GNUNET_SYSERR;
  810. return 1;
  811. }
  812. off--;
  813. }
  814. }
  815. else
  816. {
  817. struct BigMapEntry *bme;
  818. struct BigMapEntry *nxt;
  819. nxt = me.bme;
  820. while (NULL != (bme = nxt))
  821. {
  822. nxt = bme->next;
  823. if (0 == off)
  824. {
  825. if (GNUNET_OK != it (it_cls, &bme->key, bme->value))
  826. return GNUNET_SYSERR;
  827. return 1;
  828. }
  829. off--;
  830. }
  831. }
  832. }
  833. GNUNET_break (0);
  834. return GNUNET_SYSERR;
  835. }
  836. /**
  837. * Create an iterator for a multipeermap.
  838. * The iterator can be used to retrieve all the elements in the multipeermap
  839. * one by one, without having to handle all elements at once (in contrast to
  840. * #GNUNET_CONTAINER_multipeermap_iterate). Note that the iterator can not be
  841. * used anymore if elements have been removed from 'map' after the creation of
  842. * the iterator, or 'map' has been destroyed. Adding elements to 'map' may
  843. * result in skipped or repeated elements.
  844. *
  845. * @param map the map to create an iterator for
  846. * @return an iterator over the given multipeermap 'map'
  847. */
  848. struct GNUNET_CONTAINER_MultiPeerMapIterator *
  849. GNUNET_CONTAINER_multipeermap_iterator_create (
  850. const struct GNUNET_CONTAINER_MultiPeerMap *map)
  851. {
  852. struct GNUNET_CONTAINER_MultiPeerMapIterator *iter;
  853. iter = GNUNET_new (struct GNUNET_CONTAINER_MultiPeerMapIterator);
  854. iter->map = map;
  855. iter->modification_counter = map->modification_counter;
  856. iter->me = map->map[0];
  857. return iter;
  858. }
  859. /**
  860. * Retrieve the next element from the hash map at the iterator's position.
  861. * If there are no elements left, GNUNET_NO is returned, and 'key' and 'value'
  862. * are not modified.
  863. * This operation is only allowed if no elements have been removed from the
  864. * multipeermap since the creation of 'iter', and the map has not been destroyed.
  865. * Adding elements may result in repeating or skipping elements.
  866. *
  867. * @param iter the iterator to get the next element from
  868. * @param key pointer to store the key in, can be NULL
  869. * @param value pointer to store the value in, can be NULL
  870. * @return #GNUNET_YES we returned an element,
  871. * #GNUNET_NO if we are out of elements
  872. */
  873. int
  874. GNUNET_CONTAINER_multipeermap_iterator_next (
  875. struct GNUNET_CONTAINER_MultiPeerMapIterator *iter,
  876. struct GNUNET_PeerIdentity *key,
  877. const void **value)
  878. {
  879. /* make sure the map has not been modified */
  880. GNUNET_assert (iter->modification_counter == iter->map->modification_counter);
  881. /* look for the next entry, skipping empty buckets */
  882. while (1)
  883. {
  884. if (iter->idx >= iter->map->map_length)
  885. return GNUNET_NO;
  886. if (GNUNET_YES == iter->map->use_small_entries)
  887. {
  888. if (NULL != iter->me.sme)
  889. {
  890. if (NULL != key)
  891. *key = *iter->me.sme->key;
  892. if (NULL != value)
  893. *value = iter->me.sme->value;
  894. iter->me.sme = iter->me.sme->next;
  895. return GNUNET_YES;
  896. }
  897. }
  898. else
  899. {
  900. if (NULL != iter->me.bme)
  901. {
  902. if (NULL != key)
  903. *key = iter->me.bme->key;
  904. if (NULL != value)
  905. *value = iter->me.bme->value;
  906. iter->me.bme = iter->me.bme->next;
  907. return GNUNET_YES;
  908. }
  909. }
  910. iter->idx += 1;
  911. if (iter->idx < iter->map->map_length)
  912. iter->me = iter->map->map[iter->idx];
  913. }
  914. }
  915. /**
  916. * Destroy a multipeermap iterator.
  917. *
  918. * @param iter the iterator to destroy
  919. */
  920. void
  921. GNUNET_CONTAINER_multipeermap_iterator_destroy (
  922. struct GNUNET_CONTAINER_MultiPeerMapIterator *iter)
  923. {
  924. GNUNET_free (iter);
  925. }
  926. /* end of container_multipeermap.c */