integrity p2

This commit is contained in:
Gregory Burd 2024-03-22 15:03:06 -04:00
parent 64ac937a6a
commit 35f04e9d59
2 changed files with 149 additions and 107 deletions

View file

@ -1,15 +1,18 @@
#include <sys/time.h>
#include <assert.h>
#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#define DEBUG 1
#define SKIPLIST_DEBUG slex
/* Setting this will do two things:
* 1) limit our max height across all instances of this datastructure.
* 2) remove a heap allocation on frequently used paths, insert/remove/etc.

View file

@ -139,6 +139,21 @@
#define SKIPLIST_MAX_HEIGHT 1
#endif
#if defined(SKIPLIST_DEBUG)
#ifndef SKIP_DEBUGF
#define SKIP_DEBUGF
#if defined(DEBUG) && DEBUG > 0
#define __skip_debugf(...) \
do { \
fprintf(stderr, "%s:%d:%s(): ", __FILE__, __LINE__, __func__); \
fprintf(stderr, __VA_ARGS__); \
} while (0)
#else
#define __skip_debugf(fmt, args...) ((void)0)
#endif
#endif
#endif
/*
* 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
@ -971,112 +986,136 @@
return NULL; \
}
#define SKIPLIST_INTEGRITY_CHECK(decl, prefix, field) \
/* -- __skip_integrity_check_ */ \
static int __skip_integrity_check_##decl(decl##_t *slist, int flags) \
{ \
unsigned nth, n_err = 0; \
size_t size; \
FILE *of = stderr; \
decl##_node_t *node; \
struct __skiplist_##decl_idx *this, *that, *prev, *next; \
\
if (slist == NULL) { \
fprintf(of, "slist was NULL, nothing to check"); \
n_err++; \
return n_err; \
} \
\
/* Check the Skiplist header (slh) */ \
\
if (slist->slh_head == NULL) { \
fprintf(of, "skiplist slh_head is NULL"); \
n_err++; \
return n_err; \
} \
\
if (slist->slh_tail == NULL) { \
fprintf(of, "skiplist slh_tail is NULL"); \
n_err++; \
return n_err; \
} \
\
if (slist->cmp == NULL) { \
fprintf(of, "skiplist comparison function (cmp) is NULL"); \
n_err++; \
return n_err; \
} \
\
if (slist->level >= slist->max) { \
/* level is 0-based, max of 12 means level cannot be > 11 */ \
fprintf(of, "skiplist level in header was >= max"); \
n_err++; \
if (flags) \
return n_err; \
} \
\
if (SKIPLIST_MAX_HEIGHT < 1) { \
fprintf(of, "SKIPLIST_MAX_HEIGHT cannot be less than 1"); \
n_err++; \
if (flags) \
return n_err; \
} \
\
if (SKIPLIST_MAX_HEIGHT > 0 && slist->max > SKIPLIST_MAX_HEIGHT) { \
fprintf(of, "slist->max cannot be greater than SKIPLIST_MAX_HEIGHT"); \
n_err++; \
if (flags) \
return n_err; \
} \
\
if (slist->length > 0 && slist->slh_head->field.sle.next[0] != slist->slh_tail) { \
fprintf(of, "slist->length is 0, but head->next == tail, not an internal node"); \
n_err++; \
if (flags) \
return n_err; \
} \
\
if (slist->length > 0 && slist->slh_tail->field.sle.prev != slist->slh_head) { \
fprintf(of, "slist->length is 0, but tail->prev == head, not an internal node"); \
n_err++; \
if (flags) \
return n_err; \
} \
\
/* Validate the head node */ \
\
/* Validate the tail node */ \
\
/* Validate each node */ \
nth = 0; \
size = prefix##skip_size_##decl(slist); \
node = prefix##skip_head_##decl(slist); \
do { \
this = &node->field.sle; \
if (this->next == NULL) { \
fprintf(of, "the %u node's [%p] next field should never NULL", nth, (void *)node); \
n_err++; \
if (flags) \
return n_err; \
} \
if (this->prev == NULL) { \
fprintf(of, "the %u node [%p] prev field should never NULL", nth, (void *)node); \
n_err++; \
if (flags) \
return n_err; \
} \
if (*this->next != node + (sizeof(struct __skiplist_##decl_idx) * slist->max)) { \
fprintf(of, "the %u node's [%p] next field isn't at the proper offset relative to the node", nth, (void *)node); \
n_err++; \
if (flags) \
return n_err; \
} \
\
node = prefix##skip_next_node_##decl(slist, node); \
nth++; \
} while (node != NULL); \
\
return 0; \
#define SKIPLIST_INTEGRITY_CHECK(decl, prefix, field) \
/* -- __skip_integrity_failure_ */ \
static void __attribute__((format(printf, 1, 2))) __skip_integrity_failure_##decl(const char *fmt, ...) \
{ \
va_list args; \
__skip_debugf(fmt, args); \
} \
\
/* -- __skip_integrity_check_ */ \
static int __skip_integrity_check_##decl(decl##_t *slist, int flags) \
{ \
size_t size; \
unsigned nth, n_err = 0; \
decl##_node_t *node; \
struct __skiplist_##decl_idx *this, *that, *prev, *next; \
\
if (slist == NULL) { \
__skip_integrity_failure_##decl("slist was NULL, nothing to check"); \
n_err++; \
return n_err; \
} \
\
/* Check the Skiplist header (slh) */ \
\
if (slist->slh_head == NULL) { \
__skip_integrity_failure_##decl("skiplist slh_head is NULL"); \
n_err++; \
return n_err; \
} \
\
if (slist->slh_tail == NULL) { \
__skip_integrity_failure_##decl("skiplist slh_tail is NULL"); \
n_err++; \
return n_err; \
} \
\
if (slist->cmp == NULL) { \
__skip_integrity_failure_##decl("skiplist comparison function (cmp) is NULL"); \
n_err++; \
return n_err; \
} \
\
if (slist->max < 2) { \
__skip_integrity_failure_##decl("skiplist max level must be 1 at minimum"); \
n_err++; \
if (flags) \
return n_err; \
} \
\
if (slist->level >= slist->max) { \
/* level is 0-based, max of 12 means level cannot be > 11 */ \
__skip_integrity_failure_##decl("skiplist level in header was >= max"); \
n_err++; \
if (flags) \
return n_err; \
} \
\
if (SKIPLIST_MAX_HEIGHT < 1) { \
__skip_integrity_failure_##decl("SKIPLIST_MAX_HEIGHT cannot be less than 1"); \
n_err++; \
if (flags) \
return n_err; \
} \
\
if (SKIPLIST_MAX_HEIGHT > 0 && slist->max > SKIPLIST_MAX_HEIGHT) { \
__skip_integrity_failure_##decl("slist->max cannot be greater than SKIPLIST_MAX_HEIGHT"); \
n_err++; \
if (flags) \
return n_err; \
} \
\
node = slist->slh_head; \
for (nth = 0; nth < node->field.sle.height; nth++) { \
if (node->field.sle.next[nth] == NULL || node->field.sle.next[nth] == slist->slh_tail) { \
__skip_integrity_failure_##decl("the head's %u next node reference should not be NULL or pointing to the tail", nth); \
n_err++; \
if (flags) \
return n_err; \
} \
} \
for (; nth < slist->max; nth++) { \
if (node->field.sle.next[nth] != slist->slh_tail) { \
__skip_integrity_failure_##decl("the head's %u next node reference above it's current height should always point to the tail", nth); \
n_err++; \
if (flags) \
return n_err; \
} \
} \
\
if (slist->length > 0 && slist->slh_tail->field.sle.prev != slist->slh_head) { \
__skip_integrity_failure_##decl("slist->length is 0, but tail->prev == head, not an internal node"); \
n_err++; \
if (flags) \
return n_err; \
} \
\
/* Validate the head node */ \
\
/* Validate the tail node */ \
\
/* Validate each node */ \
nth = 0; \
size = prefix##skip_size_##decl(slist); \
node = prefix##skip_head_##decl(slist); \
while (node) { \
this = &node->field.sle; \
if (this->next == NULL) { \
__skip_integrity_failure_##decl("the %u node's [%p] next field should never NULL", nth, (void *)node); \
n_err++; \
if (flags) \
return n_err; \
} \
if (this->prev == NULL) { \
__skip_integrity_failure_##decl("the %u node [%p] prev field should never NULL", nth, (void *)node); \
n_err++; \
if (flags) \
return n_err; \
} \
if (*this->next != node + (sizeof(struct __skiplist_##decl_idx) * slist->max)) { \
__skip_integrity_failure_##decl("the %u node's [%p] next field isn't at the proper offset relative to the node", nth, (void *)node); \
n_err++; \
if (flags) \
return n_err; \
} \
\
node = prefix##skip_next_node_##decl(slist, node); \
nth++; \
} \
\
return 0; \
}
#define SKIPLIST_KV_ACCESS(decl, prefix, ktype, vtype, qblk, rblk) \