1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3219820Sjeff * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved.
4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5219820Sjeff *
6219820Sjeff * This software is available to you under a choice of one of two
7219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
8219820Sjeff * General Public License (GPL) Version 2, available from the file
9219820Sjeff * COPYING in the main directory of this source tree, or the
10219820Sjeff * OpenIB.org BSD license below:
11219820Sjeff *
12219820Sjeff *     Redistribution and use in source and binary forms, with or
13219820Sjeff *     without modification, are permitted provided that the following
14219820Sjeff *     conditions are met:
15219820Sjeff *
16219820Sjeff *      - Redistributions of source code must retain the above
17219820Sjeff *        copyright notice, this list of conditions and the following
18219820Sjeff *        disclaimer.
19219820Sjeff *
20219820Sjeff *      - Redistributions in binary form must reproduce the above
21219820Sjeff *        copyright notice, this list of conditions and the following
22219820Sjeff *        disclaimer in the documentation and/or other materials
23219820Sjeff *        provided with the distribution.
24219820Sjeff *
25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32219820Sjeff * SOFTWARE.
33219820Sjeff *
34219820Sjeff */
35219820Sjeff
36219820Sjeff/*
37219820Sjeff * Abstract:
38219820Sjeff * Implementation of the osm_db interface using simple text files
39219820Sjeff */
40219820Sjeff
41219820Sjeff#if HAVE_CONFIG_H
42219820Sjeff#  include <config.h>
43219820Sjeff#endif				/* HAVE_CONFIG_H */
44219820Sjeff
45219820Sjeff#include <sys/stat.h>
46219820Sjeff#include <sys/types.h>
47219820Sjeff#include <stdlib.h>
48219820Sjeff#include <string.h>
49219820Sjeff#include <opensm/st.h>
50219820Sjeff#include <opensm/osm_db.h>
51219820Sjeff
52219820Sjeff/****d* Database/OSM_DB_MAX_LINE_LEN
53219820Sjeff * NAME
54219820Sjeff * OSM_DB_MAX_LINE_LEN
55219820Sjeff *
56219820Sjeff * DESCRIPTION
57219820Sjeff * The Maximal line length allowed for the file
58219820Sjeff *
59219820Sjeff * SYNOPSIS
60219820Sjeff */
61219820Sjeff#define OSM_DB_MAX_LINE_LEN 1024
62219820Sjeff/**********/
63219820Sjeff
64219820Sjeff/****d* Database/OSM_DB_MAX_GUID_LEN
65219820Sjeff * NAME
66219820Sjeff * OSM_DB_MAX_GUID_LEN
67219820Sjeff *
68219820Sjeff * DESCRIPTION
69219820Sjeff * The Maximal word length allowed for the file (guid or lid)
70219820Sjeff *
71219820Sjeff * SYNOPSIS
72219820Sjeff */
73219820Sjeff#define OSM_DB_MAX_GUID_LEN 32
74219820Sjeff/**********/
75219820Sjeff
76219820Sjeff/****s* OpenSM: Database/osm_db_domain_imp
77219820Sjeff * NAME
78219820Sjeff * osm_db_domain_imp
79219820Sjeff *
80219820Sjeff * DESCRIPTION
81219820Sjeff * An implementation for domain of the database based on text files and
82219820Sjeff *  hash tables.
83219820Sjeff *
84219820Sjeff * SYNOPSIS
85219820Sjeff */
86219820Sjefftypedef struct osm_db_domain_imp {
87219820Sjeff	char *file_name;
88219820Sjeff	st_table *p_hash;
89219820Sjeff	cl_spinlock_t lock;
90219820Sjeff} osm_db_domain_imp_t;
91219820Sjeff/*
92219820Sjeff * FIELDS
93219820Sjeff *
94219820Sjeff * SEE ALSO
95219820Sjeff * osm_db_domain_t
96219820Sjeff *********/
97219820Sjeff
98219820Sjeff/****s* OpenSM: Database/osm_db_imp_t
99219820Sjeff * NAME
100219820Sjeff * osm_db_imp_t
101219820Sjeff *
102219820Sjeff * DESCRIPTION
103219820Sjeff * An implementation for file based database
104219820Sjeff *
105219820Sjeff * SYNOPSIS
106219820Sjeff */
107219820Sjefftypedef struct osm_db_imp {
108219820Sjeff	char *db_dir_name;
109219820Sjeff} osm_db_imp_t;
110219820Sjeff/*
111219820Sjeff * FIELDS
112219820Sjeff *
113219820Sjeff * db_dir_name
114219820Sjeff *   The directory holding the database
115219820Sjeff *
116219820Sjeff * SEE ALSO
117219820Sjeff * osm_db_t
118219820Sjeff *********/
119219820Sjeff
120219820Sjeff/***************************************************************************
121219820Sjeff ***************************************************************************/
122219820Sjeffvoid osm_db_construct(IN osm_db_t * const p_db)
123219820Sjeff{
124219820Sjeff	memset(p_db, 0, sizeof(osm_db_t));
125219820Sjeff	cl_list_construct(&p_db->domains);
126219820Sjeff}
127219820Sjeff
128219820Sjeff/***************************************************************************
129219820Sjeff ***************************************************************************/
130219820Sjeffvoid osm_db_domain_destroy(IN osm_db_domain_t * const p_db_domain)
131219820Sjeff{
132219820Sjeff	osm_db_domain_imp_t *p_domain_imp;
133219820Sjeff	p_domain_imp = (osm_db_domain_imp_t *) p_db_domain->p_domain_imp;
134219820Sjeff
135219820Sjeff	osm_db_clear(p_db_domain);
136219820Sjeff
137219820Sjeff	cl_spinlock_destroy(&p_domain_imp->lock);
138219820Sjeff
139219820Sjeff	st_free_table(p_domain_imp->p_hash);
140219820Sjeff	free(p_domain_imp->file_name);
141219820Sjeff	free(p_domain_imp);
142219820Sjeff}
143219820Sjeff
144219820Sjeff/***************************************************************************
145219820Sjeff ***************************************************************************/
146219820Sjeffvoid osm_db_destroy(IN osm_db_t * const p_db)
147219820Sjeff{
148219820Sjeff	osm_db_domain_t *p_domain;
149219820Sjeff
150219820Sjeff	while ((p_domain = cl_list_remove_head(&p_db->domains)) != NULL) {
151219820Sjeff		osm_db_domain_destroy(p_domain);
152219820Sjeff		free(p_domain);
153219820Sjeff	}
154219820Sjeff	cl_list_destroy(&p_db->domains);
155219820Sjeff	free(p_db->p_db_imp);
156219820Sjeff}
157219820Sjeff
158219820Sjeff/***************************************************************************
159219820Sjeff ***************************************************************************/
160219820Sjeffint osm_db_init(IN osm_db_t * const p_db, IN osm_log_t * p_log)
161219820Sjeff{
162219820Sjeff	osm_db_imp_t *p_db_imp;
163219820Sjeff	struct stat dstat;
164219820Sjeff
165219820Sjeff	OSM_LOG_ENTER(p_log);
166219820Sjeff
167219820Sjeff	p_db_imp = (osm_db_imp_t *) malloc(sizeof(osm_db_imp_t));
168219820Sjeff	CL_ASSERT(p_db_imp != NULL);
169219820Sjeff
170219820Sjeff	p_db_imp->db_dir_name = getenv("OSM_CACHE_DIR");
171219820Sjeff	if (!p_db_imp->db_dir_name || !(*p_db_imp->db_dir_name))
172219820Sjeff		p_db_imp->db_dir_name = OSM_DEFAULT_CACHE_DIR;
173219820Sjeff
174219820Sjeff	/* Create the directory if it doesn't exist */
175219820Sjeff	/* There is a difference in creating directory between windows and linux */
176219820Sjeff#ifdef __WIN__
177219820Sjeff	/* Check if the directory exists. If not - create it. */
178219820Sjeff	CreateDirectory(p_db_imp->db_dir_name, NULL);
179219820Sjeff#else				/* __WIN__ */
180219820Sjeff	/* make sure the directory exists */
181219820Sjeff	if (lstat(p_db_imp->db_dir_name, &dstat)) {
182219820Sjeff		if (mkdir(p_db_imp->db_dir_name, 0755)) {
183219820Sjeff			OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6101: "
184219820Sjeff				"Failed to create the db directory:%s\n",
185219820Sjeff				p_db_imp->db_dir_name);
186219820Sjeff			OSM_LOG_EXIT(p_log);
187219820Sjeff			return 1;
188219820Sjeff		}
189219820Sjeff	}
190219820Sjeff#endif
191219820Sjeff
192219820Sjeff	p_db->p_log = p_log;
193219820Sjeff	p_db->p_db_imp = (void *)p_db_imp;
194219820Sjeff
195219820Sjeff	cl_list_init(&p_db->domains, 5);
196219820Sjeff
197219820Sjeff	OSM_LOG_EXIT(p_log);
198219820Sjeff
199219820Sjeff	return 0;
200219820Sjeff}
201219820Sjeff
202219820Sjeff/***************************************************************************
203219820Sjeff ***************************************************************************/
204219820Sjeffosm_db_domain_t *osm_db_domain_init(IN osm_db_t * const p_db,
205219820Sjeff				    IN char *domain_name)
206219820Sjeff{
207219820Sjeff	osm_db_domain_t *p_domain;
208219820Sjeff	osm_db_domain_imp_t *p_domain_imp;
209219820Sjeff	int dir_name_len;
210219820Sjeff	osm_log_t *p_log = p_db->p_log;
211219820Sjeff	FILE *p_file;
212219820Sjeff
213219820Sjeff	OSM_LOG_ENTER(p_log);
214219820Sjeff
215219820Sjeff	/* allocate a new domain object */
216219820Sjeff	p_domain = (osm_db_domain_t *) malloc(sizeof(osm_db_domain_t));
217219820Sjeff	CL_ASSERT(p_domain != NULL);
218219820Sjeff
219219820Sjeff	p_domain_imp =
220219820Sjeff	    (osm_db_domain_imp_t *) malloc(sizeof(osm_db_domain_imp_t));
221219820Sjeff	CL_ASSERT(p_domain_imp != NULL);
222219820Sjeff
223219820Sjeff	dir_name_len = strlen(((osm_db_imp_t *) p_db->p_db_imp)->db_dir_name);
224219820Sjeff
225219820Sjeff	/* set the domain file name */
226219820Sjeff	p_domain_imp->file_name =
227219820Sjeff	    (char *)malloc(sizeof(char) * (dir_name_len) + strlen(domain_name) +
228219820Sjeff			   2);
229219820Sjeff	CL_ASSERT(p_domain_imp->file_name != NULL);
230219820Sjeff	strcpy(p_domain_imp->file_name,
231219820Sjeff	       ((osm_db_imp_t *) p_db->p_db_imp)->db_dir_name);
232219820Sjeff	strcat(p_domain_imp->file_name, domain_name);
233219820Sjeff
234219820Sjeff	/* make sure the file exists - or exit if not writable */
235219820Sjeff	p_file = fopen(p_domain_imp->file_name, "a+");
236219820Sjeff	if (!p_file) {
237219820Sjeff		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6102: "
238219820Sjeff			"Failed to open the db file:%s\n",
239219820Sjeff			p_domain_imp->file_name);
240219820Sjeff		free(p_domain_imp);
241219820Sjeff		free(p_domain);
242219820Sjeff		p_domain = NULL;
243219820Sjeff		goto Exit;
244219820Sjeff	}
245219820Sjeff	fclose(p_file);
246219820Sjeff
247219820Sjeff	/* initialize the hash table object */
248219820Sjeff	p_domain_imp->p_hash = st_init_strtable();
249219820Sjeff	CL_ASSERT(p_domain_imp->p_hash != NULL);
250219820Sjeff
251219820Sjeff	p_domain->p_db = p_db;
252219820Sjeff	cl_list_insert_tail(&p_db->domains, p_domain);
253219820Sjeff	p_domain->p_domain_imp = p_domain_imp;
254219820Sjeff	cl_spinlock_construct(&p_domain_imp->lock);
255219820Sjeff	cl_spinlock_init(&p_domain_imp->lock);
256219820Sjeff
257219820SjeffExit:
258219820Sjeff	OSM_LOG_EXIT(p_log);
259219820Sjeff	return p_domain;
260219820Sjeff}
261219820Sjeff
262219820Sjeff/***************************************************************************
263219820Sjeff ***************************************************************************/
264219820Sjeffint osm_db_restore(IN osm_db_domain_t * p_domain)
265219820Sjeff{
266219820Sjeff
267219820Sjeff	osm_log_t *p_log = p_domain->p_db->p_log;
268219820Sjeff	osm_db_domain_imp_t *p_domain_imp =
269219820Sjeff	    (osm_db_domain_imp_t *) p_domain->p_domain_imp;
270219820Sjeff	FILE *p_file;
271219820Sjeff	int status;
272219820Sjeff	char sLine[OSM_DB_MAX_LINE_LEN];
273219820Sjeff	boolean_t before_key;
274219820Sjeff	char *p_first_word, *p_rest_of_line, *p_last;
275219820Sjeff	char *p_key = NULL;
276219820Sjeff	char *p_prev_val, *p_accum_val = NULL;
277219820Sjeff	char *endptr = NULL;
278219820Sjeff	unsigned int line_num;
279219820Sjeff
280219820Sjeff	OSM_LOG_ENTER(p_log);
281219820Sjeff
282219820Sjeff	/* take the lock on the domain */
283219820Sjeff	cl_spinlock_acquire(&p_domain_imp->lock);
284219820Sjeff
285219820Sjeff	/* open the file - read mode */
286219820Sjeff	p_file = fopen(p_domain_imp->file_name, "r");
287219820Sjeff
288219820Sjeff	if (!p_file) {
289219820Sjeff		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6103: "
290219820Sjeff			"Failed to open the db file:%s\n",
291219820Sjeff			p_domain_imp->file_name);
292219820Sjeff		status = 1;
293219820Sjeff		goto Exit;
294219820Sjeff	}
295219820Sjeff
296219820Sjeff	/* parse the file allocating new hash tables as required */
297219820Sjeff	/*
298219820Sjeff	   states:
299219820Sjeff	   before_key (0) -> in_key (1)
300219820Sjeff
301219820Sjeff	   before_key: if a word on the first byte - it is the key. state=in_key
302219820Sjeff	   the rest of the line is start of the value.
303219820Sjeff	   in_key: unless the line is empty - add it (with newlines) to the value.
304219820Sjeff	   if empty: state=before_key
305219820Sjeff	 */
306219820Sjeff	status = 0;
307219820Sjeff	before_key = TRUE;
308219820Sjeff	line_num = 0;
309219820Sjeff	/* if we got to EOF in the middle of a key we add a last newline */
310219820Sjeff	while ((fgets(sLine, OSM_DB_MAX_LINE_LEN, p_file) != NULL) ||
311219820Sjeff	       ((before_key == FALSE) && strcpy(sLine, "\n"))
312219820Sjeff	    ) {
313219820Sjeff		line_num++;
314219820Sjeff		if (before_key) {
315219820Sjeff			if ((sLine[0] != ' ') && (sLine[0] != '\t')
316219820Sjeff			    && (sLine[0] != '\n')) {
317219820Sjeff				/* we got a new key */
318219820Sjeff				before_key = FALSE;
319219820Sjeff
320219820Sjeff				/* handle the key */
321219820Sjeff				p_first_word =
322219820Sjeff				    strtok_r(sLine, " \t\n", &p_last);
323219820Sjeff				if (!p_first_word) {
324219820Sjeff					OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6104: "
325219820Sjeff						"Failed to get key from line:%u : %s (file:%s)\n",
326219820Sjeff						line_num, sLine,
327219820Sjeff						p_domain_imp->file_name);
328219820Sjeff					status = 1;
329219820Sjeff					goto EndParsing;
330219820Sjeff				}
331219820Sjeff				if (strlen(p_first_word) > OSM_DB_MAX_GUID_LEN) {
332219820Sjeff					OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 610A: "
333219820Sjeff						"Illegal key from line:%u : %s (file:%s)\n",
334219820Sjeff						line_num, sLine,
335219820Sjeff						p_domain_imp->file_name);
336219820Sjeff					status = 1;
337219820Sjeff					goto EndParsing;
338219820Sjeff				}
339219820Sjeff
340219820Sjeff				p_key =
341219820Sjeff				    (char *)malloc(sizeof(char) *
342219820Sjeff						   (strlen(p_first_word) + 1));
343219820Sjeff				strcpy(p_key, p_first_word);
344219820Sjeff
345219820Sjeff				p_rest_of_line = strtok_r(NULL, "\n", &p_last);
346219820Sjeff				if (p_rest_of_line != NULL) {
347219820Sjeff					p_accum_val =
348219820Sjeff					    (char *)malloc(sizeof(char) *
349219820Sjeff							   (strlen
350219820Sjeff							    (p_rest_of_line) +
351219820Sjeff							    1));
352219820Sjeff					strcpy(p_accum_val, p_rest_of_line);
353219820Sjeff				} else {
354219820Sjeff					p_accum_val = (char *)malloc(2);
355219820Sjeff					strcpy(p_accum_val, "\0");
356219820Sjeff				}
357219820Sjeff			} else if (sLine[0] != '\n') {
358219820Sjeff				OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6105: "
359219820Sjeff					"How did we get here? line:%u : %s (file:%s)\n",
360219820Sjeff					line_num, sLine,
361219820Sjeff					p_domain_imp->file_name);
362219820Sjeff				status = 1;
363219820Sjeff				goto EndParsing;
364219820Sjeff			}
365219820Sjeff		} /* before key */
366219820Sjeff		else {
367219820Sjeff			/* we already have a key */
368219820Sjeff
369219820Sjeff			if (sLine[0] == '\n') {
370219820Sjeff				/* got an end of key */
371219820Sjeff				before_key = TRUE;
372219820Sjeff
373219820Sjeff				/* make sure the key was not previously used */
374219820Sjeff				if (st_lookup(p_domain_imp->p_hash,
375219820Sjeff					      (st_data_t) p_key,
376219820Sjeff					      (void *) & p_prev_val)) {
377219820Sjeff					OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6106: "
378219820Sjeff						"Key:%s already exists in:%s with value:%s."
379219820Sjeff						" Removing it\n",
380219820Sjeff						p_key,
381219820Sjeff						p_domain_imp->file_name,
382219820Sjeff						p_prev_val);
383219820Sjeff				} else {
384219820Sjeff					p_prev_val = NULL;
385219820Sjeff				}
386219820Sjeff
387219820Sjeff				OSM_LOG(p_log, OSM_LOG_DEBUG,
388219820Sjeff					"Got key:%s value:%s\n", p_key,
389219820Sjeff					p_accum_val);
390219820Sjeff
391219820Sjeff				/* check that the key is a number */
392219820Sjeff				if (!strtouq(p_key, &endptr, 0)
393219820Sjeff				    && *endptr != '\0') {
394219820Sjeff					OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 610B: "
395219820Sjeff						"Key:%s is invalid\n", p_key);
396219820Sjeff				} else {
397219820Sjeff					/* store our key and value */
398219820Sjeff					st_insert(p_domain_imp->p_hash,
399219820Sjeff						  (st_data_t) p_key,
400219820Sjeff						  (st_data_t) p_accum_val);
401219820Sjeff				}
402219820Sjeff			} else {
403219820Sjeff				/* accumulate into the value */
404219820Sjeff				p_prev_val = p_accum_val;
405219820Sjeff				p_accum_val =
406219820Sjeff				    (char *)malloc(strlen(p_prev_val) +
407219820Sjeff						   strlen(sLine) + 1);
408219820Sjeff				strcpy(p_accum_val, p_prev_val);
409219820Sjeff				free(p_prev_val);
410219820Sjeff				strcat(p_accum_val, sLine);
411219820Sjeff			}
412219820Sjeff		}		/* in key */
413219820Sjeff	}			/* while lines or last line */
414219820Sjeff
415219820SjeffEndParsing:
416219820Sjeff	fclose(p_file);
417219820Sjeff
418219820SjeffExit:
419219820Sjeff	cl_spinlock_release(&p_domain_imp->lock);
420219820Sjeff	OSM_LOG_EXIT(p_log);
421219820Sjeff	return status;
422219820Sjeff}
423219820Sjeff
424219820Sjeff/***************************************************************************
425219820Sjeff ***************************************************************************/
426219820Sjeffstatic int __osm_dump_tbl_entry(st_data_t key, st_data_t val, st_data_t arg)
427219820Sjeff{
428219820Sjeff	FILE *p_file = (FILE *) arg;
429219820Sjeff	char *p_key = (char *)key;
430219820Sjeff	char *p_val = (char *)val;
431219820Sjeff
432219820Sjeff	fprintf(p_file, "%s %s\n\n", p_key, p_val);
433219820Sjeff	return ST_CONTINUE;
434219820Sjeff}
435219820Sjeff
436219820Sjeffint osm_db_store(IN osm_db_domain_t * p_domain)
437219820Sjeff{
438219820Sjeff	osm_log_t *p_log = p_domain->p_db->p_log;
439219820Sjeff	osm_db_domain_imp_t *p_domain_imp;
440219820Sjeff	FILE *p_file;
441219820Sjeff	int status = 0;
442219820Sjeff	char *p_tmp_file_name;
443219820Sjeff
444219820Sjeff	OSM_LOG_ENTER(p_log);
445219820Sjeff
446219820Sjeff	p_domain_imp = (osm_db_domain_imp_t *) p_domain->p_domain_imp;
447219820Sjeff	p_tmp_file_name =
448219820Sjeff	    (char *)malloc(sizeof(char) *
449219820Sjeff			   (strlen(p_domain_imp->file_name) + 8));
450219820Sjeff	strcpy(p_tmp_file_name, p_domain_imp->file_name);
451219820Sjeff	strcat(p_tmp_file_name, ".tmp");
452219820Sjeff
453219820Sjeff	cl_spinlock_acquire(&p_domain_imp->lock);
454219820Sjeff
455219820Sjeff	/* open up the output file */
456219820Sjeff	p_file = fopen(p_tmp_file_name, "w");
457219820Sjeff	if (!p_file) {
458219820Sjeff		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6107: "
459219820Sjeff			"Failed to open the db file:%s for writing\n",
460219820Sjeff			p_domain_imp->file_name);
461219820Sjeff		status = 1;
462219820Sjeff		goto Exit;
463219820Sjeff	}
464219820Sjeff
465219820Sjeff	st_foreach(p_domain_imp->p_hash, __osm_dump_tbl_entry,
466219820Sjeff		   (st_data_t) p_file);
467219820Sjeff	fclose(p_file);
468219820Sjeff
469219820Sjeff	/* move the domain file */
470219820Sjeff	status = remove(p_domain_imp->file_name);
471219820Sjeff	if (status) {
472219820Sjeff		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6109: "
473219820Sjeff			"Failed to remove file:%s (err:%u)\n",
474219820Sjeff			p_domain_imp->file_name, status);
475219820Sjeff	}
476219820Sjeff
477219820Sjeff	status = rename(p_tmp_file_name, p_domain_imp->file_name);
478219820Sjeff	if (status) {
479219820Sjeff		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6108: "
480219820Sjeff			"Failed to rename the db file to:%s (err:%u)\n",
481219820Sjeff			p_domain_imp->file_name, status);
482219820Sjeff	}
483219820SjeffExit:
484219820Sjeff	cl_spinlock_release(&p_domain_imp->lock);
485219820Sjeff	free(p_tmp_file_name);
486219820Sjeff	OSM_LOG_EXIT(p_log);
487219820Sjeff	return status;
488219820Sjeff}
489219820Sjeff
490219820Sjeff/***************************************************************************
491219820Sjeff ***************************************************************************/
492219820Sjeff/* simply de-allocate the key and the value and return the code
493219820Sjeff   that makes the st_foreach delete the entry */
494219820Sjeffstatic int __osm_clear_tbl_entry(st_data_t key, st_data_t val, st_data_t arg)
495219820Sjeff{
496219820Sjeff	free((char *)key);
497219820Sjeff	free((char *)val);
498219820Sjeff	return ST_DELETE;
499219820Sjeff}
500219820Sjeff
501219820Sjeffint osm_db_clear(IN osm_db_domain_t * p_domain)
502219820Sjeff{
503219820Sjeff	osm_db_domain_imp_t *p_domain_imp =
504219820Sjeff	    (osm_db_domain_imp_t *) p_domain->p_domain_imp;
505219820Sjeff
506219820Sjeff	cl_spinlock_acquire(&p_domain_imp->lock);
507219820Sjeff	st_foreach(p_domain_imp->p_hash, __osm_clear_tbl_entry,
508219820Sjeff		   (st_data_t) NULL);
509219820Sjeff	cl_spinlock_release(&p_domain_imp->lock);
510219820Sjeff
511219820Sjeff	return 0;
512219820Sjeff}
513219820Sjeff
514219820Sjeff/***************************************************************************
515219820Sjeff ***************************************************************************/
516219820Sjeffstatic int __osm_get_key_of_tbl_entry(st_data_t key, st_data_t val,
517219820Sjeff				      st_data_t arg)
518219820Sjeff{
519219820Sjeff	cl_list_t *p_list = (cl_list_t *) arg;
520219820Sjeff	cl_list_insert_tail(p_list, (void *)key);
521219820Sjeff	return ST_CONTINUE;
522219820Sjeff}
523219820Sjeff
524219820Sjeffint osm_db_keys(IN osm_db_domain_t * p_domain, OUT cl_list_t * p_key_list)
525219820Sjeff{
526219820Sjeff	osm_db_domain_imp_t *p_domain_imp =
527219820Sjeff	    (osm_db_domain_imp_t *) p_domain->p_domain_imp;
528219820Sjeff
529219820Sjeff	cl_spinlock_acquire(&p_domain_imp->lock);
530219820Sjeff
531219820Sjeff	st_foreach(p_domain_imp->p_hash,
532219820Sjeff		   __osm_get_key_of_tbl_entry, (st_data_t) p_key_list);
533219820Sjeff
534219820Sjeff	cl_spinlock_release(&p_domain_imp->lock);
535219820Sjeff
536219820Sjeff	return 0;
537219820Sjeff}
538219820Sjeff
539219820Sjeff/***************************************************************************
540219820Sjeff ***************************************************************************/
541219820Sjeffchar *osm_db_lookup(IN osm_db_domain_t * p_domain, IN char *const p_key)
542219820Sjeff{
543219820Sjeff	osm_db_domain_imp_t *p_domain_imp =
544219820Sjeff	    (osm_db_domain_imp_t *) p_domain->p_domain_imp;
545219820Sjeff	char *p_val = NULL;
546219820Sjeff
547219820Sjeff	cl_spinlock_acquire(&p_domain_imp->lock);
548219820Sjeff
549219820Sjeff	if (!st_lookup
550219820Sjeff	    (p_domain_imp->p_hash, (st_data_t) p_key, (void *) & p_val))
551219820Sjeff		p_val = NULL;
552219820Sjeff
553219820Sjeff	cl_spinlock_release(&p_domain_imp->lock);
554219820Sjeff
555219820Sjeff	return p_val;
556219820Sjeff}
557219820Sjeff
558219820Sjeff/***************************************************************************
559219820Sjeff ***************************************************************************/
560219820Sjeffint
561219820Sjeffosm_db_update(IN osm_db_domain_t * p_domain,
562219820Sjeff	      IN char *const p_key, IN char *const p_val)
563219820Sjeff{
564219820Sjeff	osm_log_t *p_log = p_domain->p_db->p_log;
565219820Sjeff	osm_db_domain_imp_t *p_domain_imp =
566219820Sjeff	    (osm_db_domain_imp_t *) p_domain->p_domain_imp;
567219820Sjeff	char *p_prev_val = NULL;
568219820Sjeff	char *p_new_key;
569219820Sjeff	char *p_new_val;
570219820Sjeff
571219820Sjeff	cl_spinlock_acquire(&p_domain_imp->lock);
572219820Sjeff
573219820Sjeff	if (st_lookup(p_domain_imp->p_hash,
574219820Sjeff		      (st_data_t) p_key, (void *) & p_prev_val)) {
575219820Sjeff		OSM_LOG(p_log, OSM_LOG_DEBUG,
576219820Sjeff			"Key:%s previously exists in:%s with value:%s\n",
577219820Sjeff			p_key, p_domain_imp->file_name, p_prev_val);
578219820Sjeff		p_new_key = p_key;
579219820Sjeff	} else {
580219820Sjeff		/* need to allocate the key */
581219820Sjeff		p_new_key = malloc(sizeof(char) * (strlen(p_key) + 1));
582219820Sjeff		strcpy(p_new_key, p_key);
583219820Sjeff	}
584219820Sjeff
585219820Sjeff	/* need to arange a new copy of the  value */
586219820Sjeff	p_new_val = malloc(sizeof(char) * (strlen(p_val) + 1));
587219820Sjeff	strcpy(p_new_val, p_val);
588219820Sjeff
589219820Sjeff	st_insert(p_domain_imp->p_hash, (st_data_t) p_new_key,
590219820Sjeff		  (st_data_t) p_new_val);
591219820Sjeff
592219820Sjeff	if (p_prev_val)
593219820Sjeff		free(p_prev_val);
594219820Sjeff
595219820Sjeff	cl_spinlock_release(&p_domain_imp->lock);
596219820Sjeff
597219820Sjeff	return 0;
598219820Sjeff}
599219820Sjeff
600219820Sjeff/***************************************************************************
601219820Sjeff ***************************************************************************/
602219820Sjeffint osm_db_delete(IN osm_db_domain_t * p_domain, IN char *const p_key)
603219820Sjeff{
604219820Sjeff	osm_log_t *p_log = p_domain->p_db->p_log;
605219820Sjeff	osm_db_domain_imp_t *p_domain_imp =
606219820Sjeff	    (osm_db_domain_imp_t *) p_domain->p_domain_imp;
607219820Sjeff	char *p_prev_val = NULL;
608219820Sjeff	int res;
609219820Sjeff
610219820Sjeff	OSM_LOG_ENTER(p_log);
611219820Sjeff
612219820Sjeff	cl_spinlock_acquire(&p_domain_imp->lock);
613219820Sjeff	if (st_delete(p_domain_imp->p_hash,
614219820Sjeff		      (void *) & p_key, (void *) & p_prev_val)) {
615219820Sjeff		if (st_lookup(p_domain_imp->p_hash,
616219820Sjeff			      (st_data_t) p_key, (void *) & p_prev_val)) {
617219820Sjeff			OSM_LOG(p_log, OSM_LOG_ERROR,
618219820Sjeff				"key:%s still exists in:%s with value:%s\n",
619219820Sjeff				p_key, p_domain_imp->file_name, p_prev_val);
620219820Sjeff			res = 1;
621219820Sjeff		} else {
622219820Sjeff			free(p_key);
623219820Sjeff			free(p_prev_val);
624219820Sjeff			res = 0;
625219820Sjeff		}
626219820Sjeff	} else {
627219820Sjeff		OSM_LOG(p_log, OSM_LOG_DEBUG,
628219820Sjeff			"fail to find key:%s. delete failed\n", p_key);
629219820Sjeff		res = 1;
630219820Sjeff	}
631219820Sjeff	cl_spinlock_release(&p_domain_imp->lock);
632219820Sjeff
633219820Sjeff	OSM_LOG_EXIT(p_log);
634219820Sjeff	return res;
635219820Sjeff}
636219820Sjeff
637219820Sjeff#ifdef TEST_OSMDB
638219820Sjeff#include <stdlib.h>
639219820Sjeff#include <math.h>
640219820Sjeff
641219820Sjeffint main(int argc, char **argv)
642219820Sjeff{
643219820Sjeff	osm_db_t db;
644219820Sjeff	osm_log_t log;
645219820Sjeff	osm_db_domain_t *p_dbd;
646219820Sjeff	cl_list_t keys;
647219820Sjeff	cl_list_iterator_t kI;
648219820Sjeff	char *p_key;
649219820Sjeff	char *p_val;
650219820Sjeff	int i;
651219820Sjeff
652219820Sjeff	cl_list_construct(&keys);
653219820Sjeff	cl_list_init(&keys, 10);
654219820Sjeff
655219820Sjeff	osm_log_init_v2(&log, TRUE, 0xff, "/var/log/osm_db_test.log", 0, FALSE);
656219820Sjeff
657219820Sjeff	osm_db_construct(&db);
658219820Sjeff	if (osm_db_init(&db, &log)) {
659219820Sjeff		printf("db init failed\n");
660219820Sjeff		exit(1);
661219820Sjeff	}
662219820Sjeff
663219820Sjeff	p_dbd = osm_db_domain_init(&db, "lid_by_guid");
664219820Sjeff
665219820Sjeff	if (osm_db_restore(p_dbd)) {
666219820Sjeff		printf("failed to restore\n");
667219820Sjeff	}
668219820Sjeff
669219820Sjeff	if (osm_db_keys(p_dbd, &keys)) {
670219820Sjeff		printf("failed to get keys\n");
671219820Sjeff	} else {
672219820Sjeff		kI = cl_list_head(&keys);
673219820Sjeff		while (kI != cl_list_end(&keys)) {
674219820Sjeff			p_key = cl_list_obj(kI);
675219820Sjeff			kI = cl_list_next(kI);
676219820Sjeff
677219820Sjeff			p_val = osm_db_lookup(p_dbd, p_key);
678219820Sjeff			printf("key = %s val = %s\n", p_key, p_val);
679219820Sjeff		}
680219820Sjeff	}
681219820Sjeff
682219820Sjeff	cl_list_remove_all(&keys);
683219820Sjeff
684219820Sjeff	/* randomly add and remove numbers */
685219820Sjeff	for (i = 0; i < 10; i++) {
686219820Sjeff		int k;
687219820Sjeff		float v;
688219820Sjeff		int is_add;
689219820Sjeff		char val_buf[16];
690219820Sjeff		char key_buf[16];
691219820Sjeff
692219820Sjeff		k = floor(1.0 * rand() / RAND_MAX * 100);
693219820Sjeff		v = rand();
694219820Sjeff		sprintf(key_buf, "%u", k);
695219820Sjeff		sprintf(val_buf, "%u", v);
696219820Sjeff
697219820Sjeff		is_add = (rand() < RAND_MAX / 2);
698219820Sjeff
699219820Sjeff		if (is_add) {
700219820Sjeff			osm_db_update(p_dbd, key_buf, val_buf);
701219820Sjeff		} else {
702219820Sjeff			osm_db_delete(p_dbd, key_buf);
703219820Sjeff		}
704219820Sjeff	}
705219820Sjeff	if (osm_db_keys(p_dbd, &keys)) {
706219820Sjeff		printf("failed to get keys\n");
707219820Sjeff	} else {
708219820Sjeff		kI = cl_list_head(&keys);
709219820Sjeff		while (kI != cl_list_end(&keys)) {
710219820Sjeff			p_key = cl_list_obj(kI);
711219820Sjeff			kI = cl_list_next(kI);
712219820Sjeff
713219820Sjeff			p_val = osm_db_lookup(p_dbd, p_key);
714219820Sjeff			printf("key = %s val = %s\n", p_key, p_val);
715219820Sjeff		}
716219820Sjeff	}
717219820Sjeff	if (osm_db_store(p_dbd))
718219820Sjeff		printf("failed to store\n");
719219820Sjeff
720219820Sjeff	osm_db_destroy(&db);
721219820Sjeff	cl_list_destroy(&keys);
722219820Sjeff}
723219820Sjeff#endif
724