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-good-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. */ 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->put(dbp, txn, &key, &data, 0); if (ret != 0) { envp->err(envp, ret, "Database put failed."); txn->abort(txn); goto err; } } /* 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); }
icalerrorenum icalbdbset_commit(icalset *set) { DB *dbp; DBC *dbcp; DBT key, data; icalcomponent *c; char *str = NULL; int ret = 0; int reterr = ICAL_NO_ERROR; char keystore[256]; char uidbuf[256]; char datastore[1024]; char *more_mem = NULL; DB_TXN *tid = NULL; icalbdbset *bset = (icalbdbset *) set; int bad_uid_counter = 0; int retry = 0, done = 0, completed = 0, deadlocked = 0; icalerror_check_arg_re((bset != 0), "bset", ICAL_BADARG_ERROR); dbp = bset->dbp; icalerror_check_arg_re((dbp != 0), "dbp is invalid", ICAL_BADARG_ERROR); if (bset->changed == 0) { return ICAL_NO_ERROR; } memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); key.flags = DB_DBT_USERMEM; key.data = keystore; key.ulen = (u_int32_t) sizeof(keystore); data.flags = DB_DBT_USERMEM; data.data = datastore; data.ulen = (u_int32_t) sizeof(datastore); if (!ICAL_DB_ENV) { if (icalbdbset_init_dbenv(NULL, NULL) != 0) { return ICAL_INTERNAL_ERROR; } } while ((retry < MAX_RETRY) && !done) { if ((ret = ICAL_DB_ENV->txn_begin(ICAL_DB_ENV, NULL, &tid, 0)) != 0) { if (ret == DB_LOCK_DEADLOCK) { retry++; continue; } else if (ret == DB_RUNRECOVERY) { ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "icalbdbset_commit: txn_begin failed"); abort(); } else { ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "icalbdbset_commit"); return ICAL_INTERNAL_ERROR; } } /* first delete everything in the database, because there could be removed components */ if ((ret = dbp->cursor(dbp, tid, &dbcp, DB_DIRTY_READ)) != 0) { tid->abort(tid); if (ret == DB_LOCK_DEADLOCK) { retry++; continue; } else if (ret == DB_RUNRECOVERY) { ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "curor failed"); abort(); } else { ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "curor failed"); /* leave bset->changed set to true */ return ICAL_INTERNAL_ERROR; } } /* fetch the key/data pair, then delete it */ completed = 0; while (!completed && !deadlocked) { ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT); if (ret == DB_NOTFOUND) { completed = 1; } else if (ret == ENOMEM) { if (more_mem) { free(more_mem); } more_mem = malloc(data.ulen + 1024); data.data = more_mem; data.ulen = data.ulen + 1024; } else if (ret == DB_LOCK_DEADLOCK) { deadlocked = 1; } else if (ret == DB_RUNRECOVERY) { tid->abort(tid); ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_get failed."); abort(); } else if (ret == 0) { if ((ret = dbcp->c_del(dbcp, 0)) != 0) { dbp->err(dbp, ret, "cursor"); if (ret == DB_KEYEMPTY) { /* never actually created, continue onward.. */ /* do nothing - break; */ } else if (ret == DB_LOCK_DEADLOCK) { deadlocked = 1; } else { /*char *foo = db_strerror(ret); */ abort(); } } } else { /* some other non-fatal error */ dbcp->c_close(dbcp); tid->abort(tid); if (more_mem) { free(more_mem); more_mem = NULL; } return ICAL_INTERNAL_ERROR; } } if (more_mem) { free(more_mem); more_mem = NULL; } if (deadlocked) { dbcp->c_close(dbcp); tid->abort(tid); retry++; continue; /* next retry */ } deadlocked = 0; for (c = icalcomponent_get_first_component(bset->cluster, ICAL_ANY_COMPONENT); c != 0 && !deadlocked; c = icalcomponent_get_next_component(bset->cluster, ICAL_ANY_COMPONENT)) { memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); /* Note that we're always inserting into a primary index. */ if (icalcomponent_isa(c) != ICAL_VAGENDA_COMPONENT) { char *uidstr = (char *)icalcomponent_get_uid(c); if (!uidstr) { /* this shouldn't happen */ /* no uid string, we need to add one */ snprintf(uidbuf, 256, "baduid%d-%d", getpid(), bad_uid_counter++); key.data = uidbuf; } else { key.data = uidstr; } } else { char *relcalid = NULL; relcalid = (char *)icalcomponent_get_relcalid(c); if (relcalid == NULL) { snprintf(uidbuf, 256, "baduid%d-%d", getpid(), bad_uid_counter++); key.data = uidbuf; } else { key.data = relcalid; } } key.size = (u_int32_t) strlen(key.data); str = icalcomponent_as_ical_string_r(c); data.data = str; data.size = (u_int32_t) strlen(str); if ((ret = dbcp->c_put(dbcp, &key, &data, DB_KEYLAST)) != 0) { if (ret == DB_LOCK_DEADLOCK) { deadlocked = 1; } else if (ret == DB_RUNRECOVERY) { ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_put failed."); abort(); } else { ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_put failed %s.", str); /* continue to try to put as many icalcomponent as possible */ reterr = ICAL_INTERNAL_ERROR; } } } if (str) { free(str); } if (deadlocked) { dbcp->c_close(dbcp); tid->abort(tid); retry++; continue; } if ((ret = dbcp->c_close(dbcp)) != 0) { tid->abort(tid); if (ret == DB_LOCK_DEADLOCK) { retry++; continue; } else if (ret == DB_RUNRECOVERY) { ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_closed failed."); abort(); } else { ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "c_closed failed."); reterr = ICAL_INTERNAL_ERROR; } } if ((ret = tid->commit(tid, 0)) != 0) { tid->abort(tid); if (ret == DB_LOCK_DEADLOCK) { retry++; continue; } else if (ret == DB_RUNRECOVERY) { ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "commit failed."); abort(); } else { ICAL_DB_ENV->err(ICAL_DB_ENV, ret, "commit failed."); reterr = ICAL_INTERNAL_ERROR; } } done = 1; } bset->changed = 0; return reterr; }
void run_xact(DB_ENV *dbenv, DB *db, int offset, int count) { // va_list ap; DBC *dbc; DBT key, data; DB_TXN *tid; int ret; char *s; /* Initialization. */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); int keyPtr; int valPtr; key.data = &keyPtr; key.size = sizeof(int);/*strlen(name);*/ data.data = &valPtr; data.size = sizeof(int); retry: /* Begin the transaction. */ if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) { dbenv->err(dbenv, ret, "DB_ENV->txn_begin"); exit (1); } /* Delete any previously existing item. */ /* switch (ret = db->del(db, tid, &key, 0)) { case 0: case DB_NOTFOUND: break; case DB_LOCK_DEADLOCK: abort(); / * Deadlock: retry the operation. * / if ((ret = tid->abort(tid)) != 0) { dbenv->err(dbenv, ret, "DB_TXN->abort"); exit (1); } goto retry; default: // dbenv->err(dbenv, ret, "db->del: %s", name); abort(); exit (1); } */ /* Create a cursor. */ /* if ((ret = db->cursor(db, tid, &dbc, 0)) != 0) { dbenv->err(dbenv, ret, "db->cursor"); exit (1); } */ int q; /* Count is one for this test */ // assert(count == 1); for(q = offset; q < offset + count; q++) { keyPtr = q+1; valPtr = q; /* switch (ret = db->del(db, tid, &key, 0)) { case 0: case DB_NOTFOUND: break; case DB_LOCK_DEADLOCK: abort(); // Deadlock: retry the operation. if ((ret = tid->abort(tid)) != 0) { dbenv->err(dbenv, ret, "DB_TXN->abort"); exit (1); } goto retry; default: // dbenv->err(dbenv, ret, "db->del: %s", name); abort(); exit (1); } */ // pthread_mutex_lock(&hack); switch (ret = db->put(db, tid, &key, &data, 0)) { case 0: break; case DB_LOCK_DEADLOCK: // va_end(ap); abort(); // Locking should be disabled! /* Deadlock: retry the operation. */ if ((ret = dbc->c_close(dbc)) != 0) { dbenv->err( dbenv, ret, "dbc->c_close"); exit (1); } if ((ret = tid->abort(tid)) != 0) { dbenv->err(dbenv, ret, "DB_TXN->abort"); exit (1); } goto retry; default: /* Error: run recovery. */ dbenv->err(dbenv, ret, "dbc->put: %d/%d", q, q); abort(); // Error invalidates benchmark! exit (1); } // pthread_mutex_unlock(&hack); putCount++; } if ((ret = tid->commit(tid, 0)) != 0) { dbenv->err(dbenv, ret, "DB_TXN->commit"); exit (1); } commitCount++; #ifdef DEBUG_BDB printf("Called commit\n"); #endif }
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); }
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); }
/* 批量插入示例函数。*/ 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); }
/* * 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 add_cat(DB_ENV *dbenv, DB *db, char *name, ...) { va_list ap; DBC *dbc; DBT key, data; DB_TXN *tid; int ret; char *s; /* Initialization. */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); key.data = name; key.size = strlen(name); retry: /* Begin the transaction. */ if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) { dbenv->err(dbenv, ret, "DB_ENV->txn_begin"); exit (1); } /* Delete any previously existing item. */ switch (ret = db->del(db, tid, &key, 0)) { case 0: case DB_NOTFOUND: break; case DB_LOCK_DEADLOCK: /* Deadlock: retry the operation. */ if ((ret = tid->abort(tid)) != 0) { dbenv->err(dbenv, ret, "DB_TXN->abort"); exit (1); } goto retry; default: dbenv->err(dbenv, ret, "db->del: %s", name); exit (1); } /* Create a cursor. */ if ((ret = db->cursor(db, tid, &dbc, 0)) != 0) { dbenv->err(dbenv, ret, "db->cursor"); exit (1); } /* Append the items, in order. */ va_start(ap, name); while ((s = va_arg(ap, char *)) != NULL) { data.data = s; data.size = strlen(s); switch (ret = dbc->c_put(dbc, &key, &data, DB_KEYLAST)) { case 0: break; case DB_LOCK_DEADLOCK: va_end(ap); /* Deadlock: retry the operation. */ if ((ret = dbc->c_close(dbc)) != 0) { dbenv->err( dbenv, ret, "dbc->c_close"); exit (1); } if ((ret = tid->abort(tid)) != 0) { dbenv->err(dbenv, ret, "DB_TXN->abort"); exit (1); } goto retry; default: /* Error: run recovery. */ dbenv->err(dbenv, ret, "dbc->put: %s/%s", name, s); exit (1); } } va_end(ap); /* Success: commit the change. */ if ((ret = dbc->c_close(dbc)) != 0) { dbenv->err(dbenv, ret, "dbc->c_close"); exit (1); } if ((ret = tid->commit(tid, 0)) != 0) { dbenv->err(dbenv, ret, "DB_TXN->commit"); exit (1); } }
void run_xact(DB_ENV *dbenv, DB *db, int offset, int count) { va_list ap; DBC *dbc; DBT key, data; DB_TXN *tid; int ret; char *s; /* Initialization. */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); int keyPtr; int valPtr; key.data = &keyPtr; key.size = sizeof(int);/*strlen(name);*/ data.data = &valPtr; data.size = sizeof(int); retry: /* Begin the transaction. */ if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) { dbenv->err(dbenv, ret, "DB_ENV->txn_begin"); exit (1); } /* Delete any previously existing item. */ /* switch (ret = db->del(db, tid, &key, 0)) { case 0: case DB_NOTFOUND: break; case DB_LOCK_DEADLOCK: / * Deadlock: retry the operation. * / if ((ret = tid->abort(tid)) != 0) { dbenv->err(dbenv, ret, "DB_TXN->abort"); exit (1); } goto retry; default: dbenv->err(dbenv, ret, "db->del: %s", name); exit (1); } */ /* Create a cursor. */ if ((ret = db->cursor(db, tid, &dbc, 0)) != 0) { dbenv->err(dbenv, ret, "db->cursor"); exit (1); } /* Append the items, in order. */ // va_start(ap, name); // while ((s = va_arg(ap, char *)) != NULL) { int q; for(q = offset; q < offset + count; q++) { keyPtr = q; valPtr = q; /* data.data = s; data.size = strlen(s); */ // printf("A"); fflush(NULL); switch (ret = dbc->c_put(dbc, &key, &data, DB_KEYLAST)) { case 0: // printf("B"); fflush(NULL); break; case DB_LOCK_DEADLOCK: va_end(ap); /* Deadlock: retry the operation. */ if ((ret = dbc->c_close(dbc)) != 0) { dbenv->err( dbenv, ret, "dbc->c_close"); exit (1); } if ((ret = tid->abort(tid)) != 0) { dbenv->err(dbenv, ret, "DB_TXN->abort"); exit (1); } goto retry; default: /* Error: run recovery. */ dbenv->err(dbenv, ret, "dbc->put: %d/%d", q, q); exit (1); } } va_end(ap); /* Success: commit the change. */ if ((ret = dbc->c_close(dbc)) != 0) { dbenv->err(dbenv, ret, "dbc->c_close"); exit (1); } if ((ret = tid->commit(tid, 0)) != 0) { dbenv->err(dbenv, ret, "DB_TXN->commit"); exit (1); } }
void add_color(DB_ENV *dbenv, DB *dbp, char *color, int increment) { DBT key, data; DB_TXN *tid; int original, ret; char buf[64]; /* Initialization. */ memset(&key, 0, sizeof(key)); key.data = color; key.size = strlen(color); memset(&data, 0, sizeof(data)); data.flags = DB_DBT_MALLOC; for (;;) { /* Begin the transaction. */ if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) { dbenv->err(dbenv, ret, "DB_ENV->txn_begin"); exit (1); } /* * Get the key. If it exists, we increment the value. If it * doesn't exist, we create it. */ switch (ret = dbp->get(dbp, tid, &key, &data, 0)) { case 0: original = atoi(data.data); break; case DB_LOCK_DEADLOCK: /* Deadlock: retry the operation. */ if ((ret = tid->abort(tid)) != 0) { dbenv->err(dbenv, ret, "DB_TXN->abort"); exit (1); } continue; case DB_NOTFOUND: original = 0; break; default: /* Error: run recovery. */ dbenv->err( dbenv, ret, "dbc->get: %s/%d", color, increment); exit (1); } if (data.data != NULL) free(data.data); /* Create the new data item. */ (void)snprintf(buf, sizeof(buf), "%d", original + increment); data.data = buf; data.size = strlen(buf) + 1; /* Store the new value. */ switch (ret = dbp->put(dbp, tid, &key, &data, 0)) { case 0: /* Success: commit the change. */ if ((ret = tid->commit(tid, 0)) != 0) { dbenv->err(dbenv, ret, "DB_TXN->commit"); exit (1); } return; case DB_LOCK_DEADLOCK: /* Deadlock: retry the operation. */ if ((ret = tid->abort(tid)) != 0) { dbenv->err(dbenv, ret, "DB_TXN->abort"); exit (1); } break; default: /* Error: run recovery. */ dbenv->err( dbenv, ret, "dbc->put: %s/%d", color, increment); exit (1); } } }
int b_txn(int argc, char *argv[]) { extern char *optarg; extern int optind; DB_ENV *dbenv; DB_TXN *txn; int tabort, ch, i, count; count = 1000; tabort = 0; while ((ch = getopt(argc, argv, "ac:")) != EOF) switch (ch) { case 'a': tabort = 1; break; case 'c': count = atoi(optarg); break; case '?': default: return (usage()); } argc -= optind; argv += optind; if (argc != 0) return (usage()); /* Create the environment. */ DB_BENCH_ASSERT(db_env_create(&dbenv, 0) == 0); dbenv->set_errfile(dbenv, stderr); #if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR < 1 DB_BENCH_ASSERT(dbenv->open(dbenv, TESTDIR, NULL, DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN | DB_PRIVATE, 0666) == 0); #else DB_BENCH_ASSERT(dbenv->open(dbenv, TESTDIR, DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN | DB_PRIVATE, 0666) == 0); #endif /* Start and commit/abort a transaction count times. */ TIMER_START; if (tabort) for (i = 0; i < count; ++i) { #if DB_VERSION_MAJOR < 4 DB_BENCH_ASSERT(txn_begin(dbenv, NULL, &txn, 0) == 0); DB_BENCH_ASSERT(txn_abort(txn) == 0); #else DB_BENCH_ASSERT( dbenv->txn_begin(dbenv, NULL, &txn, 0) == 0); DB_BENCH_ASSERT(txn->abort(txn) == 0); #endif } else for (i = 0; i < count; ++i) { #if DB_VERSION_MAJOR < 4 DB_BENCH_ASSERT(txn_begin(dbenv, NULL, &txn, 0) == 0); DB_BENCH_ASSERT(txn_commit(txn, 0) == 0); #else DB_BENCH_ASSERT( dbenv->txn_begin(dbenv, NULL, &txn, 0) == 0); DB_BENCH_ASSERT(txn->commit(txn, 0) == 0); #endif } TIMER_STOP; printf("# %d empty transaction start/%s pairs\n", count, tabort ? "abort" : "commit"); TIMER_DISPLAY(count); DB_BENCH_ASSERT(dbenv->close(dbenv, 0) == 0); return (0); }
int next_counter(DB_ENV *env, DB *db, DB_TXN *parent, unsigned char *key, u_int32_t key_size, unsigned char *lockid, u_int32_t lockid_size) { DB_LOCK lock; DBT DBTKey, DBTData; DB_TXN *tid; int counter, tries, ret, t_ret, lockheld; u_int32_t id; /* Initialization. */ memset(&lock, 0, sizeof(lock)); memset(&DBTKey, 0, sizeof(DBTKey)); memset(&DBTData, 0, sizeof(DBTData)); DBTKey.data = key; DBTKey.size = key_size; DBTData.data = lockid; DBTData.size = lockid_size; tries = 0; loop: lockheld = 0; /* Begin the transaction. */ if ((ret = env->txn_begin(env, parent, &tid, 0)) != 0) { env->err(env, ret, "DB_ENV->txn_begin"); return (-1); } id = tid->id(tid); if ((ret = env->lock_get(env, id, 0, &DBTData, DB_LOCK_WRITE, &lock)) != 0) goto fail; lockheld = 1; memset(&DBTData, 0, sizeof(DBTData)); DBTData.data = &counter; DBTData.ulen = sizeof(counter); DBTData.flags |= DB_DBT_USERMEM; if ((ret = db->get(db, tid, &DBTKey, &DBTData, 0)) != 0) goto fail; ++counter; memset(&DBTData, 0, sizeof(DBTData)); DBTData.data = &counter; DBTData.size = sizeof(counter); if ((ret = db->put(db, tid, &DBTKey, &DBTData, 0)) != 0) goto fail; if ((ret = env->lock_put(env, &lock)) != 0) goto fail; if ((ret = tid->commit(tid, DB_TXN_NOSYNC)) != 0) { env->err(env, ret, "DB_TXN->commit"); return (-2); } return (counter); fail: if (lockheld) if ((ret = env->lock_put(env, &lock)) != 0) return (-3); /* Abort and retry the operation. */ if ((t_ret = tid->abort(tid)) != 0) { env->err(env, t_ret, "DB_TXN->abort"); return (-4); } if (tries++ == 100) return (-5); goto loop; }
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); }
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; }
// // XXX Figure out the appropriate way to pick out IDs. // int TpcbExample::txn(DB *adb, DB *bdb, DB *tdb, DB *hdb, int accounts, int branches, int tellers) { DBC *acurs, *bcurs, *tcurs; DB_TXN *t; DBT d_dbt, d_histdbt, k_dbt, k_histdbt; db_recno_t key; Defrec rec; Histrec hrec; int account, branch, teller, ret; memset(&d_dbt, 0, sizeof(d_dbt)); memset(&d_histdbt, 0, sizeof(d_histdbt)); memset(&k_dbt, 0, sizeof(k_dbt)); memset(&k_histdbt, 0, sizeof(k_histdbt)); k_histdbt.data = &key; k_histdbt.size = sizeof(key); // !!! // This is sample code -- we could move a lot of this into the driver // to make it faster. // account = randomId(ACCOUNT, accounts, branches, tellers); branch = randomId(BRANCH, accounts, branches, tellers); teller = randomId(TELLER, accounts, branches, tellers); k_dbt.size = sizeof(int); d_dbt.flags |= DB_DBT_USERMEM; d_dbt.data = &rec; d_dbt.ulen = sizeof(rec); hrec.aid = account; hrec.bid = branch; hrec.tid = teller; hrec.amount = 10; // Request 0 bytes since we're just positioning. d_histdbt.flags |= DB_DBT_PARTIAL; // START PER-TRANSACTION TIMING. // // Technically, TPCB requires a limit on response time, you only get // to count transactions that complete within 2 seconds. That's not // an issue for this sample application -- regardless, here's where // the transaction begins. if (dbenv->txn_begin(dbenv, NULL, &t, 0) != 0) goto err; if (adb->cursor(adb, t, &acurs, 0) != 0 || bdb->cursor(bdb, t, &bcurs, 0) != 0 || tdb->cursor(tdb, t, &tcurs, 0) != 0) goto err; // Account record k_dbt.data = &account; if (acurs->get(acurs, &k_dbt, &d_dbt, DB_SET) != 0) goto err; rec.balance += 10; if (acurs->put(acurs, &k_dbt, &d_dbt, DB_CURRENT) != 0) goto err; // Branch record k_dbt.data = &branch; if (bcurs->get(bcurs, &k_dbt, &d_dbt, DB_SET) != 0) goto err; rec.balance += 10; if (bcurs->put(bcurs, &k_dbt, &d_dbt, DB_CURRENT) != 0) goto err; // Teller record k_dbt.data = &teller; if (tcurs->get(tcurs, &k_dbt, &d_dbt, DB_SET) != 0) goto err; rec.balance += 10; if (tcurs->put(tcurs, &k_dbt, &d_dbt, DB_CURRENT) != 0) goto err; // History record d_histdbt.flags = 0; d_histdbt.data = &hrec; d_histdbt.ulen = sizeof(hrec); if (hdb->put(hdb, t, &k_histdbt, &d_histdbt, DB_APPEND) != 0) goto err; if (acurs->close(acurs) != 0 || bcurs->close(bcurs) != 0 || tcurs->close(tcurs) != 0) goto err; ret = t->commit(t, 0); t = NULL; if (ret != 0) goto err; // END PER-TRANSACTION TIMING. return (0); err: if (acurs != NULL) (void)acurs->close(acurs); if (bcurs != NULL) (void)bcurs->close(bcurs); if (tcurs != NULL) (void)tcurs->close(tcurs); if (t != NULL) (void)t->abort(t); return (-1); }
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; }
/* * _Index_init: initialize a new Index object. * * callspec: Index.__init__(env, name) * parameters: * env (Env): A Env object to use as the environment * name (string): The name of the Index * returns: 0 if initialization succeeded, otherwise -1 * exceptions: * terane.outputs.store.backend.Error: failed to create/open the Index */ static int _Index_init (terane_Index *self, PyObject *args, PyObject *kwds) { char *tocname = NULL; DB_TXN *txn = NULL; DB_BTREE_STAT *stats = NULL; int dbret; /* __init__ has already been called, don't repeat initialization */ if (self->env != NULL) return 0; /* parse constructor parameters */ if (!PyArg_ParseTuple (args, "O!O!", &terane_EnvType, &self->env, &PyString_Type, &self->name)) goto error; Py_INCREF (self->env); Py_INCREF (self->name); /* allocate a buffer with the full index toc name */ tocname = PyMem_Malloc (PyString_Size (self->name) + 5); if (tocname == NULL) { PyErr_NoMemory (); goto error; } sprintf (tocname, "%s.toc", PyString_AsString (self->name)); /* wrap db creation in a transaction */ dbret = self->env->env->txn_begin (self->env->env, NULL, &txn, 0); if (dbret != 0) { PyErr_Format (terane_Exc_Error, "Failed to create DB_TXN handle: %s", db_strerror (dbret)); goto error; } /* create the DB handle for the metadata store */ dbret = db_create (&self->metadata, self->env->env, 0); if (dbret != 0) { PyErr_Format (terane_Exc_Error, "Failed to create handle for metadata: %s", db_strerror (dbret)); goto error; } /* set compare function */ self->metadata->set_bt_compare (self->metadata, _terane_msgpack_DB_compare); /* open the metadata store */ dbret = self->metadata->open (self->metadata, txn, tocname, "metadata", DB_BTREE, DB_CREATE | DB_THREAD | DB_MULTIVERSION, 0); if (dbret != 0) { PyErr_Format (terane_Exc_Error, "Failed to open metadata: %s", db_strerror (dbret)); goto error; } /* create the DB handle for the schema store */ dbret = db_create (&self->schema, self->env->env, 0); if (dbret != 0) { PyErr_Format (terane_Exc_Error, "Failed to create handle for schema: %s", db_strerror (dbret)); goto error; } /* set compare function */ self->schema->set_bt_compare (self->schema, _terane_msgpack_DB_compare); /* open the schema store */ dbret = self->schema->open (self->schema, txn, tocname, "schema", DB_BTREE, DB_CREATE | DB_THREAD | DB_MULTIVERSION, 0); if (dbret != 0) { PyErr_Format (terane_Exc_Error, "Failed to open schema: %s", db_strerror (dbret)); goto error; } /* get an initial count of fields */ dbret = self->schema->stat (self->schema, txn, &stats, 0); if (dbret != 0) { if (stats) PyMem_Free (stats); PyErr_Format (terane_Exc_Error, "Failed to get field count: %s", db_strerror (dbret)); goto error; } self->nfields = (unsigned long) stats->bt_nkeys; if (stats) PyMem_Free (stats); stats = NULL; /* create the DB handle for the segments store */ dbret = db_create (&self->segments, self->env->env, 0); if (dbret != 0) { PyErr_Format (terane_Exc_Error, "Failed to create handle for segments: %s", db_strerror (dbret)); goto error; } /* open the segments store */ dbret = self->segments->open (self->segments, txn, tocname, "segments", DB_BTREE, DB_CREATE | DB_THREAD | DB_MULTIVERSION, 0); if (dbret != 0) { PyErr_Format (terane_Exc_Error, "Failed to open segments: %s", db_strerror (dbret)); goto error; } /* commit new databases */ dbret = txn->commit (txn, 0); if (dbret != 0) { PyErr_Format (terane_Exc_Error, "Failed to commit transaction: %s", db_strerror (dbret)); goto error; } PyMem_Free (tocname); return 0; /* if there is an error, then free any locally allocated memory and references */ error: if (txn != NULL) txn->abort (txn); if (tocname != NULL) PyMem_Free (tocname); if (self) _Index_dealloc ((terane_Index *) self); return -1; }
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; }
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; }
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; }
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); }
void CBDB_Env::JoinEnv(const string& db_home, TEnvOpenFlags opt, ETransactionDiscovery trans_test) { int flag = DB_JOINENV; if (opt & eThreaded) { flag |= DB_THREAD; } Open(db_home, flag); switch (trans_test) { case eTestTransactions: {{ // Check if we joined the transactional environment // Try to create a fake transaction to test the environment DB_TXN* txn = 0; int ret = m_Env->txn_begin(m_Env, 0, &txn, 0); if (ret == 0) { m_Transactional = true; ret = txn->abort(txn); } }} break; case eInspectTransactions: {{ // Check if we joined the transactional environment Uint4 flags = 0; int ret = m_Env->get_open_flags(m_Env, &flags); BDB_CHECK(ret, "DB_ENV::get_open_flags"); if (flags & DB_INIT_TXN) { m_Transactional = true; } else { m_Transactional = false; } }} break; case eAssumeTransactions: m_Transactional = true; break; case eAssumeNoTransactions: m_Transactional = false; break; default: _ASSERT(0); } // commented since it caused crash on windows trying to free // txn_statp structure. (Why it happened remains unknown) /* DB_TXN_STAT *txn_statp = 0; int ret = m_Env->txn_stat(m_Env, &txn_statp, 0); if (ret == 0) { ::free(txn_statp); txn_statp = 0; // Try to create a fake transaction to test the environment DB_TXN* txn = 0; ret = m_Env->txn_begin(m_Env, 0, &txn, 0); if (ret == 0) { m_Transactional = true; ret = txn->abort(txn); } } */ }