static la_storage_object_put_result bdb_la_storage_replace(la_storage_object_store *store, la_storage_object *obj) { DB_TXN *txn; la_storage_object_header header; DBT db_key; DBT db_value; int result; memset(&db_key, 0, sizeof(DBT)); memset(&db_value, 0, sizeof(DBT)); db_key.data = obj->key; db_key.size = db_key.ulen = (uint32_t) strlen(obj->key); db_key.flags = DB_DBT_USERMEM; db_value.data = obj->header; db_value.size = db_value.ulen = la_storage_object_total_size(obj); db_value.flags = DB_DBT_USERMEM; if (txn_begin(store->env->env, NULL, &txn, DB_TXN_NOSYNC | DB_TXN_NOWAIT) != 0) return LA_STORAGE_OBJECT_PUT_ERROR; db_seq_t seq; store->seq->get(store->seq, txn, 1, &seq, 0); obj->header->seq = seq; if (store->db->put(store->db, txn, &db_key, &db_value, 0) != 0) { txn_abort(txn); return LA_STORAGE_OBJECT_PUT_ERROR; } txn_commit(txn, DB_TXN_NOSYNC); return LA_STORAGE_OBJECT_PUT_SUCCESS; }
int edb_txn_abort(edb *db) { LOG_HERE; int err = 0; CHECK_CODE(db->readonly == 0, EDB_ERROR_READ_ONLY); CHECK(txn_abort(db)); err: return err; }
static int bdb_la_storage_stat(la_storage_object_store *store, la_storage_stat_t *stat) { DB_TXN *txn; DB_BTREE_STAT *mainStat, *seqStat; if (txn_begin(store->env->env, NULL, &txn, DB_READ_COMMITTED | DB_TXN_NOSYNC) != 0) return -1; if (store->db->stat(store->db, txn, &mainStat, DB_FAST_STAT | DB_READ_COMMITTED) != 0) { txn_abort(txn); return -1; } if (store->db->stat(store->seq_db, txn, &seqStat, DB_FAST_STAT | DB_READ_COMMITTED) != 0) { txn_abort(txn); return -1; } stat->numkeys = mainStat->bt_nkeys; stat->size = ((uint64_t) mainStat->bt_pagecnt * (uint64_t) mainStat->bt_pagesize) + ((uint64_t) seqStat->bt_pagecnt * (uint64_t) seqStat->bt_pagesize); free(mainStat); free(seqStat); txn_commit(txn, DB_TXN_NOSYNC); return 0; }
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 ofcds_copyconfig(void *UNUSED(data), NC_DATASTORE target, NC_DATASTORE source, char *config, struct nc_err **error) { int ret = EXIT_FAILURE; char *s; xmlDocPtr src_doc = NULL; xmlDocPtr dst_doc = NULL; xmlNodePtr root; static const char *ds[] = {"error", "<config>", "URL", "running", "startup", "candidate"}; nc_verb_verbose("OFC COPY-CONFIG (from %s to %s)", ds[source], ds[target]); switch (source) { case NC_DATASTORE_RUNNING: s = ofcds_getconfig(NULL, NC_DATASTORE_RUNNING, error); if (!s) { nc_verb_error ("copy-config: unable to get running source repository"); return EXIT_FAILURE; } src_doc = xmlReadMemory(s, strlen(s), NULL, NULL, XML_READ_OPT); free(s); if (!src_doc) { nc_verb_error("copy-config: invalid running source data"); *error = nc_err_new(NC_ERR_OP_FAILED); nc_err_set(*error, NC_ERR_PARAM_INFO_BADELEM, "invalid running source data"); return EXIT_FAILURE; } break; case NC_DATASTORE_STARTUP: src_doc = xmlCopyDoc(gds_startup, 1); break; case NC_DATASTORE_CANDIDATE: src_doc = xmlCopyDoc(gds_cand, 1); break; case NC_DATASTORE_CONFIG: if (config && strlen(config) > 0) { src_doc = xmlReadMemory(config, strlen(config), NULL, NULL, XML_READ_OPT); } if (!config || (strlen(config) > 0 && !src_doc)) { nc_verb_error("Invalid source configuration data."); *error = nc_err_new(NC_ERR_BAD_ELEM); nc_err_set(*error, NC_ERR_PARAM_INFO_BADELEM, "config"); return EXIT_FAILURE; } break; default: nc_verb_error("Invalid <get-config> source."); *error = nc_err_new(NC_ERR_BAD_ELEM); nc_err_set(*error, NC_ERR_PARAM_INFO_BADELEM, "source"); return EXIT_FAILURE; } switch (target) { case NC_DATASTORE_RUNNING: /* apply source to OVSDB */ s = ofcds_getconfig(NULL, NC_DATASTORE_RUNNING, error); if (!s) { nc_verb_error("copy-config: unable to get running source data"); goto cleanup; } dst_doc = xmlReadMemory(s, strlen(s), NULL, NULL, XML_READ_OPT); free(s); root = xmlDocGetRootElement(src_doc); if (!dst_doc) { /* create envelope */ dst_doc = xmlNewDoc(BAD_CAST "1.0"); } if (!rollbacking) { store_rollback(xmlCopyDoc(dst_doc, 1), target); } txn_init(); if (edit_replace(dst_doc, root, 1, error)) { txn_abort(); } else { ret = txn_commit(error); } xmlFreeDoc(dst_doc); goto cleanup; break; case NC_DATASTORE_STARTUP: case NC_DATASTORE_CANDIDATE: /* create copy */ if (src_doc) { dst_doc = src_doc; src_doc = NULL; } /* store the copy */ if (target == NC_DATASTORE_STARTUP) { if (!rollbacking) { store_rollback(gds_startup, target); } else { xmlFreeDoc(gds_startup); } gds_startup = dst_doc; } else { /* NC_DATASTORE_CANDIDATE */ if (!rollbacking) { store_rollback(gds_cand, target); } else { xmlFreeDoc(gds_cand); } gds_cand = dst_doc; } break; default: nc_verb_error("Invalid <get-config> source."); *error = nc_err_new(NC_ERR_BAD_ELEM); nc_err_set(*error, NC_ERR_PARAM_INFO_BADELEM, "source"); goto cleanup; } ret = EXIT_SUCCESS; cleanup: xmlFreeDoc(src_doc); return ret; }
int ofcds_editconfig(void *UNUSED(data), const nc_rpc * UNUSED(rpc), NC_DATASTORE target, const char *config, NC_EDIT_DEFOP_TYPE defop, NC_EDIT_ERROPT_TYPE UNUSED(errop), struct nc_err **error) { int ret = EXIT_FAILURE, running = 0; char *aux; int cfgds_new = 0; xmlDocPtr cfgds = NULL, cfg = NULL, cfg_clone = NULL; xmlNodePtr rootcfg; if (defop == NC_EDIT_DEFOP_NOTSET) { defop = NC_EDIT_DEFOP_MERGE; } cfg = xmlReadMemory(config, strlen(config), NULL, NULL, XML_READ_OPT); rootcfg = xmlDocGetRootElement(cfg); if (!cfg || (rootcfg && !xmlStrEqual(rootcfg->name, BAD_CAST "capable-switch"))) { nc_verb_error("Invalid <edit-config> configuration data."); *error = nc_err_new(NC_ERR_BAD_ELEM); nc_err_set(*error, NC_ERR_PARAM_INFO_BADELEM, "config"); return EXIT_FAILURE; } switch (target) { case NC_DATASTORE_RUNNING: /* Make a copy of parsed config - we will find port/configuration in * it. It is used after txn_commit(). */ cfg_clone = xmlCopyDoc(cfg, 1); aux = ofc_get_config_data(); if (!aux) { *error = nc_err_new(NC_ERR_OP_FAILED); goto error_cleanup; } cfgds = xmlReadMemory(aux, strlen(aux), NULL, NULL, XML_READ_OPT); free(aux); running = 1; break; case NC_DATASTORE_STARTUP: cfgds = gds_startup; break; case NC_DATASTORE_CANDIDATE: cfgds = gds_cand; break; default: nc_verb_error("Invalid <edit-config> target."); *error = nc_err_new(NC_ERR_BAD_ELEM); nc_err_set(*error, NC_ERR_PARAM_INFO_BADELEM, "target"); goto error_cleanup; } store_rollback(xmlCopyDoc(cfgds, 1), target); /* check keys in config's lists */ ret = check_keys(cfg, error); if (ret != EXIT_SUCCESS) { goto error_cleanup; } /* check operations */ ret = check_edit_ops(NC_EDIT_OP_DELETE, defop, cfgds, cfg, error); if (ret != EXIT_SUCCESS) { goto error_cleanup; } ret = check_edit_ops(NC_EDIT_OP_CREATE, defop, cfgds, cfg, error); if (ret != EXIT_SUCCESS) { goto error_cleanup; } if (target == NC_DATASTORE_RUNNING) { txn_init(); } ret = compact_edit_operations(cfg, defop); if (ret != EXIT_SUCCESS) { nc_verb_error("Compacting edit-config operations failed."); if (error != NULL) { *error = nc_err_new(NC_ERR_OP_FAILED); } goto error_cleanup; } /* perform operations */ if (!cfgds) { cfgds_new = 1; cfgds = xmlNewDoc(BAD_CAST "1.0"); } ret = edit_operations(cfgds, cfg, defop, running, error); if (ret != EXIT_SUCCESS) { goto error_cleanup; } /* with defaults capability */ if (ncdflt_get_basic_mode() == NCWD_MODE_TRIM) { /* server work in trim basic mode and therefore all default values * must be removed from the datastore. */ /* TODO */ } if (target == NC_DATASTORE_RUNNING) { ret = txn_commit(error); if (ret == EXIT_SUCCESS) { /* modify port/configuration of ports that were created */ ret = of_post_ports(xmlDocGetRootElement(cfg_clone), error); } /* config clone was used and it is not needed by now */ xmlFreeDoc(cfg_clone); xmlFreeDoc(cfgds); } else if (cfgds_new){ if (cfgds->children) { /* document changed, because we started with empty document */ if (target == NC_DATASTORE_STARTUP) { gds_startup = cfgds; cfgds = NULL; } else if (target == NC_DATASTORE_CANDIDATE) { gds_cand = cfgds; cfgds = NULL; } } xmlFreeDoc(cfgds); } xmlFreeDoc(cfg); return ret; error_cleanup: if (target == NC_DATASTORE_RUNNING) { txn_abort(); xmlFreeDoc(cfg_clone); xmlFreeDoc(cfgds); } xmlFreeDoc(cfg); return ret; }
db_t db_init(const size_t size, const char * const path, const int flags, const int mode, int mdb_flags, int ndbi, dbi_t *dbis, size_t padsize){ int fd = -1, err = 0xdeadbeef; struct stat st; db_t db; db = malloc(size < sizeof(*db) ? sizeof(*db) : size); assert(db); // always do this mdb_flags |= MDB_NOSUBDIR; int r; // ignore MDB_RDONLY - key off of OS flags // see docs for open() - O_RDONLY is not a bit! if((flags & 0x3) == O_RDONLY){ mdb_flags |= MDB_RDONLY; // disable NOSYNC/NOMETASYNC for readonly, as that burns another file descriptor mdb_flags &= ~(MDB_NOSYNC|MDB_NOMETASYNC); }else{ mdb_flags &= ~MDB_RDONLY; } // default to 100mb minimum pad db->padsize = padsize ? padsize : (1<<27); db->env = NULL; db->txns = 0; db->handles = NULL; db->updated = 0; r = pthread_mutex_init(&db->mutex, NULL); FAIL(r, err, errno, fail); r = pthread_cond_init(&db->cond, NULL); FAIL(r, err, errno, fail); // unless MDB_RDONLY is specified, lmdb will automatically create non-existant databases, // which is not what I want. Try to emulate standard unix open() flags: fd = open(path, flags, mode); FAIL(-1 == fd, err, errno, fail); r = mdb_env_create(&db->env); FAIL(r, err, r, fail); r = mdb_env_set_maxdbs(db->env, ndbi); FAIL(r, err, r, fail); size_t mapsize; do{ r = fstat(fd, &st); FAIL(r, err, errno, fail); if(!st.st_size &&( flags & O_CREAT)) db->updated = 1; // pad out such that we have at least 1gb of map overhead mapsize = (1 + st.st_size / db->padsize) * db->padsize; r = mdb_env_set_mapsize(db->env, mapsize); }while(MDB_SUCCESS != r); close(fd); fd = -1; r = mdb_env_open(db->env, path, mdb_flags, mode); // mdb_env_open can return EAGAIN somehow, but I think it really means: if(EAGAIN == r) r = EMFILE; FAIL(r, err, r, fail); r = mdb_env_get_fd(db->env, &db->fd); FAIL(r, err, r, fail); if(dbis && ndbi){ db->handles = malloc(sizeof(db->handles[0]) * ndbi); FAIL(!db->handles, err, errno, fail); // open the indexes - try read-only first unsigned int txn_flags = MDB_RDONLY; txn_t txn = db_txn_new(db, NULL, txn_flags); int i; for(i = 0; i < ndbi; i++){ int dbflags = dbis[i].flags; retry: dbflags = (txn_flags & MDB_RDONLY) ? (dbflags & ~MDB_CREATE) : (dbflags | MDB_CREATE); r = mdb_dbi_open(txn->txn, dbis[i].name, dbflags, &db->handles[i]); if(MDB_SUCCESS != r){ if(MDB_NOTFOUND == r && (txn_flags & MDB_RDONLY)){ // we were in read-only and a sub-db was missing // end txn txn_commit(txn); // switch to read-write txn_flags &= ~MDB_RDONLY; txn = db_txn_new(db, NULL, txn_flags); // and pick up where we left off goto retry; }else{ txn_abort(txn); } FAIL(r, err, r, fail); } } r = txn_commit(txn); FAIL(r, err, r, fail); } return db; fail: db_close(db); if(fd != -1){ if((flags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) unlink(path); close(fd); } errno = err; return NULL; }
/** * Put an object into the store. */ static la_storage_object_put_result bdb_la_storage_put(la_storage_object_store *store, const la_storage_rev_t *rev, la_storage_object *obj) { DB_TXN *txn; la_storage_object_header header; DBT db_key; DBT db_value_read, db_value_write; int result; #if DEBUG printf("putting %u bytes:\n", obj->data_length); la_hexdump(la_storage_object_get_data(obj), obj->data_length); #endif memset(&db_key, 0, sizeof(DBT)); memset(&db_value_read, 0, sizeof(DBT)); memset(&db_value_write, 0, sizeof(DBT)); db_key.data = obj->key; db_key.size = (u_int32_t) strlen(obj->key); db_key.ulen = (u_int32_t) strlen(obj->key); db_key.flags = DB_DBT_USERMEM; db_value_read.data = &header; db_value_read.ulen = sizeof(la_storage_object_header); db_value_read.dlen = sizeof(la_storage_object_header); db_value_read.doff = 0; db_value_read.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; if (txn_begin(store->env->env, NULL, &txn, DB_TXN_NOSYNC | DB_TXN_NOWAIT) != 0) return LA_STORAGE_OBJECT_PUT_ERROR; result = store->db->get(store->db, txn, &db_key, &db_value_read, DB_RMW); if (result != 0 && result != DB_NOTFOUND) { txn_abort(txn); if (result == DB_LOCK_NOTGRANTED) return LA_STORAGE_OBJECT_PUT_CONFLICT; return LA_STORAGE_OBJECT_PUT_ERROR; } if (result != DB_NOTFOUND) { debug("data size: %d, data: %s\n", db_value_read.size, db_value_read.data); if (rev == NULL || memcmp(rev, &header.rev, sizeof(la_storage_rev_t)) != 0) { txn_abort(txn); return LA_STORAGE_OBJECT_PUT_CONFLICT; } obj->header->doc_seq = header.doc_seq + 1; if (header.rev_count < LA_OBJECT_MAX_REVISION_COUNT) { obj->header = realloc(obj->header, la_storage_object_total_size(obj) + sizeof(la_storage_rev_t)); // If we added a revision, move the object data up to make room. memmove(la_storage_object_get_data(obj) + sizeof(la_storage_rev_t), la_storage_object_get_data(obj), obj->data_length); obj->header->rev_count = header.rev_count + 1; } // Move the rev_count-1 previous revisons over... memmove(obj->header->revs_data + sizeof(la_storage_rev_t), obj->header->revs_data, sizeof(la_storage_rev_t) * (obj->header->rev_count - 1)); // Copy the previous revision in. memcpy(obj->header->revs_data, &header.rev, sizeof(la_storage_rev_t)); #if DEBUG printf("After moving data and revisions:\nOld revisions:\n"); la_hexdump(obj->header->revs_data, obj->header->rev_count * sizeof(la_storage_rev_t)); printf("data:\n"); la_hexdump(la_storage_object_get_data(obj), obj->data_length); #endif } else { obj->header->doc_seq = 1; obj->header->rev_count = 0; } db_seq_t seq; store->seq->get(store->seq, txn, 1, &seq, 0); obj->header->seq = seq; db_value_write.size = (u_int32_t) la_storage_object_total_size(obj); db_value_write.ulen = (u_int32_t) la_storage_object_total_size(obj); db_value_write.data = obj->header; db_value_write.flags = DB_DBT_USERMEM; debug("putting { size: %u, ulen: %u, data: %s, flags: %x }\n", db_value_write.size, db_value_write.ulen, db_value_write.data, db_value_write.flags); result = store->db->put(store->db, txn, &db_key, &db_value_write, 0); if (result != 0) { txn_abort(txn); return LA_STORAGE_OBJECT_PUT_ERROR; } txn_commit(txn, DB_TXN_NOSYNC); return LA_STORAGE_OBJECT_PUT_SUCCESS; }
static la_storage_object_put_result bdb_la_storage_set_revs(la_storage_object_store *store, const char *key, la_storage_rev_t *revs, size_t revcount) { DB_TXN *txn; DBT db_key; DBT db_value; int result; la_storage_object object; int shift; revcount = la_min(revcount, LA_OBJECT_MAX_REVISION_COUNT); memset(&db_key, 0, sizeof(DBT)); memset(&db_value, 0, sizeof(DBT)); db_key.data = key; db_key.size = strlen(key); db_key.ulen = strlen(key); db_key.flags = DB_DBT_USERMEM; db_value.data = NULL; db_value.ulen = 0; db_value.flags = DB_DBT_MALLOC; if (txn_begin(store->env->env, NULL, &txn, DB_TXN_NOSYNC | DB_TXN_NOWAIT) != 0) return LA_STORAGE_OBJECT_PUT_ERROR; result = store->db->get(store->db, txn, &db_key, &db_value, DB_RMW); if (result != 0) { txn_abort(txn); if (result == DB_LOCK_NOTGRANTED) return LA_STORAGE_OBJECT_PUT_CONFLICT; return LA_STORAGE_OBJECT_PUT_ERROR; } object.header = (la_storage_object_header *) db_value.data; object.data_length = db_value.size - sizeof(la_storage_object_header) - (object.header->rev_count * sizeof(la_storage_rev_t)); shift = revcount - object.header->rev_count; if (shift > 0) { object.header = realloc(object.header, db_value.size + shift); if (object.header == NULL) { free(object.header); return LA_STORAGE_OBJECT_PUT_ERROR; } } memmove(la_storage_object_get_data(&object) + shift, la_storage_object_get_data(&object), object.data_length); memcpy(object.header->revs_data, revs, revcount * sizeof(la_storage_rev_t)); db_value.data = object.header; db_value.size = db_value.size + shift; db_value.ulen = db_value.size; db_value.flags = DB_DBT_USERMEM; result = store->db->put(store->db, txn, &db_key, &db_value, 0); free(db_value.data); if (result != 0) { txn_abort(txn); return LA_STORAGE_OBJECT_PUT_ERROR; } txn_commit(txn, DB_TXN_NOSYNC); return 0; }
static int bdb_la_storage_object_store_delete(la_storage_object_store *store) { const char *dbname; const char *seqdbname; const char *home; const char *parts[2]; DB_TXN *txn; DB_ENV *env = store->env->env; int ret; if ((ret = store->db->get_dbname(store->db, &dbname, NULL)) != 0) { syslog(LOG_NOTICE, "could not get main db name: %d", ret); return -1; } if ((ret = store->db->get_dbname(store->seq_db, &seqdbname, NULL)) != 0) { syslog(LOG_NOTICE, "could not get sequence db name: %d", ret); return -1; } if ((ret = env->get_home(env, &home)) != 0) { syslog(LOG_NOTICE, "could not get db home %d", ret); return -1; } parts[0] = home; parts[1] = dbname; dbname = string_join("/", parts, 2); parts[1] = seqdbname; seqdbname = string_join("/", parts, 2); syslog(LOG_NOTICE, "deleting db %s and sequence db %s", dbname, seqdbname); la_storage_close(store); if ((ret = txn_begin(env, NULL, &txn, DB_TXN_NOWAIT | DB_TXN_WRITE_NOSYNC)) != 0) { syslog(LOG_NOTICE, "delete db begin transaction %d", ret); free(dbname); free(seqdbname); return -1; } syslog(LOG_NOTICE, "env %p txn %p home %s name %s", env, txn, home, dbname); if ((ret = env->dbremove(env, txn, dbname, NULL, 0)) != 0) { syslog(LOG_NOTICE, "deleting main DB: %d", ret); txn_abort(txn); return -1; } syslog(LOG_NOTICE, "env %p txn %p home %s name %s", env, txn, home, seqdbname); if ((ret = env->dbremove(env, txn, seqdbname, NULL, 0)) != 0) { syslog(LOG_NOTICE, "deleting sequence DB: %d", ret); txn_abort(txn); return -1; } txn_commit(txn, DB_TXN_NOSYNC); return 0; }
static la_storage_open_result_t bdb_la_storage_open(la_storage_env *env, const char *path, int flags, la_storage_object_store **_store) { la_storage_object_store *store = (la_storage_object_store *) malloc(sizeof(struct la_storage_object_store)); DB_TXN *txn; char *seqpath; DBT seq_key; char seq_name[4]; int dbflags; int ret; if (store == NULL) return LA_STORAGE_OPEN_ERROR; store->env = env; if (txn_begin(env->env, NULL, &txn, DB_TXN_WRITE_NOSYNC) != 0) { free(store); return LA_STORAGE_OPEN_ERROR; } if (db_create(&store->db, env->env, 0) != 0) { txn_abort(txn); free(store); return LA_STORAGE_OPEN_ERROR; } if (db_create(&store->seq_db, env->env, 0) != 0) { txn_abort(txn); free(store); return LA_STORAGE_OPEN_ERROR; } dbflags = 0; if (flags & LA_STORAGE_OPEN_FLAG_CREATE) dbflags = DB_CREATE; if (flags & LA_STORAGE_OPEN_FLAG_EXCL) dbflags |= DB_EXCL; if ((ret = store->db->open(store->db, txn, path, NULL, DB_BTREE, dbflags | DB_MULTIVERSION | DB_THREAD, 0)) != 0) { txn_abort(txn); free(store); if (ret == EEXIST) return LA_STORAGE_OPEN_EXISTS; if (ret == ENOENT) return LA_STORAGE_OPEN_NOT_FOUND; return LA_STORAGE_OPEN_ERROR; } seqpath = string_append(path, ".seq"); if (seqpath == NULL) { store->db->close(store->db, 0); txn_abort(txn); free(store); return LA_STORAGE_OPEN_ERROR; } if (store->seq_db->set_bt_compare(store->seq_db, compare_seq) != 0) { store->db->close(store->db, 0); txn_abort(txn); free(store); return LA_STORAGE_OPEN_ERROR; } if (store->seq_db->open(store->seq_db, txn, seqpath, NULL, DB_BTREE, DB_CREATE | DB_THREAD, 0) != 0) { free(seqpath); store->db->close(store->db, 0); txn_abort(txn); free(store); return LA_STORAGE_OPEN_ERROR; } free(seqpath); store->db->associate(store->db, txn, store->seq_db, seqindex, 0); if (db_sequence_create(&store->seq, store->db, 0) != 0) { store->seq_db->close(store->seq_db, 0); store->db->close(store->db, 0); txn_abort(txn); free(store); return LA_STORAGE_OPEN_ERROR; } store->seq->initial_value(store->seq, 1); seq_name[0] = '\0'; seq_name[1] = 'S'; seq_name[2] = 'E'; seq_name[3] = 'Q'; seq_key.data = seq_name; seq_key.size = 4; seq_key.ulen = 4; seq_key.flags = DB_DBT_USERMEM; if (store->seq->open(store->seq, txn, &seq_key, DB_CREATE | DB_THREAD) != 0) { store->seq_db->close(store->seq_db, 0); store->db->close(store->db, 0); txn_abort(txn); free(store); return LA_STORAGE_OPEN_ERROR; } txn_commit(txn, DB_TXN_NOSYNC); *_store = store; if ((flags & (LA_STORAGE_OPEN_FLAG_CREATE|LA_STORAGE_OPEN_FLAG_EXCL)) == (LA_STORAGE_OPEN_FLAG_CREATE|LA_STORAGE_OPEN_FLAG_EXCL)) return LA_STORAGE_OPEN_CREATED; return LA_STORAGE_OPEN_OK; }