Skip to content

Instantly share code, notes, and snippets.

@qxj
Created March 24, 2013 03:31
Show Gist options
  • Save qxj/5230372 to your computer and use it in GitHub Desktop.
Save qxj/5230372 to your computer and use it in GitHub Desktop.
test multiple secondary index of berkeley db g++ -o test_secondary_db test_secondary_db.cpp -g -O2 -Wall -Wextra -ldb
// -*- mode: c++ -*-
// @(#) test_secondary_db.cpp Time-stamp: <Julian Qian 2013-03-23 22:16:12>
// Copyright 2013 Julian Qian
// Author: Julian Qian <junist@gmail.com>
// Version: $Id: test_secondary_db.cpp,v 0.1 2013-03-23 21:31:19 jqian Exp $
//
// test multiple secondary index of berkeley db
// g++ -o test_secondary_db test_secondary_db.cpp -g -O2 -Wall -Wextra -ldb
#include <stdint.h>
#include <string.h>
#include <stdlib.h> // strtoul
#include <unistd.h>
#include <sys/time.h> // gettimeofday
#include <sys/stat.h> // mkdir
#include <sys/types.h> // mkdir
#include <db.h>
typedef uint32_t KEY;
typedef struct combo
{
uint32_t head;
uint32_t tail;
} COMBO;
int
my_callback(DB *, const DBT *, const DBT *pdata, DBT *skey)
{
COMBO* combo = (COMBO*)pdata->data;
uint32_t& head = combo->head;
uint32_t& tail = combo->tail;
DBT *tmpdbt;
if(head == tail){
tmpdbt = (DBT*)malloc(sizeof(DBT) * 1);
memset(tmpdbt, 0, sizeof(DBT) * 1);
tmpdbt[0].data = &head;
tmpdbt[0].size = sizeof(uint32_t);
skey->size = 1;
}else{
tmpdbt = (DBT*)malloc(sizeof(DBT) * 2);
memset(tmpdbt, 0, sizeof(DBT) * 2);
tmpdbt[0].data = &head;
tmpdbt[0].size = sizeof(uint32_t);
tmpdbt[1].data = &tail;
tmpdbt[1].size = sizeof(uint32_t);
skey->size = 2;
}
skey->flags = DB_DBT_MULTIPLE | DB_DBT_APPMALLOC;
skey->data = tmpdbt;
return (0);
}
#if 0
int
my_callback(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey)
{
COMBO* combo = (COMBO*)pdata->data;
memset(skey, 0, sizeof(DBT));
skey->data = &combo->head;
skey->size = sizeof(uint32_t);
return (0);
}
#endif
int main(int argc, char *argv[]){
DB_ENV* envp = NULL;
DB *pri_dbp = NULL, *sec_dbp = NULL;
DBC* pri_cur = NULL, *sec_cur = NULL;
u_int32_t flags;
u_int32_t env_flags = DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOG;
int ret;
KEY keyid;
COMBO cmb;
DBT pkey, pdata, skey;
uint32_t sign = 200;
if ((ret = db_env_create(&envp, 0)) != 0) {
fprintf(stderr, "Error creating env handle: %s\n", db_strerror(ret));
return -1;
}
mkdir("bdb", S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR );
if ((ret = envp->open(envp, "bdb", env_flags, 0)) != 0) {
fprintf(stderr, "Environment open failed: %s", db_strerror(ret));
return -1;
}
if ((ret = db_create(&pri_dbp, envp, 0)) != 0) {
fprintf(stderr, "error: %s\n", db_strerror(ret));
return -1;
}
if ((ret = db_create(&sec_dbp, envp, 0)) != 0) {
fprintf(stderr, "error: %s\n", db_strerror(ret));
return -1;
}
pri_dbp->set_errfile(pri_dbp, stderr);
pri_dbp->set_errpfx(pri_dbp, argv[0]);
if ((ret = sec_dbp->set_flags(sec_dbp, DB_DUPSORT)) != 0) {
pri_dbp->err(pri_dbp, ret, "set_flags");
goto err;
}
flags = DB_CREATE;
if ((ret = pri_dbp->open(pri_dbp, NULL, "my_db.db", NULL, DB_BTREE, flags, 0)) != 0) {
pri_dbp->err(pri_dbp, ret, "open primary db");
goto err;
}
if ((ret = sec_dbp->open(sec_dbp, NULL, "my_secdb.db", NULL, DB_BTREE, flags, 0)) != 0) {
pri_dbp->err(pri_dbp, ret, "open secondary db");
goto err;
}
if ((ret = pri_dbp->associate(pri_dbp, NULL, sec_dbp, my_callback, 0)) != 0) {
pri_dbp->err(pri_dbp, ret, "associate");
goto err;
}
if((ret = pri_dbp->cursor(pri_dbp, NULL, &pri_cur, 0)) != 0){
pri_dbp->err(pri_dbp, ret, "primary cursor");
goto err;
}
if((ret = sec_dbp->cursor(sec_dbp, NULL, &sec_cur, 0)) != 0){
pri_dbp->err(pri_dbp, ret, "secondary cursor");
goto err;
}
memset(&pkey, 0, sizeof(DBT));
memset(&pdata, 0, sizeof(DBT));
// write data
for(int i = 0; i< 10; ++i){
keyid = i;
cmb.head = 100*i;
cmb.tail = 100*(i+1);
pkey.data = &keyid;
pkey.size = sizeof(uint32_t);
pdata.data = &cmb;
pdata.size = sizeof(COMBO);
if((ret = pri_cur->put(pri_cur, &pkey, &pdata, DB_KEYFIRST)) != 0){
pri_dbp->err(pri_dbp, ret, "put data");
}
}
// show data
printf("all data:\n");
pkey.data = &keyid;
pkey.ulen = sizeof(KEY);
pkey.flags = DB_DBT_USERMEM;
pdata.data = &cmb;
pdata.ulen = sizeof(COMBO);
pdata.flags = DB_DBT_USERMEM;
ret = pri_cur->get(pri_cur, &pkey, &pdata, DB_FIRST);
while(ret == 0){
printf("primary key: %u,\thead: %u,\ttail: %u\n", keyid, cmb.head, cmb.tail);
ret = pri_cur->get(pri_cur, &pkey, &pdata, DB_NEXT);
}
// search in primary
keyid = 1;
printf("search in primary, pri_key=%u:\n", keyid);
pkey.data = &keyid;
pkey.size = sizeof(uint32_t);
pdata.data = &cmb;
pdata.ulen = sizeof(COMBO);
pdata.flags = DB_DBT_USERMEM;
if((ret = pri_cur->get(pri_cur, &pkey, &pdata, DB_SET)) == 0){
printf("found combo, head: %u, tail: %u\n", cmb.head, cmb.tail);
}else{
pri_dbp->err(pri_dbp, ret, "get by primary id");
}
// search in secondary
struct timeval start, end;
gettimeofday(&start, NULL);
if(argc > 1){
sign = strtoul(argv[1], NULL, 10);
}
printf("search in secondary, sec_key=%u:\n", sign);
memset(&skey, 0, sizeof(DBT));
skey.data = &sign;
skey.size = sizeof(uint32_t);
pkey.data = &keyid;
pkey.ulen = sizeof(uint32_t);
pkey.flags = DB_DBT_USERMEM;
pdata.data = &cmb;
pdata.ulen = sizeof(COMBO);
pdata.flags = DB_DBT_USERMEM;
ret = sec_cur->pget(sec_cur, &skey, &pkey, &pdata, DB_SET);
while(ret != DB_NOTFOUND){
if(ret != 0){
pri_dbp->err(pri_dbp, ret, "get by secondary key");
break;
}
printf("found combo by second key: %u, primary key: %u, head: %u, tail: %u\n",
sign, keyid, cmb.head, cmb.tail);
ret = sec_cur->pget(sec_cur, &skey, &pkey, &pdata, DB_NEXT_DUP);
}
gettimeofday(&end, NULL);
printf("time: %.6f s.\n", (end.tv_sec - start.tv_sec) + (double) (end.tv_usec - start.tv_usec) / 1000000 );
err:
if(sec_cur != NULL) sec_cur->close(sec_cur);
if(pri_cur != NULL) pri_cur->close(pri_cur);
if(sec_dbp != NULL) sec_dbp->close(sec_dbp, 0);
if(pri_dbp != NULL) pri_dbp->close(pri_dbp, 0);
if(envp != NULL) envp->close(envp, 0);
// if(sec_dbp != NULL) sec_dbp->remove(sec_dbp, "my_secdb.db", NULL, 0);
// if(pri_dbp != NULL) pri_dbp->remove(sec_dbp, "my_db.db", NULL, 0);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment