Beispiel #1
0
/*
 * Get or create an existing transaction from tidptr, and store it in _tidptr.
 */
static int getorset_txn(struct dbengine *db,
                        struct txn **tidptr,
                        struct txn **_tidptr,
                        int readonly)
{
    struct txn *tid;
    int r;

    assert(_tidptr);
    tid = *_tidptr;

    if (!tidptr || !*tidptr) {
        /* Create a new transaction */
        if ((r = begin_txn(db, &tid, readonly))) {
            *_tidptr = NULL;
            return r;
        }
    } else {
        /* Reuse the existing transaction */
        tid = *tidptr;
    }
    if (tidptr) {
        /* Refresh tidptr */
        *tidptr = tid;
    }
    /* Return the transaction */
    *_tidptr = tid;

    PDEBUG("cyrusdb_lmdb(%s)[getorset_txn] tidptr=%p *tidptr=%p _tidptr=%p *_tidptr=%p ",
            db->fname, tidptr, tidptr ? *tidptr : NULL, _tidptr, _tidptr ? *_tidptr : NULL);

    return CYRUSDB_OK;
}
int64 LMDBFileIndex::get(const LMDBFileIndex::SIndexKey& key)
{
	begin_txn(MDB_RDONLY);

	MDB_val mdb_tkey;
	mdb_tkey.mv_data=const_cast<void*>(static_cast<const void*>(&key));
	mdb_tkey.mv_size=sizeof(SIndexKey);

	MDB_val mdb_tvalue;

	int rc=mdb_get(txn, dbi, &mdb_tkey, &mdb_tvalue);

	int64 ret = 0;
	if(rc==MDB_NOTFOUND)
	{
		
	}
	else if(rc)
	{
		Server->Log("LMDB: Failed to read ("+(std::string)mdb_strerror(rc)+")", LL_ERROR);
		_has_error=true;
	}
	else
	{
		CRData data((const char*)mdb_tvalue.mv_data, mdb_tvalue.mv_size);
		
		data.getVarInt(&ret);
	}

	abort_transaction();

	return ret;
}
int64 LMDBFileIndex::get_prefer_client( const SIndexKey& key )
{
	begin_txn(MDB_RDONLY);

	MDB_cursor* cursor;

	mdb_cursor_open(txn, dbi, &cursor);

	SIndexKey orig_key = key;

	MDB_val mdb_tkey;
	mdb_tkey.mv_data=const_cast<void*>(static_cast<const void*>(&key));
	mdb_tkey.mv_size=sizeof(SIndexKey);

	MDB_val mdb_tvalue;

	int rc=mdb_cursor_get(cursor,&mdb_tkey, &mdb_tvalue, MDB_SET_RANGE);

	int64 ret = 0;
	int retry_prev=2;
	while(rc==0 && retry_prev>0 && !_has_error)
	{
		SIndexKey* curr_key = reinterpret_cast<SIndexKey*>(mdb_tkey.mv_data);

		if(rc==MDB_NOTFOUND)
		{
			retry_prev=0;
		}
		else if(rc)
		{
			Server->Log("LMDB: Failed to read ("+(std::string)mdb_strerror(rc)+")", LL_ERROR);
			_has_error=true;
		}
		else if( curr_key->isEqualWithoutClientid(orig_key))
		{
			CRData data((const char*)mdb_tvalue.mv_data, mdb_tvalue.mv_size);
			data.getVarInt(&ret);
			retry_prev=0;
		}
		else
		{
			rc=mdb_cursor_get(cursor, &mdb_tkey, &mdb_tvalue, MDB_PREV);
			--retry_prev;
		}
	}

	mdb_cursor_close(cursor);

	abort_transaction();

	return ret;
}
std::map<int, int64> LMDBFileIndex::get_all_clients( const SIndexKey& key )
{
	begin_txn(MDB_RDONLY);

	MDB_cursor* cursor;

	mdb_cursor_open(txn, dbi, &cursor);

	SIndexKey orig_key = key;

	MDB_val mdb_tkey;
	mdb_tkey.mv_data=const_cast<void*>(static_cast<const void*>(&key));
	mdb_tkey.mv_size=sizeof(SIndexKey);

	MDB_val mdb_tvalue;

	int rc=mdb_cursor_get(cursor,&mdb_tkey, &mdb_tvalue, MDB_SET_RANGE);

	std::map<int, int64> ret;

	SIndexKey* curr_key = reinterpret_cast<SIndexKey*>(mdb_tkey.mv_data);

	while(rc==0 &&
		orig_key.isEqualWithoutClientid(*curr_key))
	{
		CRData data((const char*)mdb_tvalue.mv_data, mdb_tvalue.mv_size);
		int64 entryid;
		data.getVarInt(&entryid);

		ret[curr_key->getClientid()] = entryid;

		rc=mdb_cursor_get(cursor, &mdb_tkey, &mdb_tvalue, MDB_NEXT);
		curr_key = reinterpret_cast<SIndexKey*>(mdb_tkey.mv_data);
	}


	if(rc && rc!=MDB_NOTFOUND)
	{
		Server->Log("LMDB: Failed to read ("+(std::string)mdb_strerror(rc)+")", LL_ERROR);
		_has_error=true;
	}

	mdb_cursor_close(cursor);

	abort_transaction();

	return ret;
}
// std::string persistent test.
void StlAdvancedFeaturesExample::storing_std_strings()
{	
	string kstring = "hello world", *sstring = new string("hi there");
	if (explicit_txn)
		begin_txn(0, penv);

	db_map<string, string> pmap(dmstringdb, NULL);

	pmap[kstring] = *sstring + "!";
	*sstring = pmap[kstring];
	map<string, string> spmap;
	spmap.insert(make_pair(kstring, *sstring));
	cout<<"sstring append ! is : "<<pmap[kstring]
	    <<" ; *sstring is : "<<*sstring;
	delete sstring;
	for (db_map<string, string>::iterator ii = pmap.begin();
	    ii != pmap.end();
	    ++ii) {
		cout << (*ii).first << ": " << (*ii).second << endl;
	} 
	close_db(dmstringdb);
	
	dmstringdb = dbstl::open_db(penv, "db_map_stringdb.db", 
	    dbtype, DB_CREATE | dboflags, 0);
	db_map<string, string> pmap2(dmstringdb, NULL);
	for (db_map<string, string>::iterator ii = pmap2.begin();
	    ii != pmap2.end(); ++ii) {
		cout << (*ii).first << ": " << (*ii).second << endl;
		// assert key/data pair set equal
		check_expr((spmap.count(ii->first) == 1) && 
		    (spmap[ii->first] == ii->second));
	} 
	if (explicit_txn)
		commit_txn(penv);

	db_vector<string> strvctor(10);
	vector<string> sstrvctor(10);
	for (int i = 0; i < 10; i++) {
		strvctor[i] = "abc";
		sstrvctor[i] = strvctor[i];
	}
	check_expr(is_equal(strvctor, sstrvctor));
}
/* Initiates the non-blocking capture of a consistent snapshot of the database,
 * using the exported snapshot context->repl.snapshot_name. */
