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.
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:
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
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.
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
38 * Implementation of the osm_db interface using simple text files
43 #endif /* HAVE_CONFIG_H */
46 #include <sys/types.h>
49 #include <opensm/st.h>
50 #include <opensm/osm_db.h>
52 /****d* Database/OSM_DB_MAX_LINE_LEN
57 * The Maximal line length allowed for the file
61 #define OSM_DB_MAX_LINE_LEN 1024
64 /****d* Database/OSM_DB_MAX_GUID_LEN
69 * The Maximal word length allowed for the file (guid or lid)
73 #define OSM_DB_MAX_GUID_LEN 32
76 /****s* OpenSM: Database/osm_db_domain_imp
81 * An implementation for domain of the database based on text files and
86 typedef struct osm_db_domain_imp {
90 } osm_db_domain_imp_t;
98 /****s* OpenSM: Database/osm_db_imp_t
103 * An implementation for file based database
107 typedef struct osm_db_imp {
114 * The directory holding the database
120 /***************************************************************************
121 ***************************************************************************/
122 void osm_db_construct(IN osm_db_t * const p_db)
124 memset(p_db, 0, sizeof(osm_db_t));
125 cl_list_construct(&p_db->domains);
128 /***************************************************************************
129 ***************************************************************************/
130 void osm_db_domain_destroy(IN osm_db_domain_t * const p_db_domain)
132 osm_db_domain_imp_t *p_domain_imp;
133 p_domain_imp = (osm_db_domain_imp_t *) p_db_domain->p_domain_imp;
135 osm_db_clear(p_db_domain);
137 cl_spinlock_destroy(&p_domain_imp->lock);
139 st_free_table(p_domain_imp->p_hash);
140 free(p_domain_imp->file_name);
144 /***************************************************************************
145 ***************************************************************************/
146 void osm_db_destroy(IN osm_db_t * const p_db)
148 osm_db_domain_t *p_domain;
150 while ((p_domain = cl_list_remove_head(&p_db->domains)) != NULL) {
151 osm_db_domain_destroy(p_domain);
154 cl_list_destroy(&p_db->domains);
155 free(p_db->p_db_imp);
158 /***************************************************************************
159 ***************************************************************************/
160 int osm_db_init(IN osm_db_t * const p_db, IN osm_log_t * p_log)
162 osm_db_imp_t *p_db_imp;
165 OSM_LOG_ENTER(p_log);
167 p_db_imp = (osm_db_imp_t *) malloc(sizeof(osm_db_imp_t));
168 CL_ASSERT(p_db_imp != NULL);
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;
174 /* Create the directory if it doesn't exist */
175 /* There is a difference in creating directory between windows and linux */
177 /* Check if the directory exists. If not - create it. */
178 CreateDirectory(p_db_imp->db_dir_name, NULL);
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);
193 p_db->p_db_imp = (void *)p_db_imp;
195 cl_list_init(&p_db->domains, 5);
202 /***************************************************************************
203 ***************************************************************************/
204 osm_db_domain_t *osm_db_domain_init(IN osm_db_t * const p_db,
205 IN char *domain_name)
207 osm_db_domain_t *p_domain;
208 osm_db_domain_imp_t *p_domain_imp;
210 osm_log_t *p_log = p_db->p_log;
213 OSM_LOG_ENTER(p_log);
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);
220 (osm_db_domain_imp_t *) malloc(sizeof(osm_db_domain_imp_t));
221 CL_ASSERT(p_domain_imp != NULL);
223 dir_name_len = strlen(((osm_db_imp_t *) p_db->p_db_imp)->db_dir_name);
225 /* set the domain file name */
226 p_domain_imp->file_name =
227 (char *)malloc(sizeof(char) * (dir_name_len) + strlen(domain_name) +
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);
234 /* make sure the file exists - or exit if not writable */
235 p_file = fopen(p_domain_imp->file_name, "a+");
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);
247 /* initialize the hash table object */
248 p_domain_imp->p_hash = st_init_strtable();
249 CL_ASSERT(p_domain_imp->p_hash != NULL);
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);
262 /***************************************************************************
263 ***************************************************************************/
264 int osm_db_restore(IN osm_db_domain_t * p_domain)
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;
272 char sLine[OSM_DB_MAX_LINE_LEN];
273 boolean_t before_key;
274 char *p_first_word, *p_rest_of_line, *p_last;
276 char *p_prev_val, *p_accum_val = NULL;
278 unsigned int line_num;
280 OSM_LOG_ENTER(p_log);
282 /* take the lock on the domain */
283 cl_spinlock_acquire(&p_domain_imp->lock);
285 /* open the file - read mode */
286 p_file = fopen(p_domain_imp->file_name, "r");
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);
296 /* parse the file allocating new hash tables as required */
299 before_key (0) -> in_key (1)
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
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"))
315 if ((sLine[0] != ' ') && (sLine[0] != '\t')
316 && (sLine[0] != '\n')) {
317 /* we got a new key */
322 strtok_r(sLine, " \t\n", &p_last);
324 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6104: "
325 "Failed to get key from line:%u : %s (file:%s)\n",
327 p_domain_imp->file_name);
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",
335 p_domain_imp->file_name);
341 (char *)malloc(sizeof(char) *
342 (strlen(p_first_word) + 1));
343 strcpy(p_key, p_first_word);
345 p_rest_of_line = strtok_r(NULL, "\n", &p_last);
346 if (p_rest_of_line != NULL) {
348 (char *)malloc(sizeof(char) *
352 strcpy(p_accum_val, p_rest_of_line);
354 p_accum_val = (char *)malloc(2);
355 strcpy(p_accum_val, "\0");
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",
361 p_domain_imp->file_name);
367 /* we already have a key */
369 if (sLine[0] == '\n') {
370 /* got an end of key */
373 /* make sure the key was not previously used */
374 if (st_lookup(p_domain_imp->p_hash,
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."
381 p_domain_imp->file_name,
387 OSM_LOG(p_log, OSM_LOG_DEBUG,
388 "Got key:%s value:%s\n", p_key,
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);
397 /* store our key and value */
398 st_insert(p_domain_imp->p_hash,
400 (st_data_t) p_accum_val);
403 /* accumulate into the value */
404 p_prev_val = p_accum_val;
406 (char *)malloc(strlen(p_prev_val) +
408 strcpy(p_accum_val, p_prev_val);
410 strcat(p_accum_val, sLine);
413 } /* while lines or last line */
419 cl_spinlock_release(&p_domain_imp->lock);
424 /***************************************************************************
425 ***************************************************************************/
426 static int __osm_dump_tbl_entry(st_data_t key, st_data_t val, st_data_t arg)
428 FILE *p_file = (FILE *) arg;
429 char *p_key = (char *)key;
430 char *p_val = (char *)val;
432 fprintf(p_file, "%s %s\n\n", p_key, p_val);
436 int osm_db_store(IN osm_db_domain_t * p_domain)
438 osm_log_t *p_log = p_domain->p_db->p_log;
439 osm_db_domain_imp_t *p_domain_imp;
442 char *p_tmp_file_name;
444 OSM_LOG_ENTER(p_log);
446 p_domain_imp = (osm_db_domain_imp_t *) p_domain->p_domain_imp;
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");
453 cl_spinlock_acquire(&p_domain_imp->lock);
455 /* open up the output file */
456 p_file = fopen(p_tmp_file_name, "w");
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);
465 st_foreach(p_domain_imp->p_hash, __osm_dump_tbl_entry,
469 /* move the domain file */
470 status = remove(p_domain_imp->file_name);
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);
477 status = rename(p_tmp_file_name, p_domain_imp->file_name);
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);
484 cl_spinlock_release(&p_domain_imp->lock);
485 free(p_tmp_file_name);
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)
501 int osm_db_clear(IN osm_db_domain_t * p_domain)
503 osm_db_domain_imp_t *p_domain_imp =
504 (osm_db_domain_imp_t *) p_domain->p_domain_imp;
506 cl_spinlock_acquire(&p_domain_imp->lock);
507 st_foreach(p_domain_imp->p_hash, __osm_clear_tbl_entry,
509 cl_spinlock_release(&p_domain_imp->lock);
514 /***************************************************************************
515 ***************************************************************************/
516 static int __osm_get_key_of_tbl_entry(st_data_t key, st_data_t val,
519 cl_list_t *p_list = (cl_list_t *) arg;
520 cl_list_insert_tail(p_list, (void *)key);
524 int osm_db_keys(IN osm_db_domain_t * p_domain, OUT cl_list_t * p_key_list)
526 osm_db_domain_imp_t *p_domain_imp =
527 (osm_db_domain_imp_t *) p_domain->p_domain_imp;
529 cl_spinlock_acquire(&p_domain_imp->lock);
531 st_foreach(p_domain_imp->p_hash,
532 __osm_get_key_of_tbl_entry, (st_data_t) p_key_list);
534 cl_spinlock_release(&p_domain_imp->lock);
539 /***************************************************************************
540 ***************************************************************************/
541 char *osm_db_lookup(IN osm_db_domain_t * p_domain, IN char *const p_key)
543 osm_db_domain_imp_t *p_domain_imp =
544 (osm_db_domain_imp_t *) p_domain->p_domain_imp;
547 cl_spinlock_acquire(&p_domain_imp->lock);
550 (p_domain_imp->p_hash, (st_data_t) p_key, (void *) & p_val))
553 cl_spinlock_release(&p_domain_imp->lock);
558 /***************************************************************************
559 ***************************************************************************/
561 osm_db_update(IN osm_db_domain_t * p_domain,
562 IN char *const p_key, IN char *const p_val)
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;
571 cl_spinlock_acquire(&p_domain_imp->lock);
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);
580 /* need to allocate the key */
581 p_new_key = malloc(sizeof(char) * (strlen(p_key) + 1));
582 strcpy(p_new_key, p_key);
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);
589 st_insert(p_domain_imp->p_hash, (st_data_t) p_new_key,
590 (st_data_t) p_new_val);
595 cl_spinlock_release(&p_domain_imp->lock);
600 /***************************************************************************
601 ***************************************************************************/
602 int osm_db_delete(IN osm_db_domain_t * p_domain, IN char *const p_key)
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;
610 OSM_LOG_ENTER(p_log);
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);
627 OSM_LOG(p_log, OSM_LOG_DEBUG,
628 "fail to find key:%s. delete failed\n", p_key);
631 cl_spinlock_release(&p_domain_imp->lock);
641 int main(int argc, char **argv)
645 osm_db_domain_t *p_dbd;
647 cl_list_iterator_t kI;
652 cl_list_construct(&keys);
653 cl_list_init(&keys, 10);
655 osm_log_init_v2(&log, TRUE, 0xff, "/var/log/osm_db_test.log", 0, FALSE);
657 osm_db_construct(&db);
658 if (osm_db_init(&db, &log)) {
659 printf("db init failed\n");
663 p_dbd = osm_db_domain_init(&db, "lid_by_guid");
665 if (osm_db_restore(p_dbd)) {
666 printf("failed to restore\n");
669 if (osm_db_keys(p_dbd, &keys)) {
670 printf("failed to get keys\n");
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);
677 p_val = osm_db_lookup(p_dbd, p_key);
678 printf("key = %s val = %s\n", p_key, p_val);
682 cl_list_remove_all(&keys);
684 /* randomly add and remove numbers */
685 for (i = 0; i < 10; i++) {
692 k = floor(1.0 * rand() / RAND_MAX * 100);
694 sprintf(key_buf, "%u", k);
695 sprintf(val_buf, "%u", v);
697 is_add = (rand() < RAND_MAX / 2);
700 osm_db_update(p_dbd, key_buf, val_buf);
702 osm_db_delete(p_dbd, key_buf);
705 if (osm_db_keys(p_dbd, &keys)) {
706 printf("failed to get keys\n");
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);
713 p_val = osm_db_lookup(p_dbd, p_key);
714 printf("key = %s val = %s\n", p_key, p_val);
717 if (osm_db_store(p_dbd))
718 printf("failed to store\n");
721 cl_list_destroy(&keys);