#include "lsmtest.h"
struct CksumDb {
int nFirst;
int nLast;
int nStep;
char **azCksum;
};
CksumDb *testCksumArrayNew(
Datasource *pData,
int nFirst,
int nLast,
int nStep
){
TestDb *pDb;
CksumDb *pRet;
int i;
int nEntry;
int rc = 0;
assert( nLast>=nFirst && ((nLast-nFirst)%nStep)==0 );
pRet = malloc(sizeof(CksumDb));
memset(pRet, 0, sizeof(CksumDb));
pRet->nFirst = nFirst;
pRet->nLast = nLast;
pRet->nStep = nStep;
nEntry = 1 + ((nLast - nFirst) / nStep);
pRet->azCksum = (char **)malloc(nEntry * (sizeof(char *) + TEST_CKSUM_BYTES));
for(i=0; i<nEntry; i++){
char *pStart = (char *)(&pRet->azCksum[nEntry]);
pRet->azCksum[i] = &pStart[i * TEST_CKSUM_BYTES];
}
tdb_open("lsm", "tempdb.lsm", 1, &pDb);
testWriteDatasourceRange(pDb, pData, 0, nFirst, &rc);
for(i=0; i<nEntry; i++){
testCksumDatabase(pDb, pRet->azCksum[i]);
if( i==nEntry ) break;
testWriteDatasourceRange(pDb, pData, nFirst+i*nStep, nStep, &rc);
}
tdb_close(pDb);
return pRet;
}
char *testCksumArrayGet(CksumDb *p, int nRow){
int i;
assert( nRow>=p->nFirst );
assert( nRow<=p->nLast );
assert( ((nRow-p->nFirst) % p->nStep)==0 );
i = (nRow - p->nFirst) / p->nStep;
return p->azCksum[i];
}
void testCksumArrayFree(CksumDb *p){
free(p->azCksum);
memset(p, 0x55, sizeof(*p));
free(p);
}
void testWriteDatasource(TestDb *pDb, Datasource *pData, int i, int *pRc){
void *pKey; int nKey;
void *pVal; int nVal;
testDatasourceEntry(pData, i, &pKey, &nKey, &pVal, &nVal);
testWrite(pDb, pKey, nKey, pVal, nVal, pRc);
}
void testDeleteDatasource(TestDb *pDb, Datasource *pData, int i, int *pRc){
void *pKey; int nKey;
testDatasourceEntry(pData, i, &pKey, &nKey, 0, 0);
testDelete(pDb, pKey, nKey, pRc);
}
void testWriteDatasourceRange(
TestDb *pDb,
Datasource *pData,
int iFirst,
int nWrite,
int *pRc
){
int i;
for(i=0; i<nWrite; i++){
testWriteDatasource(pDb, pData, iFirst+i, pRc);
}
}
void testDeleteDatasourceRange(
TestDb *pDb,
Datasource *pData,
int iFirst,
int nWrite,
int *pRc
){
int i;
for(i=0; i<nWrite; i++){
testDeleteDatasource(pDb, pData, iFirst+i, pRc);
}
}
static char *getName(const char *zSystem){
char *zRet;
zRet = testMallocPrintf("rollback.%s", zSystem);
return zRet;
}
static int rollback_test_1(
const char *zSystem,
Datasource *pData
){
const int nRepeat = 100;
TestDb *pDb;
int rc;
int i;
CksumDb *pCksum;
char *zName;
zName = getName(zSystem);
testCaseStart(&rc, zName);
testFree(zName);
pCksum = testCksumArrayNew(pData, 0, nRepeat*100, 100);
pDb = 0;
rc = tdb_open(zSystem, 0, 1, &pDb);
if( pDb && tdb_transaction_support(pDb)==0 ){
testCaseSkip();
goto skip_rollback_test;
}
for(i=0; i<nRepeat && rc==0; i++){
char zCksum[TEST_CKSUM_BYTES];
int nCurrent = (((i+1)/2) * 100);
int nDbRow;
int iTrans;
nDbRow = testCountDatabase(pDb);
testCompareInt(nCurrent, nDbRow, &rc);
for(iTrans=2; iTrans<=6 && rc==0; iTrans++){
tdb_begin(pDb, iTrans);
testWriteDatasourceRange(pDb, pData, nCurrent, 100, &rc);
nCurrent += 100;
}
testCksumDatabase(pDb, zCksum);
testCompareStr(zCksum, testCksumArrayGet(pCksum, nCurrent), &rc);
for(iTrans=6; iTrans>2 && rc==0; iTrans--){
tdb_rollback(pDb, iTrans);
nCurrent -= 100;
testCksumDatabase(pDb, zCksum);
testCompareStr(zCksum, testCksumArrayGet(pCksum, nCurrent), &rc);
}
if( i%2 ){
tdb_rollback(pDb, 0);
nCurrent -= 100;
testCksumDatabase(pDb, zCksum);
testCompareStr(zCksum, testCksumArrayGet(pCksum, nCurrent), &rc);
}else{
tdb_commit(pDb, 0);
}
}
testCaseFinish(rc);
skip_rollback_test:
tdb_close(pDb);
testCksumArrayFree(pCksum);
return rc;
}
void test_rollback(
const char *zSystem,
const char *zPattern,
int *pRc
){
if( *pRc==0 ){
int bRun = 1;
if( zPattern ){
char *zName = getName(zSystem);
bRun = testGlobMatch(zPattern, zName);
testFree(zName);
}
if( bRun ){
DatasourceDefn defn = { TEST_DATASOURCE_RANDOM, 10, 15, 50, 100 };
Datasource *pData = testDatasourceNew(&defn);
*pRc = rollback_test_1(zSystem, pData);
testDatasourceFree(pData);
}
}
}