• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2020 nghttp2 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 NGHTTP2_KSL_H
27 #define NGHTTP2_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 <nghttp2/nghttp2.h>
36 
37 /*
38  * Skip List using single key instead of range.
39  */
40 
41 #define NGHTTP2_KSL_DEGR 16
42 /* NGHTTP2_KSL_MAX_NBLK is the maximum number of nodes which a single
43    block can contain. */
44 #define NGHTTP2_KSL_MAX_NBLK (2 * NGHTTP2_KSL_DEGR - 1)
45 /* NGHTTP2_KSL_MIN_NBLK is the minimum number of nodes which a single
46    block other than root must contains. */
47 #define NGHTTP2_KSL_MIN_NBLK (NGHTTP2_KSL_DEGR - 1)
48 
49 /*
50  * nghttp2_ksl_key represents key in nghttp2_ksl.
51  */
52 typedef void nghttp2_ksl_key;
53 
54 struct nghttp2_ksl_node;
55 typedef struct nghttp2_ksl_node nghttp2_ksl_node;
56 
57 struct nghttp2_ksl_blk;
58 typedef struct nghttp2_ksl_blk nghttp2_ksl_blk;
59 
60 /*
61  * nghttp2_ksl_node is a node which contains either nghttp2_ksl_blk or
62  * opaque data.  If a node is an internal node, it contains
63  * nghttp2_ksl_blk.  Otherwise, it has data.  The key is stored at the
64  * location starting at key.
65  */
66 struct nghttp2_ksl_node {
67   union {
68     nghttp2_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 nghttp2_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  * nghttp2_ksl_blk contains nghttp2_ksl_node objects.
83  */
84 struct nghttp2_ksl_blk {
85   /* next points to the next block if leaf field is nonzero. */
86   nghttp2_ksl_blk *next;
87   /* prev points to the previous block if leaf field is nonzero. */
88   nghttp2_ksl_blk *prev;
89   /* n is the number of nodes this object contains in nodes. */
90   size_t n;
91   /* leaf is nonzero if this block contains leaf nodes. */
92   int leaf;
93   union {
94     uint64_t align;
95     /* nodes is a buffer to contain NGHTTP2_KSL_MAX_NBLK
96        nghttp2_ksl_node objects.  Because nghttp2_ksl_node object is
97        allocated along with the additional variable length key
98        storage, the size of buffer is unknown until nghttp2_ksl_init is
99        called. */
100     uint8_t nodes[1];
101   };
102 };
103 
104 /*
105  * nghttp2_ksl_compar is a function type which returns nonzero if key
106  * |lhs| should be placed before |rhs|.  It returns 0 otherwise.
107  */
108 typedef int (*nghttp2_ksl_compar)(const nghttp2_ksl_key *lhs,
109                                   const nghttp2_ksl_key *rhs);
110 
111 struct nghttp2_ksl;
112 typedef struct nghttp2_ksl nghttp2_ksl;
113 
114 struct nghttp2_ksl_it;
115 typedef struct nghttp2_ksl_it nghttp2_ksl_it;
116 
117 /*
118  * nghttp2_ksl_it is a forward iterator to iterate nodes.
119  */
120 struct nghttp2_ksl_it {
121   const nghttp2_ksl *ksl;
122   nghttp2_ksl_blk *blk;
123   size_t i;
124 };
125 
126 /*
127  * nghttp2_ksl is a deterministic paged skip list.
128  */
129 struct nghttp2_ksl {
130   /* head points to the root block. */
131   nghttp2_ksl_blk *head;
132   /* front points to the first leaf block. */
133   nghttp2_ksl_blk *front;
134   /* back points to the last leaf block. */
135   nghttp2_ksl_blk *back;
136   nghttp2_ksl_compar compar;
137   size_t n;
138   /* keylen is the size of key */
139   size_t keylen;
140   /* nodelen is the actual size of nghttp2_ksl_node including key
141      storage. */
142   size_t nodelen;
143   nghttp2_mem *mem;
144 };
145 
146 /*
147  * nghttp2_ksl_init initializes |ksl|.  |compar| specifies compare
148  * function.  |keylen| is the length of key.
149  *
150  * It returns 0 if it succeeds, or one of the following negative error
151  * codes:
152  *
153  * NGHTTP2_ERR_NOMEM
154  *   Out of memory.
155  */
156 int nghttp2_ksl_init(nghttp2_ksl *ksl, nghttp2_ksl_compar compar, size_t keylen,
157                      nghttp2_mem *mem);
158 
159 /*
160  * nghttp2_ksl_free frees resources allocated for |ksl|.  If |ksl| is
161  * NULL, this function does nothing.  It does not free the memory
162  * region pointed by |ksl| itself.
163  */
164 void nghttp2_ksl_free(nghttp2_ksl *ksl);
165 
166 /*
167  * nghttp2_ksl_insert inserts |key| with its associated |data|.  On
168  * successful insertion, the iterator points to the inserted node is
169  * stored in |*it|.
170  *
171  * This function returns 0 if it succeeds, or one of the following
172  * negative error codes:
173  *
174  * NGHTTP2_ERR_NOMEM
175  *   Out of memory.
176  * NGHTTP2_ERR_INVALID_ARGUMENT
177  *   |key| already exists.
178  */
179 int nghttp2_ksl_insert(nghttp2_ksl *ksl, nghttp2_ksl_it *it,
180                        const nghttp2_ksl_key *key, void *data);
181 
182 /*
183  * nghttp2_ksl_remove removes the |key| from |ksl|.
184  *
185  * This function assigns the iterator to |*it|, which points to the
186  * node which is located at the right next of the removed node if |it|
187  * is not NULL.  If |key| is not found, no deletion takes place and
188  * the return value of nghttp2_ksl_end(ksl) is assigned to |*it|.
189  *
190  * This function returns 0 if it succeeds, or one of the following
191  * negative error codes:
192  *
193  * NGHTTP2_ERR_INVALID_ARGUMENT
194  *   |key| does not exist.
195  */
196 int nghttp2_ksl_remove(nghttp2_ksl *ksl, nghttp2_ksl_it *it,
197                        const nghttp2_ksl_key *key);
198 
199 /*
200  * nghttp2_ksl_lower_bound returns the iterator which points to the
201  * first node which has the key which is equal to |key| or the last
202  * node which satisfies !compar(&node->key, key).  If there is no such
203  * node, it returns the iterator which satisfies nghttp2_ksl_it_end(it)
204  * != 0.
205  */
206 nghttp2_ksl_it nghttp2_ksl_lower_bound(nghttp2_ksl *ksl,
207                                        const nghttp2_ksl_key *key);
208 
209 /*
210  * nghttp2_ksl_lower_bound_compar works like nghttp2_ksl_lower_bound,
211  * but it takes custom function |compar| to do lower bound search.
212  */
213 nghttp2_ksl_it nghttp2_ksl_lower_bound_compar(nghttp2_ksl *ksl,
214                                               const nghttp2_ksl_key *key,
215                                               nghttp2_ksl_compar compar);
216 
217 /*
218  * nghttp2_ksl_update_key replaces the key of nodes which has |old_key|
219  * with |new_key|.  |new_key| must be strictly greater than the
220  * previous node and strictly smaller than the next node.
221  */
222 void nghttp2_ksl_update_key(nghttp2_ksl *ksl, const nghttp2_ksl_key *old_key,
223                             const nghttp2_ksl_key *new_key);
224 
225 /*
226  * nghttp2_ksl_begin returns the iterator which points to the first
227  * node.  If there is no node in |ksl|, it returns the iterator which
228  * satisfies nghttp2_ksl_it_end(it) != 0.
229  */
230 nghttp2_ksl_it nghttp2_ksl_begin(const nghttp2_ksl *ksl);
231 
232 /*
233  * nghttp2_ksl_end returns the iterator which points to the node
234  * following the last node.  The returned object satisfies
235  * nghttp2_ksl_it_end().  If there is no node in |ksl|, it returns the
236  * iterator which satisfies nghttp2_ksl_it_begin(it) != 0.
237  */
238 nghttp2_ksl_it nghttp2_ksl_end(const nghttp2_ksl *ksl);
239 
240 /*
241  * nghttp2_ksl_len returns the number of elements stored in |ksl|.
242  */
243 size_t nghttp2_ksl_len(nghttp2_ksl *ksl);
244 
245 /*
246  * nghttp2_ksl_clear removes all elements stored in |ksl|.
247  */
248 void nghttp2_ksl_clear(nghttp2_ksl *ksl);
249 
250 /*
251  * nghttp2_ksl_nth_node returns the |n|th node under |blk|.
252  */
253 #define nghttp2_ksl_nth_node(KSL, BLK, N)                                      \
254   ((nghttp2_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N)))
255 
256 /*
257  * nghttp2_ksl_print prints its internal state in stderr.  It assumes
258  * that the key is of type int64_t.  This function should be used for
259  * the debugging purpose only.
260  */
261 void nghttp2_ksl_print(nghttp2_ksl *ksl);
262 
263 /*
264  * nghttp2_ksl_it_init initializes |it|.
265  */
266 void nghttp2_ksl_it_init(nghttp2_ksl_it *it, const nghttp2_ksl *ksl,
267                          nghttp2_ksl_blk *blk, size_t i);
268 
269 /*
270  * nghttp2_ksl_it_get returns the data associated to the node which
271  * |it| points to.  It is undefined to call this function when
272  * nghttp2_ksl_it_end(it) returns nonzero.
273  */
274 void *nghttp2_ksl_it_get(const nghttp2_ksl_it *it);
275 
276 /*
277  * nghttp2_ksl_it_next advances the iterator by one.  It is undefined
278  * if this function is called when nghttp2_ksl_it_end(it) returns
279  * nonzero.
280  */
281 #define nghttp2_ksl_it_next(IT)                                                \
282   (++(IT)->i == (IT)->blk->n && (IT)->blk->next                                \
283        ? ((IT)->blk = (IT)->blk->next, (IT)->i = 0)                            \
284        : 0)
285 
286 /*
287  * nghttp2_ksl_it_prev moves backward the iterator by one.  It is
288  * undefined if this function is called when nghttp2_ksl_it_begin(it)
289  * returns nonzero.
290  */
291 void nghttp2_ksl_it_prev(nghttp2_ksl_it *it);
292 
293 /*
294  * nghttp2_ksl_it_end returns nonzero if |it| points to the beyond the
295  * last node.
296  */
297 #define nghttp2_ksl_it_end(IT)                                                 \
298   ((IT)->blk->n == (IT)->i && (IT)->blk->next == NULL)
299 
300 /*
301  * nghttp2_ksl_it_begin returns nonzero if |it| points to the first
302  * node.  |it| might satisfy both nghttp2_ksl_it_begin(&it) and
303  * nghttp2_ksl_it_end(&it) if the skip list has no node.
304  */
305 int nghttp2_ksl_it_begin(const nghttp2_ksl_it *it);
306 
307 /*
308  * nghttp2_ksl_key returns the key of the node which |it| points to.
309  * It is undefined to call this function when nghttp2_ksl_it_end(it)
310  * returns nonzero.
311  */
312 #define nghttp2_ksl_it_key(IT)                                                 \
313   ((nghttp2_ksl_key *)nghttp2_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->key)
314 
315 #endif /* NGHTTP2_KSL_H */
316