void * logfile_thread(void *arg) { DB_ENV *dbenv; int ret; char **begin, **list; dbenv = arg; dbenv->errx(dbenv, "Log file removal thread: %lu", (u_long)pthread_self()); /* Check once every 5 minutes. */ for (;; sleep(300)) { /* Get the list of log files. */ if ((ret = dbenv->log_archive(dbenv, &list, DB_ARCH_ABS)) != 0) { dbenv->err(dbenv, ret, "DB_ENV->log_archive"); exit (1); } /* Remove the log files. */ if (list != NULL) { for (begin = list; *list != NULL; ++list) if ((ret = remove(*list)) != 0) { dbenv->err(dbenv, ret, "remove %s", *list); exit (1); } free (begin); } } /* NOTREACHED */ }
int bdblib_create_dbenv(DB_ENV **_dbenv, char* _home) { DB_ENV *env; char *progname; int rc, flags; progname = "kamailio"; /* Create an environment and initialize it for additional error * reporting. */ if ((rc = db_env_create(&env, 0)) != 0) { ERR("db_env_create failed! bdb error: %s.\n", db_strerror(rc)); return (rc); } env->set_errpfx(env, progname); /* Specify the shared memory buffer pool cachesize */ if ((rc = env->set_cachesize(env, 0, _bdb_parms->cache_size, 0)) != 0) { ERR("dbenv set_cachsize failed! bdb error: %s.\n", db_strerror(rc)); env->err(env, rc, "set_cachesize"); goto err; } /* Concurrent Data Store flags */ flags = DB_CREATE | DB_INIT_CDB | DB_INIT_MPOOL | DB_THREAD; /* Transaction Data Store flags ; not supported yet */ /* flags = DB_CREATE | DB_RECOVER | DB_INIT_LOG | DB_INIT_LOCK | DB_INIT_MPOOL | DB_THREAD | DB_INIT_TXN; */ /* Open the environment */ if ((rc = env->open(env, _home, flags, 0)) != 0) { ERR("dbenv is not initialized! bdb error: %s.\n",db_strerror(rc)); env->err(env, rc, "environment open: %s", _home); goto err; } *_dbenv = env; return (0); err: (void)env->close(env, 0); return (rc); }
db* initialize_db(const char* db_name, uint32_t flag){ db* db_ptr = NULL; DB* b_db; DB_ENV* dbenv; int ret; char* full_path = NULL; if((ret = mkdir(db_dir,S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) != 0){ if(errno!=EEXIST){ err_log("DB : Dir Creation Failed\n"); goto db_init_return; } } full_path = (char*)malloc(strlen(db_dir) + strlen(db_name) + 2); mk_path(full_path, db_dir, db_name); #ifdef ENV if ((ret = db_env_create(&dbenv, 0)) != 0) { dbenv->err(dbenv, ret, "Environment Created: %s", db_dir); goto db_init_return; } if ((ret = dbenv->open(dbenv, db_dir, DB_CREATE|DB_INIT_CDB|DB_INIT_MPOOL|DB_THREAD, 0)) != 0) { //dbenv->err(dbenv, ret, "Environment Open: %s", db_dir); goto db_init_return; } /* Initialize the DB handle */ if((ret = db_create(&b_db,dbenv,flag)) != 0){ err_log("DB : %s.\n", db_strerror(ret)); goto db_init_return; } #else /* Initialize the DB handle */ if((ret = db_create(&b_db,NULL,flag)) != 0){ err_log("DB : %s.\n", db_strerror(ret)); goto db_init_return; } #endif if((ret = b_db->set_pagesize(b_db, pagesize)) != 0){ err_log("DB : %s.\n", db_strerror(ret)); goto db_init_return; } if((ret = b_db->open(b_db, NULL, db_name, NULL, DB_BTREE, DB_THREAD|DB_CREATE,0)) != 0){ // db_name is the on-disk file that holds the database //b_db->err(b_db,ret,"%s","test.db"); goto db_init_return; } db_ptr = (db*)(malloc(sizeof(db))); db_ptr->bdb_ptr = b_db; db_init_return: if(full_path != NULL){ free(full_path); } if(db_ptr != NULL){ ; } return db_ptr; }
static void *bdb_checkpoint_thread(void *arg){ DB_ENV *dbenv; int ret; dbenv = arg; for (;; sleep(bdb_settings.checkpoint_val)) { if ((ret = dbenv->txn_checkpoint(dbenv, 0, 0, 0)) != 0) { dbenv->err(dbenv, ret, "checkpoint thread"); } dbenv->errx(dbenv, "checkpoint thread: a txn_checkpoint is done"); } return (NULL); }
static void *bdb_mempool_trickle_thread(void *arg){ DB_ENV *dbenv; int ret, nwrotep; dbenv = arg; for (;; sleep(bdb_settings.mempool_trickle_val)) { if ((ret = dbenv->memp_trickle(dbenv, bdb_settings.mempool_trickle_percent, &nwrotep)) != 0) { dbenv->err(dbenv, ret, "mempool_trickle thread"); } dbenv->errx(dbenv, "mempool_trickle thread: writing %d dirty pages", nwrotep); } return (NULL); }
void env_open(DB_ENV **dbenvp) { DB_ENV *dbenv; int ret; /* Create the environment handle. */ if ((ret = db_env_create(&dbenv, 0)) != 0) { fprintf(stderr, "txnapp: db_env_create: %s\n", db_strerror(ret)); exit (1); } /* Set up error handling. */ dbenv->set_errpfx(dbenv, "txnapp"); dbenv->set_errfile(dbenv, stderr); /* Do deadlock detection internally. */ if ((ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT)) != 0) { dbenv->err(dbenv, ret, "set_lk_detect: DB_LOCK_DEFAULT"); exit (1); } /* * Open a transactional environment: * create if it doesn't exist * free-threaded handle * run recovery * read/write owner only */ if ((ret = dbenv->open(dbenv, ENV_DIRECTORY, DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN | DB_RECOVER | DB_THREAD, S_IRUSR | S_IWUSR)) != 0) { dbenv->err(dbenv, ret, "dbenv->open: %s", ENV_DIRECTORY); exit (1); } *dbenvp = dbenv; }
void env_open(DB_ENV **dbenvp) { DB_ENV *dbenv; int ret; /* Create the environment handle. */ if ((ret = db_env_create(&dbenv, 0)) != 0) { fprintf(stderr, "txnapp: db_env_create: %s\n", db_strerror(ret)); exit (1); } /* Set up error handling. */ dbenv->set_errpfx(dbenv, "txnapp"); dbenv->set_errfile(dbenv, stderr); // match lladd's defaults... dbenv->set_lg_bsize(dbenv, 1024*1024); // match lladd's defaults... dbenv->set_cachesize(dbenv, 0, 8204288, 0); /* Do deadlock detection internally. */ /* if ((ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT)) != 0) { dbenv->err(dbenv, ret, "set_lk_detect: DB_LOCK_DEFAULT"); exit (1); }*/ dbenv->set_tx_max(dbenv, 32000); unsigned int max; dbenv->get_tx_max(dbenv, &max); printf("Max xact count: %d\n", max); /* * Open a transactional environment: * create if it doesn't exist * free-threaded handle * run recovery * read/write owner only */ if ((ret = dbenv->open(dbenv, ENV_DIRECTORY, DB_CREATE |/* DB_INIT_LOCK |*/ DB_INIT_LOG | DB_PRIVATE | DB_INIT_MPOOL | DB_INIT_TXN | DB_RECOVER | DB_THREAD, S_IRUSR | S_IWUSR)) != 0) { dbenv->err(dbenv, ret, "dbenv->open: %s", ENV_DIRECTORY); exit (1); } *dbenvp = dbenv; }
/* * env_init -- * Initialize the environment. */ DB_ENV * env_init( char *home, char *prefix, int cachesize) { DB_ENV *dbenv; int ret; if ((ret = db_env_create(&dbenv, 0)) != 0) { dbenv->err(dbenv, ret, "db_env_create"); return (NULL); } dbenv->set_errfile(dbenv, stderr); dbenv->set_errpfx(dbenv, prefix); if ((ret = dbenv->set_cachesize(dbenv, 0, cachesize, 0)) != 0) { dbenv->err(dbenv, ret, "DB_ENV->set_cachesize"); return (NULL); } if ((ret = dbenv->open(dbenv, home, DB_CREATE | DB_INIT_MPOOL | DB_INIT_TXN | DB_INIT_LOCK, 0)) != 0) { dbenv->err(dbenv, ret, "DB_ENV->open: %s", home); (void)dbenv->close(dbenv, 0); return (NULL); } return (dbenv); }
int main(int argc, char *argv[]) { extern char *optarg; DB_ENV *dbenv; const char *home; char ch; int ret; dbenv = NULL; ret = 0; home = NULL; /* Create and configure the environment handle. */ if ((ret = create_env(progname, &dbenv)) != 0) goto err; /* Collect the command line options. */ while ((ch = getopt(argc, argv, "h:")) != EOF) switch (ch) { case 'h': home = optarg; break; case '?': default: usage(); } /* Error check command line. */ if (home == NULL) usage(); /* Open the environment. */ if ((ret = env_init(dbenv, home)) != 0) goto err; if ((ret = doloop(dbenv)) != 0) { dbenv->err(dbenv, ret, "Application failed"); goto err; } err: if (dbenv != NULL) (void)dbenv->close(dbenv, 0); return (ret); }
static void *bdb_chkpoint_thread(void *arg) { DB_ENV *dbenv; int ret; dbenv = arg; if (settings.verbose > 1) { dbenv->errx(dbenv, "checkpoint thread created: %lu, every %d seconds", (u_long)pthread_self(), bdb_settings.chkpoint_val); } for (;; sleep(bdb_settings.chkpoint_val)) { if ((ret = dbenv->txn_checkpoint(dbenv, 0, 0, 0)) != 0) { dbenv->err(dbenv, ret, "checkpoint thread"); } dbenv->errx(dbenv, "checkpoint thread: a txn_checkpoint is done"); } return (NULL); }
static void *bdb_memp_trickle_thread(void *arg) { DB_ENV *dbenv; int ret, nwrotep; dbenv = arg; if (settings.verbose > 1) { dbenv->errx(dbenv, "memp_trickle thread created: %lu, every %d seconds, %d%% pages should be clean.", (u_long)pthread_self(), bdb_settings.memp_trickle_val, bdb_settings.memp_trickle_percent); } for (;; sleep(bdb_settings.memp_trickle_val)) { if ((ret = dbenv->memp_trickle(dbenv, bdb_settings.memp_trickle_percent, &nwrotep)) != 0) { dbenv->err(dbenv, ret, "memp_trickle thread"); } dbenv->errx(dbenv, "memp_trickle thread: writing %d dirty pages", nwrotep); } return (NULL); }
void * checkpoint_thread(void *arg) { DB_ENV *dbenv; int ret; dbenv = arg; dbenv->errx(dbenv, "Checkpoint thread: %lu", (u_long)pthread_self()); /* Checkpoint once a minute. */ for (;; sleep(60)) if ((ret = dbenv->txn_checkpoint(dbenv, 0, 0, 0)) != 0) { dbenv->err(dbenv, ret, "checkpoint thread"); exit (1); } /* NOTREACHED */ }
bool service_list(struct client *cli, const char *user) { GList *files = NULL, *content = NULL; char *s; enum errcode err = InternalError; int rc; bool rcb; DB_TXN *txn = NULL; DBC *cur = NULL; DB_ENV *dbenv = tdbrep.tdb.env; DB *bidx = tdbrep.tdb.buckets_idx; DBT skey, pkey, pval; if (asprintf(&s, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" "<ListAllMyBucketsResult xmlns=\"http://indy.yyz.us/doc/2006-03-01/\">\r\n" " <Owner>\r\n" " <ID>%s</ID>\r\n" " <DisplayName>%s</DisplayName>\r\n" " </Owner>\r\n" " <Buckets>\r\n", user, user) < 0) goto err_out; content = g_list_append(content, s); /* open transaction, search cursor */ rc = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_begin"); goto err_out_content; } rc = bidx->cursor(bidx, txn, &cur, 0); if (rc) { bidx->err(bidx, rc, "bidx->cursor"); goto err_out_content; } memset(&skey, 0, sizeof(skey)); memset(&pkey, 0, sizeof(pkey)); memset(&pval, 0, sizeof(pval)); skey.data = (char *) user; skey.size = strlen(user) + 1; /* FIXME: Use of DB_NEXT rather than DB_SET to begin search * means we iterate through entire db, rather than * starting at the first matching key. */ /* loop through matching buckets, if any */ while (1) { char timestr[64]; struct db_bucket_ent *ent; rc = cur->pget(cur, &skey, &pkey, &pval, DB_NEXT); if (rc) break; ent = pval.data; s = g_markup_printf_escaped( " <Bucket>\r\n" " <Name>%s</Name>\r\n" " <CreationDate>%s</CreationDate>\r\n" " </Bucket>\r\n", ent->name, hutil_time2str(timestr, sizeof(timestr), GUINT64_FROM_LE(ent->time_create))); if (!s) goto err_out_content; content = g_list_append(content, s); } if (rc != DB_NOTFOUND) bidx->err(bidx, rc, "service_list iter"); /* close cursor, transaction */ rc = cur->close(cur); if (rc) bidx->err(bidx, rc, "bidx->cursor close"); rc = txn->commit(txn, 0); if (rc) dbenv->err(dbenv, rc, "DB_ENV->txn_commit"); if (asprintf(&s, " </Buckets>\r\n" "</ListAllMyBucketsResult>\r\n") < 0) goto err_out_content; content = g_list_append(content, s); rcb = cli_resp_xml(cli, 200, content); strlist_free(files); g_list_free(content); return rcb; err_out_content: strlist_free(content); err_out: strlist_free(files); return cli_err(cli, err); }
/* * A function that performs a series of writes to a * Berkeley DB database. The information written * to the database is largely nonsensical, but the * mechanism of transactional commit/abort and * deadlock detection is illustrated here. */ void * writer_thread(void *args) { static char *key_strings[] = { "key 1", "key 2", "key 3", "key 4", "key 5", "key 6", "key 7", "key 8", "key 9", "key 10" }; DB *dbp; DB_ENV *envp; DBT key, value; DB_TXN *txn; int i, j, payload, ret, thread_num; int retry_count, max_retries = 20; /* Max retry on a deadlock */ dbp = (DB *)args; envp = dbp->get_env(dbp); /* Get the thread number */ (void)mutex_lock(&thread_num_lock); global_thread_num++; thread_num = global_thread_num; (void)mutex_unlock(&thread_num_lock); /* Initialize the random number generator */ srand(thread_num); /* Write 50 times and then quit */ for (i = 0; i < 50; i++) { retry_count = 0; /* Used for deadlock retries */ /* * Some think it is bad form to loop with a goto statement, but * we do it anyway because it is the simplest and clearest way * to achieve our abort/retry operation. */ retry: /* Begin our transaction. We group multiple writes in * this thread under a single transaction so as to * (1) show that you can atomically perform multiple writes * at a time, and (2) to increase the chances of a * deadlock occurring so that we can observe our * deadlock detection at work. * * Normally we would want to avoid the potential for deadlocks, * so for this workload the correct thing would be to perform our * puts with autocommit. But that would excessively simplify our * example, so we do the "wrong" thing here instead. */ ret = envp->txn_begin(envp, NULL, &txn, 0); if (ret != 0) { envp->err(envp, ret, "txn_begin failed"); return ((void *)EXIT_FAILURE); } for (j = 0; j < 10; j++) { /* Set up our key and values DBTs */ memset(&key, 0, sizeof(DBT)); key.data = key_strings[j]; key.size = (u_int32_t)strlen(key_strings[j]) + 1; memset(&value, 0, sizeof(DBT)); payload = rand() + i; value.data = &payload; value.size = sizeof(int); /* Perform the database put. */ switch (ret = dbp->put(dbp, txn, &key, &value, 0)) { case 0: break; /* * Here's where we perform deadlock detection. If * DB_LOCK_DEADLOCK is returned by the put operation, * then this thread has been chosen to break a deadlock. * It must abort its operation, and optionally retry the * put. */ case DB_LOCK_DEADLOCK: /* * First thing that we MUST do is abort the * transaction. */ (void)txn->abort(txn); /* * Now we decide if we want to retry the operation. * If we have retried less than max_retries, * increment the retry count and goto retry. */ if (retry_count < max_retries) { printf("Writer %i: Got DB_LOCK_DEADLOCK.\n", thread_num); printf("Writer %i: Retrying write operation.\n", thread_num); retry_count++; goto retry; } /* * Otherwise, just give up. */ printf("Writer %i: ", thread_num); printf("Got DB_LOCK_DEADLOCK and out of retries.\n"); printf("Writer %i: Giving up.\n", thread_num); return ((void *)EXIT_FAILURE); /* * If a generic error occurs, we simply abort the * transaction and exit the thread completely. */ default: envp->err(envp, ret, "db put failed"); ret = txn->abort(txn); if (ret != 0) envp->err(envp, ret, "txn abort failed"); return ((void *)EXIT_FAILURE); } /** End case statement **/ } /** End for loop **/ /* * print the number of records found in the database. * See count_records() for usage information. */ printf("Thread %i. Record count: %i\n", thread_num, count_records(dbp, txn)); /* * If all goes well, we can commit the transaction and * exit the thread. */ ret = txn->commit(txn, 0); if (ret != 0) { envp->err(envp, ret, "txn commit failed"); return ((void *)EXIT_FAILURE); } } return ((void *)EXIT_SUCCESS); }
/* 批量插入示例函数。*/ void * run_bulk_delete() { int raw_key[NUM_KEY_INT]; DBT key; DB_ENV *envp; int bulk_size = 100; DB *dbp; DB_TXN *tid; int *delete_load; int delete_count, i, ret, op_flag; char *key_buf; void *p; int j; /* Initialize structs and arrays */ memset(raw_key, 0, KEY_SIZE); memset(&key, 0, sizeof(DBT)); tid = NULL; /* * 初始化批量删除使用的key buffer。由于批量删除不需要data, * 所以只需要初始化和填充key buffer。我们同样需要使用自己分配的内存。 */ key_buf = (char*) malloc(KEY_SIZE * bulk_size * 2); memset(key_buf, 0, KEY_SIZE * bulk_size * 2); /* 初始化key buffer DBT 对象,设置正确的flags和ulen成员。 */ key.data = key_buf; key.ulen = KEY_SIZE * bulk_size * 2; key.flags = DB_DBT_USERMEM; op_flag = DB_MULTIPLE; /* 批量删除同样需要这个flag。*/ /* * 批量删除所有的数据。每一批删除由key buffer DBT 当中的key * 指定的bulk_size条key/data pair. 这两个宏的详细用法见上文。 */ for (i = 0; i < delete_count / bulk_size; ) { /* 为批量删除初始化并填充一个key buffer DBT 对象。 */ DB_MULTIPLE_WRITE_INIT(p, &key); for (j = i * bulk_size; j < (i + 1) * bulk_size; j++) { raw_key[0] = delete_load[j]; DB_MULTIPLE_WRITE_NEXT(p, &key, raw_key, KEY_SIZE); } /* 启动事务。*/ if ((ret = envp->txn_begin(envp, NULL, &tid, 0)) != 0) { envp->err(envp, ret, "[delete] DB_ENV->txn_begin"); exit(EXIT_FAILURE); } /* * 执行批量删除。key buffer DBT * 当中的bulk_size条key指定的key/data pairs会被从数据库当中删除。 */ switch(ret = dbp->del(dbp, tid, &key, op_flag)) { case 0: /* 批量删除操作成功,提交事务。*/ if ((ret = tid->commit(tid, 0)) != 0) { envp->err(envp, ret, "[delete] DB_TXN->commit"); exit(EXIT_FAILURE); } break; case DB_LOCK_DEADLOCK: /* 如果数据库操作发生死锁,那么必须abort事务。然后,可以选择重新执行该操作。*/ if ((ret = tid->abort(tid)) != 0) { envp->err(envp, ret, "[delete] DB_TXN->abort"); exit(EXIT_FAILURE); } continue; default: envp->err(envp, ret, "[delete] DB->del ([%d]%d)", i, delete_load[i]); exit(EXIT_FAILURE); } i++; } (void)free(key_buf); return (NULL); }
nfsstat4 nfs_op_lookup(struct nfs_cxn *cxn, const LOOKUP4args *args, struct list_head *writes, struct rpc_write **wr) { nfsstat4 status = NFS4_OK; struct nfs_inode *ino = NULL; bool printed = false; struct nfs_buf objname; nfsino_t inum; DB_TXN *txn = NULL; DB_ENV *dbenv = srv.fsdb.env; int rc; objname.len = args->objname.utf8string_len; objname.val = args->objname.utf8string_val; if (!objname.len) { status = NFS4ERR_INVAL; goto out; } if (!objname.val) { status = NFS4ERR_BADXDR; goto out; } if (objname.len > SRV_MAX_NAME) { status = NFS4ERR_NAMETOOLONG; goto out; } rc = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (rc) { status = NFS4ERR_IO; dbenv->err(dbenv, rc, "DB_ENV->txn_begin"); goto out; } status = dir_curfh(txn, cxn, &ino, 0); if (status != NFS4_OK) { if ((status == NFS4ERR_NOTDIR) && (ino->type == NF4LNK)) status = NFS4ERR_SYMLINK; goto out_abort; } status = dir_lookup(txn, ino, &objname, 0, &inum); if (status != NFS4_OK) goto out_abort; rc = txn->commit(txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_commit"); status = NFS4ERR_IO; goto out; } fh_set(&cxn->current_fh, inum); if (debugging) { applog(LOG_INFO, "op LOOKUP ('%.*s') -> %016llX", objname.len, objname.val, (unsigned long long) cxn->current_fh.inum); printed = true; } out: if (!printed) { if (debugging) applog(LOG_INFO, "op LOOKUP ('%.*s')", objname.len, objname.val); } WR32(status); inode_free(ino); return status; out_abort: if (txn->abort(txn)) dbenv->err(dbenv, rc, "DB_ENV->txn_abort"); goto out; }
int main(int argc, char *const* argv) { const char *progname = "dbxml_dump"; DB_ENV *dbenv; XmlManager *xmlDb; u_int32_t cache; int ch, exitval, is_private, keyflag, nflag, ret, Rflag, rflag; char *home, *passwd; if ((ret = version_check(progname)) != 0) return (ret); dbenv = NULL; xmlDb = NULL; exitval = nflag = rflag = Rflag = 0; keyflag = 0; cache = MEGABYTE; is_private = 0; home = passwd = NULL; while ((ch = getopt(argc, argv, "f:h:NP:rRV")) != EOF) switch (ch) { case 'f': if (freopen(optarg, "wb", stdout) == NULL) { fprintf(stderr, "%s: %s: reopen: %s\n", progname, optarg, strerror(errno)); return (EXIT_FAILURE); } break; case 'h': home = optarg; break; case 'N': nflag = 1; break; case 'P': passwd = strdup(optarg); memset(optarg, 0, strlen(optarg)); if (passwd == NULL) { fprintf(stderr, "%s: strdup: %s\n", progname, strerror(errno)); return (EXIT_FAILURE); } break; case 'R': Rflag = 1; /* DB_AGGRESSIVE requires DB_SALVAGE */ /* FALLTHROUGH */ case 'r': rflag = 1; break; case 'V': printf("%s\n", DbXml::dbxml_version(NULL, NULL, NULL)); printf("%s\n", db_version(NULL, NULL, NULL)); return (EXIT_SUCCESS); case '?': default: return (usage()); } argc -= optind; argv += optind; if (argc != 1) return (usage()); /* Handle possible interruptions. */ SigBlock sb; /* * Create an environment object and initialize it for error * reporting. */ if ((ret = db_env_create(&dbenv, 0)) != 0) { fprintf(stderr, "%s: db_env_create: %s\n", progname, db_strerror(ret)); goto err; } dbenv->set_errfile(dbenv, stderr); dbenv->set_errpfx(dbenv, progname); if (nflag) { if ((ret = dbenv->set_flags(dbenv, DB_NOLOCKING, 1)) != 0) { dbenv->err(dbenv, ret, "set_flags: DB_NOLOCKING"); goto err; } if ((ret = dbenv->set_flags(dbenv, DB_NOPANIC, 1)) != 0) { dbenv->err(dbenv, ret, "set_flags: DB_NOPANIC"); goto err; } } if (passwd != NULL && (ret = dbenv->set_encrypt(dbenv, passwd, DB_ENCRYPT_AES)) != 0) { dbenv->err(dbenv, ret, "set_passwd"); goto err; } /* Initialize the environment. */ if ((ret = db_init(dbenv, home, rflag, cache, &is_private)) != 0) { dbenv->err(dbenv, ret, "db_init"); goto err; } xmlDb = new XmlManager(dbenv); if (rflag) { try { xmlDb->verifyContainer(argv[0], &cout, DB_SALVAGE | (Rflag ? DB_AGGRESSIVE : 0)); } catch (XmlException &e) { dbenv->errx(dbenv, "verify %s: %s", argv[0], e.what()); goto err; } goto done; } try { xmlDb->dumpContainer(argv[0], &cout); } catch (XmlException &e) { dbenv->errx(dbenv, "dump %s: %s", argv[0], e.what()); goto err; } if (0) { err: exitval = 1; } done: if (xmlDb) delete xmlDb; if ((ret = dbenv->close(dbenv, 0)) != 0) { exitval = 1; fprintf(stderr, "%s: dbenv->close: %s\n", progname, db_strerror(ret)); } return (exitval == 0 ? EXIT_SUCCESS : EXIT_FAILURE); }
nfsstat4 nfs_op_remove(struct nfs_cxn *cxn, const REMOVE4args *args, struct list_head *writes, struct rpc_write **wr) { nfsstat4 status = NFS4_OK; struct nfs_inode *dir_ino = NULL, *target_ino = NULL; struct nfs_buf target; change_info4 cinfo = { true, 0, 0 }; DB_TXN *txn = NULL; DB_ENV *dbenv = srv.fsdb.env; int rc; nfsino_t de_inum; target.len = args->target.utf8string_len; target.val = args->target.utf8string_val; if (debugging) applog(LOG_INFO, "op REMOVE ('%.*s')", target.len, target.val); if (target.len > SRV_MAX_NAME) { status = NFS4ERR_NAMETOOLONG; goto out; } if (!valid_utf8string(&target)) { status = NFS4ERR_INVAL; goto out; } if (has_dots(&target)) { status = NFS4ERR_BADNAME; goto out; } rc = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (rc) { status = NFS4ERR_IO; dbenv->err(dbenv, rc, "DB_ENV->txn_begin"); goto out; } /* reference container directory */ status = dir_curfh(txn, cxn, &dir_ino, DB_RMW); if (status != NFS4_OK) goto out_abort; /* lookup target name in directory */ status = dir_lookup(txn, dir_ino, &target, 0, &de_inum); if (status != NFS4_OK) goto out_abort; /* reference target inode */ target_ino = inode_getdec(txn, de_inum, DB_RMW); if (!target_ino) { status = NFS4ERR_NOENT; goto out_abort; } /* prevent root dir deletion */ if (target_ino->inum == INO_ROOT) { status = NFS4ERR_INVAL; goto out_abort; } /* prevent removal of non-empty dirs */ if ((target_ino->type == NF4DIR) && !dir_is_empty(txn, target_ino)) { status = NFS4ERR_NOTEMPTY; goto out_abort; } /* remove target inode from directory */ rc = fsdb_dirent_del(&srv.fsdb, txn, dir_ino->inum, &target, 0); if (rc) { status = NFS4ERR_IO; goto out_abort; } /* record directory change info */ cinfo.before = dir_ino->version; rc = inode_touch(txn, dir_ino); if (rc) { status = NFS4ERR_IO; goto out_abort; } cinfo.after = dir_ino->version; /* remove link, possibly deleting inode */ rc = inode_unlink(txn, target_ino); if (rc) { status = NFS4ERR_IO; goto out_abort; } rc = txn->commit(txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_commit"); status = NFS4ERR_IO; goto out; } out: WR32(status); if (status == NFS4_OK) { WR32(cinfo.atomic ? 1 : 0); /* cinfo.atomic */ WR64(cinfo.before); /* cinfo.before */ WR64(cinfo.after); /* cinfo.after */ } inode_free(dir_ino); inode_free(target_ino); return status; out_abort: if (txn->abort(txn)) dbenv->err(dbenv, rc, "DB_ENV->txn_abort"); goto out; }
nfsstat4 nfs_op_link(struct nfs_cxn *cxn, const LINK4args *args, struct list_head *writes, struct rpc_write **wr) { nfsstat4 status; struct nfs_inode *dir_ino = NULL, *src_ino = NULL; struct nfs_buf newname; uint64_t before = 0, after = 0; DB_TXN *txn; DB_ENV *dbenv = srv.fsdb.env; int rc; newname.len = args->newname.utf8string_len; newname.val = args->newname.utf8string_val; if (debugging) applog(LOG_INFO, "op LINK (%.*s)", newname.len, newname.val); /* verify input parameters */ if (!valid_fh(cxn->current_fh) || !valid_fh(cxn->save_fh)) { status = NFS4ERR_NOFILEHANDLE; goto out; } if (newname.len > SRV_MAX_NAME) { status = NFS4ERR_NAMETOOLONG; goto out; } /* open transaction */ rc = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (rc) { status = NFS4ERR_IO; dbenv->err(dbenv, rc, "DB_ENV->txn_begin"); goto out; } /* read source inode's directory inode */ dir_ino = inode_fhdec(txn, cxn->current_fh, 0); if (!dir_ino) { status = NFS4ERR_NOFILEHANDLE; goto out_abort; } /* make sure target is a directory */ if (dir_ino->type != NF4DIR) { status = NFS4ERR_NOTDIR; goto out_abort; } /* read source inode */ src_ino = inode_fhdec(txn, cxn->save_fh, 0); if (!src_ino) { status = NFS4ERR_NOFILEHANDLE; goto out_abort; } /* make sure source is a not a directory */ if (src_ino->type == NF4DIR) { status = NFS4ERR_ISDIR; goto out_abort; } before = dir_ino->version; /* add directory entry */ status = dir_add(txn, dir_ino, &newname, src_ino); if (status != NFS4_OK) goto out_abort; after = dir_ino->version; /* update source inode */ src_ino->n_link++; if (inode_touch(txn, src_ino)) { status = NFS4ERR_IO; goto out_abort; } /* close transaction */ rc = txn->commit(txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_commit"); status = NFS4ERR_IO; goto out; } out: WR32(status); if (status == NFS4_OK) { WR32(1); /* cinfo.atomic */ WR64(before); /* cinfo.before */ WR64(after); /* cinfo.after */ } inode_free(src_ino); inode_free(dir_ino); return status; out_abort: if (txn->abort(txn)) dbenv->err(dbenv, rc, "DB_ENV->txn_abort"); goto out; }
nfsstat4 nfs_op_rename(struct nfs_cxn *cxn, const RENAME4args *args, struct list_head *writes, struct rpc_write **wr) { nfsstat4 status = NFS4_OK; struct nfs_inode *src_dir = NULL, *target_dir = NULL; struct nfs_inode *old_file = NULL, *new_file = NULL; struct nfs_buf oldname, newname; change_info4 src = { true, 0, 0 }; change_info4 target = { true, 0, 0 }; DB_TXN *txn = NULL; DB_ENV *dbenv = srv.fsdb.env; int rc; nfsino_t old_dirent, new_dirent; oldname.len = args->oldname.utf8string_len; oldname.val = args->oldname.utf8string_val; newname.len = args->newname.utf8string_len; newname.val = args->newname.utf8string_val; if (debugging) applog(LOG_INFO, "op RENAME (OLD:%.*s, NEW:%.*s)", oldname.len, oldname.val, newname.len, newname.val); /* validate text input */ if ((!valid_utf8string(&oldname)) || (!valid_utf8string(&newname))) { status = NFS4ERR_INVAL; goto out; } if (has_dots(&oldname) || has_dots(&newname)) { status = NFS4ERR_BADNAME; goto out; } rc = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (rc) { status = NFS4ERR_IO; dbenv->err(dbenv, rc, "DB_ENV->txn_begin"); goto out; } /* reference source, target directories. * NOTE: src_dir and target_dir may point to the same object */ src_dir = inode_fhdec(txn, cxn->save_fh, DB_RMW); if (fh_equal(cxn->save_fh, cxn->current_fh)) target_dir = src_dir; else target_dir = inode_fhdec(txn, cxn->current_fh, DB_RMW); if (!src_dir || !target_dir) { status = NFS4ERR_NOFILEHANDLE; goto out_abort; } if ((src_dir->type != NF4DIR) || (target_dir->type != NF4DIR)) { status = NFS4ERR_NOTDIR; goto out_abort; } /* lookup source, target names */ status = dir_lookup(txn, src_dir, &oldname, 0, &old_dirent); if (status != NFS4_OK) goto out_abort; old_file = inode_getdec(txn, old_dirent, 0); if (!old_file) { status = NFS4ERR_NOENT; goto out_abort; } status = dir_lookup(txn, target_dir, &newname, 0, &new_dirent); if (status != NFS4_OK && status != NFS4ERR_NOENT) goto out_abort; /* if target (newname) is present, attempt to remove */ if (status == NFS4_OK) { bool ok_to_remove = false; /* read to-be-deleted inode */ new_file = inode_getdec(txn, new_dirent, DB_RMW); if (!new_file) { status = NFS4ERR_NOENT; goto out_abort; } /* do oldname and newname refer to same file? */ if (old_file->inum == new_file->inum) { src.after = src.before = src_dir->version; target.after = target.before = target_dir->version; goto out_abort; } if (old_file->type != NF4DIR && new_file->type != NF4DIR) ok_to_remove = true; else if (old_file->type == NF4DIR && new_file->type == NF4DIR && dir_is_empty(txn, new_file)) ok_to_remove = true; if (!ok_to_remove) { status = NFS4ERR_EXIST; goto out_abort; } /* remove target inode from directory */ rc = fsdb_dirent_del(&srv.fsdb, txn, target_dir->inum, &newname, 0); if (rc == 0) rc = inode_unlink(txn, new_file); if (rc) { status = NFS4ERR_IO; goto out_abort; } } else status = NFS4_OK; new_dirent = old_dirent; /* delete entry from source directory; add to target directory */ rc = fsdb_dirent_del(&srv.fsdb, txn, src_dir->inum, &oldname, 0); if (rc == 0) rc = fsdb_dirent_put(&srv.fsdb, txn, target_dir->inum, &newname, 0, new_dirent); if (rc) { status = NFS4ERR_IO; goto out_abort; } /* if renamed file is a directory, ensure its 'parent' is updated */ if (old_file->type == NF4DIR) { old_file->parent = target_dir->inum; if (inode_touch(txn, old_file)) { status = NFS4ERR_IO; goto out_abort; } } /* record directory change info */ src.before = src_dir->version; target.before = target_dir->version; /* update last-modified stamps of directory inodes */ rc = inode_touch(txn, src_dir); if (rc == 0 && src_dir != target_dir) rc = inode_touch(txn, target_dir); if (rc) { status = NFS4ERR_IO; goto out_abort; } /* close the transaction */ rc = txn->commit(txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_commit"); status = NFS4ERR_IO; goto out; } src.after = src_dir->version; target.after = target_dir->version; out: WR32(status); if (status == NFS4_OK) { WR32(src.atomic ? 1 : 0); /* src cinfo.atomic */ WR64(src.before); /* src cinfo.before */ WR64(src.after); /* src cinfo.after */ WR32(target.atomic ? 1 : 0); /* target cinfo.atomic */ WR64(target.before); /* target cinfo.before */ WR64(target.after); /* target cinfo.after */ } inode_free(src_dir); if (src_dir != target_dir) inode_free(target_dir); inode_free(old_file); inode_free(new_file); return status; out_abort: if (txn->abort(txn)) dbenv->err(dbenv, rc, "DB_ENV->txn_abort"); goto out; }
int main(void) { int ret, ret_c; u_int32_t db_flags, env_flags; DB *dbp; DB_ENV *envp; DBT key, data; DB_TXN *txn; const char *db_home_dir = "/tmp/mai-test-1/"; const char *file_name = "mydb.db"; const char keystr[BUF_SIZE]; const char datastr[BUF_SIZE]; int i = 0; dbp = NULL; envp = NULL; /* Open the environment */ ret = db_env_create(&envp, 0); if (ret != 0) { fprintf(stderr, "Error creating environment handle: %s\n", db_strerror(ret)); return (EXIT_FAILURE); } env_flags = DB_CREATE | /* Create the environment if it does * not already exist. */ DB_INIT_TXN | /* Initialize transactions */ DB_INIT_LOCK | /* Initialize locking. */ DB_INIT_LOG | /* Initialize logging */ DB_INIT_MPOOL | /* Initialize the in-memory cache. */ DB_RECOVER; ret = envp->open(envp, db_home_dir, env_flags, 0); if (ret != 0) { fprintf(stderr, "Error opening environment: %s\n", db_strerror(ret)); goto err; } /* Initialize the DB handle */ ret = db_create(&dbp, envp, 0); if (ret != 0) { envp->err(envp, ret, "Database creation failed"); goto err; } db_flags = DB_CREATE | DB_AUTO_COMMIT; /* Open the database. Note that we are using auto commit for the open, so the database is able to support transactions. */ ret = dbp->open(dbp, /* Pointer to the database */ NULL, /* Txn pointer */ file_name, /* File name */ NULL, /* Logical db name */ DB_BTREE, /* Database type (using btree) */ db_flags, /* Open flags */ 0); /* File mode. Using defaults */ if (ret != 0) { envp->err(envp, ret, "Database '%s' open failed", file_name); goto err; } /* Get the txn handle */ txn = NULL; ret = envp->txn_begin(envp, NULL, &txn, 0); if (ret != 0) { envp->err(envp, ret, "Transaction begin failed."); goto err; } for (i = 0; i < LOOP_SIZE; i++) { /* Prepare the DBTs */ memset(&key, 0, sizeof(DBT)); memset(&data, 0, sizeof(DBT)); sprintf((char*)keystr, "key%d", i); //sprintf((char*)datastr, "data%d", i); key.data = (char*)keystr; key.size = strlen((char*)keystr) + 1; //data.data = (char*)datastr; //data.size = strlen((char*)datastr) + 1; /* Perform the database write. If this fails, abort the transaction. */ ret = dbp->get(dbp, txn, &key, &data, 0); if (ret != 0) { envp->err(envp, ret, "Database put failed."); txn->abort(txn); goto err; } printf("%s %s\n", key.data, data.data); } /* Commit the transaction. Note that the transaction handle can no longer be used. */ ret = txn->commit(txn, 0); if (ret != 0) { envp->err(envp, ret, "Transaction commit failed."); goto err; } err: /* Close the database */ if (dbp != NULL) { ret_c = dbp->close(dbp, 0); if (ret_c != 0) { envp->err(envp, ret_c, "Database close failed."); ret = ret_c; } } /* Close the environment */ if (envp != NULL) { ret_c = envp->close(envp, 0); if (ret_c != 0) { fprintf(stderr, "environment close failed: %s\n", db_strerror(ret_c)); ret = ret_c; } } return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE); }
bool bucket_del(struct client *cli, const char *user, const char *bucket) { char *hdr, timestr[64]; enum errcode err = InternalError; int rc; struct db_bucket_ent ent; DB_ENV *dbenv = tdbrep.tdb.env; DB_TXN *txn = NULL; DB *buckets = tdbrep.tdb.buckets; DB *acls = tdbrep.tdb.acls; DB *objs = tdbrep.tdb.objs; DBC *cur = NULL; DBT key, val; char structbuf[sizeof(struct db_acl_key) + 32]; struct db_acl_key *acl_key = (struct db_acl_key *) &structbuf; struct db_obj_key *obj_key = (struct db_obj_key *) &structbuf; if (!user) return cli_err(cli, AccessDenied); /* open transaction */ rc = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_begin"); goto err_none; } /* search for (bucket, *) in object database, to see if * any objects associated with this bucket exist */ rc = objs->cursor(objs, txn, &cur, 0); if (rc) { objs->err(objs, rc, "objs->cursor"); goto err_out; } memset(&structbuf, 0, sizeof(structbuf)); strncpy(obj_key->bucket, bucket, sizeof(obj_key->bucket)); obj_key->key[0] = 0; memset(&key, 0, sizeof(key)); memset(&val, 0, sizeof(val)); key.data = obj_key; key.size = sizeof(*obj_key) + strlen(obj_key->key) + 1; val.flags = DB_DBT_MALLOC; rc = cur->get(cur, &key, &val, DB_SET_RANGE); if (rc == 0) { struct db_obj_key *newkey = key.data; if (!strcmp(newkey->bucket, bucket)) { free(newkey); cur->close(cur); err = BucketNotEmpty; goto err_out; } free(newkey); } else if (rc != DB_NOTFOUND) objs->err(objs, rc, "bucket_del empty check"); rc = cur->close(cur); if (rc) { objs->err(objs, rc, "objs->cursor_close"); goto err_out; } memset(&key, 0, sizeof(key)); key.data = (char *) bucket; key.size = strlen(bucket) + 1; memset(&val, 0, sizeof(val)); val.data = &ent; val.ulen = sizeof(struct db_bucket_ent); val.flags = DB_DBT_USERMEM; /* verify the bucket exists */ rc = buckets->get(buckets, txn, &key, &val, 0); if (rc) { if (rc == DB_NOTFOUND) err = NoSuchBucket; else buckets->err(buckets, rc, "buckets->get"); goto err_out; } /* verify that it is the owner who wishes to delete bucket */ if (strncmp(user, ent.owner, sizeof(ent.owner))) { err = AccessDenied; goto err_out; } /* delete bucket */ rc = buckets->del(buckets, txn, &key, 0); if (rc) { buckets->err(buckets, rc, "bucket del"); goto err_out; } /* delete bucket ACLs */ memset(&structbuf, 0, sizeof(structbuf)); strncpy(acl_key->bucket, bucket, sizeof(acl_key->bucket)); acl_key->key[0] = 0; memset(&key, 0, sizeof(key)); key.data = acl_key; key.size = sizeof(*acl_key) + strlen(acl_key->key) + 1; rc = acls->del(acls, txn, &key, 0); if (rc && rc != DB_NOTFOUND) { acls->err(acls, rc, "acl del"); goto err_out; } /* commit */ rc = txn->commit(txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_commit"); return cli_err(cli, InternalError); } if (asprintf(&hdr, "HTTP/%d.%d 204 x\r\n" "Content-Length: 0\r\n" "Date: %s\r\n" "Server: " PACKAGE_STRING "\r\n" "\r\n", cli->req.major, cli->req.minor, hutil_time2str(timestr, sizeof(timestr), time(NULL))) < 0) return cli_err(cli, InternalError); rc = atcp_writeq(&cli->wst, hdr, strlen(hdr), atcp_cb_free, hdr); if (rc) { free(hdr); return true; } return atcp_write_start(&cli->wst); err_out: rc = txn->abort(txn); if (rc) dbenv->err(dbenv, rc, "DB_ENV->txn_abort"); err_none: return cli_err(cli, err); }
static bool bucket_list_keys(struct client *cli, const char *user, const char *bucket) { GHashTable *param; enum errcode err = InternalError; char *prefix, *marker, *maxkeys_str, *delim, *s; int maxkeys = 100, i, rc; GList *content, *tmpl; size_t pfx_len; struct bucket_list_info bli; bool rcb; DB_ENV *dbenv = tdbrep.tdb.env; DB_TXN *txn = NULL; DB *objs = tdbrep.tdb.objs; DBC *cur = NULL; DBT pkey, pval; struct db_obj_key *obj_key; size_t alloc_len; bool seen_prefix = false; int get_flags; /* verify READ access */ if (!user || !has_access(user, bucket, NULL, "READ")) { err = AccessDenied; goto err_out; } /* parse URI query string */ param = hreq_query(&cli->req); if (!param) goto err_out; /* read useful params from query string */ prefix = g_hash_table_lookup(param, "prefix"); pfx_len = prefix ? strlen(prefix) : 0; marker = g_hash_table_lookup(param, "marker"); delim = g_hash_table_lookup(param, "delimiter"); maxkeys_str = g_hash_table_lookup(param, "max-keys"); if (maxkeys_str) { i = atoi(maxkeys_str); if (i > 0 && i < maxkeys) maxkeys = i; } /* open transaction */ rc = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_begin"); goto err_out; } /* search for (bucket, *) in object database, to see if * any objects associated with this bucket exist */ rc = objs->cursor(objs, txn, &cur, 0); if (rc) { objs->err(objs, rc, "objs->cursor"); goto err_out; } alloc_len = sizeof(*obj_key) + (marker ? strlen(marker) : pfx_len) + 1; obj_key = alloca(alloc_len); memset(obj_key, 0, alloc_len); strncpy(obj_key->bucket, bucket, sizeof(obj_key->bucket)); strcpy(obj_key->key, marker ? marker : prefix ? prefix : ""); memset(&pkey, 0, sizeof(pkey)); pkey.data = obj_key; pkey.size = alloc_len; memset(&bli, 0, sizeof(bli)); bli.prefix = prefix; bli.pfx_len = pfx_len; bli.delim = delim; bli.common_pfx = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL); bli.maxkeys = maxkeys; /* iterate through each returned data row */ get_flags = DB_SET_RANGE; while (1) { struct obj_vitals v; struct db_obj_key *tmpkey; struct db_obj_ent *obj; memset(&pval, 0, sizeof(pval)); pval.flags = DB_DBT_MALLOC; rc = cur->get(cur, &pkey, &pval, get_flags); if (rc) { if (rc != DB_NOTFOUND) objs->err(objs, rc, "bucket_list_keys iter"); break; } get_flags = DB_NEXT; tmpkey = pkey.data; obj = pval.data; if (strcmp(tmpkey->bucket, bucket)) { free(obj); break; } if (prefix) { if (strncmp(tmpkey->key, prefix, pfx_len) != 0) { free(obj); if (!seen_prefix) /* continue searching for * a record that begins with this * prefix */ continue; else /* no more records with our prefix */ break; } seen_prefix = true; } memset(&v, 0, sizeof(v)); strcpy(v.md5, obj->md5); strncpy(v.owner, obj->owner, sizeof(v.owner)-1); if (!(GUINT32_FROM_LE(obj->flags) & DB_OBJ_INLINE)) memcpy(&v.addr, &obj->d.a, sizeof(v.addr)); v.mtime = GUINT64_FROM_LE(obj->mtime); v.size = GUINT64_FROM_LE(obj->size); free(obj); if (bucket_list_iter(tmpkey->key, &v, &bli)) break; } /* close cursor, transaction */ rc = cur->close(cur); if (rc) { objs->err(objs, rc, "objs->cursor close"); goto err_out_rb; } rc = txn->commit(txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_commit"); goto err_out_param; } s = g_markup_printf_escaped( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" "<ListBucketResult xmlns=\"http://indy.yyz.us/doc/2006-03-01/\">\r\n" " <Name>%s</Name>\r\n" " <MaxKeys>%d</MaxKeys>\r\n" " <IsTruncated>%s</IsTruncated>\r\n", bucket, maxkeys, bli.trunc ? "true" : "false"); content = g_list_append(NULL, s); if (prefix) { s = g_markup_printf_escaped(" <Prefix>%s</Prefix>\n", prefix); content = g_list_append(content, s); } if (marker) { s = g_markup_printf_escaped(" <Marker>%s</Marker>\n", marker); content = g_list_append(content, s); } tmpl = bli.res; while (tmpl) { char timestr[64]; struct obj_vitals *vp; vp = tmpl->data; tmpl = tmpl->next; /* * FIXME Use the vp->addr to verify that key still exists. * And if it doesn't, then what? (addr.nid can be 0 for inline) */ s = g_markup_printf_escaped( " <Contents>\r\n" " <Key>%s</Key>\r\n" " <LastModified>%s</LastModified>\r\n" " <ETag>%s</ETag>\r\n" " <Size>%llu</Size>\r\n" " <StorageClass>STANDARD</StorageClass>\r\n" " <Owner>\r\n" " <ID>%s</ID>\r\n" " <DisplayName>%s</DisplayName>\r\n" " </Owner>\r\n" " </Contents>\r\n", vp->key, hutil_time2str(timestr, sizeof(timestr), vp->mtime / 1000000), vp->md5, (unsigned long long) vp->size, vp->owner, vp->owner); content = g_list_append(content, s); free(vp->key); free(vp); } g_list_free(bli.res); content = bucket_list_pfx(content, bli.common_pfx, bli.delim); s = strdup("</ListBucketResult>\r\n"); content = g_list_append(content, s); free(bli.last_comp); g_hash_table_destroy(bli.common_pfx); g_hash_table_destroy(param); rcb = cli_resp_xml(cli, 200, content); g_list_free(content); return rcb; err_out_rb: rc = txn->abort(txn); if (rc) dbenv->err(dbenv, rc, "DB_ENV->txn_abort"); err_out_param: g_hash_table_destroy(param); err_out: return cli_err(cli, err); }
bool bucket_add(struct client *cli, const char *user, const char *bucket) { char *hdr, timestr[64]; enum errcode err = InternalError; int rc; struct db_bucket_ent ent; bool setacl; /* is ok to put pre-existing bucket */ enum ReqACLC canacl; DB *buckets = tdbrep.tdb.buckets; DB *acls = tdbrep.tdb.acls; DB_ENV *dbenv = tdbrep.tdb.env; DB_TXN *txn = NULL; DBT key, val; if (!user) return cli_err(cli, AccessDenied); /* prepare parameters */ setacl = false; if (cli->req.uri.query_len) { switch (hreq_is_query(&cli->req)) { case URIQ_ACL: setacl = true; break; default: err = InvalidURI; goto err_par; } } if ((rc = hreq_acl_canned(&cli->req)) == ACLCNUM) { err = InvalidArgument; goto err_par; } canacl = (rc == -1)? ACLC_PRIV: rc; /* begin trans */ rc = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_begin"); goto err_db; } memset(&key, 0, sizeof(key)); memset(&val, 0, sizeof(val)); memset(&ent, 0, sizeof(ent)); strncpy(ent.name, bucket, sizeof(ent.name)); strncpy(ent.owner, user, sizeof(ent.owner)); ent.time_create = GUINT64_TO_LE(time(NULL)); key.data = &ent.name; key.size = strlen(ent.name) + 1; val.data = &ent; val.size = sizeof(ent); if (setacl) { /* check if the bucket exists, else insert it */ rc = bucket_find(txn, bucket, NULL, 0); if (rc) { if (rc != DB_NOTFOUND) { buckets->err(buckets, rc, "buckets->find"); goto err_out; } rc = buckets->put(buckets, txn, &key, &val, DB_NOOVERWRITE); if (rc) { buckets->err(buckets, rc, "buckets->put"); goto err_out; } } else { if (!has_access(user, bucket, NULL, "WRITE_ACP")) { err = AccessDenied; goto err_out; } if (!object_del_acls(txn, bucket, "")) goto err_out; } } else { /* attempt to insert new bucket */ rc = buckets->put(buckets, txn, &key, &val, DB_NOOVERWRITE); if (rc) { if (rc == DB_KEYEXIST) err = BucketAlreadyExists; else buckets->err(buckets, rc, "buckets->put"); goto err_out; } } /* insert bucket ACL */ rc = add_access_canned(txn, bucket, "", user, canacl); if (rc) { acls->err(acls, rc, "acls->put"); goto err_out; } /* commit -- no more exception emulation with goto. */ rc = txn->commit(txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_commit"); return cli_err(cli, InternalError); } if (asprintf(&hdr, "HTTP/%d.%d 200 x\r\n" "Content-Length: 0\r\n" "Date: %s\r\n" "Location: /%s\r\n" "Server: " PACKAGE_STRING "\r\n" "\r\n", cli->req.major, cli->req.minor, hutil_time2str(timestr, sizeof(timestr), time(NULL)), bucket) < 0) return cli_err(cli, InternalError); rc = atcp_writeq(&cli->wst, hdr, strlen(hdr), atcp_cb_free, hdr); if (rc) { free(hdr); return true; } return atcp_write_start(&cli->wst); err_out: rc = txn->abort(txn); if (rc) dbenv->err(dbenv, rc, "DB_ENV->txn_abort"); err_db: err_par: return cli_err(cli, err); }
int cache_init(cache_t *c, void (*freevalue)(void *value)) { memset(c, '\0', sizeof(*c)); int ret; DB_ENV *dbenv; ret = db_env_create(&dbenv, 0); dbenv->err(dbenv,ret,"err db_env_create "); dbenv->set_errfile(dbenv, stderr); dbenv->err(dbenv,ret,"err set_errfile "); if ((ret = dbenv->set_shm_key(dbenv, 664)) != 0) { dbenv->err(dbenv,ret,"err set_shm_key "); return 0; } ret = dbenv->open(dbenv,bfile(_temp_path),DB_CREATE | DB_INIT_MPOOL | DB_INIT_CDB ,0); dbenv->err(dbenv,ret,"err db_env_open "); /* Create and initialize database object */ if ((ret = db_create(&c->c_data, dbenv, 0)) != 0) { fprintf(stderr, "%s: db_create: %s\n", "bbdocument", db_strerror(ret)); return 0; } #ifdef DEBUG dbenv->stat_print(dbenv, DB_STAT_ALL); #endif /* open the database. */ if ((ret = c->c_data->open(c->c_data, NULL, "libcachedb", NULL, DB_BTREE, DB_CREATE, 0)) != 0) { c->c_data->err(c->c_data, ret, "db open"); //goto err1; //dette skjer nor collection mappen ikke er opprettet enda, typisk forde vi ikke har lagret et dokument der enda #ifdef DEBUG printf("can't dbp->open(), but db_create() was sucessful!\n"); #endif return 0; } #ifdef DEBUG c->c_data->stat_print(c->c_data, DB_STAT_ALL); #endif pthread_mutex_init(&c->c_lock, NULL); c->c_freevalue = freevalue; return 1; }
nfsstat4 nfs_op_readdir(struct nfs_cxn *cxn, const READDIR4args *args, struct list_head *writes, struct rpc_write **wr) { nfsstat4 status = NFS4_OK; struct nfs_inode *ino = NULL; uint32_t dircount, maxcount, *status_p; struct readdir_info ri; uint64_t cookie, attr_request; const verifier4 *cookie_verf; DB_TXN *txn = NULL; DB *dirent = srv.fsdb.dirent; DB_ENV *dbenv = srv.fsdb.env; DBT pkey, pval; struct fsdb_de_key key; int cget_flags; DBC *curs = NULL; int rc; uint64_t dirent_inum, db_de; struct fsdb_de_key *rkey; cookie = args->cookie; cookie_verf = &args->cookieverf; dircount = args->dircount; maxcount = args->maxcount; attr_request = bitmap4_decode(&args->attr_request); status_p = WRSKIP(4); if (debugging) { applog(LOG_INFO, "op READDIR (COOKIE:%Lu DIR:%u MAX:%u MAP:%Lx)", (unsigned long long) cookie, dircount, maxcount, (unsigned long long) attr_request); print_fattr_bitmap("op READDIR", attr_request); } /* traditionally "." and "..", hardcoded */ if (cookie == 1 || cookie == 2) { status = NFS4ERR_BAD_COOKIE; goto out; } /* don't permit request of write-only attrib */ if (attr_request & fattr_write_only_mask) { status = NFS4ERR_INVAL; goto out; } /* FIXME: very, very, very poor verifier */ if (cookie && memcmp(cookie_verf, &srv.instance_verf, sizeof(verifier4))) { status = NFS4ERR_NOT_SAME; goto out; } /* read inode of directory being read */ status = dir_curfh(NULL, cxn, &ino, 0); if (status != NFS4_OK) goto out; if (ino->mode == 0) { status = NFS4ERR_ACCESS; goto out; } /* subtract READDIR4resok header and footer size */ if (maxcount < 16) { status = NFS4ERR_TOOSMALL; goto out; } maxcount -= (8 + 4 + 4); /* verify within server limits */ if (dircount > SRV_MAX_READ || maxcount > SRV_MAX_READ) { status = NFS4ERR_INVAL; goto out; } /* open transaction */ rc = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (rc) { status = NFS4ERR_IO; dbenv->err(dbenv, rc, "DB_ENV->txn_begin"); goto out; } /* set up directory iteration */ memset(&ri, 0, sizeof(ri)); ri.cookie = cookie; ri.dircount = dircount; ri.maxcount = maxcount; ri.attr_request = attr_request; ri.status = NFS4_OK; ri.writes = writes; ri.wr = wr; ri.dir_pos = 3; ri.first_time = true; /* if dir is empty, skip directory interation loop completely */ if (dir_is_empty(txn, ino)) { WRMEM(&srv.instance_verf, sizeof(verifier4)); /* cookieverf */ ri.val_follows = WRSKIP(4); if (debugging) applog(LOG_DEBUG, " READDIR: empty directory"); goto the_finale; } /* otherwise, loop through each dirent attached to ino->inum */ rc = dirent->cursor(dirent, txn, &curs, 0); if (rc) { status = NFS4ERR_IO; dirent->err(dirent, rc, "dirent->cursor"); goto out_abort; } key.inum = inum_encode(ino->inum); memset(&pkey, 0, sizeof(pkey)); pkey.data = &key; pkey.size = sizeof(key); pkey.flags = DB_DBT_MALLOC; memset(&pval, 0, sizeof(pval)); pval.data = &db_de; pval.ulen = sizeof(db_de); pval.flags = DB_DBT_USERMEM; cget_flags = DB_SET_RANGE; while (1) { bool iter_rc; rc = curs->get(curs, &pkey, &pval, cget_flags); if (rc) { if (rc != DB_NOTFOUND) dirent->err(dirent, rc, "readdir curs->get"); break; } cget_flags = DB_NEXT; rkey = pkey.data; if (inum_decode(rkey->inum) != ino->inum) { free(rkey); break; } dirent_inum = inum_decode(db_de); iter_rc = readdir_iter(txn, rkey, pkey.size, dirent_inum, &ri); free(rkey); if (iter_rc) break; } if (!ri.n_results) { if (debugging) applog(LOG_INFO, " zero results, status %s", ri.status <= NFS4ERR_CB_PATH_DOWN ? status2str(ri.status) : "n/a"); if (ri.status == NFS4_OK) { WRMEM(&srv.instance_verf, sizeof(verifier4)); /* cookieverf */ ri.val_follows = WRSKIP(4); } } rc = curs->close(curs); if (rc) { status = NFS4ERR_IO; dirent->err(dirent, rc, "dirent->cursor close"); goto out_abort; } the_finale: /* terminate final entry4.nextentry and dirlist4.entries */ if (ri.val_follows) *ri.val_follows = htonl(0); if (ri.cookie_found && !ri.n_results && ri.hit_limit) { status = NFS4ERR_TOOSMALL; goto out_abort; } /* close transaction */ rc = txn->commit(txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_commit"); status = NFS4ERR_IO; goto out; } WR32(ri.hit_limit ? 0 : 1); /* reply eof */ out: *status_p = htonl(status); inode_free(ino); return status; out_abort: if (txn->abort(txn)) dbenv->err(dbenv, rc, "DB_ENV->txn_abort"); goto out; }
bool access_list(struct client *cli, const char *bucket, const char *key, const char *user) { struct macl { char perm[128]; /* perm(s) granted */ char grantee[64]; /* grantee user */ }; GHashTable *param; enum errcode err = InternalError; DB_ENV *dbenv = tdbrep.tdb.env; DB *acls = tdbrep.tdb.acls; int alloc_len; char owner[64]; GList *res; struct db_acl_key *acl_key; struct db_acl_ent *acl; DB_TXN *txn = NULL; DBC *cur = NULL; GList *content; DBT pkey, pval; struct macl *mp; char guser[64]; GList *p; char *s; int str_len; int rc; bool rcb; /* verify READ access for ACL */ if (!user || !has_access(user, bucket, key, "READ_ACP")) { err = AccessDenied; goto err_out; } /* parse URI query string */ param = hreq_query(&cli->req); if (!param) goto err_out; res = NULL; alloc_len = sizeof(struct db_acl_key) + strlen(key) + 1; acl_key = alloca(alloc_len); memset(acl_key, 0, alloc_len); strncpy(acl_key->bucket, bucket, sizeof(acl_key->bucket)); strcpy(acl_key->key, key); /* open transaction, search cursor */ rc = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_begin"); goto err_out_param; } rc = bucket_find(txn, bucket, &owner[0], sizeof(owner)); if (rc) { if (rc == DB_NOTFOUND) err = InvalidBucketName; else dbenv->err(dbenv, rc, "bucket_find"); goto err_out_rb; } rc = acls->cursor(acls, txn, &cur, 0); if (rc) { acls->err(acls, rc, "acls->cursor"); goto err_out_rb; } memset(&pkey, 0, sizeof(pkey)); pkey.data = acl_key; pkey.size = alloc_len; for (;; free(acl)) { memset(&pval, 0, sizeof(pval)); pval.flags = DB_DBT_MALLOC; rc = cur->get(cur, &pkey, &pval, DB_NEXT); if (rc) break; acl = pval.data; /* This is a workaround, see FIXME about DB_NEXT. */ if (strncmp(acl->bucket, bucket, sizeof(acl->bucket))) continue; if (strcmp(acl->key, key)) continue; if ((mp = malloc(sizeof(struct macl))) == NULL) { free(acl); cur->close(cur); goto err_out_rb; } memcpy(mp->grantee, acl->grantee, sizeof(mp->grantee)); mp->grantee[sizeof(mp->grantee)-1] = 0; memcpy(mp->perm, acl->perm, sizeof(mp->perm)); /* lop off the trailing comma */ mp->perm[sizeof(mp->perm)-1] = 0; str_len = strlen(mp->perm); if (str_len && mp->perm[str_len-1] == ',') mp->perm[--str_len] = 0; res = g_list_append(res, mp); } if (rc != DB_NOTFOUND) acls->err(acls, rc, "access_list iteration"); /* close cursor, transaction */ rc = cur->close(cur); if (rc) acls->err(acls, rc, "acls->cursor close"); rc = txn->commit(txn, 0); if (rc) dbenv->err(dbenv, rc, "DB_ENV->txn_commit"); /* dump collected acls -- no more exception handling */ s = g_markup_printf_escaped( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" "<AccessControlPolicy " "xmlns=\"http://indy.yyz.us/doc/2006-03-01/\">\r\n" " <Owner>\r\n" " <ID>%s</ID>\r\n" " <DisplayName>%s</DisplayName>\r\n" " </Owner>\r\n", owner, owner); content = g_list_append(NULL, s); s = g_markup_printf_escaped( " <AccessControlList>\r\n"); content = g_list_append(content, s); for (p = res; p != NULL; p = p->next) { mp = p->data; if (!strcmp(DB_ACL_ANON, mp->grantee)) { strcpy(guser, "anonymous"); } else { strncpy(guser, mp->grantee, sizeof(guser)); guser[sizeof(guser)-1] = 0; } s = g_markup_printf_escaped( " <Grant>\r\n" " <Grantee xmlns:xsi=\"http://www.w3.org/2001/" "XMLSchema-instance\" xsi:type=\"CanonicalUser\">\r\n" " <ID>%s</ID>\r\n" " <DisplayName>%s</DisplayName>\r\n" " </Grantee>\r\n", guser, guser); content = g_list_append(content, s); /* * FIXME This parsing is totally lame, we should replace * strings with a bit mask once we make sure this works. */ if (!strcmp(mp->perm, "READ,WRITE,READ_ACP,WRITE_ACP")) { s = g_markup_printf_escaped( " <Permission>FULL_CONTROL</Permission>\r\n"); } else { s = g_markup_printf_escaped( " <Permission>%s</Permission>\r\n", mp->perm); } content = g_list_append(content, s); s = g_markup_printf_escaped(" </Grant>\r\n"); content = g_list_append(content, s); free(mp); } s = g_markup_printf_escaped(" </AccessControlList>\r\n"); content = g_list_append(content, s); s = g_markup_printf_escaped("</AccessControlPolicy>\r\n"); content = g_list_append(content, s); g_list_free(res); rcb = cli_resp_xml(cli, 200, content); g_list_free(content); return rcb; err_out_rb: rc = txn->abort(txn); if (rc) dbenv->err(dbenv, rc, "DB_ENV->txn_abort"); for (p = res; p != NULL; p = p->next) free(p->data); g_list_free(res); err_out_param: g_hash_table_destroy(param); err_out: return cli_err(cli, err); }
void * writer_thread(void *args) { DB *dbp; DB_ENV *dbenv; DBT key, data; DB_TXN *txn; char *key_strings[] = {"001", "002", "003", "004", "005", "006", "007", "008", "009", "010"}; int i, j, payload, ret, thread_num; int retry_count, max_retries = 20; dbp = (DB *)args; dbenv = dbp->dbenv; /* Get the thread number */ (void)mutex_lock(&thread_num_lock); global_thread_num++; thread_num = global_thread_num; (void)mutex_unlock(&thread_num_lock); /* Initialize the random number generator */ srand(thread_num); /* Write 50 times and then quit */ for (i = 0; i < 50; i++) { retry_count = 0; /* Used for deadlock retries */ retry: ret = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (ret != 0) { dbenv->err(dbenv, ret, "txn_begin failed"); return ((void *)EXIT_FAILURE); } memset(&key, 0, sizeof(DBT)); memset(&data, 0, sizeof(DBT)); for (j = 0; j < 10; j++) { /* Set up our key and data DBTs. */ data.data = key_strings[j]; data.size = (u_int32_t)strlen(key_strings[j]) + 1; payload = rand() + i; key.data = &payload; key.size = sizeof(int); switch (ret = dbp->put(dbp, txn, &key, &data, DB_NOOVERWRITE)) { case 0: break; case DB_KEYEXIST: break; case DB_LOCK_DEADLOCK: (void)txn->abort(txn); if (retry_count < max_retries) { retry_count++; goto retry; } return ((void *)EXIT_FAILURE); default: dbenv->err(dbenv, ret, "db put failed"); ret = txn->abort(txn); if (ret != 0) dbenv->err(dbenv, ret, "txn abort failed"); return ((void *)EXIT_FAILURE); } } if ((ret = txn->commit(txn, 0)) != 0) { dbenv->err(dbenv, ret, "txn commit failed"); return ((void *)EXIT_FAILURE); } } return ((void *)EXIT_SUCCESS); }
int main(int argc, char *argv[]) { DB_ENV *dbenv; DB_SITE *dbsite; extern char *optarg; const char *home; char ch, *host, *portstr; int local_is_set, ret, is_group_creator; u_int16_t port; /* Used to track whether this is a replica or a master. */ APP_DATA my_app_data; dbenv = NULL; ret = local_is_set = is_group_creator = 0; home = NULL; my_app_data.is_master = 0; /* Assume that we start as a replica */ if ((ret = create_env(progname, &dbenv)) != 0) goto err; /* Make APP_DATA available through the environment handle. */ dbenv->app_private = &my_app_data; /* Default priority is 100. */ dbenv->rep_set_priority(dbenv, 100); /* Permanent messages require at least one ack. */ dbenv->repmgr_set_ack_policy(dbenv, DB_REPMGR_ACKS_ONE); /* Give 500 microseconds to receive the ack. */ dbenv->rep_set_timeout(dbenv, DB_REP_ACK_TIMEOUT, 500); /* Collect the command line options. */ while ((ch = getopt(argc, argv, "h:l:L:p:r:")) != EOF) switch (ch) { case 'h': home = optarg; break; /* Set the host and port used by this environment. */ case 'L': is_group_creator = 1; /* FALLTHROUGH */ case 'l': host = strtok(optarg, ":"); if ((portstr = strtok(NULL, ":")) == NULL) { fprintf(stderr, "Bad host specification.\n"); goto err; } port = (unsigned short)atoi(portstr); if ((ret = dbenv->repmgr_site(dbenv, host, port, &dbsite, 0)) != 0){ fprintf(stderr, "Could not set local address %s:%d.\n", host, port); goto err; } dbsite->set_config(dbsite, DB_LOCAL_SITE, 1); if (is_group_creator) dbsite->set_config(dbsite, DB_GROUP_CREATOR, 1); if ((ret = dbsite->close(dbsite)) != 0) { dbenv->err(dbenv, ret, "DB_SITE->close"); goto err; } local_is_set = 1; break; /* Set this replica's election priority. */ case 'p': dbenv->rep_set_priority(dbenv, atoi(optarg)); break; /* Identify another site in the replication group. */ case 'r': host = strtok(optarg, ":"); if ((portstr = strtok(NULL, ":")) == NULL) { fprintf(stderr, "Bad host specification.\n"); goto err; } port = (unsigned short)atoi(portstr); if ((ret = dbenv->repmgr_site(dbenv, host, port, &dbsite, 0)) != 0) { dbenv->err(dbenv, ret, "DB_ENV->repmgr_site"); goto err; } dbsite->set_config(dbsite, DB_BOOTSTRAP_HELPER, 1); if ((ret = dbsite->close(dbsite)) != 0) { dbenv->err(dbenv, ret, "DB_SITE->close"); goto err; } break; case '?': default: usage(); } /* Error check command line. */ if (home == NULL || !local_is_set) usage(); if ((ret = env_init(dbenv, home)) != 0) goto err; if ((ret = dbenv->repmgr_start(dbenv, 3, DB_REP_ELECTION)) != 0) goto err; if ((ret = doloop(dbenv)) != 0) { dbenv->err(dbenv, ret, "Application failed"); goto err; } err: if (dbenv != NULL) (void)dbenv->close(dbenv, 0); return (ret); }
bool has_access(const char *user, const char *bucket, const char *key, const char *perm_in) { int rc; char perm[16]; bool match = false; size_t alloc_len, key_len = 0; struct db_acl_key *acl_key; struct db_acl_ent *acl; DB_ENV *dbenv = tdbrep.tdb.env; DB_TXN *txn = NULL; DBT pkey, pval; DBC *cur = NULL; DB *acls = tdbrep.tdb.acls; if (user == NULL) user = DB_ACL_ANON; if (key == NULL) key = ""; /* alloc ACL key on stack, sized to fit 'key' function arg */ alloc_len = sizeof(struct db_acl_key) + 1; if (key) { key_len = strlen(key); alloc_len += key_len; } acl_key = alloca(alloc_len); /* fill in search key struct */ memset(acl_key, 0, alloc_len); strncpy(acl_key->bucket, bucket, sizeof(acl_key->bucket)); memcpy(acl_key->key, key, key_len); acl_key->key[key_len] = 0; snprintf(perm, sizeof(perm), "%s,", perm_in); /* open transaction, search cursor */ rc = dbenv->txn_begin(dbenv, NULL, &txn, 0); if (rc) { dbenv->err(dbenv, rc, "DB_ENV->txn_begin"); return false; } rc = acls->cursor(acls, txn, &cur, 0); if (rc) { acls->err(acls, rc, "acls->cursor"); goto err_out; } memset(&pkey, 0, sizeof(pkey)); pkey.data = acl_key; pkey.size = alloc_len; memset(&pval, 0, sizeof(pval)); pval.flags = DB_DBT_MALLOC; /* loop through matching records (if any) */ rc = cur->get(cur, &pkey, &pval, DB_SET); while (rc == 0) { acl = pval.data; if (!strncmp(acl->grantee, user, sizeof(acl->grantee))) { match = (strstr(acl->perm, perm) != NULL); free(acl); break; } free(acl); memset(&pval, 0, sizeof(pval)); pval.flags = DB_DBT_MALLOC; rc = cur->get(cur, &pkey, &pval, DB_NEXT_DUP); } if (rc && rc != DB_NOTFOUND) acls->err(acls, rc, "has_access iteration"); /* close cursor, transaction */ rc = cur->close(cur); if (rc) acls->err(acls, rc, "acls->cursor close"); rc = txn->commit(txn, 0); if (rc) dbenv->err(dbenv, rc, "DB_ENV->txn_commit"); return match; err_out: rc = txn->abort(txn); if (rc) dbenv->err(dbenv, rc, "DB_ENV->txn_abort"); return false; }