128 lines
4.4 KiB
C
128 lines
4.4 KiB
C
|
|
||
|
/*
|
||
|
** 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);
|
||
|
}
|
||
|
}
|
||
|
}
|