1/**
2 * \file
3 * \brief Skip list implementation used for attribute index.
4 */
5
6/*
7 * Copyright (c) 2011, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <assert.h>
19
20#include <barrelfish/barrelfish.h>
21
22#include "skiplist.h"
23
24#define SKIP_LEVEL_PROBABILITY 0.5
25// With probability 0.5 use log2(n) as MAX_LEVEL (n = amount of elements
26// to be expected for index). 2**14 = 16384
27#define MAX_LEVEL 14
28
29
30/**
31 * \brief This code reads the cycle counter
32 *
33 * We use this to get some randomness for the skip list algorithm.
34 **/
35static inline uint64_t get_cycle_counter(void)
36{
37#if defined(__x86_64__)
38    uint32_t eax, edx;
39    __asm volatile ("rdtsc" : "=a" (eax), "=d" (edx));
40    return ((uint64_t)edx << 32) | eax;
41#else
42    return 0xdead;
43#endif
44}
45
46/**
47 * \brief Random number generator
48 *
49 * Pseudo-random number generator using Multiply-with-carry
50 * method invented by George Marsaglia.
51 *
52 * \note This is a hack since posixcompat random does not seem
53 * to work properly.
54 */
55static uint32_t my_random(void)
56{
57    static bool seeded = false;
58    static uint32_t m_z = 0xdeadbeef;
59    static uint32_t m_w = 0;
60    if (!seeded) {
61        m_w = (uint32_t) get_cycle_counter();
62        seeded = true;
63    }
64
65    m_z = 36969 * (m_z & 65535) + (m_z >> 16);
66    m_w = 18000 * (m_w & 65535) + (m_w >> 16);
67
68    return (m_z << 16) + m_w;  // 32-bit result
69}
70
71/**
72 * \return Random number between [0.0, 1.0]
73 */
74static inline float frand(void)
75{
76    return ((float) (my_random() & 0xffffffff)) / 0xffffffff;
77}
78
79/**
80 * \brief Generates a random level number.
81 *
82 * Distribution (hopefully) for returned value:
83 * 0 => 50%
84 * 1 => 25%
85 * 2 => 12.5%
86 * ...
87 *
88 * \return A random number between 0 and MAX_LEVEL
89 */
90static inline size_t random_level(void)
91{
92    size_t level = 0;
93    while(frand() < SKIP_LEVEL_PROBABILITY && level < MAX_LEVEL) {
94        level++;
95    }
96
97    return level;
98}
99
100/**
101 * \brief Create a new skip list element.
102 */
103static errval_t new_node(struct skip_node** sn, void* element, size_t level)
104{
105    *sn = malloc(sizeof(struct skip_node));
106    if (*sn == NULL) {
107        return LIB_ERR_MALLOC_FAIL;
108    }
109
110    (*sn)->forward = calloc(level+1, sizeof(struct skip_node*));
111    if ((*sn)->forward == NULL) {
112        free(*sn);
113        *sn = NULL;
114
115        return LIB_ERR_MALLOC_FAIL;
116    }
117
118    (*sn)->element = element;
119
120    return SYS_ERR_OK;
121}
122
123/**
124 * \brief Create a skip set.
125 */
126errval_t skip_create_list(struct skip_list** ss)
127{
128    *ss = malloc(sizeof(struct skip_list));
129    if (*ss == NULL) {
130        return LIB_ERR_MALLOC_FAIL;
131    }
132
133    errval_t err = new_node(&(*ss)->header, NULL, MAX_LEVEL);
134    if (err_is_ok(err)) {
135        (*ss)->level = 0;
136        (*ss)->entries = 0;
137    }
138    else {
139        free(*ss);
140    }
141
142    return err;
143}
144
145/**
146 * \brief Print elements in set.
147 *
148 * Used for debugging.
149 */
150void skip_print_list(struct skip_list* ss)
151{
152    struct skip_node* cur = ss->header->forward[0];
153
154    printf("{");
155    while(cur != NULL) {
156        printf("%s", cur->element);
157        cur = cur->forward[0];
158        if(cur != NULL)
159            printf(",");
160    }
161
162    printf("}\n");
163}
164
165/**
166 * \brief Checks if a element is in the list.
167 *
168 * \param ss Skip list
169 * \param elem The element to find.
170 *
171 * \retval true Element found.
172 * \retval false Element not found.
173 */
174bool skip_contains(struct skip_list* ss, char* elem) {
175    assert(ss != NULL);
176    assert(elem != NULL);
177
178    struct skip_node* cur = ss->header;
179    for (int64_t i = ss->level; i >= 0; i--) {
180        while(cur->forward[i] != NULL && strcmp(cur->forward[i]->element, elem) < 0) {
181            cur = cur->forward[i];
182        }
183    }
184    cur = cur->forward[0];
185
186
187    if (cur != NULL && strcmp(cur->element, elem) == 0) {
188        return true;
189    }
190
191    return false;
192}
193
194/**
195 * \brief Insert element in list.
196 *
197 * \note The skip list is actually a set. So
198 * duplicates will be ignored.
199 *
200 * \param ss The list where we insert.
201 * \param to_insert The element we'd like to insert.
202 */
203void skip_insert(struct skip_list* ss, char* to_insert) {
204    assert(to_insert != NULL);
205
206    struct skip_node* cur = ss->header;
207    struct skip_node* update[MAX_LEVEL + 1] = { NULL };
208
209    // Find element in table and save previous pointer which
210    // needs to be modified on all levels
211    for(int64_t i = ss->level; i >= 0; i--) {
212        while(cur->forward[i] != NULL && strcmp(cur->forward[i]->element, to_insert) < 0) {
213            cur = cur->forward[i];
214        }
215        update[i] = cur;
216    }
217    cur = cur->forward[0];
218
219    // Need to insert a new node in list
220    if(cur == NULL || strcmp(cur->element, to_insert) != 0) {
221        size_t level = random_level();
222        // In case we hit a new level cap, make sure to update
223        // the header node
224        if(level > ss->level) {
225            for(size_t i = ss->level+1; i <= level; i++) {
226                update[i] = ss->header;
227            }
228            ss->level = level;
229        }
230
231        // Insert new node
232        errval_t err = new_node(&cur, to_insert, level);
233        assert(err_is_ok(err)); // XXX
234
235        // update next & prev pointer
236        for(size_t i=0; i <= level; i++) {
237            cur->forward[i] = update[i]->forward[i];
238            update[i]->forward[i] = cur;
239        }
240
241        ss->entries++; // maintain list count
242    }
243}
244
245/**
246 * \brief Remoeves an element for the skip list.
247 *
248 * \param ss List to search for the element.
249 * \param to_delete The element to remove.
250 */
251char* skip_delete(struct skip_list* ss, char* to_delete) {
252    struct skip_node* cur = ss->header;
253    struct skip_node* update[MAX_LEVEL + 1] = { NULL };
254
255    for(int64_t i = ss->level; i >= 0; i--) {
256        while(cur->forward[i] != NULL && strcmp(cur->forward[i]->element, to_delete) < 0) {
257            cur = cur->forward[i];
258        }
259        update[i] = cur;
260    }
261    cur = cur->forward[0];
262
263    if(strcmp(cur->element, to_delete) == 0) {
264        // update prev->next pointer
265        for(size_t i=0; i <= ss->level; i++) {
266            if(update[i]->forward[i] != cur)
267                break;
268            update[i]->forward[i] = cur->forward[i];
269        }
270        char* to_return = cur->element;
271        free(cur->forward);
272        free(cur);
273
274        while(ss->level > 0 && ss->header->forward[ss->level] == NULL) {
275            ss->level--;
276        }
277
278        ss->entries--;
279        return to_return;
280    }
281
282    return NULL; // element not found
283}
284
285static int compare_entry_count(const void* s1, const void* s2) {
286
287    struct skip_list* list1 = *(struct skip_list* const*) s1;
288    struct skip_list* list2 = *(struct skip_list* const*) s2;
289
290    return list1->entries - list2->entries;
291}
292
293/**
294 * \brief Compute the intersection of multiple sets on-the-fly by
295 * repeated calls to this function.
296 *
297 * \param sets Array of pointer to the lists we want to intersect.
298 * \param set_count How many lists we want to intersect.
299 * \param next Null in case we want to start a fresh intersect
300 * computation. Otherwise provide the last returned element
301 * here to continue computing subsequent intersection elements.
302 *
303 */
304char* skip_intersect(struct skip_list** sets, size_t set_count, char* next)
305{
306    static struct skip_node** state = NULL;
307    if (next == NULL) {
308        free(state);
309        state = calloc(set_count, sizeof(struct skip_node*));
310
311        // Improvement: Sort skip lists based on their amount of stored elements
312        // saves some time doing actual intersection in case
313        // the first lists have the most entries...
314        qsort(sets, set_count, sizeof(struct skip_list*), compare_entry_count);
315
316        for (size_t i = 0; i < set_count; i++) {
317            state[i] = sets[i]->header;
318        }
319    }
320
321    char* to_intersect = NULL;
322    while(state[0]->forward[0] != NULL) {
323        to_intersect = state[0]->forward[0]->element;
324
325        // Check if to_intersect is contained in all other lists
326        for (size_t j=1; j < set_count; j++) {
327            struct skip_list* set = sets[j];
328            struct skip_node* cur = state[j];
329
330            for(int64_t k = set->level; k >= 0; k--) {
331                while(cur->forward[k] != NULL && strcmp(cur->forward[k]->element, to_intersect) < 0) {
332                    cur = cur->forward[k];
333                }
334            }
335            cur = cur->forward[0];
336
337            if (cur == NULL) {
338                // reached the end of a list no more intersections possible
339                goto no_more_possible;
340            }
341            else if (strcmp(cur->element, to_intersect) != 0) {
342                // no match, continue with next element
343                to_intersect = NULL;
344                break;
345            }
346            else {
347                // continue checking other sets
348            }
349        }
350
351        state[0] = state[0]->forward[0];
352        if (to_intersect != NULL) {
353            // we found a intersection
354            return to_intersect;
355        }
356    }
357
358
359no_more_possible:
360    return NULL;
361}
362
363#ifdef TEST_SKIPLIST
364int main() {
365
366    struct skip_set* ss = NULL;
367    errval_t err = make_skipset(&ss);
368    insert(ss, "a");
369    insert(ss, "c");
370    insert(ss, "b");
371    insert(ss, "d");
372    insert(ss, "aaa");
373
374    struct skip_set* ss2 = NULL;
375    err = make_skipset(&ss2);
376    insert(ss2, "a");
377    insert(ss2, "c");
378    insert(ss2, "x");
379    insert(ss2, "wer");
380    insert(ss2, "12312");
381    insert(ss2, "aaa");
382
383    struct skip_set* ss3 = NULL;
384    err = make_skipset(&ss3);
385    insert(ss3, "asdf");
386    insert(ss3, "c");
387    insert(ss3, "x");
388    insert(ss3, "wer");
389    insert(ss3, "12312");
390    insert(ss3, "aa");
391
392    struct skip_set* sets[3] = { ss, ss2, ss3 };
393
394    char* next = NULL;
395    while( (next = skip_intersect(sets, 3, next)) != NULL) {
396       printf("next is:%s\n", next);
397    }
398
399    while( (next = skip_intersect(sets, 3, next)) != NULL) {
400       printf("next is:%s\n", next);
401    }
402
403    return 0;
404}
405#endif
406