snapshot v4/p13; more juggling
This commit is contained in:
parent
06e0b3bcd7
commit
0079415c34
2 changed files with 72 additions and 121 deletions
|
@ -1,14 +1,4 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// OPTIONS to set before including sl.h
|
||||
// ---------------------------------------------------------------------------
|
||||
#define DEBUG
|
||||
|
@ -370,9 +360,8 @@ main()
|
|||
#endif
|
||||
|
||||
#ifdef SNAPSHOTS
|
||||
sample_t *restored = api_skip_restore_snapshot_sample(list, snaps[snap_i - 1] );
|
||||
api_skip_release_snapshot_sample(list);
|
||||
api_skip_free_sample(restored);
|
||||
api_skip_restore_snapshot_sample(list, snaps[snap_i - 1] );
|
||||
api_skip_release_snapshots_sample(list);
|
||||
#endif
|
||||
|
||||
assert(strcmp(api_skip_pos_sample(list, SKIP_GTE, -(TEST_ARRAY_SIZE)-1)->value, int_to_roman_numeral(-(TEST_ARRAY_SIZE))) == 0);
|
||||
|
|
178
include/sl.h
178
include/sl.h
|
@ -31,6 +31,17 @@
|
|||
* Zhipeng Li <zhpeng.is@gmail.com>
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef _SKIPLIST_H_
|
||||
#define _SKIPLIST_H_
|
||||
|
||||
|
@ -168,59 +179,6 @@ void __attribute__((format(printf, 4, 5))) __skip_diag_(const char *file, int li
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SKIPLIST_READ_RDTSC
|
||||
#define SKIPLIST_READ_RDTSC
|
||||
#if defined(__linux__)
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static inline uint64_t
|
||||
__skip_read_rdtsc(void)
|
||||
{
|
||||
unsigned int hi, lo;
|
||||
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
|
||||
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__)
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static inline uint64_t
|
||||
__skip_read_rdtsc(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec;
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
#include <intrin.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static inline uint64_t
|
||||
__skip_read_rdtsc(void)
|
||||
{
|
||||
return __rdtsc();
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#warning Unable to read the Time Stamp Counter (TSC) register on this platform.
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Skip List declarations.
|
||||
*/
|
||||
|
@ -232,7 +190,7 @@ __skip_read_rdtsc(void)
|
|||
/*
|
||||
* A Skip List contains elements, a portion of which is used to manage those
|
||||
* elements while the rest is defined by the use case for this declaration. The
|
||||
* house keeping portion is the SKIPLIST_ENTRY below. It maintains the array of
|
||||
* housekeeping portion is the SKIPLIST_ENTRY below. It maintains the array of
|
||||
* forward pointers to nodes and has a height (a zero-based count of levels, so
|
||||
* a height of `0` means one (1) level and a height of `4` means five (5)
|
||||
* levels).
|
||||
|
@ -241,7 +199,7 @@ __skip_read_rdtsc(void)
|
|||
struct __skiplist_##decl_entry { \
|
||||
struct type *sle_prev, **sle_next; \
|
||||
size_t sle_height; \
|
||||
uint64_t sle_gen; \
|
||||
size_t sle_gen; \
|
||||
}
|
||||
|
||||
#define SKIPLIST_FOREACH_H2T(decl, prefix, list, elm, iter) \
|
||||
|
@ -284,12 +242,15 @@ __skip_read_rdtsc(void)
|
|||
size_t (*sizeof_entry)(decl##_node_t *); \
|
||||
int (*compare_entries)(struct decl *, decl##_node_t *, decl##_node_t *, void *); \
|
||||
int (*preserve_node)(struct decl * slist, const decl##_node_t *src, decl##_node_t **preserved); \
|
||||
void (*release_snapshots)(struct decl *); \
|
||||
size_t (*snapshot_current_era)(struct decl *); \
|
||||
size_t (*snapshot_incr_era)(struct decl *); \
|
||||
} slh_fns; \
|
||||
void *slh_aux; \
|
||||
decl##_node_t *slh_head; \
|
||||
decl##_node_t *slh_tail; \
|
||||
struct { \
|
||||
uint64_t gen; \
|
||||
size_t gen; \
|
||||
decl##_node_t *pres; \
|
||||
} slh_snap; \
|
||||
} decl##_t; \
|
||||
|
@ -350,16 +311,6 @@ __skip_read_rdtsc(void)
|
|||
return bytes; \
|
||||
} \
|
||||
\
|
||||
/** \
|
||||
* -- __skip_preserve_node_fn_ TODO \
|
||||
* \
|
||||
* Optional: (Snapshot) calls `slh_fns.preserve_node`. \
|
||||
*/ \
|
||||
static int __skip_preserve_node_fn_##decl(decl##_t *slist, const decl##_node_t *src, decl##_node_t **preserved) \
|
||||
{ \
|
||||
return slist->slh_fns.preserve_node(slist, src, preserved); \
|
||||
} \
|
||||
\
|
||||
/** \
|
||||
* -- __skip_compare_nodes_ \
|
||||
* \
|
||||
|
@ -407,27 +358,6 @@ __skip_read_rdtsc(void)
|
|||
return level; \
|
||||
} \
|
||||
\
|
||||
/** \
|
||||
* -- __skip_snapshot_gen \
|
||||
* \
|
||||
* Returns the current generation for snapshot purposes. \
|
||||
* We use the TSC register on x86_64 for this which, on a 4 GHz processor, \
|
||||
* would take over 146,000 years for the TSC to wrap around, starting from \
|
||||
* zero. In practice it won't generally be starting from zero, so if it \
|
||||
* is within ~5 years of wrapping we'll adjust it a bit. \
|
||||
*/ \
|
||||
static inline uint64_t __skip_snapshot_gen_##decl() \
|
||||
{ \
|
||||
static uint64_t cycles_5yr_before_a_wrap = 18444725120000000000ULL; \
|
||||
static uint64_t adjustment = 0; \
|
||||
uint64_t tsc = __skip_read_rdtsc(); \
|
||||
if (adjustment == 0) { \
|
||||
if (tsc > cycles_5yr_before_a_wrap) \
|
||||
adjustment = tsc - 1; \
|
||||
} \
|
||||
return tsc - adjustment; \
|
||||
} \
|
||||
\
|
||||
/** \
|
||||
* -- skip_alloc_node_ \
|
||||
* \
|
||||
|
@ -613,6 +543,8 @@ __skip_read_rdtsc(void)
|
|||
slist->slh_fns.free_entry(node); \
|
||||
free(node); \
|
||||
} \
|
||||
if (slist->slh_fns.snapshot_incr_era) \
|
||||
slist->slh_fns.snapshot_incr_era(slist); \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
|
@ -672,15 +604,6 @@ __skip_read_rdtsc(void)
|
|||
return len; \
|
||||
} \
|
||||
\
|
||||
/** \
|
||||
* -- skip_release_snapshot_ TODO/WIP \
|
||||
* \
|
||||
*/ \
|
||||
void prefix##skip_release_snapshot_##decl(decl##_t *slist) \
|
||||
{ \
|
||||
if (slist == NULL) \
|
||||
return; \
|
||||
} \
|
||||
/** \
|
||||
* -- __skip_insert_ \
|
||||
* \
|
||||
|
@ -715,7 +638,7 @@ __skip_read_rdtsc(void)
|
|||
return -1; \
|
||||
} \
|
||||
/* Record the generation for this node to enable snapshots. */ \
|
||||
new->field.sle_gen = __skip_snapshot_gen_##decl(); \
|
||||
new->field.sle_gen = slist->slh_fns.snapshot_current_era ? slist->slh_fns.snapshot_current_era(slist) : 0; \
|
||||
/* Coin toss to determine level of this new node [0, max) */ \
|
||||
cur_height = slist->slh_head->field.sle_height; \
|
||||
new_height = __skip_toss_##decl(slist->slh_max_height); \
|
||||
|
@ -764,7 +687,7 @@ __skip_read_rdtsc(void)
|
|||
slist->slh_tail->field.sle_height = new_height; \
|
||||
} \
|
||||
/* Record this node's generation for snapshots. */ \
|
||||
new->field.sle_gen = __skip_snapshot_gen_##decl(); \
|
||||
new->field.sle_gen = slist->slh_fns.snapshot_current_era ? slist->slh_fns.snapshot_current_era(slist) : 0; \
|
||||
/* Increase our list length (aka. size, count, etc.) by one. */ \
|
||||
slist->slh_length++; \
|
||||
\
|
||||
|
@ -1004,12 +927,14 @@ __skip_read_rdtsc(void)
|
|||
{ \
|
||||
static decl##_node_t apath[SKIPLIST_MAX_HEIGHT + 1]; \
|
||||
int rc = 0, np; \
|
||||
uint64_t cur_gen = __skip_snapshot_gen_##decl(); \
|
||||
size_t cur_gen; \
|
||||
decl##_node_t *src, **path = (decl##_node_t **)&apath; \
|
||||
\
|
||||
if (slist == NULL) \
|
||||
return -1; \
|
||||
\
|
||||
cur_gen = slist->slh_fns.snapshot_current_era ? slist->slh_fns.snapshot_current_era(slist) : 0; \
|
||||
\
|
||||
/* Allocate a buffer, or use a static one. */ \
|
||||
if (SKIPLIST_MAX_HEIGHT == 1) { \
|
||||
path = malloc(sizeof(decl##_node_t *) * slist->slh_max_height + 1); \
|
||||
|
@ -1031,9 +956,11 @@ __skip_read_rdtsc(void)
|
|||
Snapshots preserve the node if it is younger than our snapshot \
|
||||
moment. */ \
|
||||
if (slist->slh_fns.preserve_node) { \
|
||||
np = __skip_preserve_node_fn_##decl(slist, src, NULL); \
|
||||
np = slist->slh_fns.preserve_node(slist, src, NULL); \
|
||||
if (np > 0) \
|
||||
return np; \
|
||||
if (slist->slh_fns.snapshot_incr_era) \
|
||||
slist->slh_fns.snapshot_incr_era(slist); \
|
||||
} \
|
||||
\
|
||||
slist->slh_fns.update_entry(src); \
|
||||
|
@ -1073,9 +1000,11 @@ __skip_read_rdtsc(void)
|
|||
Snapshots preserve the node if it is younger than our snapshot \
|
||||
moment, this node is about to be removed. */ \
|
||||
if (slist->slh_fns.preserve_node) { \
|
||||
np = __skip_preserve_node_fn_##decl(slist, node, NULL); \
|
||||
np = slist->slh_fns.preserve_node(slist, node, NULL); \
|
||||
if (np > 0) \
|
||||
return np; \
|
||||
if (slist->slh_fns.snapshot_incr_era) \
|
||||
slist->slh_fns.snapshot_incr_era(slist); \
|
||||
} \
|
||||
/* We found it, set the next->prev to the node->prev keeping in mind \
|
||||
that the next node might be the tail). */ \
|
||||
|
@ -1129,13 +1058,23 @@ __skip_read_rdtsc(void)
|
|||
if (slist == NULL) \
|
||||
return; \
|
||||
\
|
||||
prefix##skip_release_##decl(slist); /* TODO snaps free? */ \
|
||||
prefix##skip_release_##decl(slist); \
|
||||
\
|
||||
free(slist->slh_head); \
|
||||
free(slist->slh_tail); \
|
||||
}
|
||||
|
||||
#define SKIPLIST_DECL_SNAPSHOTS(decl, prefix, field) \
|
||||
/** \
|
||||
* -- _skip_release_snapshots_ TODO \
|
||||
* \
|
||||
*/ \
|
||||
void prefix##skip_release_snapshots_##decl(decl##_t *slist) \
|
||||
{ \
|
||||
if (slist == NULL) \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
/** \
|
||||
* -- __skip_preserve_node_ \
|
||||
* \
|
||||
|
@ -1228,7 +1167,7 @@ __skip_read_rdtsc(void)
|
|||
{ \
|
||||
if (slist == NULL) \
|
||||
return 0; \
|
||||
slist->slh_snap.gen = __skip_snapshot_gen_##decl(); \
|
||||
slist->slh_snap.gen = slist->slh_fns.snapshot_current_era(slist); \
|
||||
return slist->slh_snap.gen; \
|
||||
} \
|
||||
\
|
||||
|
@ -1252,10 +1191,9 @@ __skip_read_rdtsc(void)
|
|||
* - Starting with slh_pres, the `node->field.sle_next[0]` form a \
|
||||
* singly-linked list. \
|
||||
*/ \
|
||||
decl##_t *prefix##skip_restore_snapshot_##decl(decl##_t *slist, uint64_t gen) \
|
||||
decl##_t *prefix##skip_restore_snapshot_##decl(decl##_t *slist, size_t gen) \
|
||||
{ \
|
||||
size_t i; \
|
||||
uint64_t cur_gen; \
|
||||
size_t i, cur_gen; \
|
||||
decl##_node_t *node, *prev; \
|
||||
\
|
||||
if (slist == NULL) \
|
||||
|
@ -1264,7 +1202,7 @@ __skip_read_rdtsc(void)
|
|||
if (gen >= slist->slh_snap.gen || slist->slh_snap.pres == NULL) \
|
||||
return slist; \
|
||||
\
|
||||
cur_gen = __skip_snapshot_gen_##decl(); \
|
||||
cur_gen = slist->slh_fns.snapshot_current_era(slist); \
|
||||
\
|
||||
/* (a) */ \
|
||||
SKIPLIST_FOREACH_H2T(decl, prefix, slist, node, i) \
|
||||
|
@ -1323,6 +1261,26 @@ __skip_read_rdtsc(void)
|
|||
return slist; \
|
||||
} \
|
||||
\
|
||||
/** \
|
||||
* -- __skip_snapshot_current_era \
|
||||
* \
|
||||
* Returns the current generation for snapshot purposes. \
|
||||
*/ \
|
||||
static size_t __skip_snapshot_current_era_##decl(decl##_t *slist) \
|
||||
{ \
|
||||
return slist->slh_snap.gen; \
|
||||
} \
|
||||
\
|
||||
/** \
|
||||
* -- __skip_snapshot_incr_era \
|
||||
* \
|
||||
* Increments the snapshot generation. \
|
||||
*/ \
|
||||
static size_t __skip_snapshot_incr_era_##decl(decl##_t *slist) \
|
||||
{ \
|
||||
return ++slist->slh_snap.gen; \
|
||||
} \
|
||||
\
|
||||
/** \
|
||||
* -- skip_snapshots_init_ \
|
||||
* \
|
||||
|
@ -1330,8 +1288,12 @@ __skip_read_rdtsc(void)
|
|||
*/ \
|
||||
void prefix##skip_snapshots_init_##decl(decl##_t *slist) \
|
||||
{ \
|
||||
if (slist != NULL) \
|
||||
if (slist != NULL) { \
|
||||
slist->slh_fns.preserve_node = __skip_preserve_node_##decl; \
|
||||
slist->slh_fns.release_snapshots = prefix##skip_release_snapshots_##decl; \
|
||||
slist->slh_fns.snapshot_current_era = __skip_snapshot_current_era_##decl; \
|
||||
slist->slh_fns.snapshot_incr_era = __skip_snapshot_incr_era_##decl; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SKIPLIST_DECL_ARCHIVE(decl, prefix, field) \
|
||||
|
|
Loading…
Reference in a new issue