// Fraser's SkipList Algorithm inline void fraser_search(sl_intset_t *set, uint32_t val, sl_node_t **left_list, sl_node_t **right_list) { int i; sl_node_t *left, *left_next, *right, *right_next; retry: left = set->head; for (i = LEVELMAX - 1; i >= 0; i--) { left_next = left->nexts[i]; if (is_marked((uint32_t)left_next)) goto retry; /* Find unmarked node pair at this level */ for (right = left_next; ; right = right_next) { /* Skip a sequence of marked nodes */ while(1) { right_next = right->nexts[i]; if (!is_marked((uint32_t)right_next)) break; right = (sl_node_t*)unset_mark((uint32_t)right_next); } if (right->val >= val) break; left = right; left_next = right_next; } /* Ensure left and right nodes are adjacent */ if ((left_next != right) && (!ATOMIC_CAS_MB(&left->nexts[i], left_next, right))) goto retry; if (left_list != NULL) left_list[i] = left; if (right_list != NULL) right_list[i] = right; } }
/* * [lyj] Disable the interpretation of "deleted" field. */ void fraser_insert(sl_intset_t *set, uint32_t v, bool lin) { sl_node_t *NEW, *new_next, *pred, *succ, *succs[LEVELMAX], *preds[LEVELMAX]; uint32_t i; uint32_t status; // uint32_t attempts = 0; NEW = sl_new_simple_node(v, get_rand_level(), lin); retry: fraser_search(set, v, preds, succs); for (i = 0; i < NEW->toplevel; i++) NEW->nexts[i] = succs[i]; /* Node is visible once inserted at lowest level */ if (!ATOMIC_CAS_MB(&preds[0]->nexts[0], succs[0], NEW)) goto retry; //retry_HTM: status = _xbegin(); if(status == _XBEGIN_STARTED) { for (i = 1; i < NEW->toplevel; i++) { if(preds[i]->nexts[i] == succs[i]) preds[i]->nexts[i] = NEW; else _xabort(66); } _xend(); return; }/*else { if ((status & _XABORT_EXPLICIT) && _XABORT_CODE(status) == 66) { } else if (++attempts < MAX_ATTEMPT_NUM) { goto retry_HTM; } }*/ for (i = 1; i < NEW->toplevel; i++) { while (1) { pred = preds[i]; succ = succs[i]; /* Update the forward pointer if it is stale */ new_next = NEW->nexts[i]; if ((new_next != succ) && (!ATOMIC_CAS_MB(&NEW->nexts[i], unset_mark((uint32_t)new_next), succ))) break; /* Give up if pointer is marked */ /* We retry the search if the CAS fails */ if (ATOMIC_CAS_MB(&pred->nexts[i], succ, NEW)) break; fraser_search(set, v, preds, succs); } } }
int fraser_search(sl_intset_t *set, skey_t key, sl_node_t **left_list, sl_node_t **right_list) { int i; sl_node_t *left, *left_next, *right = NULL, *right_next; retry: PARSE_TRY(); left = set->head; for (i = levelmax - 1; i >= 0; i--) { left_next = left->next[i]; if ((is_marked((uintptr_t)left_next))) { goto retry; } /* Find unmarked node pair at this level */ for (right = left_next; ; right = right_next) { /* Skip a sequence of marked nodes */ right_next = right->next[i]; while ((is_marked((uintptr_t)right_next))) { right = (sl_node_t*)unset_mark((uintptr_t)right_next); right_next = right->next[i]; } if (right->key >= key) { break; } left = right; left_next = right_next; } /* Ensure left and right nodes are adjacent */ if ((left_next != right) && (!ATOMIC_CAS_MB(&left->next[i], left_next, right))) { goto retry; } if (left_list != NULL) { left_list[i] = left; } if (right_list != NULL) { right_list[i] = right; } } return (right->key == key); }
void fraser_search(sl_intset_t *set, val_t val, sl_node_t **left_list, sl_node_t **right_list) { int i; sl_node_t *left, *left_next, *right, *right_next; #ifdef DEBUG printf("++> fraser_search\n"); IO_FLUSH; #endif retry: left = set->head; for (i = levelmax - 1; i >= 0; i--) { left_next = left->next[i]; if (is_marked((uintptr_t)left_next)) goto retry; /* Find unmarked node pair at this level */ for (right = left_next; ; right = right_next) { /* Skip a sequence of marked nodes */ while(1) { right_next = right->next[i]; if (!is_marked((uintptr_t)right_next)) break; right = (sl_node_t*)unset_mark((uintptr_t)right_next); } if (right->val >= val) break; left = right; left_next = right_next; } /* Ensure left and right nodes are adjacent */ if ((left_next != right) && (!ATOMIC_CAS_MB(&left->next[i], left_next, right))) goto retry; if (left_list != NULL) left_list[i] = left; if (right_list != NULL) right_list[i] = right; } #ifdef DEBUG printf("++> fraser_search ends\n"); IO_FLUSH; #endif }
int naive_delete_min(sl_intset_t *set, val_t *val, thread_data_t *d) { sl_node_t *first; int result; first = set->head; while(1) { do { first = (sl_node_t*)unset_mark((uintptr_t)first->next[0]); } while(first->next[0] && first->deleted); if (ATOMIC_FETCH_AND_INC_FULL(&first->deleted) != 0) { d->nb_collisions++; } else { break; } } result = (first->next[0] != NULL); if (!result) { return 1; } *val = (first->val); mark_node_ptrs(first); // unsigned int *seed = &d->seed2; // *seed = _MarsagliaXOR(*seed); // if (*seed % (d->nb_threads) == 0) { // fraser_search(set, first->val, NULL, NULL); // } if (!first->next[0]->deleted) fraser_search(set, first->val, NULL, NULL); return result; }
inline val_t get_val(sl_node_t *n) { return ((sl_node_t *)unset_mark((uintptr_t)n))->val; }
int spray_delete_min(sl_intset_t *set, val_t *val, thread_data_t *d) { unsigned int n = d->nb_threads; unsigned int *seed = &d->seed2; #ifndef DISTRIBUTION_EXPERIMENT *seed = _MarsagliaXOR(*seed); if (n == 1 || *seed % n/*/floor_log_2(n)*/ == 0) { // n == 1 is equivalent to naive delete_min d->nb_clean++; return naive_delete_min(set, val, d); } #endif sl_node_t *cur; int result; int scanlen; int height = SCANHEIGHT; int scanmax = SCANMAX; int scan_inc = SCANINC; cur = set->head; int i = height; int dummy = 0; while(1) { *seed = _MarsagliaXOR(*seed); scanlen = *seed % (scanmax+1); while (dummy < n*floor_log_2(n)/2 && scanlen > 0) { dummy += (1 << i); scanlen--; } while (scanlen > 0 && cur->next[i]) { // Step right //here: cur->next[0], or cur->next[i]?? cur = (sl_node_t*)unset_mark((uintptr_t)cur->next[i]); if (!cur->deleted) scanlen--; } // TODO: This is probably a reasonable condition to become a 'cleaner' since the list is so small // We can also just ignore it since it shouldn't happen in benchmarks? if (!cur->next[0]) return 0; //got to end of list scanmax += scan_inc; if (i == 0) break; if (i <= SCANSKIP) { i = 0; continue; } // need to guarantee bottom level gets scanned i -= SCANSKIP; } if (cur == set->head) // still in dummy range return 0; // TODO: clean instead? something else? while (cur->deleted && cur->next[0]) { cur = (sl_node_t*)unset_mark((uintptr_t)cur->next[0]); // Find first non-deleted node } if (!cur->next[0]) return 0; #ifdef DISTRIBUTION_EXPERIMENT *val = (cur->val); return 1; #endif result = 1; if (cur->deleted == 0 ) { result = ATOMIC_FETCH_AND_INC_FULL(&cur->deleted); } if (result != 0) { d->nb_collisions++; return 0; // TODO: Retry and eventually 'clean' } *val = (cur->val); mark_node_ptrs(cur); // if (((*seed) & 0x10)) return 1; // TODO: batch deletes (this method is somewhat inefficient) // fraser_search(set, cur->val, NULL, NULL); return 1; }
long get_unmarked_ref(long w) { return unset_mark(w); }
long set_mark(long i) { i = unset_mark(i); i += 1; return i; }