xref: /openssl/doc/internal/man3/ossl_ht_new.pod (revision 71fe7f09)
1=pod
2
3=head1 NAME
4
5ossl_ht_new, ossl_ht_free,
6ossl_ht_read_lock, ossl_ht_read_unlock,
7ossl_ht_write_lock, ossl_ht_write_unlock,
8ossl_ht_flush, ossl_ht_insert,
9ossl_ht_delete, ossl_ht_count,
10ossl_ht_foreach_until, ossl_ht_filter,
11ossl_ht_value_list_free, ossl_ht_get,
12ossl_ht_put, HT_START_KEY_DEFN,
13HT_END_KEY_DEFN, HT_DEF_KEY_FIELD_CHAR_ARRAY,
14HT_DEF_KEY_FIELD_UINT8T_ARRAY, HT_DEF_KEY_FIELD,
15HT_INIT_KEY, HT_KEY_RESET, HT_SET_KEY_FIELD,
16HT_SET_KEY_STRING, HT_SET_KEY_BLOB,
17TO_HT_KEY, FROM_HT_KEY,
18IMPLEMENT_HT_VALUE_TYPE_FNS
19- internal rcu locked hashtables
20
21=head1 SYNOPSIS
22
23 HT *ossl_ht_new(const HT_CONFIG *conf);
24 void ossl_ht_free(HT *htable);
25 void ossl_ht_read_lock(HT *htable);
26 void ossl_ht_read_unlock(HT *htable);
27 void ossl_ht_write_lock(HT *htable);
28 void ossl_ht_write_unlock(HT *htable);
29 int  ossl_ht_flush(HT *htable);
30 int  ossl_ht_insert(HT *htable, HT_KEY *key, HT_VALUE *data, HT_VALUE **olddata);
31 int ossl_ht_delete(HT *htable, HT_KEY *key);
32 size_t ossl_ht_count(HT *htable);
33 void ossl_ht_foreach_until(HT *htable, int (*cb)(HT_VALUE *obj, void *arg), void *arg);
34 HT_VALUE_LIST *ossl_ht_filter(HT *htable, size_t max_len, int (*filter)(HT_VALUE *obj));
35 void ossl_ht_value_list_free(HT_VALUE_LIST *list);
36 HT_VALUE *ossl_ht_get(HT *htable, HT_KEY *key);
37 void ossl_ht_put(HT_VALUE *value);
38 HT_START_KEY_DEFN(keyname);
39 HT_END_KEY_DEFN(keyname);
40 HT_DEF_KEY_FIELD(name, type);
41 HT_DEF_KEY_FIELD_CHAR_ARRAY(name, size);
42 HT_DEF_KEY_FIELD_UINT8T_ARRAY(name, size);
43 HT_INIT_KEY(key);
44 HT_KEY_RESET(key);
45 HT_SET_KEY_FIELD(key, member, value);
46 HT_SET_KEY_STRING(key, member, value);
47 HT_SET_KEY_BLOB(key, member, value, len);
48 TO_HT_KEY(key);
49 FROM_HT_KEY(key, type);
50 IMPLEMENT_HT_VALUE_TYPE_FNS(vtype, name, pfx);
51
52=head1 DESCRIPTION
53
54This API provides a library-internal implementation of a hashtable that provides
55reference counted object retrieval under the protection of an rcu lock.  API
56type safety is offered via conversion macros to and from the generic B<HT_VALUE>
57type.
58
59=over 2
60
61=item *
62
63ossl_ht_new() returns a new B<HT> (hashtable object) used to store data
64elements based on a defined key.  The call accepts an HT_CONFIG pointer which
65contains configurations options for hashtable.  Current config options consist
66of:
67    I<ht_free_fn> The function to call to free a value, may be NULL.
68    I<ht_hash_fn> The function to generate a hash value for a key, may be NULL.
69    I<init_neighborhoods> The initial number of neighborhoods in the hash table.
70
71Note that init_bucket_len may be set to zero, which will use the default initial
72bucket size, which will be automatically expanded with the hash table load
73average reaches 0.75.
74
75Note that lockless_read operation implies behavioral restrictions. Specifically
76only element additions are allowed, deletion operations will fail
77    Hash table growth is inhibited.  init_bucket_len should be set to an
78    appropriate value to prevent performance degradation
79    The table owner is responsible for ensuring there are no readers during a
80    freeing of the table.
81
82Note that lockless_write operations are done at your own risk.  Lockless
83    operation in a multithreaded environment will cause data corruption.  It
84    is the callers responsibility in this mode of operation to provide thread
85    synchronization.
86
87=item *
88
89ossl_ht_free() frees an allocated hash table.  Each element in the table
90will have its reference count dropped, and, if said count reaches zero, the hash
91tables registered free function will be called to release the element data.
92
93=item *
94
95ossl_ht_read_lock(), ossl_ht_read_unlock(), ossl_ht_write_lock() and
96ossl_ht_write_unlock() lock the table for reading and writing/modification.
97These function are not required for use in the event a table is to be used in a
98lockless fashion, but if they are not used, it is the responsibility of the caller
99to ensure thread synchronization.  Note that an rcu lock is used internally for these
100operations, so for table modifying actions (ossl_ht_flush() and ossl_ht_delete()
101the write lock must be taken and released to ensure rcu synchronization takes
102place.
103
104=item *
105
106ossl_ht_flush() empties a hash table.  All elements will have their
107reference counts decremented, and, on reaching zero, the free function will be
108called to release the element data.
109
110=item *
111
112ossl_ht_insert() inserts an B<HT_VALUE> element into the hash table, to be
113hashed using the corresponding B<HT_KEY> value.
114
115=item *
116
117ossl_ht_delete() deletes an entry from the hashtable indexed by the passed
118B<HT_KEY> value.
119
120=item *
121
122ossl_ht_count() returns the number of elements within the hash table.
123
124=item *
125
126ossl_ht_foreach_until() iterates over all elements in the hash table, calling
127the passed callback function for each. The return value of the callback
128indicates if the iteration should continue or not.  Returning 1 indicates
129iteration should continue, while returning 0 indicates that iteration should
130terminate.
131
132Note that the iteration is done under read lock protection, and as such
133modifications to the table are disallowed in the callback function.
134Modification to the value content are permitted, if the caller is able to
135properly synchronize such modifications with other threads.
136
137=item *
138
139ossl_ht_filter() iterates over all elements of the hash table, calling
140the filter callback for each element.  If the callback returns 1, the
141corresponding B<HT_VALUE> is placed on a list, and its reference count incremented.
142The completed list is returned to the caller as an B<HT_VALUE_LIST> object
143
144=item *
145
146ossl_ht_value_list_free() frees an B<HT_VALUE_LIST>.  For each element on
147the list, its reference count is decremented, and after traversing the list, the
148list object is freed.  Note, NULL elements are allowed on the list, but for any
149element which is taken from the list by a caller, they must call
150ossl_ht_put() on the B<HT_VALUE> to prevent memory leaks.
151
152=item *
153
154ossl_ht_get() performs a lookup of an B<HT_KEY> in the hashtable, returning
155its corresponding value.
156
157=item *
158
159HT_START_KEY_DEFN() Begins the definition of a key type.  the keyname parameter
160defines the structure name, and presets a common key header.
161
162=item *
163
164HT_END_KEY_DEFN() Finalizes a key definition.  the keyname parameter (which may
165differ from the name passed in HT_START_KEY_DEFN(), defines the key type name.
166The resulting type may be converted to an HT_KEY variable via the HT_TO_KEY()
167macro, and back using the HT_FROM_KEY() macro.
168
169=item *
170
171HT_DEF_KEY_FIELD() Allows for the creation of data fields within a key. Note,
172this macro can be used for any data type, but it is recommended that strings and
173binary arrays be created with the HT_DEF_KEY_FIELD_CHAR_ARRAY() and
174HT_DEF_KEY_FIELD_UINT8T_ARRAY() macros to ensure proper in-lining of key data.
175
176=item *
177
178HT_DEF_KEY_FIELD_CHAR_ARRAY() Creates a string field of fixed size
179within a key definition. Note these items will be NULL terminated.
180
181=item *
182
183HT_DEF_KEY_FIELD_UINT8T_ARRAY() Creates an array of uint8_t elements within a
184key.
185
186=item *
187
188HT_INIT_KEY() Initializes a key for use.  Can be called multiple times, but must
189be called at least once before using in any hashtable method.
190
191=item *
192
193HT_KEY_RESET() Resets a key's data to all zeros.
194
195=item *
196
197HT_SET_KEY_FIELD() Sets a field in a key (as defined by HT_DEF_KEY_FIELD()) to a
198given value.
199
200=item *
201
202HT_SET_KEY_STRING() Performs a strncpy() of a source string to the destination
203key field.
204
205=item *
206
207HT_SET_KEY_BLOB() Performs a memcpy() of a source uint8_t buffer to a
208destination key field.
209
210=item *
211
212TO_HT_KEY() Converts a key type as defined by HT_START_KEY_DEFN() and
213HE_END_KEY_DEFN() to the generic HT_KEY type
214
215=item *
216
217FROM_HT_KEY() Converts an HT_KEY back to a specific key type as defined by
218HT_START_KEY_DEFN() and HT_END_KEY_DEFN()
219
220=item *
221
222IMPLEMENT_HT_VALUE_TYPE_FNS() creates template conversion functions for
223manipulating the hashtable using specific data types.  This macro accepts two
224parameters, a NAME, which is used to prefix the hashtable function so that it
225may be associated with a specific hash table, and TYPE which defines the type of
226data the instantiated function accepts.  The list of functions instantiated by
227this macro are below.
228
229=over 2
230
231=item *
232
233int ossl_ht_NAME_TYPE_insert(HT* h, HT_KEY *key, <type> *value, HT_VALUE **olddata)
234Inserts a value to the hash table of type TYPE into the hash table using the
235provided key.  If olddata is not NULL, and a matching key already exists in the
236table, the operation is a replacement, and the old data is returned in this
237pointer
238
239=item *
240
241<TYPE> ossl_ht_NAME_TYPE_get(HT *h, HT_KEY *key, HT_VALUE **v)
242Looks up an item in the hash table based on key, and returns the data it found,
243if any.  v holds a pointer to the B<HT_VALUE> associated with the data.
244
245=item *
246
247<TYPE> *ossl_ht_NAME_TYPE_from_value(HT_VALUE *v)
248Validates that the B<HT_VALUE> provided matches the TYPE specified, and returns the
249value data.  If there is a type mismatch, NULL is returned
250
251=item *
252
253HT_VALUE *ossl_ht_NAME_TYPE_to_value(<TYPE> *data)
254Converts the data pointer provided to an B<HT_VALUE> object
255
256=item *
257
258int ossl_ht_NAME_TYPE_type(HT_VALUE *v)
259Returns true if the B<HT_VALUE> object passed in is of type <TYPE>
260
261=back
262
263=back
264
265=head1 RETURN VALUES
266
267ossl_ht_new() returns an B<HT*> struct on success and NULL on error
268
269void ossl_ht_free(HT *htable);
270
271ossl_ht_flush() and ossl_ht_insert() return 1 on success and 0 on error
272
273ossl_ht_delete() returns 1 if the key was successfully deleted, and 0 if the
274key was not found.
275
276ossl_ht_count() returns the number of elements in the hash table
277
278ossl_ht_filter() returns an B<HT_VALUE_LIST> of all elements matching the
279provided filter
280
281ossl_ht_get() returns an B<HT_VALUE> pointer, or NULL if the element was not
282found.
283
284ossl_ht_insert() returns 1 if an element was inserted, 0 if the element is
285already present, -1 on fatal errors (memory allocation or growth not allowed).
286
287=head1 EXAMPLES
288
289#include <stdio.h>
290#include <string.h>
291
292#include <openssl/err.h>
293#include <openssl/crypto.h>
294#include <internal/hashtable.h>
295
296HT_START_KEY_DEFN(intkey)
297HT_DEF_KEY_FIELD(myintkey, int)
298HT_END_KEY_DEFN(INTKEY)
299
300IMPLEMENT_HT_VALUE_TYPE_FNS(int, test, static)
301
302static void int_free_fn(HT_VALUE *v)
303{
304    int *i = ossl_crypto_test_int_from_value(v);
305
306    fprintf(stderr, "Freeing an element\n");
307    OPENSSL_free(i);
308}
309
310static int test_int_hashtable(void)
311{
312    /*
313     * our config says:
314     * int_free_fn - Our free handler
315     * NULL - Use default hash fn
316     * 0 - use default initial bucket size
317     */
318    HT_CONFIG hash_conf = {
319        int_free_fn,
320        NULL,
321        0
322    };
323    INTKEY key;
324    HT *ht = NULL;
325    HT_VALUE *v;
326    int rc;
327    int *newval = OPENSSL_malloc(sizeof(int));
328
329    ht = ossl_ht_new(&hash_conf);
330
331    if (ht == NULL)
332        return 0;
333
334    if (newval == NULL)
335        goto out;
336
337    *newval = 1;
338
339    /* insert */
340    HT_INIT_KEY(&key);
341    HT_SET_KEY_FIELD(&key, myintkey, 47);
342    ossl_ht_write_lock(ht);
343    rc = ossl_ht_test_int_insert(ht, TO_HT_KEY(&key), newval, NULL);
344    ossl_ht_write_unlock(ht);
345    if (rc == 0)
346        goto out;
347
348    /* num_items */
349    if (ossl_ht_count(ht) != 1)
350        goto out;
351
352    /* lookup */
353    HT_RESET_KEY(&key);
354    HT_SET_KEY_FIELD(&key, myintkey, 47);
355    ossl_ht_read_lock(ht);
356    v = ossl_ht_get(ht, TO_HT_KEY(&key);
357    fprintf(stderr, "found element with key 47 holding value %d\n",
358            *ossl_ht_test_int_from_value(v));
359    ossl_ht_read_unlock(ht);
360
361    rc = 1;
362end:
363    /* this will call the free function for our element */
364    ossl_ht_free(ht);
365    return rc;
366}
367
368=head1 COPYRIGHT
369
370Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
371
372Licensed under the Apache License 2.0 (the "License").  You may not use
373this file except in compliance with the License.  You can obtain a copy
374in the file LICENSE in the source distribution or at
375L<https://www.openssl.org/source/license.html>.
376
377=cut
378