modernc.org/cc@v1.0.1/v2/testdata/_sqlite/ext/lsm1/lsm-test/lsmtest3.c (about) 1 2 3 /* 4 ** This file contains tests related to the explicit rollback of database 5 ** transactions and sub-transactions. 6 */ 7 8 9 /* 10 ** Repeat 2000 times (until the db contains 100,000 entries): 11 ** 12 ** 1. Open a transaction and insert 500 rows, opening a nested 13 ** sub-transaction each 100 rows. 14 ** 15 ** 2. Roll back to each sub-transaction savepoint. Check the database 16 ** checksum looks Ok. 17 ** 18 ** 3. Every second iteration, roll back the main transaction. Check the 19 ** db checksum is correct. Every other iteration, commit the main 20 ** transaction (increasing the size of the db by 100 rows). 21 */ 22 23 24 #include "lsmtest.h" 25 26 struct CksumDb { 27 int nFirst; 28 int nLast; 29 int nStep; 30 char **azCksum; 31 }; 32 33 CksumDb *testCksumArrayNew( 34 Datasource *pData, 35 int nFirst, 36 int nLast, 37 int nStep 38 ){ 39 TestDb *pDb; 40 CksumDb *pRet; 41 int i; 42 int nEntry; 43 int rc = 0; 44 45 assert( nLast>=nFirst && ((nLast-nFirst)%nStep)==0 ); 46 47 pRet = malloc(sizeof(CksumDb)); 48 memset(pRet, 0, sizeof(CksumDb)); 49 pRet->nFirst = nFirst; 50 pRet->nLast = nLast; 51 pRet->nStep = nStep; 52 nEntry = 1 + ((nLast - nFirst) / nStep); 53 54 /* Allocate space so that azCksum is an array of nEntry pointers to 55 ** buffers each TEST_CKSUM_BYTES in size. */ 56 pRet->azCksum = (char **)malloc(nEntry * (sizeof(char *) + TEST_CKSUM_BYTES)); 57 for(i=0; i<nEntry; i++){ 58 char *pStart = (char *)(&pRet->azCksum[nEntry]); 59 pRet->azCksum[i] = &pStart[i * TEST_CKSUM_BYTES]; 60 } 61 62 tdb_open("lsm", "tempdb.lsm", 1, &pDb); 63 testWriteDatasourceRange(pDb, pData, 0, nFirst, &rc); 64 for(i=0; i<nEntry; i++){ 65 testCksumDatabase(pDb, pRet->azCksum[i]); 66 if( i==nEntry ) break; 67 testWriteDatasourceRange(pDb, pData, nFirst+i*nStep, nStep, &rc); 68 } 69 70 tdb_close(pDb); 71 72 return pRet; 73 } 74 75 char *testCksumArrayGet(CksumDb *p, int nRow){ 76 int i; 77 assert( nRow>=p->nFirst ); 78 assert( nRow<=p->nLast ); 79 assert( ((nRow-p->nFirst) % p->nStep)==0 ); 80 81 i = (nRow - p->nFirst) / p->nStep; 82 return p->azCksum[i]; 83 } 84 85 void testCksumArrayFree(CksumDb *p){ 86 free(p->azCksum); 87 memset(p, 0x55, sizeof(*p)); 88 free(p); 89 } 90 91 /* End of CksumDb code. 92 **************************************************************************/ 93 94 /* 95 ** Test utility function. Write key-value pair $i from datasource pData 96 ** into database pDb. 97 */ 98 void testWriteDatasource(TestDb *pDb, Datasource *pData, int i, int *pRc){ 99 void *pKey; int nKey; 100 void *pVal; int nVal; 101 testDatasourceEntry(pData, i, &pKey, &nKey, &pVal, &nVal); 102 testWrite(pDb, pKey, nKey, pVal, nVal, pRc); 103 } 104 105 /* 106 ** Test utility function. Delete datasource pData key $i from database pDb. 107 */ 108 void testDeleteDatasource(TestDb *pDb, Datasource *pData, int i, int *pRc){ 109 void *pKey; int nKey; 110 testDatasourceEntry(pData, i, &pKey, &nKey, 0, 0); 111 testDelete(pDb, pKey, nKey, pRc); 112 } 113 114 /* 115 ** This function inserts nWrite key/value pairs into database pDb - the 116 ** nWrite key value pairs starting at iFirst from data source pData. 117 */ 118 void testWriteDatasourceRange( 119 TestDb *pDb, /* Database to write to */ 120 Datasource *pData, /* Data source to read values from */ 121 int iFirst, /* Index of first key/value pair */ 122 int nWrite, /* Number of key/value pairs to write */ 123 int *pRc /* IN/OUT: Error code */ 124 ){ 125 int i; 126 for(i=0; i<nWrite; i++){ 127 testWriteDatasource(pDb, pData, iFirst+i, pRc); 128 } 129 } 130 131 void testDeleteDatasourceRange( 132 TestDb *pDb, /* Database to write to */ 133 Datasource *pData, /* Data source to read keys from */ 134 int iFirst, /* Index of first key */ 135 int nWrite, /* Number of keys to delete */ 136 int *pRc /* IN/OUT: Error code */ 137 ){ 138 int i; 139 for(i=0; i<nWrite; i++){ 140 testDeleteDatasource(pDb, pData, iFirst+i, pRc); 141 } 142 } 143 144 static char *getName(const char *zSystem){ 145 char *zRet; 146 zRet = testMallocPrintf("rollback.%s", zSystem); 147 return zRet; 148 } 149 150 static int rollback_test_1( 151 const char *zSystem, 152 Datasource *pData 153 ){ 154 const int nRepeat = 100; 155 156 TestDb *pDb; 157 int rc; 158 int i; 159 CksumDb *pCksum; 160 char *zName; 161 162 zName = getName(zSystem); 163 testCaseStart(&rc, zName); 164 testFree(zName); 165 166 pCksum = testCksumArrayNew(pData, 0, nRepeat*100, 100); 167 pDb = 0; 168 rc = tdb_open(zSystem, 0, 1, &pDb); 169 if( pDb && tdb_transaction_support(pDb)==0 ){ 170 testCaseSkip(); 171 goto skip_rollback_test; 172 } 173 174 for(i=0; i<nRepeat && rc==0; i++){ 175 char zCksum[TEST_CKSUM_BYTES]; 176 int nCurrent = (((i+1)/2) * 100); 177 int nDbRow; 178 int iTrans; 179 180 /* Check that the database is the expected size. */ 181 nDbRow = testCountDatabase(pDb); 182 testCompareInt(nCurrent, nDbRow, &rc); 183 184 for(iTrans=2; iTrans<=6 && rc==0; iTrans++){ 185 tdb_begin(pDb, iTrans); 186 testWriteDatasourceRange(pDb, pData, nCurrent, 100, &rc); 187 nCurrent += 100; 188 } 189 190 testCksumDatabase(pDb, zCksum); 191 testCompareStr(zCksum, testCksumArrayGet(pCksum, nCurrent), &rc); 192 193 for(iTrans=6; iTrans>2 && rc==0; iTrans--){ 194 tdb_rollback(pDb, iTrans); 195 nCurrent -= 100; 196 testCksumDatabase(pDb, zCksum); 197 testCompareStr(zCksum, testCksumArrayGet(pCksum, nCurrent), &rc); 198 } 199 200 if( i%2 ){ 201 tdb_rollback(pDb, 0); 202 nCurrent -= 100; 203 testCksumDatabase(pDb, zCksum); 204 testCompareStr(zCksum, testCksumArrayGet(pCksum, nCurrent), &rc); 205 }else{ 206 tdb_commit(pDb, 0); 207 } 208 } 209 testCaseFinish(rc); 210 211 skip_rollback_test: 212 tdb_close(pDb); 213 testCksumArrayFree(pCksum); 214 return rc; 215 } 216 217 void test_rollback( 218 const char *zSystem, 219 const char *zPattern, 220 int *pRc 221 ){ 222 if( *pRc==0 ){ 223 int bRun = 1; 224 225 if( zPattern ){ 226 char *zName = getName(zSystem); 227 bRun = testGlobMatch(zPattern, zName); 228 testFree(zName); 229 } 230 231 if( bRun ){ 232 DatasourceDefn defn = { TEST_DATASOURCE_RANDOM, 10, 15, 50, 100 }; 233 Datasource *pData = testDatasourceNew(&defn); 234 *pRc = rollback_test_1(zSystem, pData); 235 testDatasourceFree(pData); 236 } 237 } 238 }