snapshot v3/p4; WIP

This commit is contained in:
Gregory Burd 2024-03-28 22:04:33 -04:00
parent 0f79e5a5ec
commit 81abb92814

View file

@ -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); \