1 /*
2 * Copyright (c) 2011, 2020 Oracle and/or its affiliates. All rights reserved.
3 *
4 * See the file EXAMPLES-LICENSE for license information.
5 *
6 * $Id$
7 *
8 * ex_heap -- A basic example about usage of heap access method.
9 *
10 * This program demonstrates the usage of heap access method of BDB and differences
11 * between the heap and btree access method. There are many kinds of access methods
12 * for BDB, access methods determine how pages are stored in the file and how records
13 * are stored on a page. Heap access method is one of the common used access method
14 * for BDB. The records are unsorted and the key indicates the page location within
15 * heap access method. It's feature is to reuse space easily and enable the database
16 * to stay a constant size, which is different from btree access method.
17 *
18 * The application initially populates a database, and then proceeds to move into
19 * a process of adding and removing data. The sample application using a btree
20 * database will be run if the flag is specified. The system will keep a fairly
21 * constant amount of data in the database. After the insert/delete operation
22 * is completed. The system will calculate the execution time and physical file
23 * size to demonstrate the difference between btree database and heap database.
24 * The outcome shows that heap access method will maintain a constant database
25 * size if the heap size is configured properly, while the btree database will
26 * continue to grow.
27 *
28 * Database: heap.db, btree.db
29 * Program name: ex_heap
30 *
31 * Options:
32 * -b run sample application using a btree database
33 * -c specify the cache size for the environment
34 * -d test on variable-length data (default:fix-length)
35 * -h [dir] specify the home directory for the environment
36 * -n specify the number of records per repetition (default:10000)
37 * -p specify the pgsize of database
38 * -r set number of repetition (a pair of insertion and deletion, default:1)
39 * -s specify the heap size (bytes) for the heap database
40 * -S specify the heap size (gbytes) for the heap database
41 *
42 */
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47
48 #include "db.h"
49
50
51 #ifndef lint
52 static const char copyright[] =
53 "Copyright (c) 2011, 2020 Oracle and/or its affiliates. All rights reserved.\n";
54 #endif
55
56 #define BUFFER_LEN 30 /* Buffer size to hold data */
57 #define NS_PER_MS 1000000/* Nanoseconds in a millisecond*/
58 #define NS_PER_US 1000 /* Nanoseconds in a microsecond*/
59 #define DEF_INIT_RECS 10000 /* Default initial records */
60 #define DEF_RECS_PER_REP 10000 /* Default records per repeat. */
61 #define DEF_REPEATS 1 /* Default repetition value */
62
63 /*
64 * Average space each record needs, based on the data generated.
65 * The ideal heap size for this example should be set as (bytes):
66 * AVG_SPACE_PER_RECORD * (DEF_INIT_RECS + records inserted each repetition)
67 */
68 #define AVG_SPACE_PER_RECORD 36
69
70 #ifdef _WIN32
71 #include <sys/timeb.h>
72 #include <time.h>
73 #include <winsock2.h>
74 extern int getopt(int, char * const *, const char *);
75
76 /* Implement a basic high-resolution timer with a POSIX interface for Windows.*/
gettimeofday(struct timeval * tv,struct timezone * tz)77 int gettimeofday(struct timeval *tv, struct timezone *tz)
78 {
79 struct _timeb now;
80 _ftime(&now);
81 tv->tv_sec = (long)now.time;
82 tv->tv_usec = now.millitm * NS_PER_US;
83 return (0);
84 }
85 #else
86 #include <sys/time.h>
87 #include <unistd.h>
88 #endif
89
90 int compare_int(DB *, const DBT *, const DBT *, size_t *);
91 int delete_recs __P((DB *, DB_ENV *, int));
92 int file_size __P((DB *, DBTYPE, int *));
93 int generate_data __P((char [], int, int));
94 int insert_btree __P((DB *, DB_ENV *, int, int, int));
95 int insert_heap __P((DB *, DB_ENV *, int, int, int));
96 int open_db __P((
97 DB **, DB_ENV *, DBTYPE, char *, u_int32_t, u_int32_t, u_int32_t));
98 int open_env __P((DB_ENV **, char *, u_int32_t));
99 int run_workload __P((DB *, int, int, int));
100 void usage __P((void));
101
102 const char *progname = "ex_heap"; /* Program name. */
103
104 int
main(argc,argv)105 main(argc, argv)
106 int argc;
107 char *argv[];
108 {
109 extern char *optarg; /* Set by getopt(): the argv being processed. */
110 DB_ENV *dbenv; /* The environment handle. */
111 DB *dbp; /* The database handle. */
112 u_int32_t cachesize; /* The size of cache set for the environment. */
113 u_int32_t ghpsize; /* The heap size (gbytes) for the heap database. */
114 u_int32_t hpsize; /* The heap size (bytes) for the heap database. */
115 u_int32_t pgsize; /* The page size of database. */
116 char *home; /* The home directory for the program. */
117 int ch; /* The current command line option char. */
118 int ret; /* Return code from call into Berkeley DB. */
119 int ret_t; /* Return code from close operation. */
120 int set_ghpsize; /* Flag for setting gphsize. */
121 int set_hpsize; /* Flag for setting hpsize. */
122 int test_btree; /* Flag for running sample application using a btree database. */
123 int test_var_data; /* Flag for testing variable-length data. */
124
125 int recs_per_rep; /* Number of records per repetition. */
126 int repeats; /* Repetition value. */
127
128 dbenv = NULL;
129 dbp = NULL;
130 cachesize = 0;
131 ret = ret_t = set_ghpsize = set_hpsize = test_btree = 0;
132 home = NULL;
133
134 recs_per_rep = DEF_RECS_PER_REP;
135 ghpsize = hpsize = pgsize = 0;
136 repeats = DEF_REPEATS;
137 test_var_data = 0; /* Default as fix-length data. */
138
139 /* Parse the command line arguments */
140 while ((ch = getopt(argc, argv, "bc:dh:n:p:r:S:s:")) != EOF)
141 switch (ch) {
142 case 'b': /* Run sample application using a btree database. */
143 test_btree = 1;
144 break;
145 case 'c': /* Specify the cache size for the environment. */
146 cachesize = atoi(optarg);
147 break;
148 case 'd': /* Test on variable-length data. */
149 test_var_data = 1;
150 break;
151 case 'h': /* Specify the home directory for the environment. */
152 home = optarg;
153 break;
154 case 'n': /* Specify the number of records per repetition. */
155 recs_per_rep = atoi(optarg);
156 break;
157 case 'p': /* Specify the pgsize of database. */
158 pgsize = atoi(optarg);
159 break;
160 case 'r': /* Set number of repetition. */
161 repeats = atoi(optarg);
162 break;
163 case 's': /* Specify the heap size (bytes) for the heap database. */
164 set_hpsize = 1;
165 hpsize = atoi(optarg);
166 break;
167 case 'S': /* Specify the heap size (gbytes) for the heap database. */
168 set_ghpsize = 1;
169 ghpsize = atoi(optarg);
170 break;
171 default:
172 usage();
173 }
174
175 if (!home)
176 usage();
177
178 srand((int)time(NULL));
179
180 /*
181 * If heap size is not specified, then use our default configuration
182 * as follows.
183 */
184 if (!set_hpsize && !set_ghpsize)
185 hpsize = AVG_SPACE_PER_RECORD * (DEF_INIT_RECS + recs_per_rep);
186
187 /* Open the evnironment for usage. */
188 if ((ret = open_env(&dbenv, home, cachesize)) != 0) {
189 fprintf(stderr, "%s: open_env: %s", progname, db_strerror(ret));
190 goto err;
191 }
192 /* Open a heap database for insert/delete operations. */
193 if ((ret = open_db(&dbp, dbenv, DB_HEAP, home,
194 ghpsize, hpsize, pgsize)) != 0) {
195 dbenv->err(dbenv, ret, "Failed to open heap database.");
196 goto err;
197 }
198
199 /*
200 * Perform requested rounds of insert/delete operations
201 * using heap database.
202 */
203 if ((ret =
204 run_workload(dbp, repeats, recs_per_rep, test_var_data)) != 0) {
205 dbenv->err(dbenv, ret,
206 "Failed to perform operations on heap database.");
207 goto err;
208 }
209
210 if (test_btree) {
211 /* Close the DB handle for heap. */
212 if ((ret = dbp->close(dbp, 0)) != 0) {
213 dbenv->err(dbenv, ret, "DB->close");
214 goto err;
215 }
216 dbp = NULL;
217 /* Open a b-tree database for insert/delete operations. */
218 if ((ret =
219 open_db(&dbp, dbenv, DB_BTREE, home, 0, 0, pgsize)) != 0) {
220 dbenv->err(dbenv, ret,
221 "Failed to open btree database.");
222 goto err;
223 }
224
225 /*
226 * Perform requested rounds of insert/delete operations
227 * using btree database.
228 */
229 if ((ret = run_workload(dbp,
230 repeats, recs_per_rep, test_var_data)) != 0) {
231 dbenv->err(dbenv, ret,
232 "Failed to perform operations on btree database.");
233 goto err;
234 }
235 }
236 err:
237 if (dbp != NULL && (ret_t = dbp->close(dbp, 0)) != 0) {
238 dbenv->err(dbenv, ret_t, "DB->close");
239 ret = (ret == 0 ? ret_t : ret);
240 }
241
242 if (dbenv != NULL && (ret_t = dbenv->close(dbenv, 0)) != 0) {
243 fprintf(stderr, "%s: dbenv->close: %s", progname,
244 db_strerror(ret_t));
245 ret = (ret == 0 ? ret_t : ret);
246 }
247
248 return (ret);
249 }
250
251 /*
252 * run_workload --
253 * Perform requested rounds of insert/delete operations.
254 *
255 * Parameters:
256 * dbp the database handle
257 * repeats the number of repetition (a pair of insertion and deletion)
258 * recs_per_rep the number of records per repetition
259 * test_var test on variable-length data flag
260 */
261 int
run_workload(dbp,repeats,recs_per_rep,test_var)262 run_workload(dbp, repeats, recs_per_rep, test_var)
263 DB *dbp;
264 int repeats, recs_per_rep, test_var;
265 {
266 DB_ENV *dbenv; /* The environment handle. */
267 DBTYPE dbtype; /* The access method used by the database. */
268 u_int32_t ghpsize; /* The heap size (gbytes). */
269 u_int32_t hpsize; /* The heap size (bytes). */
270 struct timeval end_time; /* The end time of each iteration. */
271 struct timeval start_time; /* The start time of each iteration. */
272 double *time_secs; /* The array of each iteration's run time. */
273 int *db_file_sizes; /* The array of file sizes after each iteration. */
274 int fsize; /* The file size after the current iteration. */
275 int i; /* Iteration number. */
276 int ret; /* The return value. */
277
278 dbenv = dbp->dbenv;
279 fsize = 0;
280 time_secs = NULL;
281 db_file_sizes = NULL;
282
283 /* Get the access method of the database. */
284 if ((ret = dbp->get_type(dbp, &dbtype)) != 0) {
285 dbenv->err(dbenv, ret, "DB->get_type");
286 goto err;
287 }
288
289 /* Get the heap size if the database uses the heap access method. */
290 if (dbtype == DB_HEAP &&
291 (ret = dbp->get_heapsize(dbp, &ghpsize, &hpsize)) != 0) {
292 dbenv->err(dbenv, ret, "DB->get_heapsize");
293 goto err;
294 }
295
296 /* Initialize the array holding file sizes after each iteration. */
297 if ((db_file_sizes =
298 (int *)malloc((repeats + 1) * sizeof(int))) == NULL) {
299 fprintf(stderr,
300 "%s: Unable to allocate space for array db_file_sizes.\n",
301 progname);
302 goto err;
303 }
304 memset(db_file_sizes, 0, (repeats + 1) * sizeof(int));
305
306 /* Initialize the array holding each iteration's run time. */
307 if ((time_secs =
308 (double *)malloc((repeats + 1) * sizeof(double))) == NULL) {
309 fprintf(stderr,
310 "%s: Unable to allocate space for array time_secs.\n",
311 progname);
312 goto err;
313 }
314 memset(time_secs, 0, (repeats + 1) * sizeof(double));
315
316 printf("\n\n======================================================");
317 printf("\nAbout to enter the insert phase.");
318 printf("\n\tDatabase type: %s \t",
319 dbtype == DB_HEAP ? "Heap" : "Btree");
320 if (dbtype == DB_HEAP)
321 printf("with configured heapsize = %d gbytes and %d bytes.",
322 ghpsize, hpsize);
323 printf("\n\tPagesize: %d", dbp->pgsize);
324 printf("\n\tInitial records number: %d", DEF_INIT_RECS);
325 printf("\n\tNumber of repetitions: %d", repeats);
326 printf("\n\tNumber of inserts per repetition: %d\n", recs_per_rep);
327
328 /*
329 * Insert records to the database and delete the same number from
330 * the database, then check the change of the physical database file.
331 *
332 * Don't delete after the first insertion to leave some data
333 * in the tables for subsequent iterations.
334 */
335 for (i = 0; i <= repeats; i++) {
336 /* Get the start time. */
337 (void)gettimeofday(&start_time, NULL);
338
339 /*
340 * Insert records into the database. Depending on the type
341 * of the database, different types of keys are used. Calling
342 * different functions to perform insertions.
343 */
344 if ((dbtype == DB_HEAP) && (ret = insert_heap(dbp, dbenv,
345 i == 0 ? DEF_INIT_RECS : recs_per_rep,
346 i == 0 ? 0 : (DEF_INIT_RECS + (i - 1) * recs_per_rep),
347 test_var)) != 0) {
348 dbenv->err(dbenv, ret,
349 "Failed to insert records to heap database.");
350 goto err;
351 }
352
353 if ((dbtype == DB_BTREE) && (ret = insert_btree(dbp, dbenv,
354 i == 0 ? DEF_INIT_RECS : recs_per_rep,
355 i == 0 ? 0 : (DEF_INIT_RECS + (i - 1) * recs_per_rep),
356 test_var)) != 0) {
357 dbenv->err(dbenv, ret,
358 "Failed to insert records to btree database.");
359 goto err;
360 }
361
362 /*
363 * Delete the same number of records except for the first
364 * iteration.
365 */
366 if (i > 0 &&
367 (ret = delete_recs(dbp, dbenv, recs_per_rep)) != 0) {
368 dbenv->err(dbenv, ret, "Failed to delete records.");
369 goto err;
370 }
371
372 /* Get the end time. */
373 (void)gettimeofday(&end_time, NULL);
374
375 /* Calculate the runtime. */
376 time_secs[i] =
377 (((double)end_time.tv_sec * NS_PER_MS +
378 end_time.tv_usec) -
379 ((double)start_time.tv_sec * NS_PER_MS +
380 start_time.tv_usec)) / NS_PER_MS;
381
382 /* Calculate the physical file size. */
383 if ((ret = file_size(dbp, dbtype, &fsize)) != 0) {
384 dbenv->err(dbenv, ret, "Failed to calculate "
385 "the file size on repeat %d.\n", i);
386 goto err;
387 }
388 db_file_sizes[i] = fsize;
389 }
390 printf("\n------------------------------------------------------\n");
391 printf("%5s \t %10s \t %10s\n", "repetition", "physical file size",
392 "running time");
393 for (i = 0; i <= repeats; i++)
394 printf("%5d \t\t %10d \t\t %.2f seconds\n",
395 i, db_file_sizes[i], time_secs[i]);
396
397 err:
398 if (db_file_sizes != NULL)
399 free(db_file_sizes);
400 if (time_secs != NULL)
401 free(time_secs);
402
403 return (ret);
404 }
405
406 /*
407 * file_size --
408 * Calculate the physical file size of the given database.
409 *
410 * Parameters:
411 * dbp the database handle
412 * dbtype the database type
413 * fsize the physical file size of database
414 */
415 int
file_size(dbp,dbtype,fsize)416 file_size(dbp, dbtype, fsize)
417 DB *dbp;
418 DBTYPE dbtype;
419 int *fsize;
420 {
421 DB_ENV *dbenv; /* The environment handle. */
422 u_int32_t pgcnt; /* The number of pages in the database. */
423 u_int32_t pgsize; /* The page size. */
424 int ret; /* The return value. */
425 int size; /* The file size. */
426 void *statp; /* The statistic pointer for database size. */
427
428 dbenv = dbp->dbenv;
429 pgsize = dbp->pgsize;
430 ret = size = 0;
431
432 /* Retrieve the database's statistics. */
433 if ((ret = dbp->stat(dbp, NULL, &statp, DB_FAST_STAT)) != 0) {
434 dbenv->err(dbenv, ret, "DB->stat");
435 return (ret);
436 }
437
438 /* Get the page count. */
439 pgcnt = (dbtype == DB_HEAP ? ((DB_HEAP_STAT *)statp)->heap_pagecnt :
440 ((DB_BTREE_STAT *)statp)->bt_pagecnt);
441
442 /* the file size is the value of page count multiplied by the page size. */
443 size = pgcnt * pgsize;
444 *fsize = size;
445
446 free(statp);
447
448 return (ret);
449 }
450
451 /*
452 * insert_heap --
453 * Insert a specified number of records to a heap database,
454 * with keys beginning with a specified value.
455 *
456 * Parameters:
457 * dbp the database handle
458 * dbenv the database environment
459 * numrecs the number of records to insert
460 * start the start position to insert records
461 * test_var test on variable-length data flag
462 */
463
464 int
insert_heap(dbp,dbenv,numrecs,start,test_var)465 insert_heap(dbp, dbenv, numrecs, start, test_var)
466 DB *dbp;
467 DB_ENV *dbenv;
468 int numrecs, start, test_var;
469 {
470 DB_HEAP_RID rid; /* The returned record id. */
471 DBT key, data; /* The key/data pair. */
472 char buf[BUFFER_LEN]; /* The data buffer. */
473 int cnt, ret;
474
475 memset(&rid, 0, sizeof(DB_HEAP_RID));
476 memset(&key, 0, sizeof(DBT));
477 memset(&data, 0, sizeof(DBT));
478
479 ret = 0;
480
481 /* For a heap database, the key must be an empty DB_HEAP_RID. */
482 key.data = &rid;
483 key.size = key.ulen = sizeof(DB_HEAP_RID);
484 key.flags = DB_DBT_USERMEM;
485 data.data = buf;
486 data.flags = DB_DBT_USERMEM;
487
488 /*
489 * Insert a certain number of records into btree database,
490 * the data to insert is generated randomly.
491 */
492 for (cnt = start; cnt < (numrecs + start) &&
493 (ret = generate_data(buf, cnt, test_var)) == 0; ++cnt) {
494 data.size = data.ulen = (u_int32_t)strlen(buf) + 1;
495
496 /* Require DB_APPEND flag to add new data to the database.*/
497 if ((ret = dbp->put(dbp, NULL, &key, &data, DB_APPEND)) != 0) {
498 dbenv->err(dbenv, ret, "insert_heap:DB->put");
499 break;
500 }
501 }
502
503 return (ret);
504 }
505
506 /*
507 * insert_btree --
508 * Insert a specified number of records to a btree database,
509 * with keys beginning with a specified value.
510 *
511 * Parameters:
512 * dbp the database handle
513 * dbenv the database environment
514 * numrecs the number of records to insert
515 * start the start position to insert records
516 * test_var test on variable-length data flag
517 */
518
519 int
insert_btree(dbp,dbenv,numrecs,start,test_var)520 insert_btree(dbp, dbenv, numrecs, start, test_var)
521 DB *dbp;
522 DB_ENV *dbenv;
523 int numrecs, start, test_var;
524 {
525 DBT key, data;
526 char buf[BUFFER_LEN];
527 int cnt, ret;
528
529 memset(&key, 0, sizeof(DBT));
530 memset(&data, 0, sizeof(DBT));
531
532 ret = 0;
533
534 key.data = &cnt;
535 key.size = key.ulen = sizeof(int);
536 key.flags = DB_DBT_USERMEM;
537 data.data = buf;
538 data.flags = DB_DBT_USERMEM;
539
540 /*
541 * Insert a certain number of records into btree database,
542 * the data to insert is generated by randomly.
543 */
544 for (cnt = start; cnt < (numrecs + start) &&
545 (ret = generate_data(buf, cnt, test_var)) == 0; ++cnt) {
546 data.size = data.ulen = (u_int32_t)strlen(buf) + 1;
547
548 if ((ret = dbp->put(dbp, NULL, &key, &data, 0)) != 0) {
549 dbenv->err(dbenv, ret, "insert_btree:DB->put");
550 break;
551 }
552 }
553
554 return (ret);
555 }
556
557 /*
558 * generate_data --
559 * Generate data for the specified record.
560 *
561 * Parameters:
562 * buf the buffer variable to hold data
563 * rec_no the record number
564 * test_var test on variable-length data flag
565 */
566
567 int
generate_data(buf,rec_no,test_var)568 generate_data(buf, rec_no, test_var)
569 char *buf;
570 int rec_no, test_var;
571 {
572 const char *str = "abcdefghijklmnopqrst";
573 int len = (int)strlen(str);
574
575 /*
576 * Default use the fix-length data,
577 * if required then use variable-length data.
578 */
579 if (test_var == 1)
580 len = rand() % (len - 2) + 1;
581
582 (void)sprintf(buf, "%04d_%*s", rec_no, len, str);
583
584 return (0);
585 }
586
587 /*
588 * delete_recs --
589 * Delete a specified number of records.
590 *
591 * Parameters:
592 * dbp the database handle
593 * dbenv the database environment handle
594 * numrecs number of records to delete
595 */
596
597 int
delete_recs(dbp,dbenv,numrecs)598 delete_recs(dbp, dbenv, numrecs)
599 DB *dbp;
600 DB_ENV *dbenv;
601 int numrecs;
602 {
603 DBC *dbcp;
604 DBT key, data;
605 int cnt, ret;
606
607 memset(&key, 0, sizeof(DBT));
608 memset(&data, 0, sizeof(DBT));
609
610 dbcp = NULL;
611 cnt = ret = 0;
612
613 /* Create a cursor to delete records. */
614 if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) {
615 dbenv->err(dbenv, ret, "delete_recs:DB->cursor");
616 goto err;
617 }
618
619 /* Delete the first numrecs records. */
620 while ((ret = dbcp->get(dbcp, &key, &data, DB_NEXT)) == 0 &&
621 cnt < numrecs) {
622 if ((ret = dbcp->del(dbcp, 0)) != 0) {
623 dbenv->err(dbenv, ret, "delete_recs:DBCursor->del");
624 break;
625 } else
626 ++cnt;
627 }
628
629 err:
630 if (dbcp != NULL && (ret = dbcp->close(dbcp)) != 0)
631 dbenv->err(dbenv, ret, "delete_recs:DBCursor->close");
632
633 return (ret);
634 }
635
636 /*
637 * usage --
638 * Describe this program's command line options, then exit.
639 */
640 void
usage()641 usage()
642 {
643 fprintf(stderr, "usage: %s:\n%s \n %s\n", progname,
644 "\t[-b][-c cachesize][-d] -h home [-n recs_per_rep]",
645 "\t[-p pgsize][-r repeats][-S ghpsize][-s hpsize]");
646
647 fprintf(stderr, "-b: run sample application using a btree database.\n");
648 fprintf(stderr, "-c: specify the cache size for the environment.\n");
649 fprintf(stderr, "-d: test on variable-length data "
650 "(default: fix-length).\n");
651 fprintf(stderr, "-h: specify the home directory for "
652 "the environment (required).\n");
653 fprintf(stderr, "-n: specify the num. of records "
654 "per repetition (default: %d).\n", DEF_RECS_PER_REP);
655 fprintf(stderr, "-p: specify the pgsize of database.\n");
656 fprintf(stderr, "-r: number of repetition (a pair of "
657 "insertion and deletion (default: %d)).\n", DEF_REPEATS);
658 fprintf(stderr,
659 "-S: specify the heap size (gbytes) for the heap database.\n");
660 fprintf(stderr,
661 "-s: specify the heap size (bytes) for the heap database.\n");
662
663 exit(EXIT_FAILURE);
664 }
665
666 /*
667 * open_env --
668 * Open the environment before insert/delete operation
669 *
670 * Parameters:
671 * dbenvp the database environment handle
672 * home the home directory for the environment
673 * cachesize the cache size for the environment
674 */
675
676 int
open_env(dbenvp,home,cachesize)677 open_env(dbenvp, home, cachesize)
678 DB_ENV **dbenvp;
679 char *home;
680 u_int32_t cachesize;
681 {
682 DB_ENV *dbenv;
683 int ret = 0;
684
685 /* Create an environment handle and open an environment. */
686 if ((ret = db_env_create(&dbenv, 0)) != 0) {
687 fprintf(stderr, "%s: db_env_create: %s\n",
688 progname, db_strerror(ret));
689 return (ret);
690 }
691
692 *dbenvp = dbenv;
693
694 /*
695 * Prefix any error messages with the name of this program and a ':'.
696 * Setting the errfile to stderr is not necessary, since that is the
697 * default; it is provided here as a placeholder showing where one
698 * could direct error messages to an application-specific log file.
699 */
700 dbenv->set_errfile(dbenv, stderr);
701 dbenv->set_errpfx(dbenv, progname);
702
703 /* Set cachesize for the database environment. */
704 if ((cachesize > 0) && (ret =
705 dbenv->set_cachesize(dbenv, (u_int32_t)0, cachesize, 1)) != 0) {
706 dbenv->err(dbenv, ret, "DB_ENV->set_cachesize");
707 return (ret);
708 }
709
710 if ((ret = dbenv->open(dbenv, home, DB_CREATE | DB_INIT_MPOOL, 0)) != 0)
711 dbenv->err(dbenv, ret, "DB_ENV->open");
712
713 return (ret);
714 }
715
716 /*
717 * open_db --
718 * Open the database before insert/delete operation.
719 *
720 * Parameters:
721 * dbpp the database handle
722 * dbenv the database environment
723 * dbtype the database type
724 * home the home directory for the environment
725 * gphsize the heap size (gbytes) for the heap database
726 * hpsize the heap size (bytes) for the heap database
727 * pgsize the page size for the heap database
728 */
729 int
open_db(dbpp,dbenv,dbtype,home,ghpsize,hpsize,pgsize)730 open_db(dbpp, dbenv, dbtype, home, ghpsize, hpsize, pgsize)
731 DB **dbpp;
732 DB_ENV *dbenv;
733 DBTYPE dbtype;
734 char *home;
735 u_int32_t ghpsize, hpsize, pgsize;
736 {
737 DB *dbp;
738 u_int32_t dbflags = 0;
739 char *dbname;
740 int ret = 0;
741
742 dbname = (dbtype == DB_HEAP) ? "heap.db" : "btree.db";
743
744 /* Create a database handle and open a database. */
745 if ((ret = db_create(&dbp, dbenv, 0)) != 0) {
746 dbenv->err(dbenv, ret, "db_create : %s", dbname);
747 goto err;
748 }
749
750 *dbpp = dbp;
751
752 /* Set the record compare function for the btree database. */
753 if ((dbtype == DB_BTREE) &&
754 (ret = dbp->set_bt_compare(dbp, compare_int)) != 0) {
755 dbp->err(dbp, ret, "DB->set_bt_compare");
756 goto err;
757 }
758
759 /* Set heap size for the heap database. */
760 if ((dbtype == DB_HEAP) && (ghpsize > 0 || hpsize > 0) &&
761 (ret = dbp->set_heapsize(dbp, ghpsize, hpsize, 0)) != 0) {
762 dbenv->err(dbenv, ret, "DB->set_heapsize");
763 return (ret);
764 }
765 /* Set page size for the database. */
766 if ((pgsize > 0) && (ret = dbp->set_pagesize(dbp, pgsize)) != 0) {
767 dbenv->err(dbenv, ret, "DB->set_pagesize");
768 return (ret);
769 }
770
771 if ((ret =
772 dbp->open(dbp, NULL, dbname, NULL, dbtype, DB_CREATE, 0)) != 0)
773 dbenv->err(dbenv, ret, "DB->open");
774 err:
775
776 return (ret);
777 }
778
779 /*
780 * compare_int --
781 * Compare two data value for btree database.
782 *
783 * Parameters:
784 * dbp the database handle
785 * a one of the data value use to compare
786 * b another data value use to compare
787 * locp lock handle
788 */
789 int
compare_int(dbp,a,b,locp)790 compare_int(dbp, a, b, locp)
791 DB *dbp;
792 const DBT *a, *b;
793 size_t *locp;
794 {
795 int ai, bi;
796
797 dbp = NULL;
798 locp = NULL;
799
800 /*
801 * Returns:
802 * < 0 if a < b
803 * = 0 if a = b
804 * > 0 if a > b
805 */
806 memcpy(&ai, a->data, sizeof(int));
807 memcpy(&bi, b->data, sizeof(int));
808 return (ai - bi);
809 }
810