snapshot v3/p1; WIP
This commit is contained in:
parent
a723597bdc
commit
84a8aacce3
2 changed files with 86 additions and 124 deletions
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
#define DEBUG 1
|
#define DEBUG 1
|
||||||
#define SKIPLIST_DEBUG slex
|
#define SKIPLIST_DEBUG slex
|
||||||
//define SKIPLIST_MAX_HEIGHT 12
|
#define SKIPLIST_MAX_HEIGHT 12
|
||||||
/* Setting this will do two things:
|
/* Setting this will do two things:
|
||||||
* 1) limit our max height across all instances of this datastructure.
|
* 1) limit our max height across all instances of this datastructure.
|
||||||
* 2) remove a heap allocation on frequently used paths, insert/remove/etc.
|
* 2) remove a heap allocation on frequently used paths, insert/remove/etc.
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//define SNAPSHOTS
|
//define SNAPSHOTS
|
||||||
//define DOT
|
#define DOT
|
||||||
#define TEST_ARRAY_SIZE 10
|
#define TEST_ARRAY_SIZE 10
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,19 +62,19 @@ SKIPLIST_DECL(
|
||||||
/* update node */
|
/* update node */
|
||||||
{
|
{
|
||||||
//char *old = node->value;
|
//char *old = node->value;
|
||||||
node->value = new->value;
|
dest->value = src->value;
|
||||||
// In this case, don't free, we're just calling to_upper and using the same memory.
|
// In this case, don't free, we're just calling to_upper and using the same memory.
|
||||||
// free(old);
|
// free(old);
|
||||||
},
|
},
|
||||||
/* archive a node */
|
/* archive a node */
|
||||||
{
|
{
|
||||||
new->key = node->key;
|
dest->key = src->key;
|
||||||
char *nv = calloc(strlen(node->value) + 1, sizeof(char));
|
char *nv = calloc(strlen(src->value) + 1, sizeof(char));
|
||||||
if (nv == NULL)
|
if (nv == NULL)
|
||||||
rc = ENOMEM;
|
rc = ENOMEM;
|
||||||
else {
|
else {
|
||||||
strncpy(nv, node->value, strlen(node->value));
|
strncpy(nv, src->value, strlen(src->value));
|
||||||
new->value = nv;
|
dest->value = nv;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/* size in bytes of the content stored in an entry by you */
|
/* size in bytes of the content stored in an entry by you */
|
||||||
|
@ -319,8 +319,8 @@ main()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SNAPSHOTS
|
#ifdef SNAPSHOTS
|
||||||
slex_t *restored = api_skip_restore_snapshot_slex(list, snp[r]);
|
slex_t *restored = api_skip_restore_snapshot_slex(list);
|
||||||
api_skip_dispose_snapshot_slex(list, r+1);
|
api_skip_release_snapshot_slex(list);
|
||||||
api_skip_destroy_slex(restored);
|
api_skip_destroy_slex(restored);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
190
include/sl.h
190
include/sl.h
|
@ -268,6 +268,7 @@
|
||||||
void *slh_aux; \
|
void *slh_aux; \
|
||||||
decl##_node_t *slh_head; \
|
decl##_node_t *slh_head; \
|
||||||
decl##_node_t *slh_tail; \
|
decl##_node_t *slh_tail; \
|
||||||
|
decl##_node_t *slh_snap; \
|
||||||
} decl##_t; \
|
} decl##_t; \
|
||||||
\
|
\
|
||||||
/* Skip List comparison function type */ \
|
/* Skip List comparison function type */ \
|
||||||
|
@ -584,7 +585,7 @@
|
||||||
if (path == NULL) \
|
if (path == NULL) \
|
||||||
return ENOMEM; \
|
return ENOMEM; \
|
||||||
} \
|
} \
|
||||||
memset(path, 0, sizeof(sizeof(decl##_node_t *) * slist->slh_max + 1)); \
|
memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max + 1); \
|
||||||
\
|
\
|
||||||
/* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \
|
/* Find a `path` to `new` in the list and a match (`path[0]`) if it exists. */ \
|
||||||
len = __skip_locate_##decl(slist, new, path); \
|
len = __skip_locate_##decl(slist, new, path); \
|
||||||
|
@ -900,6 +901,7 @@
|
||||||
free(path); \
|
free(path); \
|
||||||
\
|
\
|
||||||
if (node) { \
|
if (node) { \
|
||||||
|
decl##_node_t *src = node, *dest = new; \
|
||||||
update_node_blk; \
|
update_node_blk; \
|
||||||
return rc; \
|
return rc; \
|
||||||
} \
|
} \
|
||||||
|
@ -991,128 +993,88 @@
|
||||||
return; \
|
return; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
|
/** \
|
||||||
|
* -- skip_release_snapshot_ \
|
||||||
|
* \
|
||||||
|
* Removes ... TODO \
|
||||||
|
*/ \
|
||||||
|
void prefix##skip_release_snapshot_##decl(decl##_t *slist) \
|
||||||
|
{ \
|
||||||
|
((void)slist); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/** \
|
||||||
|
* -- __skip_preserve_node_ \
|
||||||
|
* \
|
||||||
|
* Preserve given node in the slh_pres list. \
|
||||||
|
*/ \
|
||||||
|
static int __skip_preserve_node_##decl(decl##_t *slist, decl##_node_t *node, decl##_node_t **preserved) \
|
||||||
|
{ \
|
||||||
|
int rc = 0; \
|
||||||
|
size_t amt, i; \
|
||||||
|
char *d; \
|
||||||
|
const char *s; \
|
||||||
|
decl##_node_t *src, *dest; \
|
||||||
|
\
|
||||||
|
if (slist == NULL || node == NULL) \
|
||||||
|
return 0; \
|
||||||
|
\
|
||||||
|
/* (a) alloc */ \
|
||||||
|
rc = prefix##skip_alloc_node_##decl(slist, &dest); \
|
||||||
|
if (rc) \
|
||||||
|
return rc; \
|
||||||
|
amt = sizeof(decl##_node_t); \
|
||||||
|
\
|
||||||
|
/* (b) shallow copy */ \
|
||||||
|
s = (const char *)node; \
|
||||||
|
d = (char *)dest; \
|
||||||
|
for (i = 0; i < amt; i++) \
|
||||||
|
d[i] = s[i]; \
|
||||||
|
\
|
||||||
|
/* (d) deep copy */ \
|
||||||
|
src = node; \
|
||||||
|
archive_node_blk; \
|
||||||
|
if (rc) { \
|
||||||
|
prefix##skip_free_node_##decl(dest); \
|
||||||
|
return rc; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
*preserved = dest; \
|
||||||
|
\
|
||||||
|
return rc; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/** \
|
||||||
|
* -- skip_restore_snapshot_ TODO/WIP \
|
||||||
|
* \
|
||||||
|
* Restores the Skiplist to the snapshot. \
|
||||||
|
*/ \
|
||||||
|
decl##_t *prefix##skip_restore_snapshot_##decl(decl##_t *slist) \
|
||||||
|
{ \
|
||||||
|
((void)slist); \
|
||||||
|
return NULL; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
/** \
|
/** \
|
||||||
* -- skip_snapshot_ \
|
* -- skip_snapshot_ \
|
||||||
* \
|
* \
|
||||||
* A snapshot is a read-only view of a Skip List at a point in time. Once \
|
* A snapshot is a read-only view of a Skip List at a point in time. Once \
|
||||||
* taken, a snapshot must be restored or disposed. Any number of snapshots \
|
* taken, a snapshot must be restored or released. Any number of snapshots \
|
||||||
* can be created. \
|
* can be created. \
|
||||||
*/ \
|
*/ \
|
||||||
size_t prefix##skip_snapshot_##decl(decl##_t *slist) \
|
size_t prefix##skip_snapshot_##decl(decl##_t *slist) \
|
||||||
{ \
|
{ \
|
||||||
|
int rc; \
|
||||||
|
\
|
||||||
if (slist == NULL) \
|
if (slist == NULL) \
|
||||||
return 0; \
|
return 0; \
|
||||||
\
|
if (slist->slh_snap != NULL) \
|
||||||
|
prefix##skip_release_snapshot_##decl(slist); \
|
||||||
|
rc = __skip_preserve_node_##decl(slist, slist->slh_head, &slist->slh_snap); \
|
||||||
|
if (rc > 0) \
|
||||||
|
return rc; \
|
||||||
slist->slh_gen++; \
|
slist->slh_gen++; \
|
||||||
return slist->slh_gen; \
|
return slist->slh_gen; \
|
||||||
} \
|
|
||||||
\
|
|
||||||
/* Archive of a Skip List */ \
|
|
||||||
typedef struct decl##_archive { \
|
|
||||||
decl##_t list; \
|
|
||||||
decl##_node_t *nodes; \
|
|
||||||
size_t bytes; \
|
|
||||||
} decl##_archive_t; \
|
|
||||||
\
|
|
||||||
/** \
|
|
||||||
* -- skip_to_bytes_ TODO/WIP \
|
|
||||||
* \
|
|
||||||
* Writes out list and node content to a portable array of bytes \
|
|
||||||
* suitable for archiving to disk. \
|
|
||||||
*/ \
|
|
||||||
decl##_archive_t *prefix##skip_to_bytes_##decl(decl##_t *slist) \
|
|
||||||
{ \
|
|
||||||
int rc = 0; \
|
|
||||||
size_t size, bytes, i; \
|
|
||||||
decl##_archive_t *archive; \
|
|
||||||
decl##_node_t *node, *new; \
|
|
||||||
\
|
|
||||||
if (slist == NULL) \
|
|
||||||
return NULL; \
|
|
||||||
\
|
|
||||||
bytes = sizeof(decl##_archive_t) + (slist->slh_length * sizeof(decl##_node_t)); \
|
|
||||||
node = prefix##skip_head_##decl(slist); \
|
|
||||||
while (node) { \
|
|
||||||
sizeof_entry_blk; \
|
|
||||||
bytes += sizeof(size_t); \
|
|
||||||
bytes += size; \
|
|
||||||
node = prefix##skip_next_node_##decl(slist, node); \
|
|
||||||
} \
|
|
||||||
archive = (decl##_archive_t *)calloc(1, bytes); \
|
|
||||||
if (archive == NULL) \
|
|
||||||
return NULL; \
|
|
||||||
\
|
|
||||||
archive->bytes = bytes; \
|
|
||||||
archive->list.slh_length = slist->slh_length; \
|
|
||||||
archive->list.slh_max = slist->slh_max; \
|
|
||||||
archive->nodes = (decl##_node_t *)(archive + sizeof(decl##_archive_t)); \
|
|
||||||
\
|
|
||||||
i = 0; \
|
|
||||||
node = prefix##skip_head_##decl(slist); \
|
|
||||||
while (node) { \
|
|
||||||
decl##_node_t *n = (decl##_node_t *)archive->nodes + (i++ * sizeof(decl##_node_t)); \
|
|
||||||
new = (decl##_node_t *)&n; \
|
|
||||||
archive_node_blk; \
|
|
||||||
if (rc) \
|
|
||||||
return NULL; \
|
|
||||||
node = prefix##skip_next_node_##decl(slist, node); \
|
|
||||||
} \
|
|
||||||
return archive; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
/** \
|
|
||||||
* -- skip_from_bytes_ TODO/WIP \
|
|
||||||
* \
|
|
||||||
*/ \
|
|
||||||
decl##_t *prefix##skip_from_bytes_##decl(decl##_archive_t *archive, int (*cmp)(decl##_t * head, decl##_node_t * a, decl##_node_t * b, void *aux)) \
|
|
||||||
{ \
|
|
||||||
int rc; \
|
|
||||||
size_t i; \
|
|
||||||
decl##_t *slist; \
|
|
||||||
decl##_node_t *node, *new; \
|
|
||||||
\
|
|
||||||
if (archive == NULL || cmp == NULL) \
|
|
||||||
return 0; \
|
|
||||||
slist = (decl##_t *)calloc(1, sizeof(decl##_t)); \
|
|
||||||
if (slist == NULL) \
|
|
||||||
return NULL; \
|
|
||||||
\
|
|
||||||
slist->slh_cmp = cmp; \
|
|
||||||
slist->slh_max = archive->list.slh_max; \
|
|
||||||
\
|
|
||||||
rc = prefix##skip_alloc_node_##decl(slist, &slist->slh_head); \
|
|
||||||
if (rc) \
|
|
||||||
goto fail; \
|
|
||||||
rc = prefix##skip_alloc_node_##decl(slist, &slist->slh_tail); \
|
|
||||||
if (rc) \
|
|
||||||
goto fail; \
|
|
||||||
\
|
|
||||||
slist->slh_head->field.sle_height = 0; \
|
|
||||||
for (i = 0; i < slist->slh_max; i++) \
|
|
||||||
slist->slh_head->field.sle_next[i] = slist->slh_tail; \
|
|
||||||
slist->slh_head->field.sle_prev = NULL; \
|
|
||||||
\
|
|
||||||
slist->slh_tail->field.sle_height = slist->slh_max; \
|
|
||||||
for (i = 0; i < slist->slh_max; i++) \
|
|
||||||
slist->slh_tail->field.sle_next[i] = NULL; \
|
|
||||||
slist->slh_tail->field.sle_prev = slist->slh_head; \
|
|
||||||
\
|
|
||||||
i = 0; \
|
|
||||||
while (archive->list.slh_length > 0) { \
|
|
||||||
decl##_node_t *n = (decl##_node_t *)archive->nodes + (i++ * sizeof(decl##_node_t)); \
|
|
||||||
node = (decl##_node_t *)&n; \
|
|
||||||
rc = prefix##skip_alloc_node_##decl(slist, &new); \
|
|
||||||
archive_node_blk; \
|
|
||||||
__skip_insert_##decl(slist, new, 1); \
|
|
||||||
archive->list.slh_length--; \
|
|
||||||
} \
|
|
||||||
return slist; \
|
|
||||||
fail:; \
|
|
||||||
if (slist->slh_head) \
|
|
||||||
free(slist->slh_head); \
|
|
||||||
if (slist->slh_tail) \
|
|
||||||
free(slist->slh_tail); \
|
|
||||||
return NULL; \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SKIPLIST_INTEGRITY_CHECK(decl, prefix, field) \
|
#define SKIPLIST_INTEGRITY_CHECK(decl, prefix, field) \
|
||||||
|
@ -1526,7 +1488,7 @@
|
||||||
if (next) \
|
if (next) \
|
||||||
fprintf(os, "%p } |", (void *)next); \
|
fprintf(os, "%p } |", (void *)next); \
|
||||||
else \
|
else \
|
||||||
fprintf(os, "NULL } |"); \
|
fprintf(os, "tail } |"); \
|
||||||
fflush(os); \
|
fflush(os); \
|
||||||
} \
|
} \
|
||||||
if (fn) { \
|
if (fn) { \
|
||||||
|
@ -1635,7 +1597,7 @@
|
||||||
if (next) \
|
if (next) \
|
||||||
fprintf(os, "%p }", (void *)next); \
|
fprintf(os, "%p }", (void *)next); \
|
||||||
else \
|
else \
|
||||||
fprintf(os, "NULL }"); \
|
fprintf(os, "tail }"); \
|
||||||
__SKIP_IS_LAST_ENTRY_T2B() continue; \
|
__SKIP_IS_LAST_ENTRY_T2B() continue; \
|
||||||
fprintf(os, " | "); \
|
fprintf(os, " | "); \
|
||||||
} \
|
} \
|
||||||
|
@ -1683,7 +1645,7 @@
|
||||||
size_t th = slist->slh_head->field.sle_height; \
|
size_t th = slist->slh_head->field.sle_height; \
|
||||||
for (size_t lvl = th; lvl != (size_t)-1; lvl--) { \
|
for (size_t lvl = th; lvl != (size_t)-1; lvl--) { \
|
||||||
next = (node->field.sle_next[lvl] == slist->slh_tail) ? NULL : node->field.sle_next[lvl]; \
|
next = (node->field.sle_next[lvl] == slist->slh_tail) ? NULL : node->field.sle_next[lvl]; \
|
||||||
fprintf(os, "<w%lu> NULL", lvl); \
|
fprintf(os, "<w%lu> TAIL", lvl); \
|
||||||
__SKIP_IS_LAST_ENTRY_T2B() continue; \
|
__SKIP_IS_LAST_ENTRY_T2B() continue; \
|
||||||
fprintf(os, " | "); \
|
fprintf(os, " | "); \
|
||||||
} \
|
} \
|
||||||
|
|
Loading…
Reference in a new issue