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 <assert.h>
#include <errno.h> #include <errno.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#define DEBUG 1
#define SKIPLIST_DEBUG slex
/* 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.

View file

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