1 /*
2 * $Id$
3 *
4 * recovery for berkeley_db module
5 * Copyright (C) 2007 Cisco Systems
6 *
7 * This file is part of Kamailio, a free SIP server.
8 *
9 * Kamailio is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version
13 *
14 * Kamailio is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 * History:
24 * --------
25 * 2007-09-19 genesis (wiquan)
26 */
27
28 #include <unistd.h>
29 #include "kambdb_recover.h"
30
31 tbl_cache_p tables;
32 char* schema_dir = NULL;
33 char* db_home = NULL;
34 const char *progname;
35
36 /**
37 * main --
38 */
main(int argc,char * argv[])39 int main(int argc, char* argv[])
40 {
41 int ret, ch, i;
42
43 ret = 0;
44 progname = argv[0];
45
46 while ((ch = getopt(argc, argv, "s:h:c:C:r:R:")) != EOF)
47 switch (ch)
48 {
49 case 's':
50 schema_dir = optarg;
51 load_schema(optarg);
52 break;
53
54 case 'c': /*create <tablename> */
55 ret = create(optarg);
56 break;
57
58 case 'C': /*Create all*/
59 ret = create_all();
60 break;
61
62 case 'r': /*recover <filename> */
63 ret = recover(optarg);
64 break;
65
66 case 'R': /*recover_all <MAXFILES> */
67 ret = sscanf(optarg,"%i", &i);
68 if(ret != 1) return -1;
69 ret = recover_all(i);
70 break;
71
72 case 'h':
73 db_home = optarg;
74 break;
75
76 case '?':
77 default:
78 return(usage());
79
80 }
81
82 argc -= optind;
83 argv += optind;
84
85 /*free mem; close open files.*/
86 cleanup();
87
88 return ret;
89 }
90
91
92 /**
93 * usage --
94 *
95 */
usage(void)96 int usage(void)
97 {
98 fprintf(stderr, "usage: %s %s\n", progname,
99 "-s schemadir [-h home] [-c tablename]");
100
101 fprintf(stderr, "usage: %s %s\n", progname,
102 "-s schemadir [-h home] [-C all]");
103
104 fprintf(stderr, "usage: %s %s\n", progname,
105 "-s schemadir [-h home] [-r journal-file]");
106
107 fprintf(stderr, "usage: %s %s\n", progname,
108 "-s schemadir [-h home] [-R lastN]");
109
110 return (EXIT_FAILURE);
111 }
112
113
114 /**
115 * create -- creates a Berkeley DB file with tablename (tn), along with
116 * the needed metadata.
117 * requires the schema data to be already parsed '-L' option.
118 */
create(char * tn)119 int create(char* tn)
120 {
121 DB* db;
122 int rc;
123 tbl_cache_p tbc = NULL;
124 table_p tp = NULL;
125 rc = 0;
126
127 tbc = get_table(tn);
128 if(!tbc)
129 { fprintf(stderr, "[create] Table %s is not supported.\n",tn);
130 return 1;
131 }
132
133 tp = tbc->dtp;
134 db = get_db(tp);
135
136 if(db)
137 {
138 printf("Created table %s\n",tn);
139 rc = 0;
140 }
141 else
142 {
143 fprintf(stderr, "[create] Failed to create table %s\n",tn);
144 rc = 1;
145 }
146
147 return rc;
148 }
149
150
151 /**
152 * create_all -- creates a new Berkeley DB table for only the core tables
153 */
create_all(void)154 int create_all(void)
155 {
156 tbl_cache_p _tbc = tables;
157 int rc;
158 rc = 0;
159
160 #ifdef EXTRA_DEBUG
161 time_t tim1 = time(NULL);
162 time_t tim2;
163 #endif
164
165 while(_tbc)
166 {
167 if(_tbc->dtp)
168 if((rc = create(_tbc->dtp->name)) != 0 )
169 break;
170 _tbc = _tbc->next;
171 }
172
173 #ifdef EXTRA_DEBUG
174 tim2 = time(NULL);
175 int i = tim2 - tim1;
176 printf("took %i sec\n", i);
177 #endif
178
179 return rc;
180 }
181
182
183 /**
184 * file_list --
185 * returns a sorted linkedlist of all files in d
186 *
187 * parmameter d is the directory name
188 * parameter tn is optional,
189 * if tablename (tn) is specified returns only jnl files for tablename (tn)
190 * else returns a sorted linkedlist of all files in d
191 * returns lnode_p
192 * the head linknode points to the latests file.
193 */
file_list(char * d,char * tn)194 lnode_p file_list(char* d, char* tn)
195 {
196 DIR *dirp;
197 int i, j, len;
198 char *fn;
199 char *list[MAXFILES];
200 char dir[MAX_FILENAME_SIZE];
201 struct dirent *dp;
202 lnode_p h,n;
203
204 h = n = NULL;
205 i = j = 0;
206
207 if(!d)
208 {
209 fprintf(stderr, "[file_list]: null path to schema files.\n");
210 return NULL;
211 }
212
213 memset(dir, 0, MAX_FILENAME_SIZE);
214 strcpy(dir, d);
215 strcat(dir, "/");
216 //strcat(dir, ".");
217 dirp = opendir(dir);
218
219 while ((dp = readdir(dirp)) != NULL)
220 { j=0;
221 if (i> (MAXFILES-1) )
222 continue;
223
224 fn = dp->d_name;
225
226 if (fn[0] == '.')
227 continue;
228
229 if(tn)
230 {
231 /* only looking for jnl files */
232 len = strlen(tn);
233 if (!strstr(fn, ".jnl")) continue;
234 if (strncmp(fn, tn, len)) continue;
235 }
236
237 j = strlen(fn) +1;
238 list[i] = malloc(sizeof(char) * j);
239 memset(list[i], 0 , j);
240 strcat(list[i], fn);
241 i++;
242 }
243
244 closedir(dirp);
245 qsort(list, i, sizeof(char*), compare);
246
247 for(j=0;j<i;j++)
248 {
249 n = malloc(sizeof(lnode_t));
250 if(!n) return NULL;
251 n->prev=NULL;
252 n->p = list[j];
253 if(h) h->prev = n;
254 n->next = h;
255 h = n;
256 }
257 return h;
258 }
259
260
261 /** qsort C-string comparison function */
compare(const void * a,const void * b)262 int compare (const void *a, const void *b)
263 {
264 const char **ia = (const char **)a;
265 const char **ib = (const char **)b;
266 return strcmp(*ia, *ib);
267 }
268
269
270
271 /**
272 * recover -- given a journal filename, creates a new db w. metadata, and replays
273 * the events in journalized order.
274 * Results in a new db containing the journaled data.
275 *
276 * fn (filename) must be in the form:
277 * location-20070803175446.jnl
278 */
recover(char * jfn)279 int recover(char* jfn)
280 {
281
282 #ifdef EXTRA_DEBUG
283 time_t tim1 = time(NULL);
284 time_t tim2;
285 #endif
286
287 int len, i, cs, ci, cd, cu;
288 char *v, *s;
289 char line [MAX_ROW_SIZE];
290 char tn [MAX_TABLENAME_SIZE];
291 char fn [MAX_FILENAME_SIZE];
292 char op [7]; //INSERT, DELETE, UPDATE are all 7 char wide (w. null)
293 FILE * fp = NULL;
294 tbl_cache_p tbc = NULL;
295 table_p tp = NULL;
296 i = 0 ;
297 cs = ci = cd = cu = 0;
298
299 if(!strstr(jfn, ".jnl"))
300 {
301 fprintf(stderr, "[recover]: Does NOT look like a journal file: %s.\n", jfn);
302 return 1;
303 }
304
305 if(!db_home)
306 {
307 fprintf(stderr, "[recover]: null path to db_home.\n");
308 return 1;
309 }
310
311 /*tablename tn*/
312 s = strchr(jfn, '-');
313 len = s - jfn;
314 strncpy(tn, jfn, len);
315 tn[len] = 0;
316
317 /*create abs path to journal file relative to db_home*/
318 memset(fn, 0 , MAX_FILENAME_SIZE);
319 strcat(fn, db_home);
320 strcat(fn, "/");
321 strcat(fn, jfn);
322
323 fp = fopen(fn, "r");
324 if(!fp)
325 {
326 fprintf(stderr, "[recover]: FAILED to load journal file: %s.\n", jfn);
327 return 2;
328 }
329
330 tbc = get_table(tn);
331 if(!tbc)
332 {
333 fprintf(stderr, "[recover]: Table %s is not supported.\n",tn);
334 fprintf(stderr, "[recover]: FAILED to load journal file: %s.\n", jfn);
335 fclose(fp);
336 return 2;
337 }
338
339 if(!tbc || !tbc->dtp)
340 {
341 fprintf(stderr, "[recover]: FAILED to get find metadata for : %s.\n", tn);
342 fclose(fp);
343 return 3;
344 }
345
346 tp = tbc->dtp;
347
348 while ( fgets(line , MAX_ROW_SIZE, fp) != NULL )
349 {
350 len = strlen(line);
351 if(line[0] == '#' || line[0] == '\n') continue;
352
353 if(len > 0) line[len-1] = 0; /*chomp trailing \n */
354
355 v = strchr(line, '|');
356 len = v - line;
357
358 strncpy(op, line, len);
359 op[len] = 0;
360
361 switch( get_op(op, len) )
362 {
363 case INSERT:
364 v++; //now v points to data
365 len = strlen(v);
366 insert(tp, v, len);
367 ci++;
368 break;
369
370 case UPDATE:
371 v++;
372 len = strlen(v);
373 update(tp, v, len);
374 cu++;
375 break;
376
377 case DELETE:
378 //v is really the key
379 delete(tp, v, len);
380 cd++;
381 break;
382
383 case UNKNOWN_OP:
384 fprintf(stderr,"[recover]: UnknownOP - Skipping ROW: %s\n",line);
385 cs++;
386 continue;
387 }
388 i++;
389 }
390
391 #ifdef EXTRA_DEBUG
392 printf("Processed journal file: %s.\n", jfn);
393 printf("INSERT %i records.\n",ci);
394 printf("UPDATE %i records.\n",cu);
395 printf("DELETE %i records.\n",cd);
396 printf("SKIPed %i records.\n",cs);
397 printf("------------------------\n");
398 printf("Total %i records.\n",i);
399
400 tim2 = time(NULL);
401 i = tim2 - tim1;
402 printf("took %i sec\n", i);
403 #endif
404
405 fclose(fp);
406
407 return 0;
408 }
409
410 /**
411 * recover_all -- Iterates over all core tables in enumerated order for recovery from
412 * journal files (.jnl).
413 * The parm 'lastn' is the number of journal files needed to be recovered.
414 * Hardcoded to only find MAXFILES.
415 *
416 * e.g.
417 * 25 journal files are present for the 'acc' table, however you only
418 * want to restore the latest 3; so lastn=3.
419 */
recover_all(int lastn)420 int recover_all(int lastn)
421 {
422 lnode_p n, h;
423 tbl_cache_p _tbc = tables;
424
425 if(MAXFILES < lastn) return 1;
426
427 if(!schema_dir)
428 {
429 fprintf(stderr, "[recover_all]: null path to schema files.\n");
430 return 1;
431 }
432
433 if(!db_home)
434 {
435 fprintf(stderr, "[recover_all]: null path to db_home.\n");
436 return 1;
437 }
438
439 while(_tbc)
440 {
441 int j;
442
443 if(_tbc->dtp)
444 h = file_list(db_home, _tbc->dtp->name);
445 n = h;
446
447 /*lastn; move to the oldest of the N*/
448 for(j=1;j<lastn;j++)
449 if(n && (n->next != NULL) )
450 n = n->next;
451 while(n)
452 { printf("[recover_all] recovering file: %s\n",n->p);
453 if(recover(n->p))
454 fprintf(stderr, "[recover_all]: Error while recovering: [%s]\n. Continuing..\n",n->p);
455 n = n->prev;
456 }
457
458 while(h) /*free mem*/
459 { n = h->next;
460 free(h->p);
461 free(h);
462 h = n;
463 }
464
465 _tbc = _tbc->next;
466 }
467
468 return 0;
469 }
470
471
472 /**
473 * extract_key -- uses the internal schema to extract the key from the data
474 * row that was found in the journal.
475 * caller provides inititialize memory for destination key (k).
476 * data is provided ; key is filled in
477 */
extract_key(table_p tp,char * k,char * d)478 int extract_key(table_p tp, char* k, char* d)
479 {
480 char *s, *p;
481 char buf[MAX_ROW_SIZE];
482 int n, len;
483
484 if(!tp || !k || !d) return -1;
485 len=n=0;
486 p = k;
487
488 /*copy data so we can tokenize w.o trampling */
489 len = strlen(d);
490 strncpy(buf, d, len);
491 buf[len] = 0;
492
493 s = strtok(buf, "|");
494 while(s!=NULL && n<MAX_NUM_COLS)
495 {
496 len = strlen(s);
497 if( (tp->ncols-1) > n)
498 {
499 if( tp->colp[n]->kflag )
500 {
501 strncpy(p, s, len);
502 p+=len;
503
504 *p = '|';
505 p++;
506 }
507 }
508
509 s=strtok(NULL, "|");
510 n++;
511 }
512
513 *p = 0;
514 return 0;
515 }
516
517 /**
518 * delete -- deletes a row from the db we are trying to rebuild
519 */
delete(table_p tp,char * k,int len)520 int delete(table_p tp, char* k, int len)
521 {
522 DBT key;
523 DB *db;
524
525 if(!tp || !k) return 1;
526 if((db = get_db(tp)) == NULL) return 2;
527
528 memset(&key, 0, sizeof(DBT));
529 key.data = k;
530 key.ulen = MAX_ROW_SIZE;
531 key.size = len;
532
533 if ( db->del(db, NULL, &key, 0))
534 {
535 fprintf(stderr, "[delete] FAILED --> [%.*s] \n", len, k);
536 return 3;
537 }
538
539 return 0;
540 }
541
542
543 /**
544 * _insert -- inserts a new row in to the db we are trying to rebuild
545 * I needed this to directly insert metadata when the db is created.
546 */
_insert(DB * db,char * k,char * v,int klen,int vlen)547 int _insert(DB* db, char* k, char* v, int klen, int vlen)
548 {
549 DBT key, data;
550
551 if(!db || !k || !v) return 1;
552
553 memset(&key, 0, sizeof(DBT));
554 key.data = k;
555 key.ulen = MAX_ROW_SIZE;
556 key.size = klen;
557
558 memset(&data, 0, sizeof(DBT));
559 data.data = v;
560 data.ulen = MAX_ROW_SIZE;
561 data.size = vlen;
562 if (db->put(db, NULL, &key, &data, 0))
563 {
564 fprintf(stderr, "[insert] FAILED --> [%.*s] \n", vlen, v);
565 return 1;
566 }
567 return 0;
568 }
569
570
571 /**
572 * insert -- given the data row (v) and its length (vlen), we build the corresponding
573 * key, and insert the data in to the db.
574 * This will over-right the value if already present.
575 */
insert(table_p tp,char * v,int vlen)576 int insert(table_p tp, char* v, int vlen)
577 {
578 char k[MAX_ROW_SIZE];
579 int rc, klen;
580 DB *db;
581
582 if(!tp || !v) return 1;
583 if((db = get_db(tp)) == NULL) return 2;
584
585 memset(k,0,MAX_ROW_SIZE);
586 if( extract_key(tp, k, v) )
587 {
588 fprintf(stderr, "[insert] failed to extract key for row: %.*s",vlen, v);
589 return 2;
590 }
591
592 klen = strlen(k);
593 rc = _insert(db, k, v, klen, vlen);
594
595 return rc;
596 }
597
598
599 /**
600 * update -- given the data row (v) and its length (vlen), we build the corresponding
601 * key, and update the data in the db.
602 * This is implemented as DELETE + INSERT.
603 */
update(table_p tp,char * v,int len)604 int update(table_p tp, char* v, int len)
605 {
606 char k[MAX_ROW_SIZE];
607
608 if(!tp || !v) return 1;
609
610 memset(k,0,MAX_ROW_SIZE);
611 if( extract_key(tp, k, v) )
612 {
613 fprintf(stderr, "[update] failed to extract key for row: %.*s",len, v);
614 return 2;
615 }
616
617 /* if( delete(tp, k, strlen(k)) ) return 3; */
618 if( insert(tp, v, len) ) return 4;
619 return 0;
620 }
621
622
623
624 /**
625 * get_op -- used to convert the string operation name to an enumerated op
626 */
get_op(char * op,int len)627 int get_op(char* op, int len)
628 {
629 if((len==6) && strstr("INSERT",op) ) return INSERT;
630 if((len==6) && strstr("UPDATE",op) ) return UPDATE;
631 if((len==6) && strstr("DELETE",op) ) return DELETE;
632
633 return UNKNOWN_OP;
634 }
635
636
637 /**
638 * load_schema -- sets up the internal representation of the schema.
639 */
load_schema(char * d)640 int load_schema(char* d)
641 { int rc;
642 char *tn;
643 char line1 [MAX_ROW_SIZE];
644 char line2 [MAX_ROW_SIZE];
645 char fn [MAX_FILENAME_SIZE];
646 tbl_cache_p tbc = NULL;
647 table_p tp = NULL;
648 FILE * fp = NULL;
649 lnode_p h,n;
650
651 rc=0;
652 h = n = NULL;
653
654 if(!d)
655 {
656 fprintf(stderr, "[load_schema]: null path to schema files.\n");
657 return 1;
658 }
659
660 tables = (tbl_cache_p)malloc(sizeof(tbl_cache_t));
661 if(!tables) return 1;
662
663 h = file_list(d, NULL);
664
665 while(h)
666 {
667 n = h->next;
668
669 /*create abs path to journal file (relative to db_home) */
670 memset(fn, 0 , MAX_FILENAME_SIZE);
671 strcat(fn, d);
672 strcat(fn, "/");
673 strcat(fn, h->p);
674
675 fp = fopen(fn, "r");
676 if(!fp)
677 {
678 fprintf(stderr, "[load_schema]: FAILED to load schema file: %s.\n", h->p);
679 break;
680 }
681
682 tn = h->p;
683 tbc = get_table(tn);
684 if(!tbc)
685 {
686 fprintf(stderr, "[load_schema]: Table %s is not supported.\n",tn);
687 fprintf(stderr, "[load_schema]: FAILED to load data for table: %s.\n", tn);
688 goto done;
689 }
690
691 tp = tbc->dtp;
692
693 while ( fgets(line1 , MAX_ROW_SIZE, fp) != NULL )
694 {
695 if ( fgets(line2 , MAX_ROW_SIZE, fp) != NULL )
696 {
697 if(strstr(line1, METADATA_COLUMNS))
698 {
699 if(0!=load_metadata_columns(tp, line2))
700 {
701 fprintf(stderr, "[load_schema]: FAILED to load METADATA COLS in table: %s.\n", tn);
702 goto done;
703 }
704 }
705
706 if(strstr(line1, METADATA_KEY))
707 {
708 if(0!=load_metadata_key(tp, line2))
709 {
710 fprintf(stderr, "[load_schema]: FAILED to load METADATA KEYS in table: %s.\n", tn);
711 goto done;
712 }
713 }
714 }
715 else
716 {
717 fprintf(stderr, "[load_schema]: FAILED to read schema value in table: %s.\n", tn);
718 goto done;
719 }
720
721 }
722 done:
723 fclose(fp);
724 h = n;
725 }
726
727 while(h) /*free mem*/
728 { n = h->next;
729 free(h->p);
730 free(h);
731 h = n;
732 }
733
734 return rc;
735 }
736
737
738
739 /**
740 * get_table -- return pointer to lazy initialized table struct
741 */
get_table(char * _s)742 tbl_cache_p get_table(char *_s)
743 {
744 tbl_cache_p _tbc = tables;
745 table_p _tp = NULL;
746
747 while(_tbc)
748 {
749 if(_tbc->dtp)
750 {
751 if(_tbc->dtp->name
752 && !strcmp(_tbc->dtp->name,_s))
753 {
754 return _tbc;
755 }
756 }
757 _tbc = _tbc->next;
758 }
759
760 _tbc = (tbl_cache_p)malloc(sizeof(tbl_cache_t));
761 if(!_tbc)
762 return NULL;
763
764 _tp = create_table(_s);
765
766 if(!_tp)
767 {
768 fprintf(stderr, "[get_table]: failed to create table.\n");
769 free(_tbc);
770 return NULL;
771 }
772
773 _tbc->dtp = _tp;
774
775 if(tables)
776 (tables)->prev = _tbc;
777
778 _tbc->next = tables;
779 tables = _tbc;
780
781 return _tbc;
782 }
783
784
785 /**
786 * create_table -- returns an initialed table struct
787 */
create_table(char * _s)788 table_p create_table(char *_s)
789 {
790 int i;
791 table_p tp = NULL;
792
793 tp = (table_p)malloc(sizeof(table_t));
794 if(!tp) return NULL;
795
796 i=strlen(_s)+1;
797 tp->name = (char*)malloc(i*sizeof(char));
798 strncpy(tp->name, _s, i);
799
800 tp->ncols=0;
801 tp->nkeys=0;
802 tp->ro=0;
803 tp->logflags=0;
804 tp->db = NULL;
805
806 for(i=0;i<MAX_NUM_COLS;i++)
807 tp->colp[i] = NULL;
808
809 return tp;
810 }
811
812
813 /**
814 * load_metadata_columns -- parses the METADATA_COLUMNS line into the internal
815 * representation.
816 */
load_metadata_columns(table_p _tp,char * line)817 int load_metadata_columns(table_p _tp, char* line)
818 {
819 int n,len;
820 char *s = NULL;
821 char cn[64], ct[16];
822 column_p col;
823 n = len = 0;
824
825 if(!_tp) return -1;
826 if(_tp->ncols!=0) return 0;
827
828 /* eg: line = "table_name(str) table_version(int)" */
829 s = strtok(line, " \t");
830 while(s!=NULL && n<MAX_NUM_COLS)
831 {
832 /* eg: meta[0]=table_name meta[1]=str */
833 sscanf(s,"%20[^(](%10[^)])[^\n]", cn, ct);
834
835 /* create column*/
836 col = (column_p) malloc(sizeof(column_t));
837 if(!col)
838 { fprintf(stderr, "load_metadata_columns: out of memory \n");
839 return -1;
840 }
841
842 /* set name*/
843 len = strlen( cn )+1;
844 col->name = (char*)malloc(len * sizeof(char));
845 strcpy(col->name, cn );
846
847 /* set type*/
848 len = strlen( ct )+1;
849 col->type = (char*)malloc(len * sizeof(char));
850 strcpy(col->type, ct );
851
852 _tp->colp[n] = col;
853 n++;
854 _tp->ncols++;
855 s=strtok(NULL, " \t");
856 }
857
858 return 0;
859 }
860
861
862 /**
863 * load_metadata_key -- parses the METADATA_KEY line into the internal
864 * representation.
865 */
load_metadata_key(table_p _tp,char * line)866 int load_metadata_key(table_p _tp, char* line)
867 {
868 int ret,n,ci;
869 char *s = NULL;
870 ret = n = ci = 0;
871
872 if(!_tp)return -1;
873
874 s = strtok(line, " \t");
875 while(s!=NULL && n< _tp->ncols)
876 {
877 ret = sscanf(s,"%i", &ci);
878 if(ret != 1) return -1;
879 if( _tp->colp[ci] )
880 { _tp->colp[ci]->kflag = 1;
881 _tp->nkeys++;
882 }
883 n++;
884 s=strtok(NULL, " ");
885 }
886
887 return 0;
888 }
889
890
891 /**
892 * get_db -- lazy initialized DB access
893 * Its like this so we get new db files only for the tables that have
894 * journal files.
895 * The db file on disk will be named:
896 * <tablename>.new
897 */
get_db(table_p tp)898 DB* get_db(table_p tp)
899 {
900 int rc;
901 DB* db;
902 char dfn[MAX_FILENAME_SIZE];
903
904 if( !tp) return NULL;
905 if( tp->db) return tp->db;
906
907 memset(dfn, 0, MAX_FILENAME_SIZE);
908 if(db_home)
909 {
910 strcpy(dfn, db_home);
911 strcat(dfn, "/");
912 }
913
914 /*creation of DB follows*/
915 strcat(dfn, tp->name);
916
917 if ((rc = db_create(&db, NULL, 0)) != 0)
918 {
919 fprintf(stderr, "[create_table]: error db_create for table: %s.\n",dfn);
920 return NULL;
921 }
922
923 if ((rc = db->open(db, NULL, dfn, NULL, DB_HASH, DB_CREATE, 0664)) != 0)
924 {
925 fprintf(stderr, "[create_table]: error opening %s.\n",dfn);
926 fprintf(stderr, "[create_table]: error msg: %s.\n",db_strerror(rc));
927 return NULL;
928 }
929 tp->db = db;
930
931 import_schema(tp);
932
933 return db;
934 }
935
936
937 /**
938 */
import_schema(table_p tp)939 int import_schema(table_p tp)
940 {
941 int rc, len1, len2;
942 char line1 [MAX_ROW_SIZE];
943 char line2 [MAX_ROW_SIZE];
944 char fn [MAX_FILENAME_SIZE];
945 FILE * fp = NULL;
946 rc = 0;
947
948 if(!schema_dir)
949 {
950 fprintf(stderr, "[import_schema]: null schema dir.\n");
951 return 1;
952 }
953
954 if(!tp)
955 {
956 fprintf(stderr, "[import_schema]: null table parameter.\n");
957 return 1;
958 }
959
960 /*create abs path to journal file (relative to db_home) */
961 memset(fn, 0 , MAX_FILENAME_SIZE);
962 strcat(fn, schema_dir);
963 strcat(fn, "/");
964 strcat(fn, tp->name);
965
966 fp = fopen(fn, "r");
967 if(!fp)
968 {
969 fprintf(stderr, "[import_schema]: FAILED to open def schema file: %s.\n", fn);
970 return 1;
971 }
972
973 while ( fgets(line1 , MAX_ROW_SIZE, fp) != NULL )
974 {
975 if ( fgets(line2 , MAX_ROW_SIZE, fp) != NULL )
976 {
977 len1 = strlen(line1)-1;
978 len2 = strlen(line2)-1;
979 line1[len1] = 0;
980 line2[len2] = 0;
981
982 if((rc = _insert(tp->db, line1, line2, len1, len2) )!=0)
983 {
984 fprintf(stderr, "[import_schema]: FAILED to write schema def into table: %s.\n", tp->name);
985 goto done;
986 }
987 }
988 else
989 {
990 fprintf(stderr, "[import_schema]: FAILED to read schema def value in table: %s.\n", tp->name);
991 goto done;
992 }
993
994 }
995 done:
996 fclose(fp);
997 return rc;
998 }
999
1000
1001
1002 /**
1003 * cleanup -- frees memory; closes any files.
1004 */
cleanup(void)1005 void cleanup(void)
1006 {
1007 //cleanup
1008 while(tables)
1009 { int i;
1010 tbl_cache_p n = tables->next;
1011 table_p tp = tables->dtp;
1012 if(tp)
1013 {
1014 free(tp->name);
1015 for(i=0;i< tp->ncols;i++)
1016 {
1017 free(tp->colp[i]->name);
1018 free(tp->colp[i]->type);
1019 free(tp->colp[i]);
1020 }
1021
1022 if(tp->db)
1023 tp->db->close(tp->db, 0);
1024
1025 free(tp);
1026 }
1027 free(tables);
1028 tables = n;
1029 }
1030 }
1031
1032