summaryrefslogtreecommitdiffstats
path: root/ext/lsm1/lsm-test/lsmtest3.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/lsm1/lsm-test/lsmtest3.c')
-rw-r--r--ext/lsm1/lsm-test/lsmtest3.c238
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);
+ }
+ }
+}