diff options
Diffstat (limited to 'ext/lsm1/lsm-test/lsmtest3.c')
-rw-r--r-- | ext/lsm1/lsm-test/lsmtest3.c | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/ext/lsm1/lsm-test/lsmtest3.c b/ext/lsm1/lsm-test/lsmtest3.c new file mode 100644 index 0000000..760dec3 --- /dev/null +++ b/ext/lsm1/lsm-test/lsmtest3.c @@ -0,0 +1,238 @@ + + +/* +** This file contains tests related to the explicit rollback of database +** transactions and sub-transactions. +*/ + + +/* +** Repeat 2000 times (until the db contains 100,000 entries): +** +** 1. Open a transaction and insert 500 rows, opening a nested +** sub-transaction each 100 rows. +** +** 2. Roll back to each sub-transaction savepoint. Check the database +** checksum looks Ok. +** +** 3. Every second iteration, roll back the main transaction. Check the +** db checksum is correct. Every other iteration, commit the main +** transaction (increasing the size of the db by 100 rows). +*/ + + +#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); + + /* Allocate space so that azCksum is an array of nEntry pointers to + ** buffers each TEST_CKSUM_BYTES in size. */ + 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); +} + +/* End of CksumDb code. +**************************************************************************/ + +/* +** Test utility function. Write key-value pair $i from datasource pData +** into database pDb. +*/ +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); +} + +/* +** Test utility function. Delete datasource pData key $i from database pDb. +*/ +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); +} + +/* +** This function inserts nWrite key/value pairs into database pDb - the +** nWrite key value pairs starting at iFirst from data source pData. +*/ +void testWriteDatasourceRange( + TestDb *pDb, /* Database to write to */ + Datasource *pData, /* Data source to read values from */ + int iFirst, /* Index of first key/value pair */ + int nWrite, /* Number of key/value pairs to write */ + int *pRc /* IN/OUT: Error code */ +){ + int i; + for(i=0; i<nWrite; i++){ + testWriteDatasource(pDb, pData, iFirst+i, pRc); + } +} + +void testDeleteDatasourceRange( + TestDb *pDb, /* Database to write to */ + Datasource *pData, /* Data source to read keys from */ + int iFirst, /* Index of first key */ + int nWrite, /* Number of keys to delete */ + int *pRc /* IN/OUT: Error code */ +){ + 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; + + /* Check that the database is the expected size. */ + 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); + } + } +} |