xref: /unit/src/nxt_lvlhsh.h (revision 2084:7d479274f334)
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) NGINX, Inc.
5  */
6 
7 #ifndef _NXT_LEVEL_HASH_H_INCLUDED_
8 #define _NXT_LEVEL_HASH_H_INCLUDED_
9 
10 
11 typedef struct nxt_lvlhsh_query_s  nxt_lvlhsh_query_t;
12 
13 typedef nxt_int_t (*nxt_lvlhsh_test_t)(nxt_lvlhsh_query_t *lhq, void *data);
14 typedef void *(*nxt_lvlhsh_alloc_t)(void *ctx, size_t size);
15 typedef void (*nxt_lvlhsh_free_t)(void *ctx, void *p);
16 
17 
18 #if (NXT_64BIT)
19 
20 #define NXT_LVLHSH_DEFAULT_BUCKET_SIZE  128
21 #define NXT_LVLHSH_ENTRY_SIZE           3
22 #define NXT_LVLHSH_BATCH_ALLOC          16
23 
24 /* 3 is shift of 64-bit pointer. */
25 #define NXT_LVLHSH_MEMALIGN_SHIFT       (NXT_MAX_MEMALIGN_SHIFT - 3)
26 
27 #else
28 
29 #define NXT_LVLHSH_DEFAULT_BUCKET_SIZE  64
30 #define NXT_LVLHSH_ENTRY_SIZE           2
31 #define NXT_LVLHSH_BATCH_ALLOC          8
32 
33 /* 2 is shift of 32-bit pointer. */
34 #define NXT_LVLHSH_MEMALIGN_SHIFT       (NXT_MAX_MEMALIGN_SHIFT - 2)
35 
36 #endif
37 
38 
39 #if (NXT_LVLHSH_MEMALIGN_SHIFT < 10)
40 #define NXT_LVLHSH_MAX_MEMALIGN_SHIFT   NXT_LVLHSH_MEMALIGN_SHIFT
41 #else
42 #define NXT_LVLHSH_MAX_MEMALIGN_SHIFT   10
43 #endif
44 
45 
46 #define NXT_LVLHSH_BUCKET_END(bucket_size)                                    \
47     (((bucket_size) - sizeof(void *))                                         \
48         / (NXT_LVLHSH_ENTRY_SIZE * sizeof(uint32_t))                          \
49      * NXT_LVLHSH_ENTRY_SIZE)
50 
51 
52 #define NXT_LVLHSH_BUCKET_SIZE(bucket_size)                                   \
53     NXT_LVLHSH_BUCKET_END(bucket_size), bucket_size, (bucket_size - 1)
54 
55 
56 #define NXT_LVLHSH_DEFAULT                                                    \
57     NXT_LVLHSH_BUCKET_SIZE(NXT_LVLHSH_DEFAULT_BUCKET_SIZE),                   \
58     { 4, 4, 4, 4, 4, 4, 4, 0 }
59 
60 
61 #define NXT_LVLHSH_LARGE_SLAB                                                 \
62     NXT_LVLHSH_BUCKET_SIZE(NXT_LVLHSH_DEFAULT_BUCKET_SIZE),                   \
63     { 10, 4, 4, 4, 4, 4, 4, 0 }
64 
65 
66 #define NXT_LVLHSH_LARGE_MEMALIGN                                             \
67     NXT_LVLHSH_BUCKET_SIZE(NXT_LVLHSH_DEFAULT_BUCKET_SIZE),                   \
68     { NXT_LVLHSH_MAX_MEMALIGN_SHIFT, 4, 4, 4, 4, 0, 0, 0 }
69 
70 
71 typedef struct {
72     uint32_t                  bucket_end;
73     uint32_t                  bucket_size;
74     uint32_t                  bucket_mask;
75     uint8_t                   shift[8];
76 
77     nxt_lvlhsh_test_t         test;
78     nxt_lvlhsh_alloc_t        alloc;
79     nxt_lvlhsh_free_t         free;
80 } nxt_lvlhsh_proto_t;
81 
82 
83 typedef struct {
84     void                      *slot;
85 } nxt_lvlhsh_t;
86 
87 
88 struct nxt_lvlhsh_query_s {
89     uint32_t                  key_hash;
90     uint32_t                  replace;   /* 1 bit */
91     nxt_str_t                 key;
92     void                      *value;
93 
94     const nxt_lvlhsh_proto_t  *proto;
95     void                      *pool;
96 
97     /* Opaque data passed for the test function. */
98     void                      *data;
99 };
100 
101 
102 typedef struct {
103     const nxt_lvlhsh_proto_t  *proto;
104     /*
105      * Fields to store current bucket entry position.  They cannot be
106      * combined in a single bucket pointer with number of entries in low
107      * bits, because entry positions are not aligned.  A current level is
108      * stored as key bit path from the root.
109      */
110     uint32_t                  *bucket;
111     uint32_t                  current;
112     uint32_t                  entry;
113     uint32_t                  entries;
114 } nxt_lvlhsh_each_t;
115 
116 
117 #define nxt_lvlhsh_is_empty(lh)                                               \
118     ((lh)->slot == NULL)
119 
120 
121 #define nxt_lvlhsh_init(lh)                                                   \
122     (lh)->slot = NULL
123 
124 /*
125  * nxt_lvlhsh_find() finds a hash element.  If the element has been
126  * found then it is stored in the lhq->value and nxt_lvlhsh_find()
127  * returns NXT_OK.  Otherwise NXT_DECLINED is returned.
128  *
129  * The required nxt_lvlhsh_query_t fields: key_hash, key, proto.
130  */
131 NXT_EXPORT nxt_int_t nxt_lvlhsh_find(nxt_lvlhsh_t *lh, nxt_lvlhsh_query_t *lhq);
132 
133 /*
134  * nxt_lvlhsh_insert() adds a hash element.  If the element already
135  * presents in lvlhsh and the lhq->replace flag is zero, then lhq->value
136  * is updated with the old element and NXT_DECLINED is returned.
137  * If the element already presents in lvlhsh and the lhq->replace flag
138  * is non-zero, then the old element is replaced with the new element.
139  * lhq->value is updated with the old element, and NXT_OK is returned.
140  * If the element is not present in lvlhsh, then it is inserted and
141  * NXT_OK is returned.  The lhq->value is not changed.
142  * On memory allocation failure NXT_ERROR is returned.
143  *
144  * The required nxt_lvlhsh_query_t fields: key_hash, key, proto, replace, value.
145  * The optional nxt_lvlhsh_query_t fields: pool.
146  */
147 NXT_EXPORT nxt_int_t nxt_lvlhsh_insert(nxt_lvlhsh_t *lh,
148     nxt_lvlhsh_query_t *lhq);
149 
150 /*
151  * nxt_lvlhsh_delete() deletes a hash element.  If the element has been
152  * found then it is removed from lvlhsh and is stored in the lhq->value,
153  * and NXT_OK is returned.  Otherwise NXT_DECLINED is returned.
154  *
155  * The required nxt_lvlhsh_query_t fields: key_hash, key, proto.
156  * The optional nxt_lvlhsh_query_t fields: pool.
157  */
158 NXT_EXPORT nxt_int_t nxt_lvlhsh_delete(nxt_lvlhsh_t *lh,
159     nxt_lvlhsh_query_t *lhq);
160 
161 /*
162  * nxt_lvlhsh_each_init() initializes iterator.
163  * It must be called before the first nxt_lvlhsh_each() call.
164  */
165 #define nxt_lvlhsh_each_init(lhe, _proto)                                     \
166     do {                                                                      \
167         (lhe)->proto = _proto;                                                \
168         (lhe)->bucket = NULL;                                                 \
169     } while (0)
170 
171 /*
172  * nxt_lvlhsh_each() iterates over a lvlhsh.
173  * It returns NULL if there is no more elements.
174  */
175 NXT_EXPORT void *nxt_lvlhsh_each(nxt_lvlhsh_t *lh, nxt_lvlhsh_each_t *lhe);
176 
177 /*
178  * nxt_lvlhsh_peek() is used to iterate over a lvlhsh during the lvlhsh
179  * destruction.  The returned hash element should be deleted from the lvlhsh,
180  * otherwise it will be returned again by the next nxt_lvlhsh_peek() call.
181  * The function returns NULL if there is no more elements in the lvlhsh.
182  */
183 NXT_EXPORT void *nxt_lvlhsh_peek(nxt_lvlhsh_t *lh,
184     const nxt_lvlhsh_proto_t *proto);
185 
186 /*
187  * nxt_lvlhsh_retrieve() is used to iterate over a lvlhsh during the lvlhsh
188  * destruction.  As opposed to nxt_lvlhsh_peek() the returned hash element
189  * is deleted from the lvlhsh.  The function returns NULL if there is no
190  * more elements in the lvlhsh.
191  */
192 NXT_EXPORT void *nxt_lvlhsh_retrieve(nxt_lvlhsh_t *lh,
193     const nxt_lvlhsh_proto_t *proto, void *pool);
194 
195 
196 NXT_EXPORT void *nxt_lvlhsh_alloc(void *data, size_t size);
197 NXT_EXPORT void nxt_lvlhsh_free(void *data, void *p);
198 
199 
200 #endif /* _NXT_LEVEL_HASH_H_INCLUDED_ */
201