Skip to content

Commit

Permalink
ready for another multi-art
Browse files Browse the repository at this point in the history
  • Loading branch information
UncP committed Mar 23, 2019
1 parent b891edd commit fb654b4
Show file tree
Hide file tree
Showing 3 changed files with 429 additions and 230 deletions.
185 changes: 91 additions & 94 deletions art/art.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,116 +36,102 @@ void free_adaptive_radix_tree(adaptive_radix_tree *art)
// return 0 on success,
// return +1 on failure,
// return -1 for retry
static int _adaptive_radix_tree_put(art_node **an, const void *key, size_t len, size_t off, const void *val)
static int _adaptive_radix_tree_put(art_node *parent, art_node **ptr, const void *key, size_t len, size_t off, const void *val)
{
// TODO: val should be packed with key
(void)val;
art_node *cur;
art_node *an;
uint64_t v, v1;
int p;

begin:
// NOTE: __ATOMIC_RELAXED is not ok
__atomic_load(an, &cur, __ATOMIC_ACQUIRE);
__atomic_load(ptr, &an, __ATOMIC_ACQUIRE);

if (unlikely(cur == 0)) {
// this is an empty tree
if (unlikely(an == 0)) {
assert(parent == 0);
art_node *leaf = (art_node *)make_leaf(key);
if (likely(__atomic_compare_exchange_n(an, &cur, leaf, 0 /* weak */, __ATOMIC_RELEASE, __ATOMIC_RELAXED)))
if (likely(__atomic_compare_exchange_n(ptr, &an, leaf, 0 /* weak */, __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)))
return 0;
else
return -1;
}

if (unlikely(is_leaf(cur))) {
const char *k1 = get_leaf_key(cur), *k2 = (const char *)key;
size_t l1 = get_leaf_len(cur), l2 = len, i;
for (i = off; i < l1 && i < l2 && k1[i] == k2[i]; ++i)
;
if (unlikely(i == l1 && i == l2))
return 1; // key exists
art_node *new = new_art_node();
assert(art_node_lock(new) == 0);
// TODO: i - off might be bigger than 8
art_node_set_prefix(new, k1, off, i - off);
off = i;
unsigned char byte;
byte = off == l1 ? 0 : k1[off];
assert(art_node_add_child(&new, byte, cur) == 0);
byte = off == l2 ? 0 : k2[off];
assert(art_node_add_child(&new, byte, (art_node *)make_leaf(k2)) == 0);
art_node_unlock(new);
if (likely(__atomic_compare_exchange_n(an, &cur, new, 0 /* weak */, __ATOMIC_RELEASE, __ATOMIC_RELAXED))) {
return 0;
} else {
free_art_node(new);
return -1;
}
// this is a leaf
if (unlikely(is_leaf(an))) {
int r = art_node_replace_leaf_child(parent, ptr, key, len, off);
if (unlikely(r == -2))
goto begin; // `an` is changed
return r;
}

v = art_node_get_stable_expand_version(cur);
// verify node prefix
v = art_node_get_stable_expand_version(an);
if (art_node_version_is_old(v))
goto begin;

p = art_node_prefix_compare(cur, v, key, len, off);

v1 = art_node_get_version(cur);
p = art_node_prefix_compare(an, v, key, len, off);

v1 = art_node_get_version(an);
if (unlikely(art_node_version_is_old(v1) || art_node_version_compare_expand(v, v1)))
goto begin; // prefix is changing or changed by another thread
goto begin;
v = v1;

if (p != art_node_version_get_prefix_len(v)) {
if (unlikely(art_node_lock(cur)))
goto begin; // node is replaced by a new node
if (unlikely(art_node_version_compare_expand(v, art_node_get_version_unsafe(cur))))
goto begin; // node prefix is changed by another thread
art_node *new = new_art_node();
assert(art_node_lock(new) == 0);
art_node_set_prefix(new, key, off, p);
unsigned char byte;
byte = (off + p < len) ? ((unsigned char *)key)[off + p] : 0;
assert(art_node_add_child(&new, byte, (art_node *)make_leaf(key)) == 0);
byte = art_node_truncate_prefix(cur, p);
assert(art_node_add_child(&new, byte, cur) == 0);
art_node_unlock(new);
__atomic_store(an, &new, __ATOMIC_RELEASE);
art_node_unlock(cur);
if (unlikely(art_node_lock(an)))
goto begin;
art_node *new = art_node_expand_and_insert(an, key, len, off, p);
parent = art_node_lock_force(parent);
if (likely(parent)) {
debug_assert(off);
art_node_replace_child(parent, ((unsigned char *)key)[off - 1], an, new);
} else { // this is root
__atomic_store(ptr, &new, __ATOMIC_RELEASE);
}
art_node_unlock(parent);
art_node_unlock(an);
return 0;
}

off += p;
debug_assert(off < len);

// now that the prefix is matched, we can descend

art_node **next = art_node_find_child(cur, v, ((unsigned char *)key)[off]);
// prefix is matched, we can descend
art_node **next = art_node_find_child(an, v, ((unsigned char *)key)[off]);

v = art_node_get_version(cur);
v = art_node_get_version(an);

if (unlikely(art_node_version_is_old(v))) {
off -= p;
goto begin;
}

if (next) {
an = next;
++off;
goto begin;
}
if (next)
return _adaptive_radix_tree_put(an, next, key, len, off + 1, val);

if (unlikely(art_node_lock(cur))) { // node is replaced by a new node
if (unlikely(art_node_lock(an))) {
off -= p;
goto begin;
}

next = art_node_add_child(an, ((unsigned char *)key)[off], (art_node *)make_leaf(key));
art_node_unlock(cur);

// another thread might inserted same byte before we acquire lock
if (unlikely(next)) {
an = next;
++off;
goto begin;
art_node *new = 0;
next = art_node_add_child(an, ((unsigned char *)key)[off], (art_node *)make_leaf(key), &new);
if (unlikely(new)) {
parent = art_node_lock_force(parent);
if (parent) {
debug_assert((int)off > p);
art_node_replace_child(parent, ((unsigned char *)key)[off - p - 1], an, new);
} else {
__atomic_store(ptr, &new, __ATOMIC_RELEASE);
}
art_node_unlock(parent);
}
art_node_unlock(an);

// ptrother thread might inserted same byte before we acquire lock
if (unlikely(next))
return _adaptive_radix_tree_put(an, next, key, len, off + 1, val);

return 0;
}
Expand All @@ -154,78 +140,89 @@ static int _adaptive_radix_tree_put(art_node **an, const void *key, size_t len,
// return 1 on duplication
int adaptive_radix_tree_put(adaptive_radix_tree *art, const void *key, size_t len, const void *val)
{
//unsigned char *n = (unsigned char *)key;
//for (int i = 0; i < 8; ++i) {
// printf("%d ", n[i]);
//}
//printf("\n");
//print_key(key, len);
int ret;
// retry should be rare
while (unlikely((ret = _adaptive_radix_tree_put(&art->root, key, len, 0, val)) == -1))
while (unlikely((ret = _adaptive_radix_tree_put(0 /* parent */, &art->root, key, len, 0, val)) == -1))
;
return ret;
}

static void* _adaptive_radix_tree_get(art_node **an, const void *key, size_t len, size_t off)
// TODO: for now we retry from root for every failure, but this can be relaxed
static void* _adaptive_radix_tree_get(art_node *parent, art_node **ptr, const void *key, size_t len, size_t off)
{
art_node *cur;
(void)parent;
art_node *an;
uint64_t v, v1;

debug_assert(off <= len);

begin:
__atomic_load(an, &cur, __ATOMIC_ACQUIRE);
__atomic_load(ptr, &an, __ATOMIC_ACQUIRE);

if (unlikely(cur == 0))
if (unlikely(an == 0)) {
return 0;
}

if (unlikely(is_leaf(cur))) {
const char *k1 = get_leaf_key(cur), *k2 = (const char *)key;
size_t l1 = get_leaf_len(cur), l2 = len, i;
if (unlikely(is_leaf(an))) {
const char *k1 = get_leaf_key(an), *k2 = (const char *)key;
size_t l1 = get_leaf_len(an), l2 = len, i;
for (i = off; i < l1 && i < l2 && k1[i] == k2[i]; ++i)
;
if (i == l1 && i == l2)
return (void *)k1; // key exists
//art_node_print(parent);
//print_key(k1, l1);
//printf("off:%lu\n", off);
return 0;
}

v = art_node_get_stable_expand_version(cur);
if (art_node_version_is_old(v))
v = art_node_get_stable_expand_version(an);
if (art_node_version_is_old(v)) {
assert(0);
goto begin;
}

int p = art_node_prefix_compare(cur, v, key, len, off);
int p = art_node_prefix_compare(an, v, key, len, off);

v1 = art_node_get_version(cur);
if (art_node_version_is_old(v1) || art_node_version_compare_expand(v, v1))
v1 = art_node_get_version(an);
if (art_node_version_is_old(v1) || art_node_version_compare_expand(v, v1)) {
assert(0);
goto begin;
}
v = v1;

if (p != art_node_version_get_prefix_len(v))
if (p != art_node_version_get_prefix_len(v)) {
assert(0);
return 0;
}

off += art_node_version_get_prefix_len(v);
debug_assert(off <= len);

int advance = off != len;
unsigned char byte = advance ? ((unsigned char *)key)[off] : 0;
int advptrce = off != len;
unsigned char byte = advptrce ? ((unsigned char *)key)[off] : 0;

art_node **next = art_node_find_child(cur, v, byte);
art_node **next = art_node_find_child(an, v, byte);

v1 = art_node_get_version(cur);
v1 = art_node_get_version(an);

if (art_node_version_is_old(v1))
if (art_node_version_is_old(v1)) {
assert(0);
goto begin;
}

if (next) {
an = next;
off += advance;
parent = *ptr;
ptr = next;
off += advptrce;
goto begin;
}
return 0;
}

void* adaptive_radix_tree_get(adaptive_radix_tree *art, const void *key, size_t len)
{
return _adaptive_radix_tree_get(&art->root, key, len, 0);
return _adaptive_radix_tree_get(art->root, &art->root, key, len, 0);
}

Loading

0 comments on commit fb654b4

Please sign in to comment.