//
// 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);
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
/* 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;
	}
}
Example #5
0
/* 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;
	}
}
Example #6
0
/* 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;
	}
}
Example #7
0
/* 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;
	}
}
Example #8
0
//
// 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);
}
Example #9
0
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;
}
Example #10
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;
}