| |
| /* |
| ** This file contains test cases involving multiple database clients. |
| */ |
| |
| #include "lsmtest.h" |
| |
| /* |
| ** The following code implements test cases "mc1.*". |
| ** |
| ** This test case uses one writer and $nReader readers. All connections |
| ** are driven by a single thread. All connections are opened at the start |
| ** of the test and remain open until the test is finished. |
| ** |
| ** The test consists of $nStep steps. Each step the following is performed: |
| ** |
| ** 1. The writer inserts $nWriteStep records into the db. |
| ** |
| ** 2. The writer checks that the contents of the db are as expected. |
| ** |
| ** 3. Each reader that currently has an open read transaction also checks |
| ** that the contents of the db are as expected (according to the snapshot |
| ** the read transaction is reading - see below). |
| ** |
| ** After step 1, reader 1 opens a read transaction. After step 2, reader |
| ** 2 opens a read transaction, and so on. At step ($nReader+1), reader 1 |
| ** closes the current read transaction and opens a new one. And so on. |
| ** The result is that at step N (for N > $nReader), there exists a reader |
| ** with an open read transaction reading the snapshot committed following |
| ** steps (N-$nReader-1) to N. |
| */ |
| typedef struct Mctest Mctest; |
| struct Mctest { |
| DatasourceDefn defn; /* Datasource to use */ |
| int nStep; /* Total number of steps in test */ |
| int nWriteStep; /* Number of rows to insert each step */ |
| int nReader; /* Number of read connections */ |
| }; |
| static void do_mc_test( |
| const char *zSystem, /* Database system to test */ |
| Mctest *pTest, |
| int *pRc /* IN/OUT: return code */ |
| ){ |
| const int nDomain = pTest->nStep * pTest->nWriteStep; |
| Datasource *pData; /* Source of data */ |
| TestDb *pDb; /* First database connection (writer) */ |
| int iReader; /* Used to iterate through aReader */ |
| int iStep; /* Current step in test */ |
| int iDot = 0; /* Current step in test */ |
| |
| /* Array of reader connections */ |
| struct Reader { |
| TestDb *pDb; /* Connection handle */ |
| int iLast; /* Current snapshot contains keys 0..iLast */ |
| } *aReader; |
| |
| /* Create a data source */ |
| pData = testDatasourceNew(&pTest->defn); |
| |
| /* Open the writer connection */ |
| pDb = testOpen(zSystem, 1, pRc); |
| |
| /* Allocate aReader */ |
| aReader = (struct Reader *)testMalloc(sizeof(aReader[0]) * pTest->nReader); |
| for(iReader=0; iReader<pTest->nReader; iReader++){ |
| aReader[iReader].pDb = testOpen(zSystem, 0, pRc); |
| } |
| |
| for(iStep=0; iStep<pTest->nStep; iStep++){ |
| int iLast; |
| int iBegin; /* Start read trans using aReader[iBegin] */ |
| |
| /* Insert nWriteStep more records into the database */ |
| int iFirst = iStep*pTest->nWriteStep; |
| testWriteDatasourceRange(pDb, pData, iFirst, pTest->nWriteStep, pRc); |
| |
| /* Check that the db is Ok according to the writer */ |
| iLast = (iStep+1) * pTest->nWriteStep - 1; |
| testDbContents(pDb, pData, nDomain, 0, iLast, iLast, 1, pRc); |
| |
| /* Have reader (iStep % nReader) open a read transaction here. */ |
| iBegin = (iStep % pTest->nReader); |
| if( iBegin<iStep ) tdb_commit(aReader[iBegin].pDb, 0); |
| tdb_begin(aReader[iBegin].pDb, 1); |
| aReader[iBegin].iLast = iLast; |
| |
| /* Check that the db is Ok for each open reader */ |
| for(iReader=0; iReader<pTest->nReader && aReader[iReader].iLast; iReader++){ |
| iLast = aReader[iReader].iLast; |
| testDbContents( |
| aReader[iReader].pDb, pData, nDomain, 0, iLast, iLast, 1, pRc |
| ); |
| } |
| |
| /* Report progress */ |
| testCaseProgress(iStep, pTest->nStep, testCaseNDot(), &iDot); |
| } |
| |
| /* Close all readers */ |
| for(iReader=0; iReader<pTest->nReader; iReader++){ |
| testClose(&aReader[iReader].pDb); |
| } |
| testFree(aReader); |
| |
| /* Close the writer-connection and free the datasource */ |
| testClose(&pDb); |
| testDatasourceFree(pData); |
| } |
| |
| |
| void test_mc( |
| const char *zSystem, /* Database system name */ |
| const char *zPattern, /* Run test cases that match this pattern */ |
| int *pRc /* IN/OUT: Error code */ |
| ){ |
| int i; |
| Mctest aTest[] = { |
| { { TEST_DATASOURCE_RANDOM, 10,10, 100,100 }, 100, 10, 5 }, |
| }; |
| |
| for(i=0; i<ArraySize(aTest); i++){ |
| if( testCaseBegin(pRc, zPattern, "mc1.%s.%d", zSystem, i) ){ |
| do_mc_test(zSystem, &aTest[i], pRc); |
| testCaseFinish(*pRc); |
| } |
| } |
| } |