]> pd.if.org Git - nbds/blob - map/unsafe_skiplist.c
add perf test driver
[nbds] / map / unsafe_skiplist.c
1 /* 
2  * Written by Josh Dybnis and released to the public domain, as explained at
3  * http://creativecommons.org/licenses/publicdomain
4  *
5  * non thread safe skiplist
6  */
7
8 #include <stdio.h>
9 #include <string.h>
10
11 #include "common.h"
12 #include "skiplist.h"
13 #include "runtime.h"
14 #include "mem.h"
15
16 #define MAX_LEVEL 31
17
18 typedef struct node {
19     map_key_t key;
20     map_val_t val;
21     int top_level;
22     struct node *next[1];
23 } node_t;
24
25 struct sl_iter {
26     node_t *next;
27 };
28
29 struct sl {
30     node_t *head;
31     const datatype_t *key_type;
32     int high_water; // max level of any item in the list
33 };
34
35 static int random_level (void) {
36     unsigned r = nbd_rand();
37     int n = __builtin_ctz(r) / 2;
38     if (n > MAX_LEVEL) { n = MAX_LEVEL; }
39     return n;
40 }
41
42 static node_t *node_alloc (int level, map_key_t key, map_val_t val) {
43     assert(level >= 0 && level <= MAX_LEVEL);
44     size_t sz = sizeof(node_t) + level * sizeof(node_t *);
45     node_t *item = (node_t *)nbd_malloc(sz);
46     memset(item, 0, sz);
47     item->key = key;
48     item->val = val;
49     item->top_level = level;
50     TRACE("s2", "node_alloc: new node %p (%llu levels)", item, level);
51     return item;
52 }
53
54 skiplist_t *sl_alloc (const datatype_t *key_type) {
55     skiplist_t *sl = (skiplist_t *)nbd_malloc(sizeof(skiplist_t));
56     sl->key_type = key_type;
57     sl->high_water = 0;
58     sl->head = node_alloc(MAX_LEVEL, 0, 0);
59     memset(sl->head->next, 0, (MAX_LEVEL+1) * sizeof(skiplist_t *));
60     return sl;
61 }
62
63 void sl_free (skiplist_t *sl) {
64     node_t *item = sl->head->next[0];
65     while (item) {
66         node_t *next = item->next[0];
67         if (sl->key_type != NULL) {
68             nbd_free((void *)item->key);
69         }
70         nbd_free(item);
71         item = next;
72     }
73 }
74
75 size_t sl_count (skiplist_t *sl) {
76     size_t count = 0;
77     node_t *item = sl->head->next[0];
78     while (item) {
79         count++;
80         item = item->next[0];
81     }
82     return count;
83 }
84
85 static node_t *find_preds (node_t **preds, node_t **succs, int n, skiplist_t *sl, map_key_t key, int help_remove) {
86     node_t *pred = sl->head;
87     node_t *item = NULL;
88     TRACE("s2", "find_preds: searching for key %p in skiplist (head is %p)", key, pred);
89     int d = 0;
90     int start_level = sl->high_water;
91     if (EXPECT_FALSE(start_level < n)) {
92         start_level = n;
93     }
94
95     // Traverse the levels of <sl> from the top level to the bottom
96     for (int level = start_level; level >= 0; --level) {
97         node_t *next = pred->next[level];
98         if (next == DOES_NOT_EXIST && level > n)
99             continue;
100         TRACE("s3", "find_preds: traversing level %p starting at %p", level, pred);
101         item = next;
102         while (item != NULL) {
103             next = item->next[level];
104
105             if (EXPECT_TRUE(sl->key_type == NULL)) {
106                 d = item->key - key;
107             } else {
108                 d = sl->key_type->cmp((void *)item->key, (void *)key);
109             }
110
111             if (d >= 0)
112                 break;
113
114             pred = item;
115             item = next;
116         }
117
118         TRACE("s3", "find_preds: found pred %p next %p", pred, item);
119
120         // The cast to unsigned is for the case when n is -1.
121         if ((unsigned)level <= (unsigned)n) { 
122             if (preds != NULL) {
123                 preds[level] = pred;
124             }
125             if (succs != NULL) {
126                 succs[level] = item;
127             }
128         }
129     }
130
131     // fill in empty levels
132     if (n == -1 && item != NULL && preds != NULL) {
133         assert(item->top_level <= MAX_LEVEL);
134         for (int level = start_level + 1; level <= item->top_level; ++level) {
135             preds[level] = sl->head;
136         }
137     }
138
139     if (d == 0) {
140         TRACE("s2", "find_preds: found matching item %p in skiplist, pred is %p", item, pred);
141         return item;
142     }
143     TRACE("s2", "find_preds: found proper place for key %p in skiplist, pred is %p. returning null", key, pred);
144     return NULL;
145 }
146
147 static void sl_unlink (skiplist_t *sl, map_key_t key) {
148     node_t *pred = sl->head;
149     node_t *item = NULL;
150     TRACE("s2", "sl_unlink: unlinking marked item with key %p", key, 0);
151     int d = 0;
152
153     // Traverse the levels of <sl>
154     for (int level = sl->high_water; level >= 0; --level) {
155         node_t *next = pred->next[level];
156         if (next == DOES_NOT_EXIST)
157             continue;
158         TRACE("s3", "sl_unlink: traversing level %p starting at %p", level, pred);
159         item = next;
160         while (item != NULL) {
161             next = item->next[level];
162
163             if (EXPECT_TRUE(sl->key_type == NULL)) {
164                 d = item->key - key;
165             } else {
166                 d = sl->key_type->cmp((void *)item->key, (void *)key);
167             }
168
169             if (d == 0) {
170                 pred->next[level] = next;
171                 TRACE("s3", "sl_unlink: unlinked item from pred %p", pred, 0);
172                 item = next;
173                 next = (item != NULL) ? item->next[level] : DOES_NOT_EXIST;
174                 break;
175             }
176             if (d > 0) 
177                 break;
178
179             pred = item;
180             item = next;
181         }
182
183         TRACE("s3", "sl_unlink: at pred %p next %p", pred, item);
184     }
185 }
186
187 // Fast find that does not return the node's predecessors.
188 map_val_t sl_lookup (skiplist_t *sl, map_key_t key) {
189     TRACE("s1", "sl_lookup: searching for key %p in skiplist %p", key, sl);
190     node_t *item = find_preds(NULL, NULL, 0, sl, key, FALSE);
191
192     // If we found an <item> matching the <key> return its value.
193     if (item != NULL) {
194         map_val_t val = item->val;
195         return val;
196     }
197
198     TRACE("l1", "sl_lookup: no item in the skiplist matched the key", 0, 0);
199     return DOES_NOT_EXIST;
200 }
201
202 map_key_t sl_min_key (skiplist_t *sl) {
203     node_t *item = sl->head->next[0];
204     while (item != NULL)
205         return item->key;
206     return DOES_NOT_EXIST;
207 }
208
209 map_val_t sl_cas (skiplist_t *sl, map_key_t key, map_val_t expectation, map_val_t new_val) {
210     TRACE("s1", "sl_cas: key %p skiplist %p", key, sl);
211     TRACE("s1", "sl_cas: expectation %p new value %p", expectation, new_val);
212     ASSERT((int64_t)new_val > 0);
213
214     node_t *preds[MAX_LEVEL+1];
215     node_t *nexts[MAX_LEVEL+1];
216     node_t *new_item = NULL;
217     int n = random_level();
218     node_t *old_item = find_preds(preds, nexts, n, sl, key, TRUE);
219
220     // If there is already an item in the skiplist that matches the key just update its value.
221     if (old_item != NULL) {
222         map_val_t old_val = old_item->val;
223         if (expectation == CAS_EXPECT_DOES_NOT_EXIST || 
224            (expectation != CAS_EXPECT_WHATEVER && expectation != CAS_EXPECT_EXISTS && expectation != old_val)) {
225             TRACE("s1", "update_item: found an item %p in the skiplist that matched the key. the expectation was "
226                     "not met, the skiplist was not changed", item, old_val);
227             return old_val;
228         } 
229         old_item->val = new_val;
230         return old_val;
231     }
232
233     if (EXPECT_FALSE(expectation != CAS_EXPECT_DOES_NOT_EXIST && expectation != CAS_EXPECT_WHATEVER)) {
234         TRACE("l1", "sl_cas: the expectation was not met, the skiplist was not changed", 0, 0);
235         return DOES_NOT_EXIST; // failure, the caller expected an item for the <key> to already exist 
236     }
237
238     TRACE("s3", "sl_cas: inserting a new item between %p and %p", preds[0], nexts[0]);
239
240     // Create a new node and insert it into the skiplist.
241     map_key_t new_key = sl->key_type == NULL ? key : (map_key_t)sl->key_type->clone((void *)key);
242     if (n > sl->high_water) {
243         n = ++sl->high_water;
244         TRACE("s2", "sl_cas: incremented high water mark to %p", sl->high_water, 0);
245     }
246     new_item = node_alloc(n, new_key, new_val);
247
248     // Set <new_item>'s next pointers to their proper values
249     for (int level = 0; level <= new_item->top_level; ++level) {
250         new_item->next[level] = nexts[level];
251     }
252
253     // Link <new_item> into <sl> 
254     for (int level = 0; level <= new_item->top_level; ++level) {
255         preds[level]->next[level] = new_item;
256     }
257
258     return DOES_NOT_EXIST; // success, inserted a new item
259 }
260
261 map_val_t sl_remove (skiplist_t *sl, map_key_t key) {
262     TRACE("s1", "sl_remove: removing item with key %p from skiplist %p", key, sl);
263     node_t *preds[MAX_LEVEL+1];
264     node_t *item = find_preds(preds, NULL, -1, sl, key, TRUE);
265     if (item == NULL) {
266         TRACE("s3", "sl_remove: remove failed, an item with a matching key does not exist in the skiplist", 0, 0);
267         return DOES_NOT_EXIST;
268     }
269     map_val_t val = item->val; 
270
271     // unlink the item
272     sl_unlink(sl, key);
273
274     // free the node
275     if (sl->key_type != NULL) {
276         nbd_free((void *)item->key);
277     }
278     nbd_free(item);
279
280     return val;
281 }
282
283 void sl_print (skiplist_t *sl) {
284
285     printf("high water: %d levels\n", sl->high_water);
286     for (int level = MAX_LEVEL; level >= 0; --level) {
287         node_t *item = sl->head;
288         if (item->next[level] == DOES_NOT_EXIST)
289             continue;
290         printf("(%d) ", level);
291         int i = 0;
292         while (item) {
293             node_t *next = item->next[level];
294             printf("%p ", item);
295             item = next;
296             if (i++ > 30) {
297                 printf("...");
298                 break;
299             }
300         }
301         printf("\n");
302         fflush(stdout);
303     }
304     node_t *item = sl->head;
305     int i = 0;
306     while (item) {
307         printf("%p:0x%llx ", item, (uint64_t)item->key);
308         if (item != sl->head) {
309             printf("[%d]", item->top_level);
310         } else {
311             printf("[HEAD]");
312         }
313         for (int level = 1; level <= item->top_level; ++level) {
314             node_t *next = item->next[level];
315             printf(" %p", next);
316             if (item == sl->head && item->next[level] == DOES_NOT_EXIST)
317                 break;
318         }
319         printf("\n");
320         fflush(stdout);
321         item = item->next[0];
322         if (i++ > 30) {
323             printf("...\n");
324             break;
325         }
326     }
327 }
328
329 sl_iter_t *sl_iter_begin (skiplist_t *sl, map_key_t key) {
330     sl_iter_t *iter = (sl_iter_t *)nbd_malloc(sizeof(sl_iter_t));
331     if (key != DOES_NOT_EXIST) {
332         find_preds(NULL, &iter->next, 0, sl, key, FALSE);
333     } else {
334         iter->next = sl->head->next[0];
335     }
336     return iter;
337 }
338
339 map_val_t sl_iter_next (sl_iter_t *iter, map_key_t *key_ptr) {
340     assert(iter);
341     node_t *item = iter->next;
342     if (item == NULL) {
343         iter->next = NULL;
344         return DOES_NOT_EXIST;
345     }
346     iter->next = item->next[0];
347     if (key_ptr != NULL) {
348         *key_ptr = item->key;
349     }
350     return item->val;
351 }
352
353 void sl_iter_free (sl_iter_t *iter) {
354     nbd_free(iter);
355 }