Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 1 | /* |
| 2 | *------------------------------------------------------------------ |
| 3 | * persist.c - persistent data structure storage test / demo code |
| 4 | * |
| 5 | * Copyright (c) 2013 Cisco and/or its affiliates. |
| 6 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 7 | * you may not use this file except in compliance with the License. |
| 8 | * You may obtain a copy of the License at: |
| 9 | * |
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | * |
| 12 | * Unless required by applicable law or agreed to in writing, software |
| 13 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 15 | * See the License for the specific language governing permissions and |
| 16 | * limitations under the License. |
| 17 | *------------------------------------------------------------------ |
| 18 | */ |
| 19 | |
| 20 | #include <stdio.h> |
| 21 | #include <stdlib.h> |
| 22 | #include <sys/types.h> |
| 23 | #include <sys/mman.h> |
| 24 | #include <sys/stat.h> |
| 25 | #include <netinet/in.h> |
| 26 | #include <signal.h> |
| 27 | #include <pthread.h> |
| 28 | #include <unistd.h> |
| 29 | #include <time.h> |
| 30 | #include <fcntl.h> |
| 31 | #include <string.h> |
| 32 | #include <vppinfra/clib.h> |
| 33 | #include <vppinfra/vec.h> |
| 34 | #include <vppinfra/hash.h> |
| 35 | #include <vppinfra/bitmap.h> |
| 36 | #include <vppinfra/fifo.h> |
| 37 | #include <vppinfra/time.h> |
| 38 | #include <vppinfra/mheap.h> |
| 39 | #include <vppinfra/heap.h> |
| 40 | #include <vppinfra/pool.h> |
| 41 | #include <vppinfra/format.h> |
| 42 | #include <vppinfra/serialize.h> |
| 43 | #include <svmdb.h> |
| 44 | |
| 45 | typedef struct { |
| 46 | svmdb_client_t *c; |
| 47 | } persist_main_t; |
| 48 | |
| 49 | persist_main_t persist_main; |
| 50 | |
| 51 | typedef struct { |
| 52 | u8 * string1; |
| 53 | u8 * string2; |
| 54 | } demo_struct2_t; |
| 55 | |
| 56 | typedef struct { |
| 57 | demo_struct2_t * demo2; |
| 58 | u8 * name; |
| 59 | } demo_struct1_t; |
| 60 | |
| 61 | /* |
| 62 | * Data structures in persistent shared memory, all the time |
| 63 | */ |
| 64 | clib_error_t * persist_malloc (persist_main_t * pm) |
| 65 | { |
| 66 | demo_struct2_t *demo2; |
| 67 | demo_struct1_t *demo1; |
| 68 | time_t starttime = time(0); |
| 69 | char *datestring = ctime(&starttime); |
| 70 | void *oldheap; |
| 71 | |
| 72 | /* Get back the root pointer */ |
| 73 | demo1 = svmdb_local_get_variable_reference |
| 74 | (pm->c, SVMDB_NAMESPACE_VEC, "demo1_location"); |
| 75 | |
| 76 | /* It doesnt exist create our data structures */ |
| 77 | if (demo1 == 0) { |
| 78 | /* If you want MP / thread safety, lock the region... */ |
| 79 | pthread_mutex_lock(&pm->c->db_rp->mutex); |
| 80 | |
| 81 | /* Switch to the shared memory region heap */ |
| 82 | oldheap = svm_push_data_heap (pm->c->db_rp); |
| 83 | |
| 84 | /* Allocate the top-level structure as a single element vector */ |
| 85 | vec_validate (demo1, 0); |
| 86 | |
| 87 | /* Allocate the next-level structure as a plain old memory obj */ |
| 88 | demo2 = clib_mem_alloc (sizeof (*demo2)); |
| 89 | |
| 90 | demo1->demo2 = demo2; |
| 91 | demo1->name = format (0, "My name is Ishmael%c", 0); |
| 92 | demo2->string1 = format (0, "Here is string1%c", 0); |
| 93 | demo2->string2 = format (0, "Born at %s%c", datestring, 0); |
| 94 | |
| 95 | /* Back to the process-private heap */ |
| 96 | svm_pop_heap(oldheap); |
| 97 | pthread_mutex_unlock(&pm->c->db_rp->mutex); |
| 98 | |
| 99 | /* |
| 100 | * Set the root pointer. Note: this guy switches heaps, locks, etc. |
| 101 | * We allocated demo1 as a vector to make this "just work..." |
| 102 | */ |
| 103 | svmdb_local_set_vec_variable (pm->c, "demo1_location", |
| 104 | demo1, sizeof (demo1)); |
| 105 | |
| 106 | } |
| 107 | else { |
| 108 | /* retrieve and print data from shared memory */ |
| 109 | demo2 = demo1->demo2; |
| 110 | fformat (stdout, "name: %s\n", demo1->name); |
| 111 | fformat (stdout, "demo2 location: %llx\n", demo2); |
| 112 | fformat (stdout, "string1: %s\n", demo2->string1); |
| 113 | fformat (stdout, "string2: %s\n", demo2->string2); |
| 114 | } |
| 115 | return 0; |
| 116 | } |
| 117 | |
| 118 | void unserialize_demo1 (serialize_main_t *sm, va_list * args) |
| 119 | { |
| 120 | demo_struct1_t ** result = va_arg (*args, demo_struct1_t **); |
| 121 | demo_struct1_t * demo1; |
| 122 | demo_struct2_t * demo2; |
| 123 | |
| 124 | /* Allocate data structures in process private memory */ |
| 125 | demo1 = clib_mem_alloc (sizeof (*demo1)); |
| 126 | demo2 = clib_mem_alloc (sizeof (*demo2)); |
| 127 | demo1->demo2 = demo2; |
| 128 | |
| 129 | /* retrieve data from shared memory checkpoint */ |
| 130 | unserialize_cstring (sm, (char **) &demo1->name); |
| 131 | unserialize_cstring (sm, (char **) &demo2->string1); |
| 132 | unserialize_cstring (sm, (char **) &demo2->string2); |
| 133 | *result = demo1; |
| 134 | } |
| 135 | |
| 136 | void serialize_demo1 (serialize_main_t *sm, va_list * args) |
| 137 | { |
| 138 | demo_struct1_t * demo1 = va_arg (*args, demo_struct1_t *); |
| 139 | demo_struct2_t * demo2 = demo1->demo2; |
| 140 | |
| 141 | serialize_cstring (sm, (char *)demo1->name); |
| 142 | serialize_cstring (sm, (char *)demo2->string1); |
| 143 | serialize_cstring (sm, (char *)demo2->string2); |
| 144 | } |
| 145 | |
| 146 | /* Serialize / unserialize variant */ |
| 147 | clib_error_t * |
| 148 | persist_serialize (persist_main_t * pm) |
| 149 | { |
| 150 | u8 * checkpoint; |
| 151 | serialize_main_t sm; |
| 152 | |
| 153 | demo_struct2_t *demo2; |
| 154 | demo_struct1_t *demo1; |
| 155 | time_t starttime = time(0); |
| 156 | char *datestring = ctime(&starttime); |
| 157 | |
| 158 | /* Get back the root pointer */ |
| 159 | checkpoint = svmdb_local_get_vec_variable (pm->c, "demo1_checkpoint", |
| 160 | sizeof (u8)); |
| 161 | |
| 162 | /* It doesnt exist create our data structures */ |
| 163 | if (checkpoint == 0) { |
| 164 | /* Allocate data structures in process-private memory */ |
| 165 | demo1 = clib_mem_alloc (sizeof (*demo2)); |
| 166 | vec_validate (demo1, 0); |
| 167 | demo2 = clib_mem_alloc (sizeof (*demo2)); |
| 168 | |
| 169 | demo1->demo2 = demo2; |
| 170 | demo1->name = format (0, "My name is Ishmael%c", 0); |
| 171 | demo2->string1 = format (0, "Here is string1%c", 0); |
| 172 | demo2->string2 = format (0, "Born at %s%c", datestring, 0); |
| 173 | |
| 174 | /* Create checkpoint */ |
| 175 | serialize_open_vector (&sm, checkpoint); |
| 176 | serialize (&sm, serialize_demo1, demo1); |
| 177 | checkpoint = serialize_close_vector (&sm); |
| 178 | |
| 179 | /* Copy checkpoint into shared memory */ |
| 180 | svmdb_local_set_vec_variable (pm->c, "demo1_checkpoint", |
| 181 | checkpoint, sizeof (u8)); |
| 182 | /* Toss the process-private-memory original.. */ |
| 183 | vec_free (checkpoint); |
| 184 | } |
| 185 | else { |
| 186 | /* Open the checkpoint */ |
| 187 | unserialize_open_data (&sm, checkpoint, vec_len (checkpoint)); |
| 188 | unserialize (&sm, unserialize_demo1, &demo1); |
| 189 | |
| 190 | /* Toss the process-private-memory checkpoint copy */ |
| 191 | vec_free (checkpoint); |
| 192 | |
| 193 | /* Off we go... */ |
| 194 | demo2 = demo1->demo2; |
| 195 | fformat (stdout, "name: %s\n", demo1->name); |
| 196 | fformat (stdout, "demo2 location: %llx\n", demo2); |
| 197 | fformat (stdout, "string1: %s\n", demo2->string1); |
| 198 | fformat (stdout, "string2: %s\n", demo2->string2); |
| 199 | } |
| 200 | return 0; |
| 201 | } |
| 202 | |
| 203 | |
| 204 | int main (int argc, char **argv) |
| 205 | { |
| 206 | unformat_input_t _input, *input=&_input; |
| 207 | persist_main_t * pm = &persist_main; |
| 208 | clib_error_t * error = 0; |
| 209 | |
| 210 | /* Make a 4mb database arena, chroot so it's truly private */ |
| 211 | pm->c = svmdb_map_chroot_size ("/ptest", 4<<20); |
| 212 | |
| 213 | ASSERT(pm->c); |
| 214 | |
| 215 | unformat_init_command_line (input, argv); |
| 216 | |
| 217 | while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT) { |
| 218 | if (unformat (input, "malloc")) |
| 219 | error = persist_malloc (pm); |
| 220 | else if (unformat (input, "serialize")) |
| 221 | error = persist_serialize (pm); |
| 222 | else { |
| 223 | error = clib_error_return (0, "Unknown flavor '%U'", |
| 224 | format_unformat_error, input); |
| 225 | break; |
| 226 | } |
| 227 | } |
| 228 | |
| 229 | svmdb_unmap (pm->c); |
| 230 | |
| 231 | if (error) { |
| 232 | clib_error_report (error); |
| 233 | exit (1); |
| 234 | } |
| 235 | return 0; |
| 236 | } |