snapshot v3/p4; WIP
This commit is contained in:
parent
0f79e5a5ec
commit
81abb92814
1 changed files with 56 additions and 23 deletions
79
include/sl.h
79
include/sl.h
|
@ -1017,7 +1017,6 @@
|
||||||
\
|
\
|
||||||
free(slist->slh_head); \
|
free(slist->slh_head); \
|
||||||
free(slist->slh_tail); \
|
free(slist->slh_tail); \
|
||||||
return; \
|
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/** \
|
/** \
|
||||||
|
@ -1065,13 +1064,19 @@
|
||||||
if (slist == NULL) \
|
if (slist == NULL) \
|
||||||
return; \
|
return; \
|
||||||
\
|
\
|
||||||
|
if (slist->slh_snap.head == NULL) \
|
||||||
|
return; \
|
||||||
|
\
|
||||||
sn = prefix##skip_snap_head_##decl(slist); \
|
sn = prefix##skip_snap_head_##decl(slist); \
|
||||||
|
if (sn == NULL) \
|
||||||
|
goto free_head_and_tail; \
|
||||||
|
\
|
||||||
SKIPLIST_FOREACH_H2T(decl, prefix, slist, ln, nth) \
|
SKIPLIST_FOREACH_H2T(decl, prefix, slist, ln, nth) \
|
||||||
{ \
|
{ \
|
||||||
goto top_of_loop; \
|
goto top_of_loop; \
|
||||||
sn_forward_only:; \
|
sn_forward_only:; \
|
||||||
sn = sn->field.sle_next[0]; \
|
sn = sn->field.sle_next[0]; \
|
||||||
if (sn == slist->slh_snap.tail) \
|
if (sn == slist->slh_tail) \
|
||||||
break; \
|
break; \
|
||||||
top_of_loop:; \
|
top_of_loop:; \
|
||||||
/* When a node is referenced by both, keep going. */ \
|
/* When a node is referenced by both, keep going. */ \
|
||||||
|
@ -1094,10 +1099,15 @@
|
||||||
/* ... we could have: \
|
/* ... we could have: \
|
||||||
a) a duplicate, or \
|
a) a duplicate, or \
|
||||||
b) a copied a node, but not it's value, because it was \
|
b) a copied a node, but not it's value, because it was \
|
||||||
adjacent to some mutated node (it was in the `path[]` \
|
adjacent to some mutated node (it was in the `path[]` \
|
||||||
during an insert, update, or delete), or \
|
during an insert, update, or delete), or \
|
||||||
c) ...? \
|
c) ...? \
|
||||||
*/ \
|
*/ \
|
||||||
|
/* TODO \
|
||||||
|
free_node_blk; \
|
||||||
|
free(sn->field.sle_next); \
|
||||||
|
free(sn); \
|
||||||
|
*/ \
|
||||||
cnt++; \
|
cnt++; \
|
||||||
} \
|
} \
|
||||||
/* ln forward only */ \
|
/* ln forward only */ \
|
||||||
|
@ -1115,9 +1125,21 @@
|
||||||
node = sn; \
|
node = sn; \
|
||||||
free_node_blk; \
|
free_node_blk; \
|
||||||
next = sn->field.sle_next[0]; \
|
next = sn->field.sle_next[0]; \
|
||||||
|
/* Nodes are a block of contigious memory that includes the `next[]` \
|
||||||
|
pointers except when they are preserved nodes. In this case the \
|
||||||
|
`next[]` array is a separate heap object (unless you're the head \
|
||||||
|
or tail nodes in a preserved snapshot). */ \
|
||||||
|
free(sn->field.sle_next); \
|
||||||
free(sn); \
|
free(sn); \
|
||||||
sn = next; \
|
sn = next; \
|
||||||
|
cnt++; \
|
||||||
} \
|
} \
|
||||||
|
\
|
||||||
|
free_head_and_tail:; \
|
||||||
|
free(slist->slh_snap.head); \
|
||||||
|
free(slist->slh_snap.tail); \
|
||||||
|
slist->slh_snap.head = NULL; \
|
||||||
|
slist->slh_snap.tail = NULL; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/** \
|
/** \
|
||||||
|
@ -1129,22 +1151,44 @@
|
||||||
{ \
|
{ \
|
||||||
int rc = 0; \
|
int rc = 0; \
|
||||||
decl##_node_t *dest; \
|
decl##_node_t *dest; \
|
||||||
|
struct __skiplist_##decl_entry *entry = NULL; \
|
||||||
\
|
\
|
||||||
if (slist == NULL || src == NULL) \
|
if (slist == NULL || src == NULL) \
|
||||||
return 0; \
|
return 0; \
|
||||||
\
|
\
|
||||||
/* (a) alloc */ \
|
/* (a) alloc */ \
|
||||||
|
size_t sle_arr_sz = sizeof(struct __skiplist_##decl_entry) * slist->slh_max; \
|
||||||
rc = prefix##skip_alloc_node_##decl(slist, &dest); \
|
rc = prefix##skip_alloc_node_##decl(slist, &dest); \
|
||||||
if (rc) \
|
if (rc) \
|
||||||
return rc; \
|
return rc; \
|
||||||
|
if (!(src == slist->slh_head || src == slist->slh_tail)) { \
|
||||||
|
entry = (struct __skiplist_##decl_entry *)calloc(1, sle_arr_sz); \
|
||||||
|
if (entry == NULL) { \
|
||||||
|
prefix##skip_free_node_##decl(dest); \
|
||||||
|
return ENOMEM; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
\
|
\
|
||||||
/* (b) shallow copy */ \
|
/* (b) shallow copy, point to separate sle_next, and copy into it */ \
|
||||||
size_t sle_arr_sz = sizeof(struct __skiplist_##decl_entry) * slist->slh_max; \
|
|
||||||
memcpy(dest, src, sizeof(decl##_node_t) + sle_arr_sz); \
|
memcpy(dest, src, sizeof(decl##_node_t) + sle_arr_sz); \
|
||||||
|
if (!(src == slist->slh_head || src == slist->slh_tail)) { \
|
||||||
|
dest->field.sle_next = (decl##_node_t **)entry; \
|
||||||
|
memcpy(dest->field.sle_next, src->field.sle_next, sizeof(sle_arr_sz)); \
|
||||||
|
} else \
|
||||||
|
dest->field.sle_next = (decl##_node_t **)((uintptr_t)dest + sizeof(decl##_node_t)); \
|
||||||
\
|
\
|
||||||
/* (d) adjust pointer to sle_next for this node */ \
|
/* (d) update any references in the new node's next[] array to point to \
|
||||||
dest->field.sle_next = (decl##_node_t **)((uintptr_t)dest + sizeof(decl##_node_t)); \
|
the snap tail; update the prev field in the new node to the snap head \
|
||||||
|
for similar reasons. */ \
|
||||||
|
__SKIP_ENTRIES_B2T(field, dest) \
|
||||||
|
{ \
|
||||||
|
if (dest->field.sle_next[lvl] == slist->slh_tail) \
|
||||||
|
dest->field.sle_next[lvl] = slist->slh_snap.tail; \
|
||||||
|
} \
|
||||||
|
if (dest->field.sle_prev == slist->slh_head) \
|
||||||
|
dest->field.sle_prev = slist->slh_snap.head; \
|
||||||
\
|
\
|
||||||
|
/* If we're not preserving the head or the tail, ... */ \
|
||||||
if (!(src == slist->slh_head || src == slist->slh_tail)) { \
|
if (!(src == slist->slh_head || src == slist->slh_tail)) { \
|
||||||
/* (e) deep copy */ \
|
/* (e) deep copy */ \
|
||||||
archive_node_blk; \
|
archive_node_blk; \
|
||||||
|
@ -1184,29 +1228,18 @@
|
||||||
\
|
\
|
||||||
if (slist == NULL) \
|
if (slist == NULL) \
|
||||||
return 0; \
|
return 0; \
|
||||||
/* (a) preserve the head node */ \
|
/* (a) release previous snapshot, assign the new one */ \
|
||||||
|
prefix##skip_release_snapshot_##decl(slist); \
|
||||||
|
/* (b) preserve the head node */ \
|
||||||
rc = __skip_preserve_node_##decl(slist, slist->slh_head, &head); \
|
rc = __skip_preserve_node_##decl(slist, slist->slh_head, &head); \
|
||||||
if (rc > 0) \
|
if (rc > 0) \
|
||||||
return rc; \
|
return rc; \
|
||||||
/* (b) preserve the tail node */ \
|
/* (c) preserve the tail node */ \
|
||||||
rc = __skip_preserve_node_##decl(slist, slist->slh_tail, &tail); \
|
rc = __skip_preserve_node_##decl(slist, slist->slh_tail, &tail); \
|
||||||
if (rc > 0) { \
|
if (rc > 0) { \
|
||||||
prefix##skip_free_node_##decl(head); \
|
prefix##skip_free_node_##decl(head); \
|
||||||
return rc; \
|
return rc; \
|
||||||
} \
|
} \
|
||||||
/* (c) update any references in the new head's next[] array to point to \
|
|
||||||
the new tail; update the prev field in the new tail to the new head \
|
|
||||||
for similar reasons. */ \
|
|
||||||
__SKIP_ENTRIES_B2T(field, head) \
|
|
||||||
{ \
|
|
||||||
if (head->field.sle_next[lvl] == slist->slh_tail) \
|
|
||||||
head->field.sle_next[lvl] = tail; \
|
|
||||||
} \
|
|
||||||
if (tail->field.sle_prev == slist->slh_head) \
|
|
||||||
tail->field.sle_prev = head; \
|
|
||||||
/* (d) release previous snapshot, assign the new one */ \
|
|
||||||
if (slist->slh_snap.head != NULL) \
|
|
||||||
prefix##skip_release_snapshot_##decl(slist); \
|
|
||||||
slist->slh_snap.head = head; \
|
slist->slh_snap.head = head; \
|
||||||
slist->slh_snap.tail = tail; \
|
slist->slh_snap.tail = tail; \
|
||||||
slist->slh_snap.gen = __skip_incr_gen_##decl(slist); \
|
slist->slh_snap.gen = __skip_incr_gen_##decl(slist); \
|
||||||
|
|
Loading…
Reference in a new issue