snapshot v4/p8; preserve, tsc
This commit is contained in:
parent
5989bcd340
commit
440ade6b82
3 changed files with 98 additions and 135 deletions
2
Makefile
2
Makefile
|
@ -3,7 +3,7 @@ OBJS = skiplist.o
|
||||||
STATIC_LIB = libskiplist.a
|
STATIC_LIB = libskiplist.a
|
||||||
SHARED_LIB = libskiplist.so
|
SHARED_LIB = libskiplist.so
|
||||||
|
|
||||||
CFLAGS = -DDEBUG -DSKIPLIST_DIAGNOSTIC -Wall -Wextra -Wpedantic -Og -g -std=c99 -fsanitize=address,undefined -Iinclude/ -fPIC
|
CFLAGS = -DDEBUG -DSKIPLIST_DIAGNOSTIC -Wall -Wextra -Wpedantic -Og -g -std=c99 -Iinclude/ -fPIC
|
||||||
TEST_FLAGS = -Itests/
|
TEST_FLAGS = -Itests/
|
||||||
#-fsanitize=address,undefined
|
#-fsanitize=address,undefined
|
||||||
|
|
||||||
|
|
|
@ -42,14 +42,14 @@
|
||||||
/*
|
/*
|
||||||
* To start, you must create a type node that will contain the
|
* To start, you must create a type node that will contain the
|
||||||
* fields you'd like to maintain in your Skiplist. In this case
|
* fields you'd like to maintain in your Skiplist. In this case
|
||||||
* we map int -> int, but what you put here is up to you. You
|
* we map int -> char [] on the heap, but what you put here is up
|
||||||
* don't even need a "key", just a way to compare one node against
|
* to you. You don't even need a "key", just a way to compare one
|
||||||
* another, logic you'll provide in SKIP_DECL as a block below.
|
* node against another, logic you'll provide in SKIP_DECL as a
|
||||||
|
* block below.
|
||||||
*/
|
*/
|
||||||
struct slex_node {
|
struct slex_node {
|
||||||
int key;
|
int key;
|
||||||
char *value;
|
char *value;
|
||||||
/* NOTE: This _must_ be last element in node for snapshots to work!!! */
|
|
||||||
SKIPLIST_ENTRY(slex_node) entries;
|
SKIPLIST_ENTRY(slex_node) entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -255,8 +255,10 @@ main()
|
||||||
//rc = api_skip_put_slex(list, array[i], numeral);
|
//rc = api_skip_put_slex(list, array[i], numeral);
|
||||||
INTEGRITY_CHK;
|
INTEGRITY_CHK;
|
||||||
#ifdef SNAPSHOTS
|
#ifdef SNAPSHOTS
|
||||||
|
if (i > TEST_ARRAY_SIZE + 1) {
|
||||||
snaps[snap_i++] = api_skip_snapshot_slex(list);
|
snaps[snap_i++] = api_skip_snapshot_slex(list);
|
||||||
INTEGRITY_CHK;
|
INTEGRITY_CHK;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef DOT
|
#ifdef DOT
|
||||||
sprintf(msg, "put key: %d value: %s", i, numeral);
|
sprintf(msg, "put key: %d value: %s", i, numeral);
|
||||||
|
@ -284,10 +286,6 @@ main()
|
||||||
api_skip_dot_slex(of, list, gen++, msg, sprintf_slex_node);
|
api_skip_dot_slex(of, list, gen++, msg, sprintf_slex_node);
|
||||||
INTEGRITY_CHK;
|
INTEGRITY_CHK;
|
||||||
#endif
|
#endif
|
||||||
#ifdef SNAPSHOTS
|
|
||||||
snaps[snap_i++] = api_skip_snapshot_slex(list);
|
|
||||||
INTEGRITY_CHK;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
api_skip_del_slex(list, 0);
|
api_skip_del_slex(list, 0);
|
||||||
INTEGRITY_CHK;
|
INTEGRITY_CHK;
|
||||||
|
@ -305,10 +303,6 @@ main()
|
||||||
numeral = int_to_roman_numeral(key);
|
numeral = int_to_roman_numeral(key);
|
||||||
api_skip_del_slex(list, key);
|
api_skip_del_slex(list, key);
|
||||||
INTEGRITY_CHK;
|
INTEGRITY_CHK;
|
||||||
#ifdef SNAPSHOTS
|
|
||||||
snaps[snap_i++] = api_skip_snapshot_slex(list);
|
|
||||||
INTEGRITY_CHK;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DOT
|
#ifdef DOT
|
||||||
sprintf(msg, "deleted key: %d, value: %s", 0, numeral);
|
sprintf(msg, "deleted key: %d, value: %s", 0, numeral);
|
||||||
|
|
119
include/sl.h
119
include/sl.h
|
@ -157,6 +157,7 @@
|
||||||
#ifndef SKIPLIST_READ_RDTSC
|
#ifndef SKIPLIST_READ_RDTSC
|
||||||
#define SKIPLIST_READ_RDTSC
|
#define SKIPLIST_READ_RDTSC
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
|
#if defined(__x86_64__) || defined(__i386__)
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
@ -167,6 +168,17 @@ __skip_read_rdtsc(void)
|
||||||
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
|
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
|
||||||
return ((uint64_t)lo) | (((uint64_t)hi) << 32);
|
return ((uint64_t)lo) | (((uint64_t)hi) << 32);
|
||||||
}
|
}
|
||||||
|
#elif defined(__arm__) && defined(__aarch64__)
|
||||||
|
uint64_t
|
||||||
|
__skip_read_rdtsc()
|
||||||
|
{
|
||||||
|
uint64_t value;
|
||||||
|
asm volatile("MRS %0, PMCCNTR_EL0" : "=r"(value));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#warning Unsupported arch, unable to read the TSC or MRS register on this platform.
|
||||||
|
#endif
|
||||||
#elif defined(__unix__) || defined(__APPLE__)
|
#elif defined(__unix__) || defined(__APPLE__)
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
@ -671,7 +683,7 @@ __skip_read_rdtsc(void)
|
||||||
static int __skip_preserve_node_##decl(decl##_t *slist, const decl##_node_t *src, decl##_node_t **preserved) \
|
static int __skip_preserve_node_##decl(decl##_t *slist, const decl##_node_t *src, decl##_node_t **preserved) \
|
||||||
{ \
|
{ \
|
||||||
int rc = 0; \
|
int rc = 0; \
|
||||||
decl##_node_t *dest, *is_dup; \
|
decl##_node_t *dest, *is_dup = 0; \
|
||||||
\
|
\
|
||||||
if (slist == NULL || src == NULL) \
|
if (slist == NULL || src == NULL) \
|
||||||
return 0; \
|
return 0; \
|
||||||
|
@ -712,9 +724,10 @@ __skip_read_rdtsc(void)
|
||||||
dest->field.sle_next[1] = (decl##_node_t *)is_dup; \
|
dest->field.sle_next[1] = (decl##_node_t *)is_dup; \
|
||||||
\
|
\
|
||||||
/* (g) insert node into slh_pres list at head */ \
|
/* (g) insert node into slh_pres list at head */ \
|
||||||
if (slist->slh_snap.pres == NULL) \
|
if (slist->slh_snap.pres == NULL) { \
|
||||||
|
dest->field.sle_next[0] = NULL; \
|
||||||
slist->slh_snap.pres = dest; \
|
slist->slh_snap.pres = dest; \
|
||||||
else { \
|
} else { \
|
||||||
/* The next[0] pointer forms the singly-linked list when \
|
/* The next[0] pointer forms the singly-linked list when \
|
||||||
preserved. */ \
|
preserved. */ \
|
||||||
dest->field.sle_next[0] = slist->slh_snap.pres; \
|
dest->field.sle_next[0] = slist->slh_snap.pres; \
|
||||||
|
@ -728,54 +741,6 @@ __skip_read_rdtsc(void)
|
||||||
return -rc; \
|
return -rc; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/** \
|
|
||||||
* -- __skip_preserve_ \
|
|
||||||
* \
|
|
||||||
* Preserve nodes for snapshots if necessary. Returns > 0 are \
|
|
||||||
* errors, 0 means nothing preserved, negative number represents \
|
|
||||||
* the number of nodes preserved. \
|
|
||||||
* \
|
|
||||||
* ALGORITHM: \
|
|
||||||
* Foreach node in `path`, if the generation in that element \
|
|
||||||
* is less than the current generation for the list then \
|
|
||||||
* that node must be preserved before being mutated for this \
|
|
||||||
* insert. So we preserve that node, see _preserve_node(). \
|
|
||||||
* Meanwhile, don't duplicate head and the tail nodes if they \
|
|
||||||
* are in the path[]. \
|
|
||||||
*/ \
|
|
||||||
static int __skip_preserve_##decl(decl##_t *slist, decl##_node_t **path, size_t len) \
|
|
||||||
{ \
|
|
||||||
int rc = 0, n; \
|
|
||||||
size_t i; \
|
|
||||||
decl##_node_t *prev = NULL; \
|
|
||||||
\
|
|
||||||
if (path == NULL) \
|
|
||||||
return 0; \
|
|
||||||
\
|
|
||||||
for (i = 0; i < len; i++) { \
|
|
||||||
/* This is the case when there was no match, path[0] will be NULL. */ \
|
|
||||||
if (path[i] == NULL) \
|
|
||||||
continue; \
|
|
||||||
/* No need to preserve the head or tail sentry nodes. */ \
|
|
||||||
if (path[i] == slist->slh_head || path[i] == slist->slh_tail) \
|
|
||||||
continue; \
|
|
||||||
/* No need to preserve a node more than once. */ \
|
|
||||||
if (path[i] == prev) \
|
|
||||||
continue; \
|
|
||||||
prev = path[i]; \
|
|
||||||
\
|
|
||||||
/* When the generation of the node in the path is < the list's \
|
|
||||||
current generation, we must preserve it. */ \
|
|
||||||
if (path[i]->field.sle_gen < slist->slh_snap.gen) { \
|
|
||||||
n = __skip_preserve_node_##decl(slist, path[i], NULL); \
|
|
||||||
if (n > 0) \
|
|
||||||
return n; \
|
|
||||||
rc += n; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
return -rc; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
/** \
|
/** \
|
||||||
* -- skip_snapshot_ \
|
* -- skip_snapshot_ \
|
||||||
* \
|
* \
|
||||||
|
@ -824,11 +789,6 @@ __skip_read_rdtsc(void)
|
||||||
/* Don't insert, duplicate if flag not set. */ \
|
/* Don't insert, duplicate if flag not set. */ \
|
||||||
return -1; \
|
return -1; \
|
||||||
} \
|
} \
|
||||||
/* Snapshots preserve those nodes in the `path` that are will be \
|
|
||||||
modified on insert. */ \
|
|
||||||
if (slist->slh_snap.pres != NULL) { \
|
|
||||||
__skip_preserve_##decl(slist, path, len); \
|
|
||||||
} \
|
|
||||||
/* Record the generation for this node to enable snapshots. */ \
|
/* Record the generation for this node to enable snapshots. */ \
|
||||||
new->field.sle_gen = __skip_snapshot_gen_##decl(); \
|
new->field.sle_gen = __skip_snapshot_gen_##decl(); \
|
||||||
/* Coin toss to determine level of this new node [0, max) */ \
|
/* Coin toss to determine level of this new node [0, max) */ \
|
||||||
|
@ -1115,11 +1075,12 @@ __skip_read_rdtsc(void)
|
||||||
* WARNING: Do not update the portion of the node used for ordering \
|
* WARNING: Do not update the portion of the node used for ordering \
|
||||||
* (e.g. `key`) unless you really know what you're doing. \
|
* (e.g. `key`) unless you really know what you're doing. \
|
||||||
*/ \
|
*/ \
|
||||||
int prefix##skip_update_##decl(decl##_t *slist, decl##_node_t *new) \
|
int prefix##skip_update_##decl(decl##_t *slist, decl##_node_t *dest) \
|
||||||
{ \
|
{ \
|
||||||
static decl##_node_t apath[SKIPLIST_MAX_HEIGHT + 1]; \
|
static decl##_node_t apath[SKIPLIST_MAX_HEIGHT + 1]; \
|
||||||
int rc = 0; \
|
int rc = 0, np; \
|
||||||
decl##_node_t *node, **path = (decl##_node_t **)&apath; \
|
uint64_t cur_gen = __skip_snapshot_gen_##decl(); \
|
||||||
|
decl##_node_t *src, **path = (decl##_node_t **)&apath; \
|
||||||
\
|
\
|
||||||
if (slist == NULL) \
|
if (slist == NULL) \
|
||||||
return -1; \
|
return -1; \
|
||||||
|
@ -1132,19 +1093,26 @@ __skip_read_rdtsc(void)
|
||||||
} \
|
} \
|
||||||
memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \
|
memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \
|
||||||
\
|
\
|
||||||
__skip_locate_##decl(slist, new, path); \
|
__skip_locate_##decl(slist, dest, path); \
|
||||||
node = path[0]; \
|
src = path[0]; \
|
||||||
\
|
\
|
||||||
if (SKIPLIST_MAX_HEIGHT == 1) \
|
if (SKIPLIST_MAX_HEIGHT == 1) \
|
||||||
free(path); \
|
free(path); \
|
||||||
\
|
\
|
||||||
if (node) { \
|
if (src == NULL) \
|
||||||
decl##_node_t *src = node, *dest = new; \
|
|
||||||
update_node_blk; \
|
|
||||||
node->field.sle_gen = __skip_snapshot_gen_##decl(); \
|
|
||||||
return rc; \
|
|
||||||
} \
|
|
||||||
return -1; \
|
return -1; \
|
||||||
|
\
|
||||||
|
/* Snapshots preserve the node if it is younger than our snapshot \
|
||||||
|
moment. */ \
|
||||||
|
if (src->field.sle_gen < slist->slh_snap.gen) { \
|
||||||
|
np = __skip_preserve_node_##decl(slist, src, NULL); \
|
||||||
|
if (np > 0) \
|
||||||
|
return np; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
update_node_blk; \
|
||||||
|
src->field.sle_gen = cur_gen; \
|
||||||
|
return rc; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/** \
|
/** \
|
||||||
|
@ -1152,13 +1120,13 @@ __skip_read_rdtsc(void)
|
||||||
* \
|
* \
|
||||||
* Removes the node `n` from the `slist` if present. \
|
* Removes the node `n` from the `slist` if present. \
|
||||||
*/ \
|
*/ \
|
||||||
int prefix##skip_remove_node_##decl(decl##_t *slist, decl##_node_t *n) \
|
int prefix##skip_remove_node_##decl(decl##_t *slist, decl##_node_t *query) \
|
||||||
{ \
|
{ \
|
||||||
size_t i, len, np = 0, height; \
|
|
||||||
static decl##_node_t apath[SKIPLIST_MAX_HEIGHT + 1]; \
|
static decl##_node_t apath[SKIPLIST_MAX_HEIGHT + 1]; \
|
||||||
|
size_t i, len, np = 0, height; \
|
||||||
decl##_node_t *node, **path = (decl##_node_t **)&apath; \
|
decl##_node_t *node, **path = (decl##_node_t **)&apath; \
|
||||||
\
|
\
|
||||||
if (slist == NULL || n == NULL) \
|
if (slist == NULL || query == NULL) \
|
||||||
return -1; \
|
return -1; \
|
||||||
if (slist->slh_length == 0) \
|
if (slist->slh_length == 0) \
|
||||||
return 0; \
|
return 0; \
|
||||||
|
@ -1172,12 +1140,12 @@ __skip_read_rdtsc(void)
|
||||||
memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \
|
memset(path, 0, sizeof(decl##_node_t *) * slist->slh_max_height + 1); \
|
||||||
\
|
\
|
||||||
/* Attempt to locate the node in the list. */ \
|
/* Attempt to locate the node in the list. */ \
|
||||||
len = __skip_locate_##decl(slist, n, path); \
|
len = __skip_locate_##decl(slist, query, path); \
|
||||||
node = path[0]; \
|
node = path[0]; \
|
||||||
if (node) { \
|
if (node) { \
|
||||||
/* Preserve this node about to be removed. */ \
|
/* Preserve this node about to be removed. */ \
|
||||||
if (slist->slh_snap.pres != NULL) { \
|
if (node->field.sle_gen < slist->slh_snap.gen) { \
|
||||||
np = __skip_preserve_node_##decl(slist, node, NULL); \
|
__skip_preserve_node_##decl(slist, node, NULL); \
|
||||||
if (np > 0) \
|
if (np > 0) \
|
||||||
return np; \
|
return np; \
|
||||||
} \
|
} \
|
||||||
|
@ -1200,7 +1168,7 @@ __skip_read_rdtsc(void)
|
||||||
} \
|
} \
|
||||||
/* Account for delete at tail. */ \
|
/* Account for delete at tail. */ \
|
||||||
if (node->field.sle_next[0] == slist->slh_tail) { \
|
if (node->field.sle_next[0] == slist->slh_tail) { \
|
||||||
slist->slh_tail->field.sle_prev = n->field.sle_prev; \
|
slist->slh_tail->field.sle_prev = query->field.sle_prev; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
if (SKIPLIST_MAX_HEIGHT == 1) \
|
if (SKIPLIST_MAX_HEIGHT == 1) \
|
||||||
|
@ -1578,7 +1546,8 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
||||||
this = &node->field; \
|
this = &node->field; \
|
||||||
\
|
\
|
||||||
if (this->sle_height >= slist->slh_max_height) { \
|
if (this->sle_height >= slist->slh_max_height) { \
|
||||||
__skip_integrity_failure_##decl("the %luth node's [%p] height %lu is >= max %lu\n", nth, (void *)node, this->sle_height, slist->slh_max_height); \
|
__skip_integrity_failure_##decl("the %luth node's [%p] height %lu is >= max %lu\n", nth, (void *)node, this->sle_height, \
|
||||||
|
slist->slh_max_height); \
|
||||||
n_err++; \
|
n_err++; \
|
||||||
if (flags) \
|
if (flags) \
|
||||||
return n_err; \
|
return n_err; \
|
||||||
|
|
Loading…
Reference in a new issue