8a7fb0cf68
Change-Id: I816de8b1f255dc3bc6d2904566ea0b0f68fac5d8 Signed-off-by: Dave Barach <dave@barachs.net>
259 lines
6.9 KiB
C
259 lines
6.9 KiB
C
/*
|
|
*------------------------------------------------------------------
|
|
* persist.c - persistent data structure storage test / demo code
|
|
*
|
|
* Copyright (c) 2013 Cisco and/or its affiliates.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at:
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*------------------------------------------------------------------
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <netinet/in.h>
|
|
#include <signal.h>
|
|
#include <pthread.h>
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <vppinfra/clib.h>
|
|
#include <vppinfra/vec.h>
|
|
#include <vppinfra/hash.h>
|
|
#include <vppinfra/bitmap.h>
|
|
#include <vppinfra/fifo.h>
|
|
#include <vppinfra/time.h>
|
|
#include <vppinfra/mheap.h>
|
|
#include <vppinfra/heap.h>
|
|
#include <vppinfra/pool.h>
|
|
#include <vppinfra/format.h>
|
|
#include <vppinfra/serialize.h>
|
|
#include <svmdb.h>
|
|
|
|
typedef struct
|
|
{
|
|
svmdb_client_t *c;
|
|
} persist_main_t;
|
|
|
|
persist_main_t persist_main;
|
|
|
|
typedef struct
|
|
{
|
|
u8 *string1;
|
|
u8 *string2;
|
|
} demo_struct2_t;
|
|
|
|
typedef struct
|
|
{
|
|
demo_struct2_t *demo2;
|
|
u8 *name;
|
|
} demo_struct1_t;
|
|
|
|
/*
|
|
* Data structures in persistent shared memory, all the time
|
|
*/
|
|
clib_error_t *
|
|
persist_malloc (persist_main_t * pm)
|
|
{
|
|
demo_struct2_t *demo2;
|
|
demo_struct1_t *demo1;
|
|
time_t starttime = time (0);
|
|
char *datestring = ctime (&starttime);
|
|
void *oldheap;
|
|
|
|
/* Get back the root pointer */
|
|
demo1 = svmdb_local_get_variable_reference
|
|
(pm->c, SVMDB_NAMESPACE_VEC, "demo1_location");
|
|
|
|
/* It doesnt exist create our data structures */
|
|
if (demo1 == 0)
|
|
{
|
|
/* If you want MP / thread safety, lock the region... */
|
|
pthread_mutex_lock (&pm->c->db_rp->mutex);
|
|
|
|
/* Switch to the shared memory region heap */
|
|
oldheap = svm_push_data_heap (pm->c->db_rp);
|
|
|
|
/* Allocate the top-level structure as a single element vector */
|
|
vec_validate (demo1, 0);
|
|
|
|
/* Allocate the next-level structure as a plain old memory obj */
|
|
demo2 = clib_mem_alloc (sizeof (*demo2));
|
|
|
|
demo1->demo2 = demo2;
|
|
demo1->name = format (0, "My name is Ishmael%c", 0);
|
|
demo2->string1 = format (0, "Here is string1%c", 0);
|
|
demo2->string2 = format (0, "Born at %s%c", datestring, 0);
|
|
|
|
/* Back to the process-private heap */
|
|
svm_pop_heap (oldheap);
|
|
pthread_mutex_unlock (&pm->c->db_rp->mutex);
|
|
|
|
/*
|
|
* Set the root pointer. Note: this guy switches heaps, locks, etc.
|
|
* We allocated demo1 as a vector to make this "just work..."
|
|
*/
|
|
svmdb_local_set_vec_variable (pm->c, "demo1_location",
|
|
demo1, sizeof (demo1));
|
|
|
|
}
|
|
else
|
|
{
|
|
/* retrieve and print data from shared memory */
|
|
demo2 = demo1->demo2;
|
|
fformat (stdout, "name: %s\n", demo1->name);
|
|
fformat (stdout, "demo2 location: %llx\n", demo2);
|
|
fformat (stdout, "string1: %s\n", demo2->string1);
|
|
fformat (stdout, "string2: %s\n", demo2->string2);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
unserialize_demo1 (serialize_main_t * sm, va_list * args)
|
|
{
|
|
demo_struct1_t **result = va_arg (*args, demo_struct1_t **);
|
|
demo_struct1_t *demo1;
|
|
demo_struct2_t *demo2;
|
|
|
|
/* Allocate data structures in process private memory */
|
|
demo1 = clib_mem_alloc (sizeof (*demo1));
|
|
demo2 = clib_mem_alloc (sizeof (*demo2));
|
|
demo1->demo2 = demo2;
|
|
|
|
/* retrieve data from shared memory checkpoint */
|
|
unserialize_cstring (sm, (char **) &demo1->name);
|
|
unserialize_cstring (sm, (char **) &demo2->string1);
|
|
unserialize_cstring (sm, (char **) &demo2->string2);
|
|
*result = demo1;
|
|
}
|
|
|
|
void
|
|
serialize_demo1 (serialize_main_t * sm, va_list * args)
|
|
{
|
|
demo_struct1_t *demo1 = va_arg (*args, demo_struct1_t *);
|
|
demo_struct2_t *demo2 = demo1->demo2;
|
|
|
|
serialize_cstring (sm, (char *) demo1->name);
|
|
serialize_cstring (sm, (char *) demo2->string1);
|
|
serialize_cstring (sm, (char *) demo2->string2);
|
|
}
|
|
|
|
/* Serialize / unserialize variant */
|
|
clib_error_t *
|
|
persist_serialize (persist_main_t * pm)
|
|
{
|
|
u8 *checkpoint;
|
|
serialize_main_t sm;
|
|
|
|
demo_struct2_t *demo2;
|
|
demo_struct1_t *demo1;
|
|
time_t starttime = time (0);
|
|
char *datestring = ctime (&starttime);
|
|
|
|
/* Get back the root pointer */
|
|
checkpoint = svmdb_local_get_vec_variable (pm->c, "demo1_checkpoint",
|
|
sizeof (u8));
|
|
|
|
/* It doesnt exist create our data structures */
|
|
if (checkpoint == 0)
|
|
{
|
|
/* Allocate data structures in process-private memory */
|
|
demo1 = clib_mem_alloc (sizeof (*demo2));
|
|
vec_validate (demo1, 0);
|
|
demo2 = clib_mem_alloc (sizeof (*demo2));
|
|
|
|
demo1->demo2 = demo2;
|
|
demo1->name = format (0, "My name is Ishmael%c", 0);
|
|
demo2->string1 = format (0, "Here is string1%c", 0);
|
|
demo2->string2 = format (0, "Born at %s%c", datestring, 0);
|
|
|
|
/* Create checkpoint */
|
|
serialize_open_vector (&sm, checkpoint);
|
|
serialize (&sm, serialize_demo1, demo1);
|
|
checkpoint = serialize_close_vector (&sm);
|
|
|
|
/* Copy checkpoint into shared memory */
|
|
svmdb_local_set_vec_variable (pm->c, "demo1_checkpoint",
|
|
checkpoint, sizeof (u8));
|
|
/* Toss the process-private-memory original.. */
|
|
vec_free (checkpoint);
|
|
}
|
|
else
|
|
{
|
|
/* Open the checkpoint */
|
|
unserialize_open_data (&sm, checkpoint, vec_len (checkpoint));
|
|
unserialize (&sm, unserialize_demo1, &demo1);
|
|
|
|
/* Toss the process-private-memory checkpoint copy */
|
|
vec_free (checkpoint);
|
|
|
|
/* Off we go... */
|
|
demo2 = demo1->demo2;
|
|
fformat (stdout, "name: %s\n", demo1->name);
|
|
fformat (stdout, "demo2 location: %llx\n", demo2);
|
|
fformat (stdout, "string1: %s\n", demo2->string1);
|
|
fformat (stdout, "string2: %s\n", demo2->string2);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
main (int argc, char **argv)
|
|
{
|
|
unformat_input_t _input, *input = &_input;
|
|
persist_main_t *pm = &persist_main;
|
|
clib_error_t *error = 0;
|
|
|
|
/* Make a 4mb database arena, chroot so it's truly private */
|
|
pm->c = svmdb_map_chroot_size ("/ptest", 4 << 20);
|
|
|
|
ASSERT (pm->c);
|
|
|
|
unformat_init_command_line (input, argv);
|
|
|
|
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
|
|
{
|
|
if (unformat (input, "malloc"))
|
|
error = persist_malloc (pm);
|
|
else if (unformat (input, "serialize"))
|
|
error = persist_serialize (pm);
|
|
else
|
|
{
|
|
error = clib_error_return (0, "Unknown flavor '%U'",
|
|
format_unformat_error, input);
|
|
break;
|
|
}
|
|
}
|
|
|
|
svmdb_unmap (pm->c);
|
|
|
|
if (error)
|
|
{
|
|
clib_error_report (error);
|
|
exit (1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* fd.io coding-style-patch-verification: ON
|
|
*
|
|
* Local Variables:
|
|
* eval: (c-set-style "gnu")
|
|
* End:
|
|
*/
|