static int mdb_waitfixup( Operation *op, ww_ctx *ww, MDB_cursor *mci, MDB_cursor *mcd ) { int rc = 0; ww->flag = 0; mdb_txn_renew( ww->txn ); mdb_cursor_renew( ww->txn, mci ); mdb_cursor_renew( ww->txn, mcd ); if ( ww->mcd ) { MDB_val key, data; key.mv_size = sizeof(ID); key.mv_data = &ww->key; data = ww->data; rc = mdb_cursor_get( mcd, &key, &data, MDB_GET_BOTH ); if ( rc == MDB_NOTFOUND ) { data = ww->data; rc = mdb_cursor_get( mcd, &key, &data, MDB_GET_BOTH_RANGE ); /* the loop will skip this node using NEXT_DUP but we want it * sent, so go back one space first */ if ( rc == MDB_SUCCESS ) mdb_cursor_get( mcd, &key, &data, MDB_PREV_DUP ); else rc = LDAP_BUSY; } else if ( rc ) { rc = LDAP_OTHER; } op->o_tmpfree( ww->data.mv_data, op->o_tmpmemctx ); ww->data.mv_data = NULL; } return rc; }
static int mdb_waitfixup( Operation *op, ww_ctx *ww, MDB_cursor *mci, MDB_cursor *mcd, IdScopes *isc ) { MDB_val key; int rc = 0; ww->flag = 0; ww->nentries = 0; rc = mdb_txn_renew( ww->txn ); assert(rc == MDB_SUCCESS); rc = mdb_cursor_renew( ww->txn, mci ); assert(rc == MDB_SUCCESS); rc = mdb_cursor_renew( ww->txn, mcd ); assert(rc == MDB_SUCCESS); key.mv_size = sizeof(ID); if ( ww->mcd ) { /* scope-based search using dn2id_walk */ if ( isc->numrdns ) mdb_dn2id_wrestore( op, isc ); if ( ww->data.mv_data ) { MDB_val data; key.mv_data = &ww->key; data = ww->data; rc = mdb_cursor_get( mcd, &key, &data, MDB_GET_BOTH ); if ( rc == MDB_NOTFOUND ) { data = ww->data; rc = mdb_cursor_get( mcd, &key, &data, MDB_GET_BOTH_RANGE ); /* the loop will skip this node using NEXT_DUP but we want it * sent, so go back one space first */ if ( rc == MDB_SUCCESS ) mdb_cursor_get( mcd, &key, &data, MDB_PREV_DUP ); else rc = LDAP_BUSY; } else if ( rc ) { rc = LDAP_OTHER; } op->o_tmpfree( ww->data.mv_data, op->o_tmpmemctx ); ww->data.mv_data = NULL; } ww->flag = 0; } else if ( isc->scopes[0].mid > 1 ) { /* candidate-based search */ int i; for ( i=1; i<isc->scopes[0].mid; i++ ) { if ( !isc->scopes[i].mval.mv_data ) continue; key.mv_data = &isc->scopes[i].mid; rc = mdb_cursor_get( mcd, &key, &isc->scopes[i].mval, MDB_SET_RANGE ); if ( rc != MDB_SUCCESS ) { /* LY: Yea, this is my paranoia */ rc = (rc == MDB_NOTFOUND) ? LDAP_BUSY : LDAP_OTHER; break; } } } return rc; }
static void *perform(void *arg) { db_thread *thr = (db_thread*)arg; int i,rc; mdbinf* mdb = &thr->mdb; srand((u32)pthread_self()); open_txn(mdb, MDB_RDONLY); thr->resFrames = alloca((SQLITE_DEFAULT_PAGE_SIZE/thr->maxvalsize + 1)*sizeof(MDB_val)); for (i = 0; i < 1000*100; i++) { int j = rand() % NCONS; if (i % 1000 == 0) printf("r %lld %d\n",(i64)pthread_self(),i); if (pthread_mutex_trylock(&g_cons[j].wal.mtx) != 0) continue; g_tsd_conn = &g_cons[j]; rc = sqlite3_exec(g_cons[j].db,"SELECT max(id) FROM tab;",NULL,NULL,NULL); if (rc != SQLITE_OK) { printf("Error select"); break; } pthread_mutex_unlock(&g_cons[j].wal.mtx); mdb_txn_reset(thr->mdb.txn); rc = mdb_txn_renew(thr->mdb.txn); if (rc != MDB_SUCCESS) break; rc = mdb_cursor_renew(mdb->txn, mdb->cursorLog); if (rc != MDB_SUCCESS) break; rc = mdb_cursor_renew(mdb->txn, mdb->cursorPages); if (rc != MDB_SUCCESS) break; rc = mdb_cursor_renew(mdb->txn, mdb->cursorInfo); if (rc != MDB_SUCCESS) break; } mdb_cursor_close(mdb->cursorLog); mdb_cursor_close(mdb->cursorPages); mdb_cursor_close(mdb->cursorInfo); mdb_txn_abort(mdb->txn); return NULL; }
CAMLprim value caml_mdb_cursor_renew(value txn,value cursor){ CAMLparam2(txn,cursor); if(mdb_cursor_renew( (MDB_txn*) txn, (MDB_cursor*) cursor)){ caml_failwith("error in mdb_cursor_renew"); } CAMLreturn0; }
int db_cursor_first_pfx(MDB_cursor *const cursor, MDB_val const *const pfx, MDB_val *const key, MDB_val *const data) { *key = *pfx; int rc = mdb_cursor_seek(cursor, key, data, +1); rc = db_pfx(rc, pfx, key); if(MDB_SUCCESS == rc) return MDB_SUCCESS; mdb_cursor_renew(mdb_cursor_txn(cursor), cursor); return MDB_NOTFOUND; }
int db_cursor_seekr(MDB_cursor *const cursor, DB_range const *const range, MDB_val *const key, MDB_val *const data, int const dir) { int rc = mdb_cursor_seek(cursor, key, data, dir); if(MDB_SUCCESS != rc) return rc; MDB_val const *const limit = dir < 0 ? range->min : range->max; int x = mdb_cmp(mdb_cursor_txn(cursor), key, limit); if(x * dir < 0) return MDB_SUCCESS; mdb_cursor_renew(mdb_cursor_txn(cursor), cursor); return MDB_NOTFOUND; }
/* * Class: jmdb_DatabaseWrapper * Method: cursorRenew * Signature: (JJ)V */ JNIEXPORT void JNICALL Java_jmdb_DatabaseWrapper_cursorRenew(JNIEnv *vm, jclass clazz, jlong txnL, jlong cursorL) { MDB_txn *txnC = (MDB_txn*) txnL; MDB_cursor *cursorC = (MDB_cursor*) cursorL; jint code = mdb_cursor_renew(txnC, cursorC); if (code) { throwDatabaseException(vm, code); } }
int db_cursor_firstr(MDB_cursor *const cursor, DB_range const *const range, MDB_val *const key, MDB_val *const data, int const dir) { if(!cursor) return EINVAL; if(0 == dir) return EINVAL; MDB_val const *const first = dir < 0 ? range->min : range->max; *key = first; int rc = mdb_cursor_seek(cursor, key, data, dir); if(MDB_SUCCESS != rc) return rc; int x = mdb_cmp(mdb_cursor_txn(cursor), first, key); if(0 == x) rc = mdb_cursor_next(cursor, key, data, dir); if(MDB_SUCCESS != rc) return rc; MDB_val const *const last = dir < 0 ? range->max : range->min; x = mdb_cmp(mdb_cursor_txn(cursor), key, last); if(x * dir < 0) return MDB_SUCCESS; mdb_cursor_renew(mdb_cursor_txn(cursor), cursor); return MDB_NOTFOUND; }
int main(int argc, const char* argv[]) { g_log = stdout; db_thread thr; db_thread threads[RTHREADS]; pthread_t tids[RTHREADS]; priv_data pd; mdbinf* mdb = &thr.mdb; int i, rc; db_connection *cons; g_pd = &pd; char commit = 1; MDB_env *menv = NULL; char *lmpath = "lmdb"; MDB_txn *txn; MDB_val key = {1,(void*)"?"}, data = {0,NULL}; MDB_envinfo stat; sqlite3_initialize(); sqlite3_vfs_register(sqlite3_nullvfs(), 1); unlink(lmpath); memset(threads, 0, sizeof(threads)); memset(&thr, 0, sizeof(db_thread)); memset(&pd, 0, sizeof(priv_data)); pd.wmdb = calloc(1,sizeof(mdbinf)); pd.nEnvs = 1; pd.nReadThreads = RTHREADS; pd.nWriteThreads = 1; pd.syncNumbers = calloc(1,sizeof(u64)); pd.actorIndexes = calloc(1,sizeof(atomic_llong)); atomic_init(pd.actorIndexes,0); g_cons = cons = calloc(NCONS, sizeof(db_connection)); g_tsd_cursync = 0; g_tsd_conn = NULL; g_tsd_wmdb = NULL; g_tsd_thread = &thr; if (mdb_env_create(&menv) != MDB_SUCCESS) return -1; if (mdb_env_set_maxdbs(menv,5) != MDB_SUCCESS) return -1; if (mdb_env_set_mapsize(menv,1024*1024*1024) != MDB_SUCCESS) return -1; // Syncs are handled from erlang. if (mdb_env_open(menv, lmpath, MDB_NOSUBDIR|MDB_NOTLS|MDB_NOSYNC, 0664) != MDB_SUCCESS) //MDB_NOSYNC return -1; if (mdb_txn_begin(menv, NULL, 0, &txn) != MDB_SUCCESS) return -1; if (mdb_dbi_open(txn, "info", MDB_INTEGERKEY | MDB_CREATE, &pd.wmdb[0].infodb) != MDB_SUCCESS) return -1; if (mdb_dbi_open(txn, "actors", MDB_CREATE, &pd.wmdb[0].actorsdb) != MDB_SUCCESS) return -1; if (mdb_dbi_open(txn, "log", MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED | MDB_INTEGERDUP, &pd.wmdb[0].logdb) != MDB_SUCCESS) return -1; if (mdb_dbi_open(txn, "pages", MDB_CREATE | MDB_DUPSORT, &pd.wmdb[0].pagesdb) != MDB_SUCCESS) return -1; if (mdb_txn_commit(txn) != MDB_SUCCESS) return -1; pd.wmdb[0].env = menv; thr.nEnv = 0; thr.isreadonly = 0; thr.mdb.env = menv; thr.mdb.infodb = pd.wmdb[0].infodb; thr.mdb.actorsdb = pd.wmdb[0].actorsdb; thr.mdb.logdb = pd.wmdb[0].logdb; thr.mdb.pagesdb = pd.wmdb[0].pagesdb; thr.maxvalsize = mdb_env_get_maxkeysize(mdb->env); thr.resFrames = alloca((SQLITE_DEFAULT_PAGE_SIZE/thr.maxvalsize + 1)*sizeof(MDB_val)); open_txn(&thr.mdb, MDB_RDONLY); for (i = 0; i < NCONS; i++) { char filename[256]; char commit = 1; g_tsd_conn = &cons[i]; sprintf(filename, "ac%d.db", i); pthread_mutex_init(&cons[i].wal.mtx, NULL); thr.pagesChanged = 0; rc = sqlite3_open(filename,&(cons[i].db)); if(rc != SQLITE_OK) { DBG("Unable to open db"); break; } rc = sqlite3_exec(cons[i].db,"PRAGMA synchronous=0;PRAGMA journal_mode=wal;",NULL,NULL,NULL); if (rc != SQLITE_OK) { DBG("unable to open wal"); break; } cons[i].wal.inProgressTerm = 1; cons[i].wal.inProgressEvnum = 1; rc = sqlite3_exec(cons[i].db,"CREATE TABLE tab (id INTEGER PRIMARY KEY, txt TEXT);" "insert into tab values (1,'aaaa');",NULL,NULL,NULL); if (rc != SQLITE_OK) { DBG("Cant create table"); break; } unlock_write_txn(thr.nEnv, 0, &commit); mdb_txn_reset(thr.mdb.txn); rc = mdb_txn_renew(thr.mdb.txn); if (rc != MDB_SUCCESS) break; rc = mdb_cursor_renew(thr.mdb.txn, mdb->cursorLog); if (rc != MDB_SUCCESS) break; rc = mdb_cursor_renew(thr.mdb.txn, mdb->cursorPages); if (rc != MDB_SUCCESS) break; rc = mdb_cursor_renew(thr.mdb.txn, mdb->cursorInfo); if (rc != MDB_SUCCESS) break; } // mdb_cursor_close(thr.mdb.cursorLog); // mdb_cursor_close(thr.mdb.cursorPages); // mdb_cursor_close(thr.mdb.cursorInfo); // mdb_txn_abort(thr.mdb.txn); for (i = 0; i < RTHREADS; i++) { threads[i].nEnv = 0; threads[i].isreadonly = 0; threads[i].mdb.env = menv; threads[i].mdb.infodb = pd.wmdb[0].infodb; threads[i].mdb.actorsdb = pd.wmdb[0].actorsdb; threads[i].mdb.logdb = pd.wmdb[0].logdb; threads[i].mdb.pagesdb = pd.wmdb[0].pagesdb; threads[i].maxvalsize = mdb_env_get_maxkeysize(mdb->env); pthread_create(&tids[i], NULL, perform, (void *)&threads[i]); } srand((u32)pthread_self() + time(NULL)); for (i = 0; i < 1000*200; i++) { char commit = 1; int j = rand() % NCONS; db_connection *con = &g_cons[j]; char str[100]; if (pthread_mutex_trylock(&con->wal.mtx) != 0) { i--; continue; } if (i % 1000 == 0) printf("w %d\n",i); g_tsd_conn = con; lock_wtxn(thr.nEnv); thr.pagesChanged = 0; if (con->wal.firstCompleteEvnum+10 < con->wal.lastCompleteEvnum) { // printf("CHECKPOINT? %llu %llu\n",con->wal.firstCompleteEvnum,con->wal.lastCompleteEvnum); if (checkpoint(&con->wal, con->wal.lastCompleteEvnum-10) != SQLITE_OK) { printf("Checkpoint failed\n"); break; } } con->wal.inProgressTerm = 1; con->wal.inProgressEvnum = con->wal.lastCompleteEvnum+1; sprintf(str,"INSERT INTO tab VALUES (%d,'VALUE VALUE13456');", i); sqlite3_exec(con->db,str,NULL,NULL,NULL); pthread_mutex_unlock(&con->wal.mtx); unlock_write_txn(thr.nEnv, 0, &commit); mdb_txn_reset(thr.mdb.txn); rc = mdb_txn_renew(thr.mdb.txn); if (rc != MDB_SUCCESS) break; rc = mdb_cursor_renew(thr.mdb.txn, mdb->cursorLog); if (rc != MDB_SUCCESS) break; rc = mdb_cursor_renew(thr.mdb.txn, mdb->cursorPages); if (rc != MDB_SUCCESS) break; rc = mdb_cursor_renew(thr.mdb.txn, mdb->cursorInfo); if (rc != MDB_SUCCESS) break; } unlock_write_txn(thr.nEnv, 1, &commit); for (i = 0; i < RTHREADS; i++) pthread_join(tids[i],NULL); return 1; }