kambdb_recover.c 19 KB

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