dictionary.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #ifndef NETDATA_DICTIONARY_H
  3. #define NETDATA_DICTIONARY_H 1
  4. #include "../libnetdata.h"
  5. /*
  6. * Netdata DICTIONARY features:
  7. *
  8. * CLONE or LINK
  9. * Names and Values in the dictionary can be cloned or linked.
  10. * In clone mode, the dictionary does all the memory management.
  11. * The default is clone for both names and values.
  12. * Set DICTIONARY_FLAG_NAME_LINK_DONT_CLONE to link names.
  13. * Set DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE to link names.
  14. *
  15. * ORDERED
  16. * Items are ordered in the order they are added (new items are appended at the end).
  17. * You may reverse the order by setting the flag DICTIONARY_FLAG_ADD_IN_FRONT.
  18. *
  19. * LOOKUP
  20. * The dictionary uses JudyHS to maintain a very fast randomly accessible hash table.
  21. *
  22. * MULTI-THREADED and SINGLE-THREADED
  23. * Each dictionary may be single threaded (no locks), or multi-threaded (multiple readers or one writer).
  24. * The default is multi-threaded. Add the flag DICTIONARY_FLAG_SINGLE_THREADED for single-threaded.
  25. *
  26. * WALK-THROUGH and FOREACH traversal
  27. * The dictionary can be traversed on read or write mode, either with a callback (walkthrough) or with
  28. * a loop (foreach).
  29. *
  30. * In write mode traversal, the caller may delete only the current item, but may add as many items as needed.
  31. *
  32. */
  33. typedef struct dictionary DICTIONARY;
  34. typedef struct dictionary_item DICTIONARY_ITEM;
  35. typedef enum dictionary_flags {
  36. DICTIONARY_FLAG_NONE = 0, // the default is the opposite of all below
  37. DICTIONARY_FLAG_SINGLE_THREADED = (1 << 0), // don't use any locks (default: use locks)
  38. DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE = (1 << 1), // don't copy the value, just point to the one provided (default: copy)
  39. DICTIONARY_FLAG_NAME_LINK_DONT_CLONE = (1 << 2), // don't copy the name, just point to the one provided (default: copy)
  40. DICTIONARY_FLAG_DONT_OVERWRITE_VALUE = (1 << 3), // don't overwrite values of dictionary items (default: overwrite)
  41. DICTIONARY_FLAG_ADD_IN_FRONT = (1 << 4), // add dictionary items at the front of the linked list (default: at the end)
  42. // to change the value of the following, you also need to change the corresponding #defines in dictionary.c
  43. DICTIONARY_FLAG_RESERVED1 = (1 << 29), // reserved for DICTIONARY_FLAG_EXCLUSIVE_ACCESS
  44. DICTIONARY_FLAG_RESERVED2 = (1 << 30), // reserved for DICTIONARY_FLAG_DESTROYED
  45. DICTIONARY_FLAG_RESERVED3 = (1 << 31), // reserved for DICTIONARY_FLAG_DEFER_ALL_DELETIONS
  46. } DICTIONARY_FLAGS;
  47. // Create a dictionary
  48. #ifdef NETDATA_INTERNAL_CHECKS
  49. #define dictionary_create(flags) dictionary_create_advanced_with_trace(flags, 0, __FUNCTION__, __LINE__, __FILE__);
  50. #define dictionary_create_advanced(flags) dictionary_create_advanced_with_trace(flags, 0, __FUNCTION__, __LINE__, __FILE__);
  51. extern DICTIONARY *dictionary_create_advanced_with_trace(DICTIONARY_FLAGS flags, size_t scratchpad_size, const char *function, size_t line, const char *file);
  52. #else
  53. #define dictionary_create(flags) dictionary_create_advanced(flags, 0);
  54. extern DICTIONARY *dictionary_create_advanced(DICTIONARY_FLAGS flags, size_t scratchpad_size);
  55. #endif
  56. extern void *dictionary_scratchpad(DICTIONARY *dict);
  57. // an insert callback to be called just after an item is added to the dictionary
  58. // this callback is called while the dictionary is write locked!
  59. extern void dictionary_register_insert_callback(DICTIONARY *dict, void (*ins_callback)(const char *name, void *value, void *data), void *data);
  60. // a delete callback to be called just before an item is deleted forever
  61. // this callback is called while the dictionary is write locked!
  62. extern void dictionary_register_delete_callback(DICTIONARY *dict, void (*del_callback)(const char *name, void *value, void *data), void *data);
  63. // a merge callback to be called when DICTIONARY_FLAG_DONT_OVERWRITE_VALUE
  64. // and an item is already found in the dictionary - the dictionary does nothing else in this case
  65. // the old_value will remain in the dictionary - the new_value is ignored
  66. extern void dictionary_register_conflict_callback(DICTIONARY *dict, void (*conflict_callback)(const char *name, void *old_value, void *new_value, void *data), void *data);
  67. // a reaction callback to be called after every item insertion or conflict
  68. // after the constructors have finished and the items are fully available for use
  69. // and the dictionary is not write locked anymore
  70. extern void dictionary_register_react_callback(DICTIONARY *dict, void (*react_callback)(const char *name, void *value, void *data), void *data);
  71. // Destroy a dictionary
  72. // returns the number of bytes freed
  73. // the returned value will not include name and value sizes if DICTIONARY_FLAG_WITH_STATISTICS is not set
  74. extern size_t dictionary_destroy(DICTIONARY *dict);
  75. // Set an item in the dictionary
  76. // - if an item with the same name does not exist, create one
  77. // - if an item with the same name exists, then:
  78. // a) if DICTIONARY_FLAG_DONT_OVERWRITE_VALUE is set, just return the existing value (ignore the new value)
  79. // else b) reset the value to the new value passed at the call
  80. //
  81. // When DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE is set, the value is linked, otherwise it is copied
  82. // When DICTIONARY_FLAG_NAME_LINK_DONT_CLONE is set, the name is linked, otherwise it is copied
  83. //
  84. // When neither DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE nor DICTIONARY_FLAG_NAME_LINK_DONT_CLONE are set, all the
  85. // memory management for names and values is done by the dictionary.
  86. //
  87. // Passing NULL as value, the dictionary will callocz() the newly allocated value, otherwise it will copy it.
  88. // Passing 0 as value_len, the dictionary will set the value to NULL (no allocations for value will be made).
  89. extern void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t value_len);
  90. // Get an item from the dictionary
  91. // If it returns NULL, the item is not found
  92. extern void *dictionary_get(DICTIONARY *dict, const char *name);
  93. // Delete an item from the dictionary
  94. // returns 0 if the item was found and has been deleted
  95. // returns -1 if the item was not found in the index
  96. extern int dictionary_del(DICTIONARY *dict, const char *name);
  97. extern DICTIONARY_ITEM *dictionary_get_and_acquire_item_unsafe(DICTIONARY *dict, const char *name);
  98. extern DICTIONARY_ITEM *dictionary_get_and_acquire_item(DICTIONARY *dict, const char *name);
  99. extern DICTIONARY_ITEM *dictionary_set_and_acquire_item_unsafe(DICTIONARY *dict, const char *name, void *value, size_t value_len);
  100. extern DICTIONARY_ITEM *dictionary_set_and_acquire_item(DICTIONARY *dict, const char *name, void *value, size_t value_len);
  101. extern void dictionary_acquired_item_release_unsafe(DICTIONARY *dict, DICTIONARY_ITEM *item);
  102. extern void dictionary_acquired_item_release(DICTIONARY *dict, DICTIONARY_ITEM *item);
  103. extern DICTIONARY_ITEM *dictionary_acquired_item_dup(DICTIONARY_ITEM *item);
  104. extern const char *dictionary_acquired_item_name(DICTIONARY_ITEM *item);
  105. extern void *dictionary_acquired_item_value(DICTIONARY_ITEM *item);
  106. // UNSAFE functions, without locks
  107. // to be used when the user is traversing with the right lock type
  108. // Read lock is acquired by dictionary_walktrhough_read() and dfe_start_read()
  109. // Write lock is acquired by dictionary_walktrhough_write() and dfe_start_write()
  110. // For code readability, please use these macros:
  111. #define dictionary_get_having_read_lock(dict, name) dictionary_get_unsafe(dict, name)
  112. #define dictionary_get_having_write_lock(dict, name) dictionary_get_unsafe(dict, name)
  113. #define dictionary_set_having_write_lock(dict, name, value, value_len) dictionary_set_unsafe(dict, name, value, value_len)
  114. #define dictionary_del_having_write_lock(dict, name) dictionary_del_unsafe(dict, name)
  115. extern void *dictionary_get_unsafe(DICTIONARY *dict, const char *name);
  116. extern void *dictionary_set_unsafe(DICTIONARY *dict, const char *name, void *value, size_t value_len);
  117. extern int dictionary_del_unsafe(DICTIONARY *dict, const char *name);
  118. // Traverse (walk through) the items of the dictionary.
  119. // The order of traversal is currently the order of insertion.
  120. //
  121. // The callback function may return a negative number to stop the traversal,
  122. // in which case that negative value is returned to the caller.
  123. //
  124. // If all callback calls return zero or positive numbers, the sum of all of
  125. // them is returned to the caller.
  126. //
  127. // You cannot alter the dictionary from inside a dictionary_walkthrough_read() - deadlock!
  128. // You can only delete the current item from inside a dictionary_walkthrough_write() - you can add as many as you want.
  129. //
  130. #define dictionary_walkthrough_read(dict, callback, data) dictionary_walkthrough_rw(dict, 'r', callback, data)
  131. #define dictionary_walkthrough_write(dict, callback, data) dictionary_walkthrough_rw(dict, 'w', callback, data)
  132. extern int dictionary_walkthrough_rw(DICTIONARY *dict, char rw, int (*callback)(const char *name, void *value, void *data), void *data);
  133. #define dictionary_sorted_walkthrough_read(dict, callback, data) dictionary_sorted_walkthrough_rw(dict, 'r', callback, data)
  134. #define dictionary_sorted_walkthrough_write(dict, callback, data) dictionary_sorted_walkthrough_rw(dict, 'w', callback, data)
  135. int dictionary_sorted_walkthrough_rw(DICTIONARY *dict, char rw, int (*callback)(const char *name, void *entry, void *data), void *data);
  136. // Traverse with foreach
  137. //
  138. // Use like this:
  139. //
  140. // DICTFE dfe = {};
  141. // for(MY_ITEM *item = dfe_start_read(&dfe, dict); item ; item = dfe_next(&dfe)) {
  142. // // do things with the item and its dfe.name
  143. // }
  144. // dfe_done(&dfe);
  145. //
  146. // You cannot alter the dictionary from within a dfe_read_start() - deadlock!
  147. // You can only delete the current item from inside a dfe_start_write() - you can add as many as you want.
  148. //
  149. #ifdef DICTIONARY_INTERNALS
  150. #define DICTFE_CONST
  151. #else
  152. #define DICTFE_CONST const
  153. #endif
  154. #define DICTIONARY_LOCK_READ 'r'
  155. #define DICTIONARY_LOCK_WRITE 'w'
  156. #define DICTIONARY_LOCK_NONE 'u'
  157. typedef DICTFE_CONST struct dictionary_foreach {
  158. DICTFE_CONST char *name; // the dictionary name of the last item used
  159. void *value; // the dictionary value of the last item used
  160. // same as the return value of dictfe_start() and dictfe_next()
  161. // the following are for internal use only - to keep track of the point we are
  162. char rw; // the lock mode 'r' or 'w'
  163. usec_t started_ut; // the time the caller started iterating (now_realtime_usec())
  164. DICTIONARY *dict; // the dictionary upon we work
  165. void *last_item; // the item we work on, to remember the position we are at
  166. } DICTFE;
  167. #define dfe_start_read(dict, value) dfe_start_rw(dict, value, DICTIONARY_LOCK_READ)
  168. #define dfe_start_write(dict, value) dfe_start_rw(dict, value, DICTIONARY_LOCK_WRITE)
  169. #define dfe_start_rw(dict, value, mode) \
  170. do { \
  171. DICTFE value ## _dfe = {}; \
  172. const char *value ## _name; (void)(value ## _name); (void)value; \
  173. for((value) = dictionary_foreach_start_rw(&value ## _dfe, (dict), (mode)), ( value ## _name ) = value ## _dfe.name; \
  174. (value ## _dfe.name) ;\
  175. (value) = dictionary_foreach_next(&value ## _dfe), ( value ## _name ) = value ## _dfe.name) \
  176. {
  177. #define dfe_done(value) \
  178. } \
  179. dictionary_foreach_done(&value ## _dfe); \
  180. } while(0)
  181. extern void * dictionary_foreach_start_rw(DICTFE *dfe, DICTIONARY *dict, char rw);
  182. extern void * dictionary_foreach_next(DICTFE *dfe);
  183. extern usec_t dictionary_foreach_done(DICTFE *dfe);
  184. // Get statistics about the dictionary
  185. extern long int dictionary_stats_allocated_memory(DICTIONARY *dict);
  186. extern long int dictionary_stats_entries(DICTIONARY *dict);
  187. extern size_t dictionary_stats_version(DICTIONARY *dict);
  188. extern size_t dictionary_stats_inserts(DICTIONARY *dict);
  189. extern size_t dictionary_stats_searches(DICTIONARY *dict);
  190. extern size_t dictionary_stats_deletes(DICTIONARY *dict);
  191. extern size_t dictionary_stats_resets(DICTIONARY *dict);
  192. extern size_t dictionary_stats_walkthroughs(DICTIONARY *dict);
  193. extern size_t dictionary_stats_referenced_items(DICTIONARY *dict);
  194. extern int dictionary_unittest(size_t entries);
  195. extern int string_interning_unittests(void);
  196. // ----------------------------------------------------------------------------
  197. // STRING implementation
  198. typedef struct netdata_string STRING;
  199. extern STRING *string_strdupz(const char *str);
  200. extern STRING *string_dup(STRING *string);
  201. extern void string_freez(STRING *string);
  202. extern size_t string_length(STRING *string);
  203. extern const char *string2str(STRING *string) NEVERNULL;
  204. static inline int string_cmp(STRING *s1, STRING *s2) {
  205. // STRINGs are deduplicated, so the same strings have the same pointer
  206. if(unlikely(s1 == s2)) return 0;
  207. // they differ, do the typical comparison
  208. return strcmp(string2str(s1), string2str(s2));
  209. }
  210. #endif /* NETDATA_DICTIONARY_H */