| /* |
| *------------------------------------------------------------------ |
| * 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: |
| */ |