int snapshot_start(client_context_t context) {
    if (!context->repl.snapshot_name || context->repl.snapshot_name[0] == '\0') {
        client_error(context, "snapshot_name must be set in client context");
        return EINVAL;
    }

    int err = 0;
    check(err, exec_sql(context, "BEGIN"));
    check(err, exec_sql(context, "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ"));

    PQExpBuffer query = createPQExpBuffer();
    appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT '%s'", context->repl.snapshot_name);
    check(err, exec_sql(context, query->data));
    destroyPQExpBuffer(query);

    Oid argtypes[] = { 25, 16 }; // 25 == TEXTOID, 16 == BOOLOID
    const char *args[] = { "%", context->allow_unkeyed ? "t" : "f" };

    if (!PQsendQueryParams(context->sql_conn,
                "SELECT bottledwater_export(table_pattern := $1, allow_unkeyed := $2)",
                2, argtypes, args, NULL, NULL, 1)) { // The final 1 requests results in binary format
        client_error(context, "Could not dispatch snapshot fetch: %s",
                PQerrorMessage(context->sql_conn));
        return EIO;
    }

    if (!PQsetSingleRowMode(context->sql_conn)) {
        client_error(context, "Could not activate single-row mode");
        return EIO;
    }

    // Invoke the begin-transaction callback with xid==0 to indicate start of snapshot
    begin_txn_cb begin_txn = context->repl.frame_reader->on_begin_txn;
    void *cb_context = context->repl.frame_reader->cb_context;
    if (begin_txn) {
        check(err, begin_txn(cb_context, context->repl.start_lsn, 0));
    }
    return 0;
}
Beispiel #7
0
static int myopen(const char *fname, int flags, struct dbengine **ret,
                  struct txn **tidptr)
{
    struct dbengine *db;
    int r, mr = 0;

