• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * nghttp3
3  *
4  * Copyright (c) 2019 nghttp3 contributors
5  * Copyright (c) 2018 ngtcp2 contributors
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  */
26 #ifndef NGHTTP3_KSL_H
27 #define NGHTTP3_KSL_H
28 
29 #ifdef HAVE_CONFIG_H
30 #  include <config.h>
31 #endif /* HAVE_CONFIG_H */
32 
33 #include <stdlib.h>
34 
35 #include <nghttp3/nghttp3.h>
36 
37 #include "nghttp3_objalloc.h"
38 
39 /*
40  * Skip List using single key instead of range.
41  */
42 
43 #define NGHTTP3_KSL_DEGR 16
44 /* NGHTTP3_KSL_MAX_NBLK is the maximum number of nodes which a single
45    block can contain. */
46 #define NGHTTP3_KSL_MAX_NBLK (2 * NGHTTP3_KSL_DEGR - 1)
47 /* NGHTTP3_KSL_MIN_NBLK is the minimum number of nodes which a single
48    block other than root must contains. */
49 #define NGHTTP3_KSL_MIN_NBLK (NGHTTP3_KSL_DEGR - 1)
50 
51 /*
52  * nghttp3_ksl_key represents key in nghttp3_ksl.
53  */
54 typedef void nghttp3_ksl_key;
55 
56 typedef struct nghttp3_ksl_node nghttp3_ksl_node;
57 
58 typedef struct nghttp3_ksl_blk nghttp3_ksl_blk;
59 
60 /*
61  * nghttp3_ksl_node is a node which contains either nghttp3_ksl_blk or
62  * opaque data.  If a node is an internal node, it contains
63  * nghttp3_ksl_blk.  Otherwise, it has data.  The key is stored at the
64  * location starting at key.
65  */
66 struct nghttp3_ksl_node {
67   union {
68     nghttp3_ksl_blk *blk;
69     void *data;
70   };
71   union {
72     uint64_t align;
73     /* key is a buffer to include key associated to this node.
74        Because the length of key is unknown until nghttp3_ksl_init is
75        called, the actual buffer will be allocated after this
76        field. */
77     uint8_t key[1];
78   };
79 };
80 
81 /*
82  * nghttp3_ksl_blk contains nghttp3_ksl_node objects.
83  */
84 struct nghttp3_ksl_blk {
85   union {
86     struct {
87       /* next points to the next block if leaf field is nonzero. */
88       nghttp3_ksl_blk *next;
89       /* prev points to the previous block if leaf field is
90          nonzero. */
91       nghttp3_ksl_blk *prev;
92       /* n is the number of nodes this object contains in nodes. */
93       uint32_t n;
94       /* leaf is nonzero if this block contains leaf nodes. */
95       uint32_t leaf;
96       union {
97         uint64_t align;
98         /* nodes is a buffer to contain NGHTTP3_KSL_MAX_NBLK
99            nghttp3_ksl_node objects.  Because nghttp3_ksl_node object
100            is allocated along with the additional variable length key
101            storage, the size of buffer is unknown until
102            nghttp3_ksl_init is called. */
103         uint8_t nodes[1];
104       };
105     };
106 
107     nghttp3_opl_entry oplent;
108   };
109 };
110 
111 nghttp3_objalloc_def(ksl_blk, nghttp3_ksl_blk, oplent);
112 
113 /*
114  * nghttp3_ksl_compar is a function type which returns nonzero if key
115  * |lhs| should be placed before |rhs|.  It returns 0 otherwise.
116  */
117 typedef int (*nghttp3_ksl_compar)(const nghttp3_ksl_key *lhs,
118                                   const nghttp3_ksl_key *rhs);
119 
120 typedef struct nghttp3_ksl nghttp3_ksl;
121 
122 typedef struct nghttp3_ksl_it nghttp3_ksl_it;
123 
124 /*
125  * nghttp3_ksl_it is a forward iterator to iterate nodes.
126  */
127 struct nghttp3_ksl_it {
128   const nghttp3_ksl *ksl;
129   nghttp3_ksl_blk *blk;
130   size_t i;
131 };
132 
133 /*
134  * nghttp3_ksl is a deterministic paged skip list.
135  */
136 struct nghttp3_ksl {
137   nghttp3_objalloc blkalloc;
138   /* head points to the root block. */
139   nghttp3_ksl_blk *head;
140   /* front points to the first leaf block. */
141   nghttp3_ksl_blk *front;
142   /* back points to the last leaf block. */
143   nghttp3_ksl_blk *back;
144   nghttp3_ksl_compar compar;
145   size_t n;
146   /* keylen is the size of key */
147   size_t keylen;
148   /* nodelen is the actual size of nghttp3_ksl_node including key
149      storage. */
150   size_t nodelen;
151 };
152 
153 /*
154  * nghttp3_ksl_init initializes |ksl|.  |compar| specifies compare
155  * function.  |keylen| is the length of key.
156  */
157 void nghttp3_ksl_init(nghttp3_ksl *ksl, nghttp3_ksl_compar compar,
158                       size_t keylen, const nghttp3_mem *mem);
159 
160 /*
161  * nghttp3_ksl_free frees resources allocated for |ksl|.  If |ksl| is
162  * NULL, this function does nothing.  It does not free the memory
163  * region pointed by |ksl| itself.
164  */
165 void nghttp3_ksl_free(nghttp3_ksl *ksl);
166 
167 /*
168  * nghttp3_ksl_insert inserts |key| with its associated |data|.  On
169  * successful insertion, the iterator points to the inserted node is
170  * stored in |*it|.
171  *
172  * This function returns 0 if it succeeds, or one of the following
173  * negative error codes:
174  *
175  * NGHTTP3_ERR_NOMEM
176  *   Out of memory.
177  * NGHTTP3_ERR_INVALID_ARGUMENT
178  *   |key| already exists.
179  */
180 int nghttp3_ksl_insert(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
181                        const nghttp3_ksl_key *key, void *data);
182 
183 /*
184  * nghttp3_ksl_remove removes the |key| from |ksl|.
185  *
186  * This function assigns the iterator to |*it|, which points to the
187  * node which is located at the right next of the removed node if |it|
188  * is not NULL.  If |key| is not found, no deletion takes place and
189  * the return value of nghttp3_ksl_end(ksl) is assigned to |*it|.
190  *
191  * This function returns 0 if it succeeds, or one of the following
192  * negative error codes:
193  *
194  * NGHTTP3_ERR_INVALID_ARGUMENT
195  *   |key| does not exist.
196  */
197 int nghttp3_ksl_remove(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
198                        const nghttp3_ksl_key *key);
199 
200 /*
201  * nghttp3_ksl_remove_hint removes the |key| from |ksl|.  |hint| must
202  * point to the same node denoted by |key|.  |hint| is used to remove
203  * a node efficiently in some cases.  Other than that, it behaves
204  * exactly like nghttp3_ksl_remove.  |it| and |hint| can point to the
205  * same object.
206  */
207 int nghttp3_ksl_remove_hint(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
208                             const nghttp3_ksl_it *hint,
209                             const nghttp3_ksl_key *key);
210 
211 /*
212  * nghttp3_ksl_lower_bound returns the iterator which points to the
213  * first node which has the key which is equal to |key| or the last
214  * node which satisfies !compar(&node->key, key).  If there is no such
215  * node, it returns the iterator which satisfies nghttp3_ksl_it_end(it)
216  * != 0.
217  */
218 nghttp3_ksl_it nghttp3_ksl_lower_bound(nghttp3_ksl *ksl,
219                                        const nghttp3_ksl_key *key);
220 
221 /*
222  * nghttp3_ksl_lower_bound_compar works like nghttp3_ksl_lower_bound,
223  * but it takes custom function |compar| to do lower bound search.
224  */
225 nghttp3_ksl_it nghttp3_ksl_lower_bound_compar(nghttp3_ksl *ksl,
226                                               const nghttp3_ksl_key *key,
227                                               nghttp3_ksl_compar compar);
228 
229 /*
230  * nghttp3_ksl_update_key replaces the key of nodes which has |old_key|
231  * with |new_key|.  |new_key| must be strictly greater than the
232  * previous node and strictly smaller than the next node.
233  */
234 void nghttp3_ksl_update_key(nghttp3_ksl *ksl, const nghttp3_ksl_key *old_key,
235                             const nghttp3_ksl_key *new_key);
236 
237 /*
238  * nghttp3_ksl_begin returns the iterator which points to the first
239  * node.  If there is no node in |ksl|, it returns the iterator which
240  * satisfies nghttp3_ksl_it_end(it) != 0.
241  */
242 nghttp3_ksl_it nghttp3_ksl_begin(const nghttp3_ksl *ksl);
243 
244 /*
245  * nghttp3_ksl_end returns the iterator which points to the node
246  * following the last node.  The returned object satisfies
247  * nghttp3_ksl_it_end().  If there is no node in |ksl|, it returns the
248  * iterator which satisfies nghttp3_ksl_it_begin(it) != 0.
249  */
250 nghttp3_ksl_it nghttp3_ksl_end(const nghttp3_ksl *ksl);
251 
252 /*
253  * nghttp3_ksl_len returns the number of elements stored in |ksl|.
254  */
255 size_t nghttp3_ksl_len(nghttp3_ksl *ksl);
256 
257 /*
258  * nghttp3_ksl_clear removes all elements stored in |ksl|.
259  */
260 void nghttp3_ksl_clear(nghttp3_ksl *ksl);
261 
262 /*
263  * nghttp3_ksl_nth_node returns the |n|th node under |blk|.
264  */
265 #define nghttp3_ksl_nth_node(KSL, BLK, N)                                      \
266   ((nghttp3_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N)))
267 
268 /*
269  * nghttp3_ksl_print prints its internal state in stderr.  It assumes
270  * that the key is of type int64_t.  This function should be used for
271  * the debugging purpose only.
272  */
273 void nghttp3_ksl_print(nghttp3_ksl *ksl);
274 
275 /*
276  * nghttp3_ksl_it_init initializes |it|.
277  */
278 void nghttp3_ksl_it_init(nghttp3_ksl_it *it, const nghttp3_ksl *ksl,
279                          nghttp3_ksl_blk *blk, size_t i);
280 
281 /*
282  * nghttp3_ksl_it_get returns the data associated to the node which
283  * |it| points to.  It is undefined to call this function when
284  * nghttp3_ksl_it_end(it) returns nonzero.
285  */
286 #define nghttp3_ksl_it_get(IT)                                                 \
287   nghttp3_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->data
288 
289 /*
290  * nghttp3_ksl_it_next advances the iterator by one.  It is undefined
291  * if this function is called when nghttp3_ksl_it_end(it) returns
292  * nonzero.
293  */
294 #define nghttp3_ksl_it_next(IT)                                                \
295   (++(IT)->i == (IT)->blk->n && (IT)->blk->next                                \
296        ? ((IT)->blk = (IT)->blk->next, (IT)->i = 0)                            \
297        : 0)
298 
299 /*
300  * nghttp3_ksl_it_prev moves backward the iterator by one.  It is
301  * undefined if this function is called when nghttp3_ksl_it_begin(it)
302  * returns nonzero.
303  */
304 void nghttp3_ksl_it_prev(nghttp3_ksl_it *it);
305 
306 /*
307  * nghttp3_ksl_it_end returns nonzero if |it| points to the beyond the
308  * last node.
309  */
310 #define nghttp3_ksl_it_end(IT)                                                 \
311   ((IT)->blk->n == (IT)->i && (IT)->blk->next == NULL)
312 
313 /*
314  * nghttp3_ksl_it_begin returns nonzero if |it| points to the first
315  * node.  |it| might satisfy both nghttp3_ksl_it_begin(&it) and
316  * nghttp3_ksl_it_end(&it) if the skip list has no node.
317  */
318 int nghttp3_ksl_it_begin(const nghttp3_ksl_it *it);
319 
320 /*
321  * nghttp3_ksl_key returns the key of the node which |it| points to.
322  * It is undefined to call this function when nghttp3_ksl_it_end(it)
323  * returns nonzero.
324  */
325 #define nghttp3_ksl_it_key(IT)                                                 \
326   ((nghttp3_ksl_key *)nghttp3_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->key)
327 
328 /*
329  * nghttp3_ksl_range_compar is an implementation of
330  * nghttp3_ksl_compar.  lhs->ptr and rhs->ptr must point to
331  * nghttp3_range object and the function returns nonzero if (const
332  * nghttp3_range *)(lhs->ptr)->begin < (const nghttp3_range
333  * *)(rhs->ptr)->begin.
334  */
335 int nghttp3_ksl_range_compar(const nghttp3_ksl_key *lhs,
336                              const nghttp3_ksl_key *rhs);
337 
338 /*
339  * nghttp3_ksl_range_exclusive_compar is an implementation of
340  * nghttp3_ksl_compar.  lhs->ptr and rhs->ptr must point to
341  * nghttp3_range object and the function returns nonzero if (const
342  * nghttp3_range *)(lhs->ptr)->begin < (const nghttp3_range
343  * *)(rhs->ptr)->begin and the 2 ranges do not intersect.
344  */
345 int nghttp3_ksl_range_exclusive_compar(const nghttp3_ksl_key *lhs,
346                                        const nghttp3_ksl_key *rhs);
347 
348 #endif /* NGHTTP3_KSL_H */
349