summaryrefslogtreecommitdiff
path: root/examples/cxx/BulkExample.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2015-02-17 17:25:57 +0000
committer <>2015-03-17 16:26:24 +0000
commit780b92ada9afcf1d58085a83a0b9e6bc982203d1 (patch)
tree598f8b9fa431b228d29897e798de4ac0c1d3d970 /examples/cxx/BulkExample.cpp
parent7a2660ba9cc2dc03a69ddfcfd95369395cc87444 (diff)
downloadberkeleydb-780b92ada9afcf1d58085a83a0b9e6bc982203d1.tar.gz
Imported from /home/lorry/working-area/delta_berkeleydb/db-6.1.23.tar.gz.HEADdb-6.1.23master
Diffstat (limited to 'examples/cxx/BulkExample.cpp')
-rw-r--r--examples/cxx/BulkExample.cpp910
1 files changed, 910 insertions, 0 deletions
diff --git a/examples/cxx/BulkExample.cpp b/examples/cxx/BulkExample.cpp
new file mode 100644
index 00000000..0cd79f64
--- /dev/null
+++ b/examples/cxx/BulkExample.cpp
@@ -0,0 +1,910 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2012, 2015 Oracle and/or its affiliates. All rights reserved.
+ *
+ * $Id$
+ */
+#include <errno.h>
+#include <iostream>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <db_cxx.h>
+
+#define DATABASE "excxx_bulk.db" /* Database name */
+#define DATALEN 20 /* The length of data */
+#define NS_PER_MS 1000000 /* Nanoseconds in a millisecond */
+#define NS_PER_US 1000 /* Nanoseconds in a microsecond */
+#define STRLEN DATALEN - sizeof(int) /* The length of string */
+#define UPDATES_PER_BULK_PUT 100
+
+#ifdef _WIN32
+#include <sys/timeb.h>
+extern "C" {
+ int getopt(int, char * const *, const char *);
+ char *optarg;
+}
+/* Implement a basic high res timer with a POSIX interface for Windows. */
+struct timeval {
+ time_t tv_sec;
+ long tv_usec;
+};
+int gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ struct _timeb now;
+ _ftime(&now);
+ tv->tv_sec = now.time;
+ tv->tv_usec = now.millitm * NS_PER_US;
+ return (0);
+}
+#define CLEANUP_CMD "rmdir EXCXX_BULK /q/s"
+#else
+#include <sys/time.h>
+#include <unistd.h>
+#define CLEANUP_CMD "rm -rf EXCXX_BULK"
+#endif
+
+int compare_int(Db *, const Dbt *, const Dbt *, size_t *);
+int get_first_str(Db *, const Dbt *, const Dbt *, Dbt *);
+int get_string(const char *, char *, int);
+static void usage();
+
+const char *progname = "BulkExample";
+const char tstring[STRLEN] = "0123456789abcde";
+
+struct data {
+ int id;
+ char str[STRLEN];
+};
+
+using std::cin;
+using std::cout;
+using std::cerr;
+using std::endl;
+
+class BulkExample
+{
+public:
+ BulkExample();
+ ~BulkExample();
+ void bulkDelete(
+ int num, int dups, int *countp, int *iterp, int verbose);
+ void bulkRead(int num, int dups, int iter, int *countp, int verbose);
+ void bulkSecondaryDelete(
+ int num, int pair, int *countp, int *iterp, int verbose);
+ void bulkUpdate(
+ int num, int dups, int *countp, int *iterp, int verbose);
+ void initDb(int, int, int);
+ void initDbenv(const char *, u_int);
+ void run(int, char *[]);
+ void throwException(DbEnv *, DbTxn *, int, const char *);
+private:
+ DbEnv *dbenv;
+ Db *dbp, *sdbp;
+ struct data *data_val;
+ void *dbuf, *kbuf;
+ u_int32_t dlen, klen;
+};
+
+void BulkExample::throwException(
+ DbEnv *dbenvp, DbTxn *txn, int ret, const char *msg)
+{
+ if (txn != NULL) {
+ (void)txn->abort();
+ txn = NULL;
+ }
+ if (dbenvp != NULL && msg != NULL)
+ dbenvp->err(ret, msg);
+ throw DbException(ret);
+}
+
+void BulkExample::run(int argc, char *argv[])
+{
+ struct timeval start_time, end_time;
+ double secs;
+ int biter, ch, count, dflag, dups, init, iter, num, pair;
+ int rflag, sflag, verbose;
+ u_int32_t cachesize, pagesize;
+
+ dflag = dups = init = rflag = sflag = verbose = 0;
+ iter = num = 1000000;
+ pagesize = 65536;
+ cachesize = 1000 * pagesize;
+
+ while ((ch = getopt(argc, argv, "c:Dd:Ii:n:p:RSv")) != EOF)
+ switch (ch) {
+ case 'c':
+ cachesize = (u_int32_t)atoi(optarg);
+ break;
+ case 'D':
+ dflag = 1;
+ break;
+ case 'd':
+ dups = atoi(optarg);
+ if (dups < 0)
+ usage();
+ break;
+ case 'I':
+ init = 1;
+ break;
+ case 'i':
+ iter = atoi(optarg);
+ break;
+ case 'n':
+ num = atoi(optarg);
+ break;
+ case 'p':
+ pagesize = (u_int32_t)atoi(optarg);
+ break;
+ case 'R':
+ rflag = 1;
+ break;
+ case 'S':
+ sflag = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+
+ /* Remove the previous environment and database(s). */
+ if (!rflag) {
+ system(CLEANUP_CMD);
+ system("mkdir EXCXX_BULK");
+ }
+
+ initDbenv("EXCXX_BULK", cachesize);
+
+ if (init)
+ return;
+
+ initDb(dups, sflag, pagesize);
+
+ srand((int)time(NULL));
+ if (rflag) {
+ /* Time the get loop. */
+ (void)gettimeofday(&start_time, NULL);
+ bulkRead(num, dups, iter, &count, verbose);
+ (void)gettimeofday(&end_time, NULL);
+ secs =
+ (((double)end_time.tv_sec * 1000000 +
+ end_time.tv_usec) -
+ ((double)start_time.tv_sec * 1000000 +
+ start_time.tv_usec)) / 1000000;
+ printf("[STAT] Read %d records read using %d batches",
+ count, iter);
+ printf(" in %.2f seconds: ", secs);
+ printf("%.0f records/second\n", (double)count / secs);
+ } else {
+ /* Time the fill loop. */
+ (void)gettimeofday(&start_time, NULL);
+ bulkUpdate(num, dups, &count, &biter, verbose);
+ (void)gettimeofday(&end_time, NULL);
+ secs = (((double)end_time.tv_sec * 1000000 +
+ end_time.tv_usec) -
+ ((double)start_time.tv_sec * 1000000 +
+ start_time.tv_usec)) / 1000000;
+ printf("[STAT] Insert %d records using %d batches",
+ count, biter);
+ printf(" in %.2f seconds: ", secs);
+ printf("%.0f records/second\n", (double)count / secs);
+ if (dflag) {
+ if (sflag) {
+ pair = rand() % 2;
+ /* Time the delete loop in secondary db */
+ (void)gettimeofday(&start_time, NULL);
+ bulkSecondaryDelete(num,
+ pair, &count, &iter, verbose);
+ (void)gettimeofday(&end_time, NULL);
+ secs = (((double)end_time.tv_sec * 1000000 +
+ end_time.tv_usec) -
+ ((double)start_time.tv_sec * 1000000 +
+ start_time.tv_usec)) / 1000000;
+ printf("[STAT] Delete %d %s using %d batches",
+ count, (pair) ? "records" : "keys", iter);
+ printf(" in %.2f seconds: ", secs);
+ printf("%.0f records/second\n",
+ (double)count / secs);
+ } else {
+ /* Time the delete loop in primary db */
+ (void)gettimeofday(&start_time, NULL);
+ bulkDelete(num, dups, &count, &iter, verbose);
+ (void)gettimeofday(&end_time, NULL);
+ secs = (((double)end_time.tv_sec * 1000000 +
+ end_time.tv_usec) -
+ ((double)start_time.tv_sec * 1000000 +
+ start_time.tv_usec)) / 1000000;
+ printf(
+"[STAT] Delete %d records using %d batches",
+ count, iter);
+ printf(" in %.2f seconds: ", secs);
+ printf("%.0f records/second\n",
+ (double)count / secs);
+ }
+ }
+ }
+}
+
+/* Bulk delete from a database. */
+void BulkExample::bulkDelete(
+ int num, int dups, int *countp, int *iterp, int verbose)
+{
+ Dbt key;
+ DbTxn *txnp;
+ DbMultipleDataBuilder *ptrd;
+ DbMultipleKeyDataBuilder *ptrkd;
+ u_int32_t flag;
+ int count, i, j, iter, ret;
+
+ txnp = NULL;
+ count = flag = iter = ret = 0;
+ memset(&key, 0, sizeof(Dbt));
+
+ j = rand() % num;
+
+ /*
+ * The buffer must be at least as large as the page size of the
+ * underlying database and aligned for unsigned integer access.
+ * Its size must be a multiple of 1024 bytes.
+ */
+ if (klen != (u_int32_t)UPDATES_PER_BULK_PUT *
+ (sizeof(u_int32_t) + DATALEN) * 1024) {
+ klen = (u_int32_t)UPDATES_PER_BULK_PUT *
+ (sizeof(u_int32_t) + DATALEN) * 1024;
+ kbuf = realloc(kbuf, klen);
+ }
+ memset(kbuf, 0, klen);
+ key.set_ulen(klen);
+ key.set_flags(DB_DBT_USERMEM | DB_DBT_BULK);
+ key.set_data(kbuf);
+ if (data_val == NULL)
+ data_val = (data *)malloc(DATALEN);
+ memset(data_val, 0, DATALEN);
+
+ /*
+ * Bulk delete all records of a specific set of keys which includes all
+ * non-negative integers smaller than the random key. The random key is
+ * a random non-negative integer smaller than "num".
+ * If DB_MULTIPLE, construct the key Dbt by the DbMultipleDataBuilder
+ * with the specific set of keys. If DB_MULTIPLE_KEY, construct the key
+ * Dbt by the DbMultipleKeyDataBuilder with all key/data pairs of the
+ * specific set of keys.
+ */
+ flag |= (dups) ? DB_MULTIPLE_KEY : DB_MULTIPLE;
+ if (dups)
+ ptrkd = new DbMultipleKeyDataBuilder(key);
+ else
+ ptrd = new DbMultipleDataBuilder(key);
+ try {
+ for (i = 0; i < j; i++) {
+ if (i % UPDATES_PER_BULK_PUT == 0) {
+ if (txnp != NULL) {
+ ret = txnp->commit(0);
+ txnp = NULL;
+ if (ret != 0)
+ throwException(dbenv, NULL,
+ ret, "DB_TXN->commit");
+ }
+ if ((ret = dbenv->txn_begin(NULL,
+ &txnp, 0)) != 0)
+ throwException(dbenv, NULL,
+ ret, "DB_ENV->txn_begin");
+ }
+
+ if (dups) {
+ data_val->id = 0;
+ get_string(tstring, data_val->str, i);
+ do {
+ if(ptrkd->append(&i,sizeof(i),
+ data_val, DATALEN) == false)
+ throwException(dbenv,
+ txnp, EXIT_FAILURE,
+"DbMultipleKeyDataBuilder->append");
+ count++;
+ if (verbose)
+ printf(
+"Delete key: %d, \tdata: (id %d, str %s)\n",
+ i, data_val->id,
+ data_val->str);
+ } while (data_val->id++ < dups);
+ } else {
+ if(ptrd->append(&i,sizeof(i)) == false)
+ throwException(dbenv, txnp, ret,
+ "DbMultipleDataBuilder->append");
+ count++;
+ if (verbose)
+ printf("Delete key: %d\n", i);
+ }
+
+ if ((i + 1) % UPDATES_PER_BULK_PUT == 0) {
+ if ((ret = dbp->del(txnp, &key, flag)) != 0)
+ throwException(dbenv,
+ txnp, ret, "Bulk DB->del");
+ iter++;
+ if (dups)
+ ptrkd = new
+ DbMultipleKeyDataBuilder(key);
+ else
+ ptrd = new DbMultipleDataBuilder(key);
+ }
+ }
+ if ((j % UPDATES_PER_BULK_PUT) != 0) {
+ if ((ret = dbp->del(txnp, &key, flag)) != 0)
+ throwException(dbenv,
+ txnp, ret, "Bulk DB->del");
+ iter++;
+ }
+
+ ret = txnp->commit(0);
+ txnp = NULL;
+ if (ret != 0)
+ throwException(dbenv, NULL, ret, "DB_TXN->commit");
+
+ *countp = count;
+ *iterp = iter;
+ } catch (DbException &dbe) {
+ cerr << "bulkDelete " << dbe.what() << endl;
+ if (txnp != NULL)
+ (void)txnp->abort();
+ throw dbe;
+ }
+}
+
+/* Bulk delete from a secondary db. */
+void BulkExample::bulkSecondaryDelete(
+ int num, int pair, int *countp, int *iterp, int verbose)
+{
+ Dbt key;
+ DbTxn *txnp;
+ DbMultipleDataBuilder *ptrd;
+ DbMultipleKeyDataBuilder *ptrkd;
+ u_int32_t flag;
+ int count, i, iter, j, k, rc, ret;
+ char ch;
+
+ memset(&key, 0, sizeof(Dbt));
+ txnp = NULL;
+ count = flag = iter = ret = 0;
+ rc = rand() % (STRLEN - 1);
+
+ /*
+ * The buffer must be at least as large as the page size of the
+ * underlying database and aligned for unsigned integer access.
+ * Its size must be a multiple of 1024 bytes.
+ */
+ if (klen != (u_int32_t)UPDATES_PER_BULK_PUT *
+ (sizeof(u_int32_t) + DATALEN) * 1024) {
+ klen = (u_int32_t)UPDATES_PER_BULK_PUT *
+ (sizeof(u_int32_t) + DATALEN) * 1024;
+ kbuf = realloc(kbuf, klen);
+ }
+ memset(kbuf, 0, klen);
+ key.set_ulen(klen);
+ key.set_flags(DB_DBT_USERMEM | DB_DBT_BULK);
+ key.set_data(kbuf);
+
+ /*
+ * Bulk delete all records of a specific set of keys which includes all
+ * characters before the random key in the tstring. The random key is
+ * one of the characters in the tstring.
+ * If DB_MULTIPLE, construct the key Dbt by the DbMultipleDataBuilder
+ * with the specific set of keys. If DB_MULTIPLE_KEY, construct the key
+ * Dbt by the DbMultipleKeyDataBuilder with all key/data pairs of the
+ * specific set of keys.
+ */
+ flag |= (pair) ? DB_MULTIPLE_KEY : DB_MULTIPLE;
+ if (pair)
+ ptrkd = new DbMultipleKeyDataBuilder(key);
+ else
+ ptrd = new DbMultipleDataBuilder(key);
+ try {
+ for (i = 0; i <= rc; i++) {
+ if (i % UPDATES_PER_BULK_PUT == 0) {
+ if (txnp != NULL) {
+ ret = txnp->commit(0);
+ txnp = NULL;
+ if (ret != 0)
+ throwException(dbenv, NULL,
+ ret, "DB_TXN->commit");
+ }
+ if ((ret = dbenv->txn_begin(NULL,
+ &txnp, 0)) != 0)
+ throwException(dbenv,
+ NULL, ret, "DB_ENV->txn_begin");
+ }
+
+ ch = tstring[i];
+ if (!pair) {
+ if (ptrd->append(&ch, sizeof(ch)) == false)
+ throwException(dbenv,
+ txnp, EXIT_FAILURE,
+ "DbMultipleDataBuilder->append");
+ count++;
+ if (verbose)
+ printf("Delete key: %c\n", ch);
+ } else {
+ j = 0;
+ do {
+ k = j * (STRLEN - 1) + i;
+ if (ptrkd->append(&ch, sizeof(ch),
+ &k, sizeof(k)) == false)
+ throwException(dbenv,
+ txnp, EXIT_FAILURE,
+"DbMultipleKeyDataBuilder->append");
+ count++;
+ if (verbose)
+ printf(
+"Delete secondary key: %c, \tdata: %d\n",
+ ch, k);
+ } while (++j < (int)(num / (STRLEN - 1)));
+ }
+
+ if ((i + 1) % UPDATES_PER_BULK_PUT == 0) {
+ if ((ret = sdbp->del(txnp, &key, flag)) != 0)
+ throwException(dbenv,
+ txnp, ret, "Bulk DB->del");
+ iter++;
+ if (pair)
+ ptrkd = new
+ DbMultipleKeyDataBuilder(key);
+ else
+ ptrd = new DbMultipleDataBuilder(key);
+ }
+ }
+ if ((rc % UPDATES_PER_BULK_PUT) != 0) {
+ if ((ret = sdbp->del(txnp, &key, flag)) != 0)
+ throwException(dbenv,
+ txnp, ret, "Bulk DB->del");
+ iter++;
+ }
+
+ ret = txnp->commit(0);
+ txnp = NULL;
+ if (ret != 0)
+ throwException(dbenv, NULL, ret, "DB_TXN->commit");
+
+ *countp = count;
+ *iterp = iter;
+ } catch (DbException &dbe) {
+ cerr << "bulkSecondaryDelete " << dbe.what() << endl;
+ if (txnp != NULL)
+ (void)txnp->abort();
+ throw dbe;
+ }
+}
+
+/* Bulk fill a database. */
+void BulkExample::bulkUpdate(
+ int num, int dups, int *countp, int *iterp, int verbose)
+{
+ Dbt key, data;
+ u_int32_t flag;
+ DbTxn *txnp;
+ int count, i, iter, ret;
+ DbMultipleDataBuilder *ptrd, *ptrk;
+ DbMultipleKeyDataBuilder *ptrkd;
+
+ txnp = NULL;
+ count = flag = iter = ret = 0;
+ ptrk = ptrd = NULL;
+ if (data_val == NULL)
+ data_val = (struct data *)malloc(DATALEN);
+ memset(data_val, 0, DATALEN);
+ memset(&key, 0, sizeof(Dbt));
+ memset(&data, 0, sizeof(Dbt));
+
+ /*
+ * The buffer must be at least as large as the page size of
+ * the underlying database and aligned for unsigned integer
+ * access. Its size must be a multiple of 1024 bytes.
+ */
+ if (klen != (u_int32_t) UPDATES_PER_BULK_PUT *
+ (sizeof(u_int32_t) + DATALEN) * 1024) {
+ klen = (u_int32_t) UPDATES_PER_BULK_PUT *
+ (sizeof(u_int32_t) + DATALEN) * 1024;
+ kbuf = realloc(kbuf, klen);
+ }
+ memset(kbuf, 0, klen);
+ key.set_ulen(klen);
+ key.set_flags(DB_DBT_USERMEM | DB_DBT_BULK);
+ key.set_data(kbuf);
+
+ if (dlen != (u_int32_t) UPDATES_PER_BULK_PUT *
+ (sizeof(u_int32_t) + DATALEN) * 1024) {
+ dlen = (u_int32_t) UPDATES_PER_BULK_PUT *
+ (sizeof(u_int32_t) + DATALEN) * 1024;
+ dbuf = realloc(dbuf, dlen);
+ }
+ memset(dbuf, 0, dlen);
+ data.set_ulen(dlen);
+ data.set_flags(DB_DBT_USERMEM | DB_DBT_BULK);
+ data.set_data(dbuf);
+
+ /*
+ * Bulk insert with either DB_MULTIPLE in two buffers or
+ * DB_MULTIPLE_KEY in a single buffer. With DB_MULTIPLE, all keys are
+ * constructed in the key Dbt, and all data is constructed in the data
+ * Dbt. With DB_MULTIPLE_KEY, all key/data pairs are constructed in the
+ * key Dbt. We use DB_MULTIPLE mode when there are duplicate records.
+ */
+ flag |= (dups) ? DB_MULTIPLE : DB_MULTIPLE_KEY;
+ if (dups) {
+ ptrk = new DbMultipleDataBuilder(key);
+ ptrd = new DbMultipleDataBuilder(data);
+ } else
+ ptrkd = new DbMultipleKeyDataBuilder(key);
+
+ try {
+ for (i = 0; i < num; i++) {
+ if (i % UPDATES_PER_BULK_PUT == 0) {
+ if (txnp != NULL) {
+ ret = txnp->commit(0);
+ txnp = NULL;
+ if (ret != 0)
+ throwException(dbenv, NULL,
+ ret, "DB_TXN->commit");
+ }
+ if ((ret = dbenv->txn_begin(NULL,
+ &txnp, 0)) != 0)
+ throwException(dbenv,
+ NULL, ret, "DB_ENV->txn_begin");
+ }
+ data_val->id = 0;
+ get_string(tstring, data_val->str, i);
+ do {
+ if (dups) {
+ if (ptrk->append(&i,
+ sizeof(i)) == false)
+ throwException(dbenv,
+ txnp, EXIT_FAILURE,
+"DbMultipleDataBuilder->append");
+ if (ptrd->append(data_val,
+ DATALEN) == false)
+ throwException(dbenv,
+ txnp, EXIT_FAILURE,
+"DbMultipleDataBuilder->append");
+ } else {
+ if (ptrkd->append(&i, sizeof(i),
+ data_val, DATALEN) == false)
+ throwException(dbenv,
+ txnp, EXIT_FAILURE,
+"DbMultipleKeyDataBuilder->append");
+ }
+ if (verbose)
+ printf(
+"Insert key: %d, \t data: (id %d, str %s)\n",
+ i, data_val->id, data_val->str);
+ count++;
+ } while (data_val->id++ < dups);
+ if ((i + 1) % UPDATES_PER_BULK_PUT == 0) {
+ if ((ret = dbp->put(txnp,
+ &key, &data, flag)) != 0)
+ throwException(dbenv,
+ txnp, ret, "Bulk DB->put");
+ iter++;
+ if (dups) {
+ ptrk = new DbMultipleDataBuilder(key);
+ ptrd = new DbMultipleDataBuilder(data);
+ } else
+ ptrkd = new
+ DbMultipleKeyDataBuilder(key);
+ }
+ }
+ if ((num % UPDATES_PER_BULK_PUT) != 0) {
+ if ((ret = dbp->put(txnp, &key, &data, flag)) != 0)
+ throwException(dbenv,
+ txnp, ret, "Bulk DB->put");
+ iter++;
+ }
+
+ ret = txnp->commit(0);
+ txnp = NULL;
+ if (ret != 0)
+ throwException(dbenv, NULL, ret, "DB_TXN->commit");
+
+ *countp = count;
+ *iterp = iter;
+ } catch (DbException &dbe) {
+ cerr << "bulkUpdate " << dbe.what() << endl;
+ if (txnp != NULL)
+ (void)txnp->abort();
+ throw dbe;
+ }
+}
+
+/* Loop get batches of records. */
+void BulkExample::bulkRead(
+ int num, int dups, int iter, int *countp, int verbose)
+{
+ Dbc *dbcp;
+ Dbt data, dp, key, kp;
+ DbTxn *txnp;
+ DbMultipleDataIterator *ptrd;
+ DbMultipleKeyDataIterator *ptrkd;
+ u_int32_t flags;
+ int count, i, j, ret;
+
+ count = klen = ret = 0;
+ dbcp = NULL;
+ txnp = NULL;
+
+ /* Initialize key Dbt and data Dbt, malloc bulk buffer. */
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ key.set_size(sizeof(j));
+ if (dlen != DATALEN * 16 * 1024) {
+ dlen = DATALEN * 16 * 1024;
+ dbuf = realloc(dbuf, dlen);
+ }
+ memset(dbuf, 0, dlen);
+ data.set_flags(DB_DBT_USERMEM);
+ data.set_data(dbuf);
+ data.set_ulen(dlen);
+ data.set_size(dlen);
+
+ flags = DB_SET;
+ flags |= (dups) ? DB_MULTIPLE: DB_MULTIPLE_KEY;
+ try {
+ for (i = 0; i < iter; i++) {
+ if ((ret =
+ dbenv->txn_begin(NULL, &txnp, 0)) != 0)
+ throwException(dbenv, NULL,
+ ret, "DB_ENV->txn_begin");
+ if ((ret = dbp->cursor(txnp, &dbcp, 0)) != 0)
+ throwException(dbenv, txnp,
+ ret, "DB->cursor");
+
+ /*
+ * Bulk retrieve by a random key which is a random
+ * non-negative integer smaller than "num".
+ * If there are duplicates in the database, retrieve
+ * with DB_MULTIPLE and use the DbMultipleDataIterator
+ * to iterate the data of the random key in the data
+ * Dbt. Otherwise retrieve with DB_MULTIPLE_KEY and use
+ * the DbMultipleKeyDataIterator to iterate the
+ * key/data pairs of the specific set of keys which
+ * includes all integers >= the random key and < "num".
+ */
+ j = rand() % num;
+ key.set_data(&j);
+ if ((ret = dbcp->get(&key, &data, flags)) != 0)
+ throwException(dbenv, NULL, ret, "DBC->get");
+
+ if (dups) {
+ ptrd = new DbMultipleDataIterator(data);
+ while (ptrd->next(dp) == true) {
+ count++;
+ if (verbose)
+ printf(
+"Retrieve key: %d, \tdata: (id %d, str %s)\n", j, ((struct data *)(
+ dp.get_data()))->id,
+ (char *)((struct data *)(
+ dp.get_data()))->str);
+ }
+ } else {
+ ptrkd = new DbMultipleKeyDataIterator(data);
+ while (ptrkd->next(kp, dp) == true) {
+ count++;
+ if (verbose)
+ printf(
+"Retrieve key: %d, \tdata: (id %d, str %s)\n", *((int *)kp.get_data()),
+ ((struct data *)(
+ dp.get_data()))->id,
+ (char *)((struct data *)(
+ dp.get_data()))->str);
+ }
+ }
+
+ ret = dbcp->close();
+ dbcp = NULL;
+ if (ret != 0)
+ throwException(dbenv, txnp, ret, "DBC->close");
+
+ ret = txnp->commit(0);
+ txnp = NULL;
+ if (ret != 0)
+ throwException(dbenv, NULL,
+ ret, "DB_TXN->commit");
+ }
+
+ *countp = count;
+ } catch (DbException &dbe) {
+ cerr << "bulkRead " << dbe.what() << endl;
+ if (dbcp != NULL)
+ (void)dbcp->close();
+ if (txnp != NULL)
+ (void)txnp->abort();
+ throw dbe;
+ }
+}
+
+/* Initialize the database. */
+void BulkExample::initDb(int dups, int sflag, int pagesize) {
+
+ DbTxn *txnp;
+ int ret;
+
+ txnp = NULL;
+ ret = 0;
+
+ dbp = new Db(dbenv, 0);
+
+ dbp->set_error_stream(&cerr);
+ dbp->set_errpfx(progname);
+
+ try{
+ if ((ret = dbp->set_bt_compare(compare_int)) != 0)
+ throwException(dbenv, NULL, ret, "DB->set_bt_compare");
+
+ if ((ret = dbp->set_pagesize(pagesize)) != 0)
+ throwException(dbenv, NULL, ret, "DB->set_pagesize");
+
+ if (dups && (ret = dbp->set_flags(DB_DUP)) != 0)
+ throwException(dbenv, NULL, ret, "DB->set_flags");
+
+ if ((ret = dbenv->txn_begin(NULL, &txnp, 0)) != 0)
+ throwException(dbenv, NULL, ret, "DB_ENV->txn_begin");
+
+ if ((ret = dbp->open(txnp, DATABASE, "primary", DB_BTREE,
+ DB_CREATE, 0664)) != 0)
+ throwException(dbenv, txnp, ret, "DB->open");
+
+ if (sflag) {
+ sdbp = new Db(dbenv, 0);
+
+ if ((ret = sdbp->set_flags(DB_DUPSORT)) != 0)
+ throwException(dbenv, txnp,
+ ret, "DB->set_flags");
+
+ if ((ret = sdbp->open(txnp, DATABASE, "secondary",
+ DB_BTREE, DB_CREATE, 0664)) != 0)
+ throwException(dbenv, txnp, ret, "DB->open");
+
+ if ((ret = dbp->associate(
+ txnp, sdbp, get_first_str, 0)) != 0)
+ throwException(dbenv, txnp,
+ ret, "DB->associate");
+ }
+
+ ret = txnp->commit(0);
+ txnp = NULL;
+ if (ret != 0)
+ throwException(dbenv, NULL, ret, "DB_TXN->commit");
+ } catch(DbException &dbe) {
+ cerr << "initDb " << dbe.what() << endl;
+ if (txnp != NULL)
+ (void)txnp->abort();
+ throw dbe;
+ }
+}
+
+/* Initialize the environment. */
+void BulkExample::initDbenv(const char *home, u_int32_t cachesize)
+{
+ int ret;
+
+ ret = 0;
+
+ dbenv = new DbEnv(0);
+
+ dbenv->set_error_stream(&cerr);
+ dbenv->set_errpfx(progname);
+
+ try {
+ if ((ret = dbenv->set_cachesize(0, cachesize, 0)) != 0)
+ throwException(dbenv,
+ NULL, ret, "DB_ENV->set_cachesize");
+
+ /* Open the environment with full transactional support. */
+ if ((ret = dbenv->open(home, DB_CREATE | DB_INIT_LOCK |
+ DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN, 0)) != 0)
+ throwException(dbenv, NULL, ret, "DB_ENV->open");
+ } catch (DbException &dbe) {
+ cerr << "initDbenv " << dbe.what() << endl;
+ throw dbe;
+ }
+}
+
+BulkExample::BulkExample() : dbenv(NULL), dbp(NULL), sdbp(NULL),
+ data_val(NULL), dbuf(NULL), kbuf(NULL), dlen(0), klen(0) {}
+
+BulkExample::~BulkExample()
+{
+ if (sdbp != NULL) {
+ sdbp->close(0);
+ delete sdbp;
+ }
+ if (dbp != NULL) {
+ dbp->close(0);
+ delete dbp;
+ }
+ if (dbenv != NULL) {
+ dbenv->close(0);
+ delete dbenv;
+ }
+ if (dbuf != NULL)
+ free(dbuf);
+ if (kbuf != NULL)
+ free(kbuf);
+ if (data_val != NULL)
+ free(data_val);
+}
+
+int
+compare_int(Db *dbp, const Dbt *a, const Dbt *b, size_t *locp)
+{
+ int ai, bi;
+
+ locp = NULL;
+ /*
+ * Returns:
+ * < 0 if a < b
+ * = 0 if a = b
+ * > 0 if a > b
+ */
+ memcpy(&ai, a->get_data(), sizeof(int));
+ memcpy(&bi, b->get_data(), sizeof(int));
+ return (ai - bi);
+}
+
+int
+get_first_str(Db *sdbp, const Dbt *key, const Dbt *data, Dbt *skey)
+{
+ memset(skey, 0, sizeof(Dbt));
+ skey->set_data(((struct data *)(data->get_data()))->str);
+ skey->set_size(sizeof(char));
+ return (0);
+}
+
+int
+get_string(const char *src, char *des, int off)
+{
+ int i;
+
+ for (i = 0; i < (int)(STRLEN - 1); i++)
+ des[i] = src[(off + i) % (STRLEN - 1)];
+ des[STRLEN - 1] = '\0';
+ return (0);
+}
+
+static void
+usage()
+{
+ cerr << "Usage: BulkExample \n"
+ << "-c cachesize [1000 * pagesize] \n"
+ << "-D perform bulk delete \n"
+ << "-d number of duplicates [none] \n"
+ << "-I just initialize the environment \n"
+ << "-i number of read iterations [1000000] \n"
+ << "-n number of keys [1000000] \n"
+ << "-p pagesize [65536] \n"
+ << "-R perform bulk read \n"
+ << "-S perform bulk operation in secondary database \n"
+ << "-v verbose output \n";
+ exit(EXIT_FAILURE);
+}
+
+int
+main(int argc, char *argv[])
+{
+ /*
+ * Use a try block just to report any errors.
+ * An alternate approach to using exceptions is to
+ * use error models (see DbEnv::set_error_model()) so
+ * that error codes are returned for all Berkeley DB methods.
+ */
+ try {
+ BulkExample app;
+ app.run(argc, argv);
+ return (EXIT_SUCCESS);
+ } catch (DbException &dbe) {
+ cerr << "BulkExample: " << dbe.what() << endl;
+ return (EXIT_FAILURE);
+ }
+}