mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-06-01 11:10:24 +00:00
FS-9775: Implement serialization, deserialization & repopulation for dht table
This commit is contained in:
parent
183116452b
commit
66fdf5fa19
@ -570,6 +570,10 @@ KS_DECLARE(ks_status_t) ks_dhtrt_release_querynodes(ks_dhtrt_querynodes_t
|
|||||||
|
|
||||||
KS_DECLARE(void) ks_dhtrt_process_table(ks_dhtrt_routetable_t* table);
|
KS_DECLARE(void) ks_dhtrt_process_table(ks_dhtrt_routetable_t* table);
|
||||||
|
|
||||||
|
KS_DECLARE(uint32_t) ks_dhtrt_serialize(ks_dhtrt_routetable_t* table, void** ptr);
|
||||||
|
KS_DECLARE(ks_status_t) ks_dhtrt_deserialize(ks_dhtrt_routetable_t* table, void* ptr);
|
||||||
|
|
||||||
|
|
||||||
/* debugging aids */
|
/* debugging aids */
|
||||||
KS_DECLARE(void) ks_dhtrt_dump(ks_dhtrt_routetable_t* table, int level);
|
KS_DECLARE(void) ks_dhtrt_dump(ks_dhtrt_routetable_t* table, int level);
|
||||||
|
|
||||||
|
@ -106,6 +106,8 @@ typedef struct ks_dhtrt_internal_s {
|
|||||||
ks_dhtrt_deletednode_t *deleted_node;
|
ks_dhtrt_deletednode_t *deleted_node;
|
||||||
ks_dhtrt_deletednode_t *free_node_ex;
|
ks_dhtrt_deletednode_t *free_node_ex;
|
||||||
uint32_t deleted_count;
|
uint32_t deleted_count;
|
||||||
|
uint32_t bucket_count;
|
||||||
|
uint32_t header_count;
|
||||||
} ks_dhtrt_internal_t;
|
} ks_dhtrt_internal_t;
|
||||||
|
|
||||||
typedef struct ks_dhtrt_xort_s {
|
typedef struct ks_dhtrt_xort_s {
|
||||||
@ -203,7 +205,6 @@ KS_DECLARE(ks_status_t) ks_dhtrt_initroute(ks_dhtrt_routetable_t **tableP,
|
|||||||
ks_dht_t *dht,
|
ks_dht_t *dht,
|
||||||
ks_pool_t *pool)
|
ks_pool_t *pool)
|
||||||
{
|
{
|
||||||
(void)ks_dhtrt_find_relatedbucketheader;
|
|
||||||
|
|
||||||
unsigned char initmask[KS_DHT_NODEID_SIZE];
|
unsigned char initmask[KS_DHT_NODEID_SIZE];
|
||||||
memset(initmask, 0xff, sizeof(initmask));
|
memset(initmask, 0xff, sizeof(initmask));
|
||||||
@ -224,6 +225,8 @@ KS_DECLARE(ks_status_t) ks_dhtrt_initroute(ks_dhtrt_routetable_t **tableP,
|
|||||||
initial_header->flags = BHF_LEFT; /* fake left to allow splitting */
|
initial_header->flags = BHF_LEFT; /* fake left to allow splitting */
|
||||||
internal->buckets = initial_header;
|
internal->buckets = initial_header;
|
||||||
initial_header->bucket = ks_dhtrt_create_bucket(pool);
|
initial_header->bucket = ks_dhtrt_create_bucket(pool);
|
||||||
|
internal->header_count = 1;
|
||||||
|
internal->bucket_count = 1;
|
||||||
table->pool = pool;
|
table->pool = pool;
|
||||||
|
|
||||||
*tableP = table;
|
*tableP = table;
|
||||||
@ -281,6 +284,8 @@ KS_DECLARE(void) ks_dhtrt_deinitroute(ks_dhtrt_routetable_t **tableP)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
KS_DECLARE(ks_status_t) ks_dhtrt_create_node( ks_dhtrt_routetable_t *table,
|
KS_DECLARE(ks_status_t) ks_dhtrt_create_node( ks_dhtrt_routetable_t *table,
|
||||||
ks_dht_nodeid_t nodeid,
|
ks_dht_nodeid_t nodeid,
|
||||||
enum ks_dht_nodetype_t type,
|
enum ks_dht_nodetype_t type,
|
||||||
@ -500,6 +505,8 @@ ks_status_t ks_dhtrt_insert_node(ks_dhtrt_routetable_t *table, ks_dht_node_t *no
|
|||||||
newleft->left1bit = newright;
|
newleft->left1bit = newright;
|
||||||
|
|
||||||
ks_dhtrt_split_bucket(header, newleft, newright);
|
ks_dhtrt_split_bucket(header, newleft, newright);
|
||||||
|
internal->header_count += 2;
|
||||||
|
++internal->bucket_count;
|
||||||
|
|
||||||
/* ok now we need to try again to see if the bucket has capacity */
|
/* ok now we need to try again to see if the bucket has capacity */
|
||||||
/* which bucket do care about */
|
/* which bucket do care about */
|
||||||
@ -1796,6 +1803,194 @@ static char *ks_dhtrt_printableid(uint8_t *id, char *buffer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* serialization and deserialization
|
||||||
|
* ---------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct ks_dhtrt_serialized_bucket_s
|
||||||
|
{
|
||||||
|
uint16_t count;
|
||||||
|
char eye[4];
|
||||||
|
ks_dhtrt_nodeid_t id;
|
||||||
|
} ks_dhtrt_serialized_bucket_t;
|
||||||
|
|
||||||
|
typedef struct ks_dhtrt_serialized_routetable_s
|
||||||
|
{
|
||||||
|
uint32_t size;
|
||||||
|
uint8_t version;
|
||||||
|
uint8_t count;
|
||||||
|
char eye[4];
|
||||||
|
} ks_dhtrt_serialized_routetable_t;
|
||||||
|
|
||||||
|
#define DHTRT_SERIALIZATION_VERSION 1
|
||||||
|
|
||||||
|
static void ks_dhtrt_serialize_node(ks_dht_node_t *source, ks_dht_node_t *dest)
|
||||||
|
{
|
||||||
|
memcpy(dest, source, sizeof(ks_dht_node_t));
|
||||||
|
memset(&dest->table, 0, sizeof(void*));
|
||||||
|
memset(&dest->reflock, 0, sizeof(void*));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ks_dhtrt_serialize_bucket(ks_dhtrt_routetable_t *table,
|
||||||
|
ks_dhtrt_serialized_routetable_t *stable,
|
||||||
|
ks_dhtrt_bucket_header_t* header,
|
||||||
|
unsigned char* buffer)
|
||||||
|
{
|
||||||
|
uint8_t tzero = 0;
|
||||||
|
ks_dhtrt_serialized_bucket_t *s = (ks_dhtrt_serialized_bucket_t*)buffer;
|
||||||
|
|
||||||
|
memcpy(s->eye, "HEAD", 4);
|
||||||
|
memcpy(s->id, header->mask, KS_DHT_NODEID_SIZE);
|
||||||
|
buffer += sizeof(ks_dhtrt_serialized_bucket_t);
|
||||||
|
stable->size += sizeof(ks_dhtrt_serialized_bucket_t);
|
||||||
|
|
||||||
|
if (header->bucket != 0) {
|
||||||
|
ks_dhtrt_bucket_t* bucket = header->bucket;
|
||||||
|
|
||||||
|
memcpy(&s->count, &bucket->count, sizeof(uint8_t));
|
||||||
|
|
||||||
|
for (int i=0; i< KS_DHT_BUCKETSIZE; ++i) {
|
||||||
|
if (bucket->entries[i].inuse == 1) {
|
||||||
|
ks_dhtrt_serialize_node(bucket->entries[i].gptr, (ks_dht_node_t*)buffer);
|
||||||
|
buffer += sizeof(ks_dht_node_t);
|
||||||
|
stable->size += sizeof(ks_dht_node_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memcpy(&s->count, &tzero, sizeof(uint8_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ks_dhtrt_serialize_table(ks_dhtrt_routetable_t *table,
|
||||||
|
ks_dhtrt_serialized_routetable_t *stable,
|
||||||
|
unsigned char *buffer)
|
||||||
|
{
|
||||||
|
ks_dhtrt_bucket_header_t *stack[KS_DHT_NODEID_SIZE * 8];
|
||||||
|
int stackix=0;
|
||||||
|
|
||||||
|
ks_dhtrt_internal_t *internal = table->internal;
|
||||||
|
ks_dhtrt_bucket_header_t *header = internal->buckets;
|
||||||
|
|
||||||
|
while (header) {
|
||||||
|
stack[stackix++] = header;
|
||||||
|
|
||||||
|
++stable->count;
|
||||||
|
|
||||||
|
ks_dhtrt_serialize_bucket(table, stable, header, buffer);
|
||||||
|
buffer = (unsigned char*)stable + stable->size;
|
||||||
|
|
||||||
|
header = header->left;
|
||||||
|
|
||||||
|
if (header == 0 && stackix > 1) {
|
||||||
|
stackix -= 2;
|
||||||
|
header = stack[stackix];
|
||||||
|
header = header->right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
KS_DECLARE(uint32_t) ks_dhtrt_serialize(ks_dhtrt_routetable_t *table, void **ptr)
|
||||||
|
{
|
||||||
|
ks_dhtrt_internal_t *internal = table->internal;
|
||||||
|
ks_rwl_write_lock(internal->lock); /* grab write lock */
|
||||||
|
|
||||||
|
uint32_t buffer_size = 3200 * sizeof(ks_dht_node_t);
|
||||||
|
buffer_size += internal->header_count * sizeof(ks_dhtrt_serialized_bucket_t);
|
||||||
|
buffer_size += sizeof(ks_dhtrt_serialized_routetable_t);
|
||||||
|
unsigned char *buffer = (*ptr) = ks_pool_alloc(table->pool, buffer_size);
|
||||||
|
|
||||||
|
ks_dhtrt_serialized_routetable_t *stable = (ks_dhtrt_serialized_routetable_t*)buffer;
|
||||||
|
stable->size = sizeof(ks_dhtrt_serialized_routetable_t);
|
||||||
|
stable->version = DHTRT_SERIALIZATION_VERSION;
|
||||||
|
memcpy(stable->eye, "DHRT", 4);
|
||||||
|
|
||||||
|
buffer += sizeof(ks_dhtrt_serialized_routetable_t);
|
||||||
|
|
||||||
|
ks_dhtrt_serialize_table(table, stable, buffer);
|
||||||
|
ks_rwl_write_unlock(internal->lock); /* write unlock */
|
||||||
|
return stable->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ks_dhtrt_deserialize_node(ks_dhtrt_routetable_t *table,
|
||||||
|
ks_dht_node_t *source,
|
||||||
|
ks_dht_node_t *dest)
|
||||||
|
{
|
||||||
|
memcpy(dest, source, sizeof(ks_dht_node_t));
|
||||||
|
dest->table = table;
|
||||||
|
ks_rwl_create(&dest->reflock, table->pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
KS_DECLARE(ks_status_t) ks_dhtrt_deserialize(ks_dhtrt_routetable_t *table, void* buffer)
|
||||||
|
{
|
||||||
|
ks_dhtrt_internal_t *internal = table->internal;
|
||||||
|
ks_rwl_write_lock(internal->lock); /* grab write lock */
|
||||||
|
unsigned char *ptr = (unsigned char*)buffer;
|
||||||
|
|
||||||
|
ks_dhtrt_serialized_routetable_t *stable = (ks_dhtrt_serialized_routetable_t*)buffer;
|
||||||
|
ptr += sizeof(ks_dhtrt_serialized_routetable_t);
|
||||||
|
|
||||||
|
/* unpack and chain the buckets */
|
||||||
|
for (int i=0; i<stable->count; ++i) {
|
||||||
|
|
||||||
|
ks_dhtrt_serialized_bucket_t *s = (ks_dhtrt_serialized_bucket_t*)ptr;
|
||||||
|
|
||||||
|
if (memcmp(s->eye, "HEAD", 4)) {
|
||||||
|
assert(0);
|
||||||
|
ks_rwl_write_unlock(internal->lock); /* write unlock */
|
||||||
|
return KS_STATUS_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr += sizeof(ks_dhtrt_serialized_bucket_t);
|
||||||
|
|
||||||
|
/* currently adding the nodes individually
|
||||||
|
* need a better way to do this that is compatible with the pending
|
||||||
|
* changes for supernode support
|
||||||
|
*/
|
||||||
|
|
||||||
|
char buf[51];
|
||||||
|
ks_log(KS_LOG_DEBUG, "deserialize bucket [%s] count %d\n", ks_dhtrt_printableid(s->id, buf), s->count);
|
||||||
|
|
||||||
|
int mid = s->count >>1;
|
||||||
|
ks_dht_node_t *fnode = NULL;
|
||||||
|
ks_dht_node_t *node = NULL;
|
||||||
|
|
||||||
|
for(int i0=0; i0<s->count; ++i0) {
|
||||||
|
/* recreate the node */
|
||||||
|
ks_dht_node_t *node = ks_pool_alloc(table->pool, sizeof(ks_dht_node_t));
|
||||||
|
if (i0 == mid) fnode = node;
|
||||||
|
ks_dhtrt_deserialize_node(table, (ks_dht_node_t*)ptr, node);
|
||||||
|
ptr += sizeof(ks_dht_node_t);
|
||||||
|
ks_dhtrt_insert_node(table, node, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* now the bucket is complete - now trigger a find.
|
||||||
|
* This staggers the series of finds. We only do this for populated tables here.
|
||||||
|
* Once the table is loaded, process_table will as normal start the ping/find process to
|
||||||
|
* update and populate the table.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (s->count > 0) {
|
||||||
|
if (fnode) {
|
||||||
|
ks_dhtrt_find(table, internal, &fnode->nodeid);
|
||||||
|
}
|
||||||
|
else if (node) {
|
||||||
|
ks_dhtrt_find(table, internal, &node->nodeid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ks_rwl_write_unlock(internal->lock); /* write unlock */
|
||||||
|
return KS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* For Emacs:
|
/* For Emacs:
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* mode:c
|
* mode:c
|
||||||
|
@ -620,8 +620,6 @@ void test09()
|
|||||||
char ipv4[] = "123.123.123.123";
|
char ipv4[] = "123.123.123.123";
|
||||||
unsigned short port = 7000;
|
unsigned short port = 7000;
|
||||||
|
|
||||||
/* build a delete queue */
|
|
||||||
|
|
||||||
int cix=0;
|
int cix=0;
|
||||||
|
|
||||||
for(int i0=0, i1=0; i0<150; ++i0, ++i1) {
|
for(int i0=0, i1=0; i0<150; ++i0, ++i1) {
|
||||||
@ -655,6 +653,88 @@ void test09()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct ks_dhtrt_serialized_routetable_s
|
||||||
|
{
|
||||||
|
uint32_t size;
|
||||||
|
uint8_t version;
|
||||||
|
uint8_t count;
|
||||||
|
char eye[4];
|
||||||
|
} ks_dhtrt_serialized_routetable_t;
|
||||||
|
|
||||||
|
|
||||||
|
void test10()
|
||||||
|
{
|
||||||
|
printf("**** testbuckets - test10 start\n"); fflush(stdout);
|
||||||
|
|
||||||
|
ks_dht_node_t *peer;
|
||||||
|
memset(g_nodeid1.id, 0xef, KS_DHT_NODEID_SIZE);
|
||||||
|
memset(g_nodeid2.id, 0xef, KS_DHT_NODEID_SIZE);
|
||||||
|
|
||||||
|
char ipv6[] = "1234:1234:1234:1234";
|
||||||
|
char ipv4[] = "123.123.123.123";
|
||||||
|
unsigned short port = 7000;
|
||||||
|
|
||||||
|
int cix=0;
|
||||||
|
|
||||||
|
for(int i0=0, i1=0; i0<2500; ++i0, ++i1) {
|
||||||
|
if (i0%20 == 0) {
|
||||||
|
g_nodeid2.id[cix]>>=1;
|
||||||
|
//ks_dhtrt_dump(rt, 7);
|
||||||
|
if ( g_nodeid2.id[cix] == 0) ++cix;
|
||||||
|
g_nodeid2.id[19] = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++g_nodeid2.id[19];
|
||||||
|
}
|
||||||
|
ks_dhtrt_create_node(rt, g_nodeid2, KS_DHT_REMOTE, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer);
|
||||||
|
ks_dhtrt_touch_node(rt, g_nodeid2);
|
||||||
|
ks_dhtrt_release_node(peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this should expire all nodes after 15 minutes and 3 pings */
|
||||||
|
void *buffer = NULL;
|
||||||
|
uint32_t size = ks_dhtrt_serialize(rt, &buffer);
|
||||||
|
|
||||||
|
|
||||||
|
if (size > 0) {
|
||||||
|
ks_dhtrt_serialized_routetable_t* p = (ks_dhtrt_serialized_routetable_t*)buffer;
|
||||||
|
printf("\n\ntest10: version %d bucket count %d size %d\n\n", p->version, p->count, p->size);
|
||||||
|
ks_dhtrt_dump(rt, 7);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("test10: error on serialize\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ks_dhtrt_routetable_t* rt2;
|
||||||
|
ks_dhtrt_initroute(&rt2, dht, pool);
|
||||||
|
ks_dhtrt_deserialize(rt2, buffer);
|
||||||
|
ks_dhtrt_dump(rt2, 7);
|
||||||
|
|
||||||
|
ks_dht_nodeid_t id;
|
||||||
|
memset(id.id, 0xef, 20);
|
||||||
|
id.id[0] = 0x0e;
|
||||||
|
id.id[19] = 0x05;
|
||||||
|
|
||||||
|
ks_dhtrt_touch_node(rt2, id);
|
||||||
|
ks_dht_node_t* n = ks_dhtrt_find_node(rt2, id);
|
||||||
|
|
||||||
|
if (n == NULL) {
|
||||||
|
printf("test10: failed Unable to find reloaded node \n");
|
||||||
|
exit(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ks_dhtrt_deinitroute(&rt2);
|
||||||
|
|
||||||
|
printf("test10: complete\n");
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1152,6 +1232,13 @@ int main(int argc, char *argv[]) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tests[tix] == 10) {
|
||||||
|
ks_dhtrt_initroute(&rt, dht, pool);
|
||||||
|
test10();
|
||||||
|
ks_dhtrt_deinitroute(&rt);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (tests[tix] == 30) {
|
if (tests[tix] == 30) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user