// // 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 = NULL; Dbc *bcurs = NULL; Dbc *tcurs = NULL; DbTxn *t = NULL; db_recno_t key; Defrec rec; Histrec hrec; int account, branch, teller; Dbt d_dbt; Dbt d_histdbt; Dbt k_dbt; Dbt k_histdbt(&key, sizeof(key)); // // XXX We could move a lot of this into the driver to make this // faster. // account = random_id(ACCOUNT, accounts, branches, tellers); branch = random_id(BRANCH, accounts, branches, tellers); teller = random_id(TELLER, accounts, branches, tellers); k_dbt.set_size(sizeof(int)); d_dbt.set_flags(DB_DBT_USERMEM); d_dbt.set_data(&rec); d_dbt.set_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.set_flags(DB_DBT_PARTIAL); // START TIMING if (txn_begin(NULL, &t, 0) != 0) goto err; if (adb->cursor(t, &acurs, 0) != 0 || bdb->cursor(t, &bcurs, 0) != 0 || tdb->cursor(t, &tcurs, 0) != 0) goto err; // Account record k_dbt.set_data(&account); if (acurs->get(&k_dbt, &d_dbt, DB_SET) != 0) goto err; rec.balance += 10; if (acurs->put(&k_dbt, &d_dbt, DB_CURRENT) != 0) goto err; // Branch record k_dbt.set_data(&branch); if (bcurs->get(&k_dbt, &d_dbt, DB_SET) != 0) goto err; rec.balance += 10; if (bcurs->put(&k_dbt, &d_dbt, DB_CURRENT) != 0) goto err; // Teller record k_dbt.set_data(&teller); if (tcurs->get(&k_dbt, &d_dbt, DB_SET) != 0) goto err; rec.balance += 10; if (tcurs->put(&k_dbt, &d_dbt, DB_CURRENT) != 0) goto err; // History record d_histdbt.set_flags(0); d_histdbt.set_data(&hrec); d_histdbt.set_ulen(sizeof(hrec)); if (hdb->put(t, &k_histdbt, &d_histdbt, DB_APPEND) != 0) goto err; if (acurs->close() != 0 || bcurs->close() != 0 || tcurs->close() != 0) goto err; if (t->commit(0) != 0) goto err; // END TIMING return (0); err: if (acurs != NULL) (void)acurs->close(); if (bcurs != NULL) (void)bcurs->close(); if (tcurs != NULL) (void)tcurs->close(); if (t != NULL) (void)t->abort(); if (verbose) cout << "Transaction A=" << (long)account << " B=" << (long)branch << " T=" << (long)teller << " failed\n"; return (-1); }
static int run(const Ice::StringSeq& originalArgs, const Ice::CommunicatorPtr& communicator, const FreezeScript::CompactIdResolverIPtr& resolver) { vector<string> cppArgs; bool debug; bool ice = true; // Needs to be true in order to create default definitions. bool underscore; string outputFile; string inputFile; vector<string> slice; bool evictor; string keyTypeName; string valueTypeName; string selectExpr; string dbEnvName, dbName; const string appName = originalArgs[0]; IceUtilInternal::Options opts; opts.addOpt("h", "help"); opts.addOpt("v", "version"); opts.addOpt("D", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); opts.addOpt("U", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); opts.addOpt("I", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); opts.addOpt("d", "debug"); opts.addOpt("", "ice"); opts.addOpt("", "underscore"); opts.addOpt("o", "", IceUtilInternal::Options::NeedArg); opts.addOpt("f", "", IceUtilInternal::Options::NeedArg); opts.addOpt("", "load", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); opts.addOpt("e"); opts.addOpt("", "key", IceUtilInternal::Options::NeedArg); opts.addOpt("", "value", IceUtilInternal::Options::NeedArg); opts.addOpt("", "select", IceUtilInternal::Options::NeedArg); opts.addOpt("c", "catalog"); vector<string> args; try { args = opts.parse(originalArgs); } catch(const IceUtilInternal::BadOptException& e) { cerr << appName << ": " << e.reason << endl; usage(appName); return EXIT_FAILURE; } // // Freeze creates a lock file by default to prevent multiple processes from opening // the same database environment simultaneously. In the case of a read-only program // such as dumpdb, however, we still want to be able to open the environment despite // the lock. This assumes of course that the other process has opened the environment // with DbPrivate=0. If DbPrivate=0 is also set for dumpdb, we disable the lock. // if(!args.empty()) { // // If an argument is present, we assume it is the name of the database environment. // Ice::PropertiesPtr props = communicator->getProperties(); string prefix = "Freeze.DbEnv." + args[0]; if(props->getPropertyAsIntWithDefault(prefix + ".DbPrivate", 1) <= 0) { props->setProperty(prefix + ".LockFile", "0"); } } if(opts.isSet("h")) { usage(appName); return EXIT_SUCCESS; } if(opts.isSet("version")) { cout << ICE_STRING_VERSION << endl; return EXIT_SUCCESS; } if(opts.isSet("c")) { if(args.empty()) { cerr << appName << ": no database environment specified." << endl; usage(appName); return EXIT_FAILURE; } else if(args.size() > 2) { usage(appName); return EXIT_FAILURE; } try { FreezeScript::CatalogDataMap catalog = FreezeScript::readCatalog(communicator, args[0]); if(args.size() == 1) { if(catalog.empty()) { cout << "Catalog is empty." << endl; } else { cout << "Catalog contents:" << endl; for(FreezeScript::CatalogDataMap::const_iterator p = catalog.begin(); p != catalog.end(); ++p) { cout << endl; printCatalogData(p->first, p->second); } } } else { FreezeScript::CatalogDataMap::const_iterator p = catalog.find(args[1]); if(p == catalog.end()) { cerr << appName << ": database `" << args[1] << "' not found in environment `" << args[0] << "'." << endl; return EXIT_FAILURE; } else { printCatalogData(p->first, p->second); } } return EXIT_SUCCESS; } catch(const FreezeScript::FailureException& ex) { cerr << appName << ": " << ex.reason() << endl; return EXIT_FAILURE; } } if(opts.isSet("D")) { vector<string> optargs = opts.argVec("D"); for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i) { cppArgs.push_back("-D" + *i); } } if(opts.isSet("U")) { vector<string> optargs = opts.argVec("U"); for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i) { cppArgs.push_back("-U" + *i); } } if(opts.isSet("I")) { vector<string> optargs = opts.argVec("I"); for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i) { cppArgs.push_back("-I" + *i); } } debug = opts.isSet("debug"); // No need to set --ice option here -- it is always true. underscore = opts.isSet("underscore"); if(opts.isSet("o")) { outputFile = opts.optArg("o"); } if(opts.isSet("f")) { inputFile = opts.optArg("f"); } if(opts.isSet("load")) { vector<string> optArgs = opts.argVec("load"); for(vector<string>::const_iterator i = optArgs.begin(); i != optArgs.end(); ++i) { slice.push_back(*i); } } evictor = opts.isSet("e"); if(opts.isSet("key")) { keyTypeName = opts.optArg("key"); } if(opts.isSet("value")) { valueTypeName = opts.optArg("value"); } if(opts.isSet("select")) { selectExpr = opts.optArg("select"); } if(outputFile.empty() && args.size() != 2) { usage(appName); return EXIT_FAILURE; } if(!args.empty()) { dbEnvName = args[0]; } if(args.size() == 2) { dbName = args[1]; } else { usage(appName); return EXIT_FAILURE; } if(!inputFile.empty() && !selectExpr.empty()) { cerr << appName << ": an input file cannot be specified with --select" << endl; return EXIT_FAILURE; } Slice::UnitPtr unit = Slice::Unit::createUnit(true, true, ice, underscore); FreezeScript::Destroyer<Slice::UnitPtr> unitD(unit); if(!FreezeScript::parseSlice(appName, unit, slice, cppArgs, debug, "-D__DUMPDB__")) { return EXIT_FAILURE; } FreezeScript::createEvictorSliceTypes(unit); FreezeScript::collectCompactIds(unit, resolver); // // If no input file was provided, then we need to generate default descriptors. // string descriptors; if(inputFile.empty()) { const string evictorKeyTypeName = "::Ice::Identity"; const string oldEvictorValueTypeName = "::Freeze::ObjectRecord"; const string newEvictorValueTypeName = "Object"; if((!keyTypeName.empty() && valueTypeName.empty()) || (keyTypeName.empty() && !valueTypeName.empty() && !evictor)) { cerr << appName << ": a key type and a value type must be specified" << endl; usage(appName); return EXIT_FAILURE; } else if(valueTypeName.empty()) { try { FreezeScript::CatalogDataMap catalog = FreezeScript::readCatalog(communicator, dbEnvName); FreezeScript::CatalogDataMap::iterator p = catalog.find(dbName); if(p == catalog.end()) { cerr << appName << ": database `" << dbName << "' not found in catalog." << endl; cerr << "Current catalog databases:" << endl; for(p = catalog.begin(); p != catalog.end(); ++p) { cerr << " " << p->first << endl; } return EXIT_FAILURE; } else { if(p->second.evictor) { evictor = true; } keyTypeName = p->second.key; valueTypeName = p->second.value; if(evictor && valueTypeName.empty()) { valueTypeName = oldEvictorValueTypeName; } } } catch(const FreezeScript::FailureException& ex) { cerr << appName << ": " << ex.reason() << endl; return EXIT_FAILURE; } } if(evictor) { if(keyTypeName.empty()) { keyTypeName = evictorKeyTypeName; } if(valueTypeName.empty()) { valueTypeName = newEvictorValueTypeName; } } Slice::TypePtr keyType, valueType; Slice::TypeList l; l = unit->lookupType(keyTypeName, false); if(l.empty()) { cerr << appName << ": unknown key type `" << keyTypeName << "'" << endl; return EXIT_FAILURE; } keyType = l.front(); l = unit->lookupType(valueTypeName, false); if(l.empty()) { cerr << appName << ": unknown value type `" << valueTypeName << "'" << endl; return EXIT_FAILURE; } valueType = l.front(); ostringstream os; IceUtilInternal::XMLOutput out(os); out << se("dumpdb"); FreezeScript::SliceVisitor visitor(out, keyType, valueType, selectExpr); unit->visit(&visitor, false); out << ee; descriptors = os.str(); if(!outputFile.empty()) { IceUtilInternal::ofstream of(outputFile); if(!of.good()) { cerr << appName << ": unable to open file `" << outputFile << "'" << endl; return EXIT_FAILURE; } of << descriptors << endl; of.close(); return EXIT_SUCCESS; } } else { IceUtilInternal::ifstream in(inputFile); char buff[1024]; while(true) { in.read(buff, 1024); descriptors.append(buff, static_cast<size_t>(in.gcount())); if(in.gcount() < 1024) { break; } } in.close(); } FreezeScript::ObjectFactoryPtr objectFactory = new FreezeScript::ObjectFactory; communicator->addObjectFactory(objectFactory, ""); DbEnv dbEnv(0); DbTxn* txn = 0; Freeze::ConnectionPtr connection; int status = EXIT_SUCCESS; try { #ifdef _WIN32 // // Berkeley DB may use a different C++ runtime. // dbEnv.set_alloc(::malloc, ::realloc, ::free); #endif // // Open the database environment and start a transaction. // { u_int32_t flags = DB_THREAD | DB_CREATE | DB_INIT_TXN | DB_INIT_MPOOL; dbEnv.open(dbEnvName.c_str(), flags, FREEZE_SCRIPT_DB_MODE); } // // We're creating a connection just to make sure the database environment // isn't locked. // connection = Freeze::createConnection(communicator, dbEnvName, dbEnv); dbEnv.txn_begin(0, &txn, 0); FreezeScript::ErrorReporterPtr errorReporter = new FreezeScript::ErrorReporter(cerr, false); try { FreezeScript::DataFactoryPtr factory = new FreezeScript::DataFactory(communicator, unit, errorReporter); FreezeScript::DescriptorHandler dh(factory, unit, errorReporter, objectFactory); istringstream istr(descriptors); IceXML::Parser::parse(istr, dh); FreezeScript::DumpDBDescriptorPtr descriptor = dh.descriptor(); descriptor->validate(); if(evictor) { // // The evictor database file contains multiple databases. We must first // determine the names of those databases, ignoring any whose names // begin with "$index:". Each database represents a separate facet, with // the facet name used as the database name. The database named "$default" // represents the main object. // vector<string> dbNames; { Db db(&dbEnv, 0); db.open(txn, dbName.c_str(), 0, DB_UNKNOWN, DB_RDONLY, 0); Dbt dbKey, dbValue; dbKey.set_flags(DB_DBT_MALLOC); dbValue.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL); Dbc* dbc = 0; db.cursor(txn, &dbc, 0); while(dbc->get(&dbKey, &dbValue, DB_NEXT) == 0) { string s(static_cast<char*>(dbKey.get_data()), dbKey.get_size()); if(s.find("$index:") != 0) { dbNames.push_back(s); } free(dbKey.get_data()); } dbc->close(); db.close(0); } // // Dump each database. // for(vector<string>::iterator p = dbNames.begin(); p != dbNames.end(); ++p) { string name = *p; string facet = (name == "$default" ? string("") : name); Db db(&dbEnv, 0); db.open(txn, dbName.c_str(), name.c_str(), DB_BTREE, DB_RDONLY, FREEZE_SCRIPT_DB_MODE); descriptor->dump(communicator, &db, txn, facet); db.close(0); } } else { // // Dump a map database. // Db db(&dbEnv, 0); db.open(txn, dbName.c_str(), 0, DB_BTREE, DB_RDONLY, FREEZE_SCRIPT_DB_MODE); descriptor->dump(communicator, &db, txn, ""); db.close(0); } } catch(const IceXML::ParserException& ex) { errorReporter->error(ex.reason()); } } catch(const DbException& ex) { cerr << appName << ": database error: " << ex.what() << endl; status = EXIT_FAILURE; } catch(...) { try { if(txn) { txn->abort(); } dbEnv.close(0); } catch(const DbException& ex) { cerr << appName << ": database error: " << ex.what() << endl; } if(connection) { connection->close(); connection = 0; } throw; } try { if(txn) { txn->abort(); } if(connection) { connection->close(); } dbEnv.close(0); } catch(const DbException& ex) { cerr << appName << ": database error: " << ex.what() << endl; status = EXIT_FAILURE; } return status; }
bool BerkeleyBatch::Recover(const fs::path& file_path, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& newFilename) { std::string filename; BerkeleyEnvironment* env = GetWalletEnv(file_path, filename); // Recovery procedure: // move wallet file to walletfilename.timestamp.bak // Call Salvage with fAggressive=true to // get as much data as possible. // Rewrite salvaged data to fresh wallet file // Set -rescan so any missing transactions will be // found. int64_t now = GetTime(); newFilename = strprintf("%s.%d.bak", filename, now); int result = env->dbenv->dbrename(nullptr, filename.c_str(), nullptr, newFilename.c_str(), DB_AUTO_COMMIT); if (result == 0) LogPrintf("Renamed %s to %s\n", filename, newFilename); else { LogPrintf("Failed to rename %s to %s\n", filename, newFilename); return false; } std::vector<BerkeleyEnvironment::KeyValPair> salvagedData; bool fSuccess = env->Salvage(newFilename, true, salvagedData); if (salvagedData.empty()) { LogPrintf("Salvage(aggressive) found no records in %s.\n", newFilename); return false; } LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size()); std::unique_ptr<Db> pdbCopy = MakeUnique<Db>(env->dbenv.get(), 0); int ret = pdbCopy->open(nullptr, // Txn pointer filename.c_str(), // Filename "main", // Logical db name DB_BTREE, // Database type DB_CREATE, // Flags 0); if (ret > 0) { LogPrintf("Cannot create database file %s\n", filename); pdbCopy->close(0); return false; } DbTxn* ptxn = env->TxnBegin(); for (BerkeleyEnvironment::KeyValPair& row : salvagedData) { if (recoverKVcallback) { CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION); CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION); if (!(*recoverKVcallback)(callbackDataIn, ssKey, ssValue)) continue; } Dbt datKey(&row.first[0], row.first.size()); Dbt datValue(&row.second[0], row.second.size()); int ret2 = pdbCopy->put(ptxn, &datKey, &datValue, DB_NOOVERWRITE); if (ret2 > 0) fSuccess = false; } ptxn->commit(0); pdbCopy->close(0); return fSuccess; }
/* Bulk fill a database. */ void BulkExample::bulkUpdate( int num, int dups, int *countp, int *iterp, int verbose) { Dbt key, data; u_int32_t flag; DbTxn *txnp; int count, i, iter, ret; DbMultipleDataBuilder *ptrd, *ptrk; DbMultipleKeyDataBuilder *ptrkd; txnp = NULL; count = flag = iter = ret = 0; ptrk = ptrd = NULL; if (data_val == NULL) data_val = (struct data *)malloc(DATALEN); memset(data_val, 0, DATALEN); memset(&key, 0, sizeof(Dbt)); memset(&data, 0, sizeof(Dbt)); /* * The buffer must be at least as large as the page size of * the underlying database and aligned for unsigned integer * access. Its size must be a multiple of 1024 bytes. */ if (klen != (u_int32_t) UPDATES_PER_BULK_PUT * (sizeof(u_int32_t) + DATALEN) * 1024) { klen = (u_int32_t) UPDATES_PER_BULK_PUT * (sizeof(u_int32_t) + DATALEN) * 1024; kbuf = realloc(kbuf, klen); } memset(kbuf, 0, klen); key.set_ulen(klen); key.set_flags(DB_DBT_USERMEM | DB_DBT_BULK); key.set_data(kbuf); if (dlen != (u_int32_t) UPDATES_PER_BULK_PUT * (sizeof(u_int32_t) + DATALEN) * 1024) { dlen = (u_int32_t) UPDATES_PER_BULK_PUT * (sizeof(u_int32_t) + DATALEN) * 1024; dbuf = realloc(dbuf, dlen); } memset(dbuf, 0, dlen); data.set_ulen(dlen); data.set_flags(DB_DBT_USERMEM | DB_DBT_BULK); data.set_data(dbuf); /* * Bulk insert with either DB_MULTIPLE in two buffers or * DB_MULTIPLE_KEY in a single buffer. With DB_MULTIPLE, all keys are * constructed in the key Dbt, and all data is constructed in the data * Dbt. With DB_MULTIPLE_KEY, all key/data pairs are constructed in the * key Dbt. We use DB_MULTIPLE mode when there are duplicate records. */ flag |= (dups) ? DB_MULTIPLE : DB_MULTIPLE_KEY; if (dups) { ptrk = new DbMultipleDataBuilder(key); ptrd = new DbMultipleDataBuilder(data); } else ptrkd = new DbMultipleKeyDataBuilder(key); try { for (i = 0; i < num; i++) { if (i % UPDATES_PER_BULK_PUT == 0) { if (txnp != NULL) { ret = txnp->commit(0); txnp = NULL; if (ret != 0) throwException(dbenv, NULL, ret, "DB_TXN->commit"); } if ((ret = dbenv->txn_begin(NULL, &txnp, 0)) != 0) throwException(dbenv, NULL, ret, "DB_ENV->txn_begin"); } data_val->id = 0; get_string(tstring, data_val->str, i); do { if (dups) { if (ptrk->append(&i, sizeof(i)) == false) throwException(dbenv, txnp, EXIT_FAILURE, "DbMultipleDataBuilder->append"); if (ptrd->append(data_val, DATALEN) == false) throwException(dbenv, txnp, EXIT_FAILURE, "DbMultipleDataBuilder->append"); } else { if (ptrkd->append(&i, sizeof(i), data_val, DATALEN) == false) throwException(dbenv, txnp, EXIT_FAILURE, "DbMultipleKeyDataBuilder->append"); } if (verbose) printf( "Insert key: %d, \t data: (id %d, str %s)\n", i, data_val->id, data_val->str); count++; } while (data_val->id++ < dups); if ((i + 1) % UPDATES_PER_BULK_PUT == 0) { if ((ret = dbp->put(txnp, &key, &data, flag)) != 0) throwException(dbenv, txnp, ret, "Bulk DB->put"); iter++; if (dups) { ptrk = new DbMultipleDataBuilder(key); ptrd = new DbMultipleDataBuilder(data); } else ptrkd = new DbMultipleKeyDataBuilder(key); } } if ((num % UPDATES_PER_BULK_PUT) != 0) { if ((ret = dbp->put(txnp, &key, &data, flag)) != 0) throwException(dbenv, txnp, ret, "Bulk DB->put"); iter++; } ret = txnp->commit(0); txnp = NULL; if (ret != 0) throwException(dbenv, NULL, ret, "DB_TXN->commit"); *countp = count; *iterp = iter; } catch (DbException &dbe) { cerr << "bulkUpdate " << dbe.what() << endl; if (txnp != NULL) (void)txnp->abort(); throw dbe; } }
/* Loop get batches of records. */ void BulkExample::bulkRead( int num, int dups, int iter, int *countp, int verbose) { Dbc *dbcp; Dbt data, dp, key, kp; DbTxn *txnp; DbMultipleDataIterator *ptrd; DbMultipleKeyDataIterator *ptrkd; u_int32_t flags; int count, i, j, ret; count = klen = ret = 0; dbcp = NULL; txnp = NULL; /* Initialize key Dbt and data Dbt, malloc bulk buffer. */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); key.set_size(sizeof(j)); if (dlen != DATALEN * 16 * 1024) { dlen = DATALEN * 16 * 1024; dbuf = realloc(dbuf, dlen); } memset(dbuf, 0, dlen); data.set_flags(DB_DBT_USERMEM); data.set_data(dbuf); data.set_ulen(dlen); data.set_size(dlen); flags = DB_SET; flags |= (dups) ? DB_MULTIPLE: DB_MULTIPLE_KEY; try { for (i = 0; i < iter; i++) { if ((ret = dbenv->txn_begin(NULL, &txnp, 0)) != 0) throwException(dbenv, NULL, ret, "DB_ENV->txn_begin"); if ((ret = dbp->cursor(txnp, &dbcp, 0)) != 0) throwException(dbenv, txnp, ret, "DB->cursor"); /* * Bulk retrieve by a random key which is a random * non-negative integer smaller than "num". * If there are duplicates in the database, retrieve * with DB_MULTIPLE and use the DbMultipleDataIterator * to iterate the data of the random key in the data * Dbt. Otherwise retrieve with DB_MULTIPLE_KEY and use * the DbMultipleKeyDataIterator to iterate the * key/data pairs of the specific set of keys which * includes all integers >= the random key and < "num". */ j = rand() % num; key.set_data(&j); if ((ret = dbcp->get(&key, &data, flags)) != 0) throwException(dbenv, NULL, ret, "DBC->get"); if (dups) { ptrd = new DbMultipleDataIterator(data); while (ptrd->next(dp) == true) { count++; if (verbose) printf( "Retrieve key: %d, \tdata: (id %d, str %s)\n", j, ((struct data *)( dp.get_data()))->id, (char *)((struct data *)( dp.get_data()))->str); } } else { ptrkd = new DbMultipleKeyDataIterator(data); while (ptrkd->next(kp, dp) == true) { count++; if (verbose) printf( "Retrieve key: %d, \tdata: (id %d, str %s)\n", *((int *)kp.get_data()), ((struct data *)( dp.get_data()))->id, (char *)((struct data *)( dp.get_data()))->str); } } ret = dbcp->close(); dbcp = NULL; if (ret != 0) throwException(dbenv, txnp, ret, "DBC->close"); ret = txnp->commit(0); txnp = NULL; if (ret != 0) throwException(dbenv, NULL, ret, "DB_TXN->commit"); } *countp = count; } catch (DbException &dbe) { cerr << "bulkRead " << dbe.what() << endl; if (dbcp != NULL) (void)dbcp->close(); if (txnp != NULL) (void)txnp->abort(); throw dbe; } }
/* Bulk delete from a secondary db. */ void BulkExample::bulkSecondaryDelete( int num, int pair, int *countp, int *iterp, int verbose) { Dbt key; DbTxn *txnp; DbMultipleDataBuilder *ptrd; DbMultipleKeyDataBuilder *ptrkd; u_int32_t flag; int count, i, iter, j, k, rc, ret; char ch; memset(&key, 0, sizeof(Dbt)); txnp = NULL; count = flag = iter = ret = 0; rc = rand() % (STRLEN - 1); /* * The buffer must be at least as large as the page size of the * underlying database and aligned for unsigned integer access. * Its size must be a multiple of 1024 bytes. */ if (klen != (u_int32_t)UPDATES_PER_BULK_PUT * (sizeof(u_int32_t) + DATALEN) * 1024) { klen = (u_int32_t)UPDATES_PER_BULK_PUT * (sizeof(u_int32_t) + DATALEN) * 1024; kbuf = realloc(kbuf, klen); } memset(kbuf, 0, klen); key.set_ulen(klen); key.set_flags(DB_DBT_USERMEM | DB_DBT_BULK); key.set_data(kbuf); /* * Bulk delete all records of a specific set of keys which includes all * characters before the random key in the tstring. The random key is * one of the characters in the tstring. * If DB_MULTIPLE, construct the key Dbt by the DbMultipleDataBuilder * with the specific set of keys. If DB_MULTIPLE_KEY, construct the key * Dbt by the DbMultipleKeyDataBuilder with all key/data pairs of the * specific set of keys. */ flag |= (pair) ? DB_MULTIPLE_KEY : DB_MULTIPLE; if (pair) ptrkd = new DbMultipleKeyDataBuilder(key); else ptrd = new DbMultipleDataBuilder(key); try { for (i = 0; i <= rc; i++) { if (i % UPDATES_PER_BULK_PUT == 0) { if (txnp != NULL) { ret = txnp->commit(0); txnp = NULL; if (ret != 0) throwException(dbenv, NULL, ret, "DB_TXN->commit"); } if ((ret = dbenv->txn_begin(NULL, &txnp, 0)) != 0) throwException(dbenv, NULL, ret, "DB_ENV->txn_begin"); } ch = tstring[i]; if (!pair) { if (ptrd->append(&ch, sizeof(ch)) == false) throwException(dbenv, txnp, EXIT_FAILURE, "DbMultipleDataBuilder->append"); count++; if (verbose) printf("Delete key: %c\n", ch); } else { j = 0; do { k = j * (STRLEN - 1) + i; if (ptrkd->append(&ch, sizeof(ch), &k, sizeof(k)) == false) throwException(dbenv, txnp, EXIT_FAILURE, "DbMultipleKeyDataBuilder->append"); count++; if (verbose) printf( "Delete secondary key: %c, \tdata: %d\n", ch, k); } while (++j < (int)(num / (STRLEN - 1))); } if ((i + 1) % UPDATES_PER_BULK_PUT == 0) { if ((ret = sdbp->del(txnp, &key, flag)) != 0) throwException(dbenv, txnp, ret, "Bulk DB->del"); iter++; if (pair) ptrkd = new DbMultipleKeyDataBuilder(key); else ptrd = new DbMultipleDataBuilder(key); } } if ((rc % UPDATES_PER_BULK_PUT) != 0) { if ((ret = sdbp->del(txnp, &key, flag)) != 0) throwException(dbenv, txnp, ret, "Bulk DB->del"); iter++; } ret = txnp->commit(0); txnp = NULL; if (ret != 0) throwException(dbenv, NULL, ret, "DB_TXN->commit"); *countp = count; *iterp = iter; } catch (DbException &dbe) { cerr << "bulkSecondaryDelete " << dbe.what() << endl; if (txnp != NULL) (void)txnp->abort(); throw dbe; } }
/* Bulk delete from a database. */ void BulkExample::bulkDelete( int num, int dups, int *countp, int *iterp, int verbose) { Dbt key; DbTxn *txnp; DbMultipleDataBuilder *ptrd; DbMultipleKeyDataBuilder *ptrkd; u_int32_t flag; int count, i, j, iter, ret; txnp = NULL; count = flag = iter = ret = 0; memset(&key, 0, sizeof(Dbt)); j = rand() % num; /* * The buffer must be at least as large as the page size of the * underlying database and aligned for unsigned integer access. * Its size must be a multiple of 1024 bytes. */ if (klen != (u_int32_t)UPDATES_PER_BULK_PUT * (sizeof(u_int32_t) + DATALEN) * 1024) { klen = (u_int32_t)UPDATES_PER_BULK_PUT * (sizeof(u_int32_t) + DATALEN) * 1024; kbuf = realloc(kbuf, klen); } memset(kbuf, 0, klen); key.set_ulen(klen); key.set_flags(DB_DBT_USERMEM | DB_DBT_BULK); key.set_data(kbuf); if (data_val == NULL) data_val = (data *)malloc(DATALEN); memset(data_val, 0, DATALEN); /* * Bulk delete all records of a specific set of keys which includes all * non-negative integers smaller than the random key. The random key is * a random non-negative integer smaller than "num". * If DB_MULTIPLE, construct the key Dbt by the DbMultipleDataBuilder * with the specific set of keys. If DB_MULTIPLE_KEY, construct the key * Dbt by the DbMultipleKeyDataBuilder with all key/data pairs of the * specific set of keys. */ flag |= (dups) ? DB_MULTIPLE_KEY : DB_MULTIPLE; if (dups) ptrkd = new DbMultipleKeyDataBuilder(key); else ptrd = new DbMultipleDataBuilder(key); try { for (i = 0; i < j; i++) { if (i % UPDATES_PER_BULK_PUT == 0) { if (txnp != NULL) { ret = txnp->commit(0); txnp = NULL; if (ret != 0) throwException(dbenv, NULL, ret, "DB_TXN->commit"); } if ((ret = dbenv->txn_begin(NULL, &txnp, 0)) != 0) throwException(dbenv, NULL, ret, "DB_ENV->txn_begin"); } if (dups) { data_val->id = 0; get_string(tstring, data_val->str, i); do { if(ptrkd->append(&i,sizeof(i), data_val, DATALEN) == false) throwException(dbenv, txnp, EXIT_FAILURE, "DbMultipleKeyDataBuilder->append"); count++; if (verbose) printf( "Delete key: %d, \tdata: (id %d, str %s)\n", i, data_val->id, data_val->str); } while (data_val->id++ < dups); } else { if(ptrd->append(&i,sizeof(i)) == false) throwException(dbenv, txnp, ret, "DbMultipleDataBuilder->append"); count++; if (verbose) printf("Delete key: %d\n", i); } if ((i + 1) % UPDATES_PER_BULK_PUT == 0) { if ((ret = dbp->del(txnp, &key, flag)) != 0) throwException(dbenv, txnp, ret, "Bulk DB->del"); iter++; if (dups) ptrkd = new DbMultipleKeyDataBuilder(key); else ptrd = new DbMultipleDataBuilder(key); } } if ((j % UPDATES_PER_BULK_PUT) != 0) { if ((ret = dbp->del(txnp, &key, flag)) != 0) throwException(dbenv, txnp, ret, "Bulk DB->del"); iter++; } ret = txnp->commit(0); txnp = NULL; if (ret != 0) throwException(dbenv, NULL, ret, "DB_TXN->commit"); *countp = count; *iterp = iter; } catch (DbException &dbe) { cerr << "bulkDelete " << dbe.what() << endl; if (txnp != NULL) (void)txnp->abort(); throw dbe; } }
// // 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 = NULL; Dbc *bcurs = NULL; Dbc *tcurs = NULL; DbTxn *t = NULL; db_recno_t key; Defrec rec; Histrec hrec; int account, branch, teller, ret; Dbt d_dbt; Dbt d_histdbt; Dbt k_dbt; Dbt k_histdbt(&key, sizeof(key)); // !!! // This is sample code -- we could move a lot of this into the driver // to make it faster. // account = random_id(ACCOUNT, accounts, branches, tellers); branch = random_id(BRANCH, accounts, branches, tellers); teller = random_id(TELLER, accounts, branches, tellers); k_dbt.set_size(sizeof(int)); d_dbt.set_flags(DB_DBT_USERMEM); d_dbt.set_data(&rec); d_dbt.set_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.set_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 (txn_begin(NULL, &t, 0) != 0) goto err; if (adb->cursor(t, &acurs, 0) != 0 || bdb->cursor(t, &bcurs, 0) != 0 || tdb->cursor(t, &tcurs, 0) != 0) goto err; // Account record k_dbt.set_data(&account); if (acurs->get(&k_dbt, &d_dbt, DB_SET) != 0) goto err; rec.balance += 10; if (acurs->put(&k_dbt, &d_dbt, DB_CURRENT) != 0) goto err; // Branch record k_dbt.set_data(&branch); if (bcurs->get(&k_dbt, &d_dbt, DB_SET) != 0) goto err; rec.balance += 10; if (bcurs->put(&k_dbt, &d_dbt, DB_CURRENT) != 0) goto err; // Teller record k_dbt.set_data(&teller); if (tcurs->get(&k_dbt, &d_dbt, DB_SET) != 0) goto err; rec.balance += 10; if (tcurs->put(&k_dbt, &d_dbt, DB_CURRENT) != 0) goto err; // History record d_histdbt.set_flags(0); d_histdbt.set_data(&hrec); d_histdbt.set_ulen(sizeof(hrec)); if (hdb->put(t, &k_histdbt, &d_histdbt, DB_APPEND) != 0) goto err; if (acurs->close() != 0 || bcurs->close() != 0 || tcurs->close() != 0) goto err; ret = t->commit(0); t = NULL; if (ret != 0) goto err; // END PER-TRANSACTION TIMING. return (0); err: if (acurs != NULL) (void)acurs->close(); if (bcurs != NULL) (void)bcurs->close(); if (tcurs != NULL) (void)tcurs->close(); if (t != NULL) (void)t->abort(); if (verbose) cout << "Transaction A=" << (long)account << " B=" << (long)branch << " T=" << (long)teller << " failed\n"; return (-1); }
int main(int argc, char *argv[]) { try { DbEnv *dbenv = new DbEnv(0); DbTxn *dbtxn; u_int8_t conflicts[10]; dbenv->set_error_stream(&cerr); dbenv->set_timeout(0x90000000, DB_SET_LOCK_TIMEOUT); dbenv->set_lg_bsize(0x1000); dbenv->set_lg_dir("."); dbenv->set_lg_max(0x10000000); dbenv->set_lg_regionmax(0x100000); dbenv->set_lk_conflicts(conflicts, sizeof(conflicts)); dbenv->set_lk_detect(DB_LOCK_DEFAULT); dbenv->set_lk_max_lockers(100); dbenv->set_lk_max_locks(10); dbenv->set_lk_max_objects(1000); dbenv->set_mp_mmapsize(0x10000); // Need to open the environment so we // can get a transaction. // dbenv->open(".", DB_CREATE | DB_INIT_TXN | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL, 0644); dbenv->txn_begin(NULL, &dbtxn, DB_TXN_NOWAIT); dbtxn->set_timeout(0xA0000000, DB_SET_TXN_TIMEOUT); dbtxn->abort(); dbenv->close(0); // We get a db, one for each type. // That's because once we call (for instance) // set_bt_minkey, DB 'knows' that this is a // Btree Db, and it cannot be used to try Hash // or Recno functions. // Db *db_bt = new Db(NULL, 0); db_bt->set_bt_minkey(100); db_bt->set_cachesize(0, 0x100000, 0); db_bt->close(0); Db *db_h = new Db(NULL, 0); db_h->set_h_ffactor(0x10); db_h->set_h_nelem(100); db_h->set_lorder(0); db_h->set_pagesize(0x10000); db_h->close(0); Db *db_re = new Db(NULL, 0); db_re->set_re_delim('@'); db_re->set_re_pad(10); db_re->set_re_source("re.in"); db_re->close(0); Db *db_q = new Db(NULL, 0); db_q->set_q_extentsize(200); db_q->close(0); } catch (DbException &dbe) { cerr << "Db Exception: " << dbe.what() << "\n"; } return 0; }
/* Get all scores of a certain patient. * Returns 0 if everything is ok; * returns -1 if permission is denied, and error message is not sent out successfully; * returns 1 if permission is denied, but error message is sent out successfully; * returns -2 if patient ID is invalid, and error message is not sent out successfully; * returns 2 if patient ID is invalid, but error message is sent out successfully; * returns -3 if error occurs when searching score value table, and error message is not sent out successfully; * returns 3 if error occurs when searching score value table, but error message is sent out successfully; * returns -4 if no score value record is found, and error message is not sent out successfully; * returns 4 if no score value record is found, but error message is sent out successfully; * returns -5 if data size message is not sent out successfully; * returns -6 if score value data are not sent out successfully; * returns -7 if no session is available, and the message is not sent out successfully; * returns -8 if error occurs when searching session table, and error message is not sent out successfully; * returns 8 if error occurs when searching session table, but error message is sent out successfully; * returns -9 if session data are not sent out successfully. */ int srvSession::sendPatientScores() { if (!permissions.size()) { statMsg = "Permission denied"; if (sendStatMsg()) return -1; return 1; } // send error message to client if patient ID is invalid or score values not found int32 pID; bool conv_stat = str2num(c_tokens[1], pID); if (!conv_stat || pID <= 0) { statMsg = "no_data: Invalid patient ID " + c_tokens[1]; if (sendStatMsg()) return -2; return 2; } // get score values set<int32> sid_set; DbTxn* txn = NULL; dbs.env.getEnv()->txn_begin(NULL, &txn, 0); Dbc* cursorp = NULL; if (dbs.scoreValueDB.getDb().cursor(txn, &cursorp, 0)) { txn->abort(); statMsg = "no_data: db error when searching score value table"; if (sendStatMsg()) return -3; return 3; } // Iterate over score values table Dbt key, data; int ret; int32 status = 0; while ((ret = cursorp->get(&key, &data, DB_NEXT_NODUP)) == 0) { DBscorevalue svData; svData.deserializeHdr(data.get_data()); if (pID != svData.patient || svData.deleted) continue; string tmpPerm = getMaxPerm(svData, permissions); if (tmpPerm.empty()) continue; /* Add session IDs into session_list vector (session 0 is ignored here * because this session doesn't exist in session table anyway) */ int32 sess_id = svData.sessionid; if (sess_id) sid_set.insert(sess_id); // Add real score value records into DBscorevalue vector. status = 1; uint32 dat_size = data.get_size(); statMsg = "scorevalue: " + num2str(dat_size) + " " + tmpPerm; if (sendStatMsg()) { cursorp->close(); txn->abort(); return -4; } if (sendBuffer(g_session, dat_size, (char*) data.get_data())) { statMsg = "Error when sending score value to client"; cursorp->close(); txn->abort(); return -4; } } // Returns -1 if ret is non-zero and it doesn't reach the end of table if (ret && ret != DB_NOTFOUND) { cursorp->close(); txn->abort(); statMsg = "no_data: db error when searching score value table"; if (sendStatMsg()) return -3; return 3; } cursorp->close(); if (status == 0) { txn->commit(0); statMsg = "no_scorevalue"; if (sendStatMsg()) return -5; return 5; } // If session ID list is empty, tell client that no session info sent out if (sid_set.size() == 0) { txn->commit(0); statMsg = "no_session"; if (sendStatMsg()) return -7; return 0; } // get related DBsession vector<DBsession> sessList; int32 dat_size = getSessions(dbs.sessionDB, txn, sid_set, sessList); // Note that dat_size may be zero if all score values are static if (dat_size <= 0) { txn->abort(); statMsg = "no_data: Session record not found"; if (sendStatMsg()) return -8; return 8; } txn->commit(0); // send session data to client char sess_buff[dat_size]; serialize(sessList, sess_buff); if (sendData(dat_size, sess_buff)) { statMsg = "Error when sending patient session data to client: " + statMsg; return -9; } return 0; }