    PDEBUG("cyrusdb_lmdb(%s)[open] flags=0x%x tidptr=%p *tidptr=%p",
            fname, flags, tidptr, tidptr ? *tidptr : NULL);
    assert(fname && ret);

    /* Create a new database engine */
    db = (struct dbengine *) xzmalloc(sizeof(struct dbengine));
    db->fname = xstrdup(fname);
    db->flags = flags;

    /* Assert that either the parent directory or the database exists */
    r = flags & CYRUSDB_CREATE ? my_mkparentdir(fname) : my_stat(fname);
    if (r) {
        /* Both my_stat and my_mkparentdir preserve errno */
        r = errno == ENOENT ? CYRUSDB_NOTFOUND : CYRUSDB_IOERROR;
        goto fail;
    }

    /* Create the environment for this database */
    mr = mdb_env_create(&db->env);
    if (mr) {
        r = CYRUSDB_INTERNAL;
        goto fail;
    }

    /* Size (or resize) the environment */
    mr = mdb_env_set_mapsize(db->env, maxdbsize);
    if (mr) {
        r = CYRUSDB_INTERNAL;
        goto fail;
    }

    /* Open the environment */
    mr = mdb_env_open(db->env, fname, MDB_NOSUBDIR, 0600);
    if (mr) {
        r = CYRUSDB_IOERROR;
        goto fail;
    }

    /* Lock the database, if requested */
    if (tidptr) {
        r = begin_txn(db, tidptr, 0);
        if (r) goto fail;
    }

    /* Keep database for internal bookkeeping */
    register_db(db);

