#include "lsmtest.h"
#define DATA_SEQUENTIAL TEST_DATASOURCE_SEQUENCE
#define DATA_RANDOM TEST_DATASOURCE_RANDOM
typedef struct Datatest1 Datatest1;
typedef struct Datatest2 Datatest2;
struct Datatest1 {
DatasourceDefn defn;
int nRow;
int nVerify;
int nTest;
int bTestScan;
};
struct Datatest2 {
DatasourceDefn defn;
int nRange;
int nWrite;
int nIter;
};
static char *getName(const char *zSystem, int bRecover, Datatest1 *pTest){
char *zRet;
char *zData;
zData = testDatasourceName(&pTest->defn);
zRet = testMallocPrintf("data.%s.%s.rec=%d.%d.%d",
zSystem, zData, bRecover, pTest->nRow, pTest->nVerify
);
testFree(zData);
return zRet;
}
int testControlDb(TestDb **ppDb){
#ifdef HAVE_KYOTOCABINET
return tdb_open("kyotocabinet", "tmp.db", 1, ppDb);
#else
return tdb_open("sqlite3", "", 1, ppDb);
#endif
}
void testDatasourceFetch(
TestDb *pDb,
Datasource *pData,
int iKey,
int *pRc
){
void *pKey; int nKey;
void *pVal; int nVal;
testDatasourceEntry(pData, iKey, &pKey, &nKey, &pVal, &nVal);
testFetch(pDb, pKey, nKey, pVal, nVal, pRc);
}
void testDbContents(
TestDb *pDb,
Datasource *pData,
int nRow,
int iFirst,
int iLast,
int nLookupTest,
int nScanTest,
int *pRc
){
int j;
int rc = *pRc;
if( rc==0 && nScanTest ){
TestDb *pDb2 = 0;
rc = testControlDb(&pDb2);
for(j=iFirst; rc==0 && j<=iLast; j++){
void *pKey; int nKey;
void *pVal; int nVal;
testDatasourceEntry(pData, j, &pKey, &nKey, &pVal, &nVal);
rc = tdb_write(pDb2, pKey, nKey, pVal, nVal);
}
if( rc==0 ){
int iKey1;
int iKey2;
void *pKey1; int nKey1;
void *pKey2; int nKey2;
iKey1 = testPrngValue((iFirst<<8) + (iLast<<16)) % nRow;
iKey2 = testPrngValue((iLast<<8) + (iFirst<<16)) % nRow;
testDatasourceEntry(pData, iKey1, &pKey2, &nKey1, 0, 0);
pKey1 = testMalloc(nKey1+1);
memcpy(pKey1, pKey2, nKey1+1);
testDatasourceEntry(pData, iKey2, &pKey2, &nKey2, 0, 0);
testScanCompare(pDb2, pDb, 0, 0, 0, 0, 0, &rc);
testScanCompare(pDb2, pDb, 0, 0, 0, pKey2, nKey2, &rc);
testScanCompare(pDb2, pDb, 0, pKey1, nKey1, 0, 0, &rc);
testScanCompare(pDb2, pDb, 0, pKey1, nKey1, pKey2, nKey2, &rc);
testScanCompare(pDb2, pDb, 1, 0, 0, 0, 0, &rc);
testScanCompare(pDb2, pDb, 1, 0, 0, pKey2, nKey2, &rc);
testScanCompare(pDb2, pDb, 1, pKey1, nKey1, 0, 0, &rc);
testScanCompare(pDb2, pDb, 1, pKey1, nKey1, pKey2, nKey2, &rc);
testFree(pKey1);
}
tdb_close(pDb2);
}
for(j=0; rc==0 && j<nLookupTest; j++){
int iKey;
void *pKey; int nKey;
void *pVal; int nVal;
if( nLookupTest>=nRow ){
iKey = j;
}else{
iKey = testPrngValue(j + (iFirst<<8) + (iLast<<16)) % nRow;
}
testDatasourceEntry(pData, iKey, &pKey, &nKey, &pVal, &nVal);
if( iFirst>iKey || iKey>iLast ){
pVal = 0;
nVal = -1;
}
testFetch(pDb, pKey, nKey, pVal, nVal, &rc);
}
*pRc = rc;
}
void testCaseProgress(int i, int n, int nDot, int *piDot){
int iDot = *piDot;
while( iDot < ( ((nDot*2+1) * i) / (n*2) ) ){
printf(".");
fflush(stdout);
iDot++;
}
*piDot = iDot;
}
int testCaseNDot(void){ return 20; }
#if 0#endif
void testReopenRecover(TestDb **ppDb, int *pRc){
if( *pRc==0 ){
const char *zLib = tdb_library_name(*ppDb);
const char *zDflt = tdb_default_db(zLib);
testCopyLsmdb(zDflt, "bak.db");
testClose(ppDb);
testCopyLsmdb("bak.db", zDflt);
*pRc = tdb_open(zLib, 0, 0, ppDb);
}
}
static void doDataTest1(
const char *zSystem,
int bRecover,
Datatest1 *p,
int *pRc
){
int i;
int iDot;
int rc = LSM_OK;
Datasource *pData;
TestDb *pDb;
int iToggle = 0;
pDb = testOpen(zSystem, 1, &rc);
pData = testDatasourceNew(&p->defn);
i = 0;
iDot = 0;
while( rc==LSM_OK && i<p->nRow ){
testWriteDatasourceRange(pDb, pData, i, p->nVerify, &rc);
i += p->nVerify;
if( iToggle ) testBegin(pDb, 1, &rc);
testDbContents(pDb, pData, p->nRow, 0, i-1, p->nTest, p->bTestScan, &rc);
if( iToggle ) testCommit(pDb, 0, &rc);
iToggle = (iToggle+1)%2;
if( bRecover ){
testReopenRecover(&pDb, &rc);
}else{
testReopen(&pDb, &rc);
}
testDbContents(pDb, pData, p->nRow, 0, i-1, p->nTest, p->bTestScan, &rc);
testCaseProgress(i, p->nRow, testCaseNDot()/2, &iDot);
}
i = 0;
iDot = 0;
while( rc==LSM_OK && i<p->nRow ){
testDeleteDatasourceRange(pDb, pData, i, p->nVerify, &rc);
i += p->nVerify;
testDbContents(pDb, pData, p->nRow, i, p->nRow-1,p->nTest,p->bTestScan,&rc);
if( bRecover ){
testReopenRecover(&pDb, &rc);
}else{
testReopen(&pDb, &rc);
}
testDbContents(pDb, pData, p->nRow, i, p->nRow-1,p->nTest,p->bTestScan,&rc);
testCaseProgress(i, p->nRow, testCaseNDot()/2, &iDot);
}
testDatasourceFree(pData);
tdb_close(pDb);
testCaseFinish(rc);
*pRc = rc;
}
void test_data_1(
const char *zSystem,
const char *zPattern,
int *pRc
){
Datatest1 aTest[] = {
{ {DATA_RANDOM, 500,600, 1000,2000}, 1000, 100, 10, 0},
{ {DATA_RANDOM, 20,25, 100,200}, 1000, 250, 1000, 1},
{ {DATA_RANDOM, 8,10, 100,200}, 1000, 250, 1000, 1},
{ {DATA_RANDOM, 8,10, 10,20}, 1000, 250, 1000, 1},
{ {DATA_RANDOM, 8,10, 1000,2000}, 1000, 250, 1000, 1},
{ {DATA_RANDOM, 8,100, 10000,20000}, 100, 25, 100, 1},
{ {DATA_RANDOM, 80,100, 10,20}, 1000, 250, 1000, 1},
{ {DATA_RANDOM, 5000,6000, 10,20}, 100, 25, 100, 1},
{ {DATA_SEQUENTIAL, 5,10, 10,20}, 1000, 250, 1000, 1},
{ {DATA_SEQUENTIAL, 5,10, 100,200}, 1000, 250, 1000, 1},
{ {DATA_SEQUENTIAL, 5,10, 1000,2000}, 1000, 250, 1000, 1},
{ {DATA_SEQUENTIAL, 5,100, 10000,20000}, 100, 25, 100, 1},
{ {DATA_RANDOM, 10,10, 100,100}, 100000, 1000, 100, 0},
{ {DATA_SEQUENTIAL, 10,10, 100,100}, 100000, 1000, 100, 0},
};
int i;
int bRecover;
for(bRecover=0; bRecover<2; bRecover++){
if( bRecover==1 && memcmp(zSystem, "lsm", 3) ) break;
for(i=0; *pRc==LSM_OK && i<ArraySize(aTest); i++){
char *zName = getName(zSystem, bRecover, &aTest[i]);
if( testCaseBegin(pRc, zPattern, "%s", zName) ){
doDataTest1(zSystem, bRecover, &aTest[i], pRc);
}
testFree(zName);
}
}
}
void testCompareDb(
Datasource *pData,
int nData,
int iSeed,
TestDb *pControl,
TestDb *pDb,
int *pRc
){
int i;
static int nCall = 0;
nCall++;
testScanCompare(pControl, pDb, 0, 0, 0, 0, 0, pRc);
testScanCompare(pControl, pDb, 1, 0, 0, 0, 0, pRc);
if( *pRc==0 ){
int iKey1;
int iKey2;
void *pKey1; int nKey1;
void *pKey2; int nKey2;
iKey1 = testPrngValue(iSeed) % nData;
iKey2 = testPrngValue(iSeed+1) % nData;
testDatasourceEntry(pData, iKey1, &pKey2, &nKey1, 0, 0);
pKey1 = testMalloc(nKey1+1);
memcpy(pKey1, pKey2, nKey1+1);
testDatasourceEntry(pData, iKey2, &pKey2, &nKey2, 0, 0);
testScanCompare(pControl, pDb, 0, 0, 0, pKey2, nKey2, pRc);
testScanCompare(pControl, pDb, 0, pKey1, nKey1, 0, 0, pRc);
testScanCompare(pControl, pDb, 0, pKey1, nKey1, pKey2, nKey2, pRc);
testScanCompare(pControl, pDb, 1, 0, 0, pKey2, nKey2, pRc);
testScanCompare(pControl, pDb, 1, pKey1, nKey1, 0, 0, pRc);
testScanCompare(pControl, pDb, 1, pKey1, nKey1, pKey2, nKey2, pRc);
testFree(pKey1);
}
for(i=0; i<nData && *pRc==0; i++){
void *pKey; int nKey;
testDatasourceEntry(pData, i, &pKey, &nKey, 0, 0);
testFetchCompare(pControl, pDb, pKey, nKey, pRc);
}
}
static void doDataTest2(
const char *zSystem,
int bRecover,
Datatest2 *p,
int *pRc
){
TestDb *pDb;
TestDb *pControl;
Datasource *pData;
int i;
int rc = LSM_OK;
int iDot = 0;
pDb = testOpen(zSystem, 1, &rc);
pData = testDatasourceNew(&p->defn);
rc = testControlDb(&pControl);
if( tdb_lsm(pDb) ){
int nBuf = 32 * 1024 * 1024;
lsm_config(tdb_lsm(pDb), LSM_CONFIG_AUTOFLUSH, &nBuf);
}
for(i=0; rc==0 && i<p->nIter; i++){
void *pKey1; int nKey1;
void *pKey2; int nKey2;
int ii;
int nRange = MIN(p->nIter*p->nWrite, p->nRange);
for(ii=0; rc==0 && ii<p->nWrite; ii++){
int iKey = (i*p->nWrite + ii) % p->nRange;
testWriteDatasource(pControl, pData, iKey, &rc);
testWriteDatasource(pDb, pData, iKey, &rc);
}
testDatasourceEntry(pData, i+1000000, &pKey1, &nKey1, 0, 0);
pKey1 = testMallocCopy(pKey1, nKey1);
testDatasourceEntry(pData, i+2000000, &pKey2, &nKey2, 0, 0);
testDeleteRange(pDb, pKey1, nKey1, pKey2, nKey2, &rc);
testDeleteRange(pControl, pKey1, nKey1, pKey2, nKey2, &rc);
testFree(pKey1);
testCompareDb(pData, nRange, i, pControl, pDb, &rc);
if( bRecover ){
testReopenRecover(&pDb, &rc);
}else{
testReopen(&pDb, &rc);
}
testCompareDb(pData, nRange, i, pControl, pDb, &rc);
testCaseProgress(i, p->nIter, testCaseNDot(), &iDot);
}
testClose(&pDb);
testClose(&pControl);
testDatasourceFree(pData);
testCaseFinish(rc);
*pRc = rc;
}
static char *getName2(const char *zSystem, int bRecover, Datatest2 *pTest){
char *zRet;
char *zData;
zData = testDatasourceName(&pTest->defn);
zRet = testMallocPrintf("data2.%s.%s.rec=%d.%d.%d.%d",
zSystem, zData, bRecover, pTest->nRange, pTest->nWrite, pTest->nIter
);
testFree(zData);
return zRet;
}
void test_data_2(
const char *zSystem,
const char *zPattern,
int *pRc
){
Datatest2 aTest[] = {
{ {DATA_RANDOM, 20,25, 100,200}, 10000, 10, 50 },
{ {DATA_RANDOM, 20,25, 100,200}, 10000, 200, 50 },
{ {DATA_RANDOM, 20,25, 100,200}, 100, 10, 1000 },
{ {DATA_RANDOM, 20,25, 100,200}, 100, 200, 50 },
};
int i;
int bRecover;
for(bRecover=0; bRecover<2; bRecover++){
if( bRecover==1 && memcmp(zSystem, "lsm", 3) ) break;
for(i=0; *pRc==LSM_OK && i<ArraySize(aTest); i++){
char *zName = getName2(zSystem, bRecover, &aTest[i]);
if( testCaseBegin(pRc, zPattern, "%s", zName) ){
doDataTest2(zSystem, bRecover, &aTest[i], pRc);
}
testFree(zName);
}
}
}
typedef struct Datatest3 Datatest3;
struct Datatest3 {
int nRange;
int nIter;
int nWrite;
int nDelete;
int nValMin;
int nValMax;
};
void testPutU32(u8 *aBuf, u32 iVal){
aBuf[0] = (iVal >> 24) & 0xFF;
aBuf[1] = (iVal >> 16) & 0xFF;
aBuf[2] = (iVal >> 8) & 0xFF;
aBuf[3] = (iVal >> 0) & 0xFF;
}
void dt3PutKey(u8 *aBuf, int iKey){
assert( iKey<100000 && iKey>=0 );
sprintf((char *)aBuf, "%.5d", iKey);
}
static void doDataTest3(
const char *zSystem,
Datatest3 *p,
int *pRc
){
int iDot = 0;
int rc = *pRc;
TestDb *pDb;
u8 *abPresent;
char *aVal;
int i;
u32 iSeq = 10;
abPresent = (u8 *)testMalloc(p->nRange+1);
aVal = (char *)testMalloc(p->nValMax+1);
pDb = testOpen(zSystem, 1, &rc);
for(i=0; i<p->nIter && rc==0; i++){
int ii;
testCaseProgress(i, p->nIter, testCaseNDot(), &iDot);
for(ii=0; ii<p->nWrite; ii++){
u8 aKey[6];
u32 iKey;
int nVal;
iKey = (testPrngValue(iSeq++) % p->nRange) + 1;
nVal = (testPrngValue(iSeq++) % (p->nValMax - p->nValMin)) + p->nValMin;
testPrngString(testPrngValue(iSeq++), aVal, nVal);
dt3PutKey(aKey, iKey);
testWrite(pDb, aKey, sizeof(aKey)-1, aVal, nVal, &rc);
abPresent[iKey] = 1;
}
for(ii=0; ii<p->nDelete; ii++){
u8 aKey1[6];
u8 aKey2[6];
u32 iKey;
iKey = (testPrngValue(iSeq++) % p->nRange) + 1;
dt3PutKey(aKey1, iKey-1);
dt3PutKey(aKey2, iKey+1);
testDeleteRange(pDb, aKey1, sizeof(aKey1)-1, aKey2, sizeof(aKey2)-1, &rc);
abPresent[iKey] = 0;
}
testReopen(&pDb, &rc);
for(ii=1; rc==0 && ii<=p->nRange; ii++){
int nDbVal;
void *pDbVal;
u8 aKey[6];
int dbrc;
dt3PutKey(aKey, ii);
dbrc = tdb_fetch(pDb, aKey, sizeof(aKey)-1, &pDbVal, &nDbVal);
testCompareInt(0, dbrc, &rc);
if( abPresent[ii] ){
testCompareInt(1, (nDbVal>0), &rc);
}else{
testCompareInt(1, (nDbVal<0), &rc);
}
}
}
testClose(&pDb);
testCaseFinish(rc);
*pRc = rc;
}
static char *getName3(const char *zSystem, Datatest3 *p){
return testMallocPrintf("data3.%s.%d.%d.%d.%d.(%d..%d)",
zSystem, p->nRange, p->nIter, p->nWrite, p->nDelete,
p->nValMin, p->nValMax
);
}
void test_data_3(
const char *zSystem,
const char *zPattern,
int *pRc
){
Datatest3 aTest[] = {
{ 100, 1000, 5, 5, 50, 100 },
{ 100, 1000, 2, 2, 5, 10 },
};
int i;
for(i=0; *pRc==LSM_OK && i<ArraySize(aTest); i++){
char *zName = getName3(zSystem, &aTest[i]);
if( testCaseBegin(pRc, zPattern, "%s", zName) ){
doDataTest3(zSystem, &aTest[i], pRc);
}
testFree(zName);
}
}