Fix the ".lint fkey-indexes" shell command so that it works with WITHOUT ROWID
[sqlite.git] / ext / lsm1 / lsm-test / lsmtest3.c
blob760dec300f464a5d042f2f6e483ed66215a5325d
3 /*
4 ** This file contains tests related to the explicit rollback of database
5 ** transactions and sub-transactions.
6 */
9 /*
10 ** Repeat 2000 times (until the db contains 100,000 entries):
12 ** 1. Open a transaction and insert 500 rows, opening a nested
13 ** sub-transaction each 100 rows.
15 ** 2. Roll back to each sub-transaction savepoint. Check the database
16 ** checksum looks Ok.
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).
24 #include "lsmtest.h"
26 struct CksumDb {
27 int nFirst;
28 int nLast;
29 int nStep;
30 char **azCksum;
33 CksumDb *testCksumArrayNew(
34 Datasource *pData,
35 int nFirst,
36 int nLast,
37 int nStep
39 TestDb *pDb;
40 CksumDb *pRet;
41 int i;
42 int nEntry;
43 int rc = 0;
45 assert( nLast>=nFirst && ((nLast-nFirst)%nStep)==0 );
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);
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];
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);
70 tdb_close(pDb);
72 return pRet;
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 );
81 i = (nRow - p->nFirst) / p->nStep;
82 return p->azCksum[i];
85 void testCksumArrayFree(CksumDb *p){
86 free(p->azCksum);
87 memset(p, 0x55, sizeof(*p));
88 free(p);
91 /* End of CksumDb code.
92 **************************************************************************/
95 ** Test utility function. Write key-value pair $i from datasource pData
96 ** into database pDb.
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);
106 ** Test utility function. Delete datasource pData key $i from database pDb.
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);
115 ** This function inserts nWrite key/value pairs into database pDb - the
116 ** nWrite key value pairs starting at iFirst from data source pData.
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 */
125 int i;
126 for(i=0; i<nWrite; i++){
127 testWriteDatasource(pDb, pData, iFirst+i, pRc);
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 */
138 int i;
139 for(i=0; i<nWrite; i++){
140 testDeleteDatasource(pDb, pData, iFirst+i, pRc);
144 static char *getName(const char *zSystem){
145 char *zRet;
146 zRet = testMallocPrintf("rollback.%s", zSystem);
147 return zRet;
150 static int rollback_test_1(
151 const char *zSystem,
152 Datasource *pData
154 const int nRepeat = 100;
156 TestDb *pDb;
157 int rc;
158 int i;
159 CksumDb *pCksum;
160 char *zName;
162 zName = getName(zSystem);
163 testCaseStart(&rc, zName);
164 testFree(zName);
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;
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;
180 /* Check that the database is the expected size. */
181 nDbRow = testCountDatabase(pDb);
182 testCompareInt(nCurrent, nDbRow, &rc);
184 for(iTrans=2; iTrans<=6 && rc==0; iTrans++){
185 tdb_begin(pDb, iTrans);
186 testWriteDatasourceRange(pDb, pData, nCurrent, 100, &rc);
187 nCurrent += 100;
190 testCksumDatabase(pDb, zCksum);
191 testCompareStr(zCksum, testCksumArrayGet(pCksum, nCurrent), &rc);
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);
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);
209 testCaseFinish(rc);
211 skip_rollback_test:
212 tdb_close(pDb);
213 testCksumArrayFree(pCksum);
214 return rc;
217 void test_rollback(
218 const char *zSystem,
219 const char *zPattern,
220 int *pRc
222 if( *pRc==0 ){
223 int bRun = 1;
225 if( zPattern ){
226 char *zName = getName(zSystem);
227 bRun = testGlobMatch(zPattern, zName);
228 testFree(zName);
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);