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