]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ofed/management/opensm/opensm/osm_db_files.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ofed / management / opensm / opensm / osm_db_files.c
1 /*
2  * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved.
4  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5  *
6  * This software is available to you under a choice of one of two
7  * licenses.  You may choose to be licensed under the terms of the GNU
8  * General Public License (GPL) Version 2, available from the file
9  * COPYING in the main directory of this source tree, or the
10  * OpenIB.org BSD license below:
11  *
12  *     Redistribution and use in source and binary forms, with or
13  *     without modification, are permitted provided that the following
14  *     conditions are met:
15  *
16  *      - Redistributions of source code must retain the above
17  *        copyright notice, this list of conditions and the following
18  *        disclaimer.
19  *
20  *      - Redistributions in binary form must reproduce the above
21  *        copyright notice, this list of conditions and the following
22  *        disclaimer in the documentation and/or other materials
23  *        provided with the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  * SOFTWARE.
33  *
34  */
35
36 /*
37  * Abstract:
38  * Implementation of the osm_db interface using simple text files
39  */
40
41 #if HAVE_CONFIG_H
42 #  include <config.h>
43 #endif                          /* HAVE_CONFIG_H */
44
45 #include <sys/stat.h>
46 #include <sys/types.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <opensm/st.h>
50 #include <opensm/osm_db.h>
51
52 /****d* Database/OSM_DB_MAX_LINE_LEN
53  * NAME
54  * OSM_DB_MAX_LINE_LEN
55  *
56  * DESCRIPTION
57  * The Maximal line length allowed for the file
58  *
59  * SYNOPSIS
60  */
61 #define OSM_DB_MAX_LINE_LEN 1024
62 /**********/
63
64 /****d* Database/OSM_DB_MAX_GUID_LEN
65  * NAME
66  * OSM_DB_MAX_GUID_LEN
67  *
68  * DESCRIPTION
69  * The Maximal word length allowed for the file (guid or lid)
70  *
71  * SYNOPSIS
72  */
73 #define OSM_DB_MAX_GUID_LEN 32
74 /**********/
75
76 /****s* OpenSM: Database/osm_db_domain_imp
77  * NAME
78  * osm_db_domain_imp
79  *
80  * DESCRIPTION
81  * An implementation for domain of the database based on text files and
82  *  hash tables.
83  *
84  * SYNOPSIS
85  */
86 typedef struct osm_db_domain_imp {
87         char *file_name;
88         st_table *p_hash;
89         cl_spinlock_t lock;
90 } osm_db_domain_imp_t;
91 /*
92  * FIELDS
93  *
94  * SEE ALSO
95  * osm_db_domain_t
96  *********/
97
98 /****s* OpenSM: Database/osm_db_imp_t
99  * NAME
100  * osm_db_imp_t
101  *
102  * DESCRIPTION
103  * An implementation for file based database
104  *
105  * SYNOPSIS
106  */
107 typedef struct osm_db_imp {
108         char *db_dir_name;
109 } osm_db_imp_t;
110 /*
111  * FIELDS
112  *
113  * db_dir_name
114  *   The directory holding the database
115  *
116  * SEE ALSO
117  * osm_db_t
118  *********/
119
120 /***************************************************************************
121  ***************************************************************************/
122 void osm_db_construct(IN osm_db_t * const p_db)
123 {
124         memset(p_db, 0, sizeof(osm_db_t));
125         cl_list_construct(&p_db->domains);
126 }
127
128 /***************************************************************************
129  ***************************************************************************/
130 void osm_db_domain_destroy(IN osm_db_domain_t * const p_db_domain)
131 {
132         osm_db_domain_imp_t *p_domain_imp;
133         p_domain_imp = (osm_db_domain_imp_t *) p_db_domain->p_domain_imp;
134
135         osm_db_clear(p_db_domain);
136
137         cl_spinlock_destroy(&p_domain_imp->lock);
138
139         st_free_table(p_domain_imp->p_hash);
140         free(p_domain_imp->file_name);
141         free(p_domain_imp);
142 }
143
144 /***************************************************************************
145  ***************************************************************************/
146 void osm_db_destroy(IN osm_db_t * const p_db)
147 {
148         osm_db_domain_t *p_domain;
149
150         while ((p_domain = cl_list_remove_head(&p_db->domains)) != NULL) {
151                 osm_db_domain_destroy(p_domain);
152                 free(p_domain);
153         }
154         cl_list_destroy(&p_db->domains);
155         free(p_db->p_db_imp);
156 }
157
158 /***************************************************************************
159  ***************************************************************************/
160 int osm_db_init(IN osm_db_t * const p_db, IN osm_log_t * p_log)
161 {
162         osm_db_imp_t *p_db_imp;
163         struct stat dstat;
164
165         OSM_LOG_ENTER(p_log);
166
167         p_db_imp = (osm_db_imp_t *) malloc(sizeof(osm_db_imp_t));
168         CL_ASSERT(p_db_imp != NULL);
169
170         p_db_imp->db_dir_name = getenv("OSM_CACHE_DIR");
171         if (!p_db_imp->db_dir_name || !(*p_db_imp->db_dir_name))
172                 p_db_imp->db_dir_name = OSM_DEFAULT_CACHE_DIR;
173
174         /* Create the directory if it doesn't exist */
175         /* There is a difference in creating directory between windows and linux */
176 #ifdef __WIN__
177         /* Check if the directory exists. If not - create it. */
178         CreateDirectory(p_db_imp->db_dir_name, NULL);
179 #else                           /* __WIN__ */
180         /* make sure the directory exists */
181         if (lstat(p_db_imp->db_dir_name, &dstat)) {
182                 if (mkdir(p_db_imp->db_dir_name, 0755)) {
183                         OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6101: "
184                                 "Failed to create the db directory:%s\n",
185                                 p_db_imp->db_dir_name);
186                         OSM_LOG_EXIT(p_log);
187                         return 1;
188                 }
189         }
190 #endif
191
192         p_db->p_log = p_log;
193         p_db->p_db_imp = (void *)p_db_imp;
194
195         cl_list_init(&p_db->domains, 5);
196
197         OSM_LOG_EXIT(p_log);
198
199         return 0;
200 }
201
202 /***************************************************************************
203  ***************************************************************************/
204 osm_db_domain_t *osm_db_domain_init(IN osm_db_t * const p_db,
205                                     IN char *domain_name)
206 {
207         osm_db_domain_t *p_domain;
208         osm_db_domain_imp_t *p_domain_imp;
209         int dir_name_len;
210         osm_log_t *p_log = p_db->p_log;
211         FILE *p_file;
212
213         OSM_LOG_ENTER(p_log);
214
215         /* allocate a new domain object */
216         p_domain = (osm_db_domain_t *) malloc(sizeof(osm_db_domain_t));
217         CL_ASSERT(p_domain != NULL);
218
219         p_domain_imp =
220             (osm_db_domain_imp_t *) malloc(sizeof(osm_db_domain_imp_t));
221         CL_ASSERT(p_domain_imp != NULL);
222
223         dir_name_len = strlen(((osm_db_imp_t *) p_db->p_db_imp)->db_dir_name);
224
225         /* set the domain file name */
226         p_domain_imp->file_name =
227             (char *)malloc(sizeof(char) * (dir_name_len) + strlen(domain_name) +
228                            2);
229         CL_ASSERT(p_domain_imp->file_name != NULL);
230         strcpy(p_domain_imp->file_name,
231                ((osm_db_imp_t *) p_db->p_db_imp)->db_dir_name);
232         strcat(p_domain_imp->file_name, domain_name);
233
234         /* make sure the file exists - or exit if not writable */
235         p_file = fopen(p_domain_imp->file_name, "a+");
236         if (!p_file) {
237                 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6102: "
238                         "Failed to open the db file:%s\n",
239                         p_domain_imp->file_name);
240                 free(p_domain_imp);
241                 free(p_domain);
242                 p_domain = NULL;
243                 goto Exit;
244         }
245         fclose(p_file);
246
247         /* initialize the hash table object */
248         p_domain_imp->p_hash = st_init_strtable();
249         CL_ASSERT(p_domain_imp->p_hash != NULL);
250
251         p_domain->p_db = p_db;
252         cl_list_insert_tail(&p_db->domains, p_domain);
253         p_domain->p_domain_imp = p_domain_imp;
254         cl_spinlock_construct(&p_domain_imp->lock);
255         cl_spinlock_init(&p_domain_imp->lock);
256
257 Exit:
258         OSM_LOG_EXIT(p_log);
259         return p_domain;
260 }
261
262 /***************************************************************************
263  ***************************************************************************/
264 int osm_db_restore(IN osm_db_domain_t * p_domain)
265 {
266
267         osm_log_t *p_log = p_domain->p_db->p_log;
268         osm_db_domain_imp_t *p_domain_imp =
269             (osm_db_domain_imp_t *) p_domain->p_domain_imp;
270         FILE *p_file;
271         int status;
272         char sLine[OSM_DB_MAX_LINE_LEN];
273         boolean_t before_key;
274         char *p_first_word, *p_rest_of_line, *p_last;
275         char *p_key = NULL;
276         char *p_prev_val, *p_accum_val = NULL;
277         char *endptr = NULL;
278         unsigned int line_num;
279
280         OSM_LOG_ENTER(p_log);
281
282         /* take the lock on the domain */
283         cl_spinlock_acquire(&p_domain_imp->lock);
284
285         /* open the file - read mode */
286         p_file = fopen(p_domain_imp->file_name, "r");
287
288         if (!p_file) {
289                 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6103: "
290                         "Failed to open the db file:%s\n",
291                         p_domain_imp->file_name);
292                 status = 1;
293                 goto Exit;
294         }
295
296         /* parse the file allocating new hash tables as required */
297         /*
298            states:
299            before_key (0) -> in_key (1)
300
301            before_key: if a word on the first byte - it is the key. state=in_key
302            the rest of the line is start of the value.
303            in_key: unless the line is empty - add it (with newlines) to the value.
304            if empty: state=before_key
305          */
306         status = 0;
307         before_key = TRUE;
308         line_num = 0;
309         /* if we got to EOF in the middle of a key we add a last newline */
310         while ((fgets(sLine, OSM_DB_MAX_LINE_LEN, p_file) != NULL) ||
311                ((before_key == FALSE) && strcpy(sLine, "\n"))
312             ) {
313                 line_num++;
314                 if (before_key) {
315                         if ((sLine[0] != ' ') && (sLine[0] != '\t')
316                             && (sLine[0] != '\n')) {
317                                 /* we got a new key */
318                                 before_key = FALSE;
319
320                                 /* handle the key */
321                                 p_first_word =
322                                     strtok_r(sLine, " \t\n", &p_last);
323                                 if (!p_first_word) {
324                                         OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6104: "
325                                                 "Failed to get key from line:%u : %s (file:%s)\n",
326                                                 line_num, sLine,
327                                                 p_domain_imp->file_name);
328                                         status = 1;
329                                         goto EndParsing;
330                                 }
331                                 if (strlen(p_first_word) > OSM_DB_MAX_GUID_LEN) {
332                                         OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 610A: "
333                                                 "Illegal key from line:%u : %s (file:%s)\n",
334                                                 line_num, sLine,
335                                                 p_domain_imp->file_name);
336                                         status = 1;
337                                         goto EndParsing;
338                                 }
339
340                                 p_key =
341                                     (char *)malloc(sizeof(char) *
342                                                    (strlen(p_first_word) + 1));
343                                 strcpy(p_key, p_first_word);
344
345                                 p_rest_of_line = strtok_r(NULL, "\n", &p_last);
346                                 if (p_rest_of_line != NULL) {
347                                         p_accum_val =
348                                             (char *)malloc(sizeof(char) *
349                                                            (strlen
350                                                             (p_rest_of_line) +
351                                                             1));
352                                         strcpy(p_accum_val, p_rest_of_line);
353                                 } else {
354                                         p_accum_val = (char *)malloc(2);
355                                         strcpy(p_accum_val, "\0");
356                                 }
357                         } else if (sLine[0] != '\n') {
358                                 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6105: "
359                                         "How did we get here? line:%u : %s (file:%s)\n",
360                                         line_num, sLine,
361                                         p_domain_imp->file_name);
362                                 status = 1;
363                                 goto EndParsing;
364                         }
365                 } /* before key */
366                 else {
367                         /* we already have a key */
368
369                         if (sLine[0] == '\n') {
370                                 /* got an end of key */
371                                 before_key = TRUE;
372
373                                 /* make sure the key was not previously used */
374                                 if (st_lookup(p_domain_imp->p_hash,
375                                               (st_data_t) p_key,
376                                               (void *) & p_prev_val)) {
377                                         OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6106: "
378                                                 "Key:%s already exists in:%s with value:%s."
379                                                 " Removing it\n",
380                                                 p_key,
381                                                 p_domain_imp->file_name,
382                                                 p_prev_val);
383                                 } else {
384                                         p_prev_val = NULL;
385                                 }
386
387                                 OSM_LOG(p_log, OSM_LOG_DEBUG,
388                                         "Got key:%s value:%s\n", p_key,
389                                         p_accum_val);
390
391                                 /* check that the key is a number */
392                                 if (!strtouq(p_key, &endptr, 0)
393                                     && *endptr != '\0') {
394                                         OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 610B: "
395                                                 "Key:%s is invalid\n", p_key);
396                                 } else {
397                                         /* store our key and value */
398                                         st_insert(p_domain_imp->p_hash,
399                                                   (st_data_t) p_key,
400                                                   (st_data_t) p_accum_val);
401                                 }
402                         } else {
403                                 /* accumulate into the value */
404                                 p_prev_val = p_accum_val;
405                                 p_accum_val =
406                                     (char *)malloc(strlen(p_prev_val) +
407                                                    strlen(sLine) + 1);
408                                 strcpy(p_accum_val, p_prev_val);
409                                 free(p_prev_val);
410                                 strcat(p_accum_val, sLine);
411                         }
412                 }               /* in key */
413         }                       /* while lines or last line */
414
415 EndParsing:
416         fclose(p_file);
417
418 Exit:
419         cl_spinlock_release(&p_domain_imp->lock);
420         OSM_LOG_EXIT(p_log);
421         return status;
422 }
423
424 /***************************************************************************
425  ***************************************************************************/
426 static int __osm_dump_tbl_entry(st_data_t key, st_data_t val, st_data_t arg)
427 {
428         FILE *p_file = (FILE *) arg;
429         char *p_key = (char *)key;
430         char *p_val = (char *)val;
431
432         fprintf(p_file, "%s %s\n\n", p_key, p_val);
433         return ST_CONTINUE;
434 }
435
436 int osm_db_store(IN osm_db_domain_t * p_domain)
437 {
438         osm_log_t *p_log = p_domain->p_db->p_log;
439         osm_db_domain_imp_t *p_domain_imp;
440         FILE *p_file;
441         int status = 0;
442         char *p_tmp_file_name;
443
444         OSM_LOG_ENTER(p_log);
445
446         p_domain_imp = (osm_db_domain_imp_t *) p_domain->p_domain_imp;
447         p_tmp_file_name =
448             (char *)malloc(sizeof(char) *
449                            (strlen(p_domain_imp->file_name) + 8));
450         strcpy(p_tmp_file_name, p_domain_imp->file_name);
451         strcat(p_tmp_file_name, ".tmp");
452
453         cl_spinlock_acquire(&p_domain_imp->lock);
454
455         /* open up the output file */
456         p_file = fopen(p_tmp_file_name, "w");
457         if (!p_file) {
458                 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6107: "
459                         "Failed to open the db file:%s for writing\n",
460                         p_domain_imp->file_name);
461                 status = 1;
462                 goto Exit;
463         }
464
465         st_foreach(p_domain_imp->p_hash, __osm_dump_tbl_entry,
466                    (st_data_t) p_file);
467         fclose(p_file);
468
469         /* move the domain file */
470         status = remove(p_domain_imp->file_name);
471         if (status) {
472                 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6109: "
473                         "Failed to remove file:%s (err:%u)\n",
474                         p_domain_imp->file_name, status);
475         }
476
477         status = rename(p_tmp_file_name, p_domain_imp->file_name);
478         if (status) {
479                 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6108: "
480                         "Failed to rename the db file to:%s (err:%u)\n",
481                         p_domain_imp->file_name, status);
482         }
483 Exit:
484         cl_spinlock_release(&p_domain_imp->lock);
485         free(p_tmp_file_name);
486         OSM_LOG_EXIT(p_log);
487         return status;
488 }
489
490 /***************************************************************************
491  ***************************************************************************/
492 /* simply de-allocate the key and the value and return the code
493    that makes the st_foreach delete the entry */
494 static int __osm_clear_tbl_entry(st_data_t key, st_data_t val, st_data_t arg)
495 {
496         free((char *)key);
497         free((char *)val);
498         return ST_DELETE;
499 }
500
501 int osm_db_clear(IN osm_db_domain_t * p_domain)
502 {
503         osm_db_domain_imp_t *p_domain_imp =
504             (osm_db_domain_imp_t *) p_domain->p_domain_imp;
505
506         cl_spinlock_acquire(&p_domain_imp->lock);
507         st_foreach(p_domain_imp->p_hash, __osm_clear_tbl_entry,
508                    (st_data_t) NULL);
509         cl_spinlock_release(&p_domain_imp->lock);
510
511         return 0;
512 }
513
514 /***************************************************************************
515  ***************************************************************************/
516 static int __osm_get_key_of_tbl_entry(st_data_t key, st_data_t val,
517                                       st_data_t arg)
518 {
519         cl_list_t *p_list = (cl_list_t *) arg;
520         cl_list_insert_tail(p_list, (void *)key);
521         return ST_CONTINUE;
522 }
523
524 int osm_db_keys(IN osm_db_domain_t * p_domain, OUT cl_list_t * p_key_list)
525 {
526         osm_db_domain_imp_t *p_domain_imp =
527             (osm_db_domain_imp_t *) p_domain->p_domain_imp;
528
529         cl_spinlock_acquire(&p_domain_imp->lock);
530
531         st_foreach(p_domain_imp->p_hash,
532                    __osm_get_key_of_tbl_entry, (st_data_t) p_key_list);
533
534         cl_spinlock_release(&p_domain_imp->lock);
535
536         return 0;
537 }
538
539 /***************************************************************************
540  ***************************************************************************/
541 char *osm_db_lookup(IN osm_db_domain_t * p_domain, IN char *const p_key)
542 {
543         osm_db_domain_imp_t *p_domain_imp =
544             (osm_db_domain_imp_t *) p_domain->p_domain_imp;
545         char *p_val = NULL;
546
547         cl_spinlock_acquire(&p_domain_imp->lock);
548
549         if (!st_lookup
550             (p_domain_imp->p_hash, (st_data_t) p_key, (void *) & p_val))
551                 p_val = NULL;
552
553         cl_spinlock_release(&p_domain_imp->lock);
554
555         return p_val;
556 }
557
558 /***************************************************************************
559  ***************************************************************************/
560 int
561 osm_db_update(IN osm_db_domain_t * p_domain,
562               IN char *const p_key, IN char *const p_val)
563 {
564         osm_log_t *p_log = p_domain->p_db->p_log;
565         osm_db_domain_imp_t *p_domain_imp =
566             (osm_db_domain_imp_t *) p_domain->p_domain_imp;
567         char *p_prev_val = NULL;
568         char *p_new_key;
569         char *p_new_val;
570
571         cl_spinlock_acquire(&p_domain_imp->lock);
572
573         if (st_lookup(p_domain_imp->p_hash,
574                       (st_data_t) p_key, (void *) & p_prev_val)) {
575                 OSM_LOG(p_log, OSM_LOG_DEBUG,
576                         "Key:%s previously exists in:%s with value:%s\n",
577                         p_key, p_domain_imp->file_name, p_prev_val);
578                 p_new_key = p_key;
579         } else {
580                 /* need to allocate the key */
581                 p_new_key = malloc(sizeof(char) * (strlen(p_key) + 1));
582                 strcpy(p_new_key, p_key);
583         }
584
585         /* need to arange a new copy of the  value */
586         p_new_val = malloc(sizeof(char) * (strlen(p_val) + 1));
587         strcpy(p_new_val, p_val);
588
589         st_insert(p_domain_imp->p_hash, (st_data_t) p_new_key,
590                   (st_data_t) p_new_val);
591
592         if (p_prev_val)
593                 free(p_prev_val);
594
595         cl_spinlock_release(&p_domain_imp->lock);
596
597         return 0;
598 }
599
600 /***************************************************************************
601  ***************************************************************************/
602 int osm_db_delete(IN osm_db_domain_t * p_domain, IN char *const p_key)
603 {
604         osm_log_t *p_log = p_domain->p_db->p_log;
605         osm_db_domain_imp_t *p_domain_imp =
606             (osm_db_domain_imp_t *) p_domain->p_domain_imp;
607         char *p_prev_val = NULL;
608         int res;
609
610         OSM_LOG_ENTER(p_log);
611
612         cl_spinlock_acquire(&p_domain_imp->lock);
613         if (st_delete(p_domain_imp->p_hash,
614                       (void *) & p_key, (void *) & p_prev_val)) {
615                 if (st_lookup(p_domain_imp->p_hash,
616                               (st_data_t) p_key, (void *) & p_prev_val)) {
617                         OSM_LOG(p_log, OSM_LOG_ERROR,
618                                 "key:%s still exists in:%s with value:%s\n",
619                                 p_key, p_domain_imp->file_name, p_prev_val);
620                         res = 1;
621                 } else {
622                         free(p_key);
623                         free(p_prev_val);
624                         res = 0;
625                 }
626         } else {
627                 OSM_LOG(p_log, OSM_LOG_DEBUG,
628                         "fail to find key:%s. delete failed\n", p_key);
629                 res = 1;
630         }
631         cl_spinlock_release(&p_domain_imp->lock);
632
633         OSM_LOG_EXIT(p_log);
634         return res;
635 }
636
637 #ifdef TEST_OSMDB
638 #include <stdlib.h>
639 #include <math.h>
640
641 int main(int argc, char **argv)
642 {
643         osm_db_t db;
644         osm_log_t log;
645         osm_db_domain_t *p_dbd;
646         cl_list_t keys;
647         cl_list_iterator_t kI;
648         char *p_key;
649         char *p_val;
650         int i;
651
652         cl_list_construct(&keys);
653         cl_list_init(&keys, 10);
654
655         osm_log_init_v2(&log, TRUE, 0xff, "/var/log/osm_db_test.log", 0, FALSE);
656
657         osm_db_construct(&db);
658         if (osm_db_init(&db, &log)) {
659                 printf("db init failed\n");
660                 exit(1);
661         }
662
663         p_dbd = osm_db_domain_init(&db, "lid_by_guid");
664
665         if (osm_db_restore(p_dbd)) {
666                 printf("failed to restore\n");
667         }
668
669         if (osm_db_keys(p_dbd, &keys)) {
670                 printf("failed to get keys\n");
671         } else {
672                 kI = cl_list_head(&keys);
673                 while (kI != cl_list_end(&keys)) {
674                         p_key = cl_list_obj(kI);
675                         kI = cl_list_next(kI);
676
677                         p_val = osm_db_lookup(p_dbd, p_key);
678                         printf("key = %s val = %s\n", p_key, p_val);
679                 }
680         }
681
682         cl_list_remove_all(&keys);
683
684         /* randomly add and remove numbers */
685         for (i = 0; i < 10; i++) {
686                 int k;
687                 float v;
688                 int is_add;
689                 char val_buf[16];
690                 char key_buf[16];
691
692                 k = floor(1.0 * rand() / RAND_MAX * 100);
693                 v = rand();
694                 sprintf(key_buf, "%u", k);
695                 sprintf(val_buf, "%u", v);
696
697                 is_add = (rand() < RAND_MAX / 2);
698
699                 if (is_add) {
700                         osm_db_update(p_dbd, key_buf, val_buf);
701                 } else {
702                         osm_db_delete(p_dbd, key_buf);
703                 }
704         }
705         if (osm_db_keys(p_dbd, &keys)) {
706                 printf("failed to get keys\n");
707         } else {
708                 kI = cl_list_head(&keys);
709                 while (kI != cl_list_end(&keys)) {
710                         p_key = cl_list_obj(kI);
711                         kI = cl_list_next(kI);
712
713                         p_val = osm_db_lookup(p_dbd, p_key);
714                         printf("key = %s val = %s\n", p_key, p_val);
715                 }
716         }
717         if (osm_db_store(p_dbd))
718                 printf("failed to store\n");
719
720         osm_db_destroy(&db);
721         cl_list_destroy(&keys);
722 }
723 #endif