Fixed issue with json output in vpp_api_test.
[vpp.git] / svm / persist.c
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 }