/* ** 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; iazCksum[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; iazCksum[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; i2 && 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); } } }