    /* Return the database handle */
    *ret = db;
    return CYRUSDB_OK;

fail:
    if (mr)
        syslog(LOG_ERR, "cryusdb_lmdb(%s): %s", db->fname, mdb_strerror(mr));
    if (db->env)
        mdb_env_close(db->env);
    free(db->fname);
    free(db);
    return r;
}
void StlAdvancedFeaturesExample::secondary_containers()
{
	int i;

	if (explicit_txn)
		begin_txn(0, penv);
	// test secondary db
	cout<<"\ndb container backed by secondary database.";
	
	dbp3->associate(dbstl::current_txn(penv), dbp3sec, 
	    get_dest_secdb_callback, DB_CREATE);
	typedef db_multimap<int, BaseMsg>  sec_mmap_t;
	sec_mmap_t secmmap(dbp3sec, penv);// index "to" field
	db_map<int, BaseMsg> basemsgs(dbp3, penv);
	basemsgs.clear();
	BaseMsg tmpmsg;
	multiset<BaseMsg> bsmsgs, bsmsgs2;
	multiset<BaseMsg>::iterator bsitr1, bsitr2;
	// populate primary and sec db
	for (i = 0; i < 10; i++) {
		tmpmsg.when = time(NULL);
		tmpmsg.to = 100 - i % 3;// sec index multiple
		tmpmsg.from = i + 20;
		bsmsgs.insert( tmpmsg);
		basemsgs.insert(make_pair(i, tmpmsg));

	}
	check_expr(basemsgs.size() == 10);
	// check retrieved data is identical to those fed in
	sec_mmap_t::iterator itrsec;
	for (itrsec = secmmap.begin(
	    ReadModifyWriteOption::no_read_modify_write(), true);
	    itrsec != secmmap.end(); itrsec++) {
		bsmsgs2.insert(itrsec->second);
	}
	for (bsitr1 = bsmsgs.begin(), bsitr2 = bsmsgs2.begin(); 
	    bsitr1 != bsmsgs.end() && bsitr2 != bsmsgs2.end(); 
	    bsitr1++, bsitr2++) {
		check_expr(*bsitr1 == *bsitr2);
	}
	check_expr(bsitr1 == bsmsgs.end() && bsitr2 == bsmsgs2.end());

	// search using sec index, check the retrieved data is expected
	// and exists in bsmsgs
	check_expr(secmmap.size() == 10);
	pair<sec_mmap_t::iterator, sec_mmap_t::iterator> secrg = 
	    secmmap.equal_range(98);

	for (itrsec = secrg.first; itrsec != secrg.second; itrsec++) {
		check_expr(itrsec->second.to == 98 && 
		    bsmsgs.count(itrsec->second) > 0);
	}
	// delete via sec db
	size_t nersd = secmmap.erase(98);
	check_expr(10 - nersd == basemsgs.size());
	secrg = secmmap.equal_range(98);
	check_expr(secrg.first == secrg.second);

	if (explicit_txn)
		dbstl::commit_txn(penv);
	 
} // secondary_containers
void StlAdvancedFeaturesExample::arbitrary_object_storage()
{
	int i;

	if (explicit_txn)
		begin_txn(0, penv);
	// varying length objects test
	cout<<"\nArbitary object storage using Dbt..\n";
	
	rand_str_dbt smsdbt;
	DbstlDbt dbt, dbtmsg;
	string msgstr;
	SMSMsg *smsmsgs[10];

	dbtmsg.set_flags(DB_DBT_USERMEM);
	dbt.set_data(DbstlMalloc(256));
	dbt.set_flags(DB_DBT_USERMEM);
	dbt.set_ulen(256);
	db_map<int, DbstlDbt> msgmap(dbp3, penv);
	for (i = 0; i < 10; i++) {
		smsdbt(dbt, msgstr, 10, 200);
		SMSMsg *pmsg = SMSMsg::make_sms_msg(time(NULL), 
		    (char *)dbt.get_data(), i);
		smsmsgs[i] = SMSMsg::make_sms_msg(time(NULL), 
		    (char *)dbt.get_data(), i);
		dbtmsg.set_data(pmsg);
		dbtmsg.set_ulen((u_int32_t)(pmsg->mysize));
		dbtmsg.set_size((u_int32_t)(pmsg->mysize));
		dbtmsg.set_flags(DB_DBT_USERMEM);
		msgmap.insert(make_pair(i, dbtmsg));
		free(pmsg);
		memset(&dbtmsg, 0, sizeof(dbtmsg));
	}
	dbtmsg.set_data(NULL);

	SMSMsg *psmsmsg;
	for (i = 0; i < 10; i++) {
		db_map<int, DbstlDbt>::data_type_wrap msgref = msgmap[i];
		psmsmsg = (SMSMsg *)msgref.get_data();
		check_expr(memcmp(smsmsgs[i], psmsmsg, 
		    smsmsgs[i]->mysize) == 0);
	}

	i = 0;
	for (db_map<int, DbstlDbt>::iterator msgitr = 
	    msgmap.begin(ReadModifyWriteOption::
	    read_modify_write()); msgitr != msgmap.end(); ++msgitr, i++) {
		db_map<int, DbstlDbt>::reference smsmsg = *msgitr;
		(((SMSMsg*)(smsmsg.second.get_data())))->when = time(NULL);
		smsmsg.second._DB_STL_StoreElement();
		
	}

	for (i = 0; i < 10; i++) 
		free(smsmsgs[i]);
	
	msgmap.clear();


	cout<<"\nArbitary object(sparse, varying length) storage support using registered callbacks.\n";
	db_map<int, SMSMsg2> msgmap2(dbp3, penv);
	SMSMsg2 smsmsgs2[10];
	DbstlElemTraits<SMSMsg2>::instance()->set_copy_function(SMSMsgCopy);
	DbstlElemTraits<SMSMsg2>::instance()->set_size_function(SMSMsgSize);
	DbstlElemTraits<SMSMsg2>::instance()->set_restore_function(SMSMsgRestore);
	// use new technique to store varying length and inconsecutive objs
	for (i = 0; i < 10; i++) {
		smsdbt(dbt, msgstr, 10, 200);
		SMSMsg2 msg2(time(NULL), msgstr.c_str(), i);
		smsmsgs2[i] = msg2;
		
		msgmap2.insert(make_pair(i, msg2));
	 
	}
	
	// check that retrieved data is identical to stored data
	SMSMsg2 tmpmsg2;
	for (i = 0; i < 10; i++) {
		tmpmsg2 = msgmap2[i];
		check_expr(smsmsgs2[i] == tmpmsg2);
	}
	for (db_map<int, SMSMsg2>::iterator msgitr = 
	    msgmap2.begin(ReadModifyWriteOption::
	    read_modify_write()); msgitr != msgmap2.end(); msgitr++) {
		    db_map<int, SMSMsg2>::reference smsmsg = *msgitr;
		smsmsg.second.when = time(NULL);
		smsmsg.second._DB_STL_StoreElement();
		
	}
	msgmap2.clear();
	if (explicit_txn)
		commit_txn(penv);
} // arbitrary_object_storage
void LMDBFileIndex::start_transaction(void)
{
	begin_txn(0);
}
void LMDBFileIndex::create(get_data_callback_t get_data_callback, void *userdata)
{
	begin_txn(0);

	IDatabase *db=Server->getDatabase(Server->getThreadID(), URBACKUPDB_SERVER_FILES_NEW);

	ServerFilesDao filesdao(db);

	size_t n_done=0;
	size_t n_rows=0;

	SIndexKey last;
	int64 last_prev_entry;
	int64 last_id;
	db_results res;
	do
	{
		res=get_data_callback(n_done, n_rows, userdata);

		++n_rows;

		for(size_t i=0;i<res.size();++i)
		{
			const std::string& shahash=res[i]["shahash"];
			int64 id = watoi64(res[i]["id"]);
			SIndexKey key(reinterpret_cast<const char*>(shahash.c_str()), watoi64(res[i]["filesize"]), watoi(res[i]["clientid"]));

			int64 next_entry = watoi64(res[i]["next_entry"]);
			int64 prev_entry = watoi64(res[i]["prev_entry"]);
			int pointed_to = watoi(res[i]["pointed_to"]);

			assert(memcmp(&last, &key, sizeof(SIndexKey))!=1);

			if(key==last)
			{
				if(last_prev_entry==0)
				{
					filesdao.setPrevEntry(id, last_id);
				}

				if(next_entry==0
					&& (last_prev_entry==0 || last_prev_entry==id) )
				{
					filesdao.setNextEntry(last_id, id);
				}

				if(pointed_to)
				{
					filesdao.setPointedTo(0, id);
				}

				last=key;
				last_id=id;
				last_prev_entry=prev_entry;

				continue;
			}
			else
			{
				if(!pointed_to)
				{
					filesdao.setPointedTo(1, id);
				}
			}
			
			put(key, id, MDB_APPEND);

			if(_has_error)
			{
				Server->Log("LMDB error after putting element. Error state interrupting..", LL_ERROR);
				return;
			}

			if(n_done % 1000 == 0 && n_done>0)
			{
				if ((Server->getFailBits() & IServer::FAIL_DATABASE_CORRUPTED) ||
					(Server->getFailBits() & IServer::FAIL_DATABASE_IOERR) ||
					(Server->getFailBits() & IServer::FAIL_DATABASE_FULL))
				{
					Server->Log("Database error. Stopping.", LL_ERROR);
					return;
				}
				Server->Log("File entry index contains "+convert(n_done)+" entries now.", LL_INFO);
			}

			if(n_done % c_create_commit_n == 0 && n_done>0)
			{
				commit_transaction();
				begin_txn(0);
			}

			++n_done;

			last=key;
			last_id=id;
			last_prev_entry=prev_entry;
		}		
	}
	while(!res.empty());

	commit_transaction();
}