mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-01 06:27:03 +03:00
557 lines
18 KiB
C
557 lines
18 KiB
C
/*
|
|
** 2016-05-07
|
|
**
|
|
** The author disclaims copyright to this source code. In place of
|
|
** a legal notice, here is a blessing:
|
|
**
|
|
** May you do good and not evil.
|
|
** May you find forgiveness for yourself and forgive others.
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
*************************************************************************
|
|
*/
|
|
|
|
|
|
#include <sqlite3.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include "tt3_core.c"
|
|
|
|
#ifdef USE_OSINST
|
|
# include "../src/test_osinst.c"
|
|
#else
|
|
# define vfslog_time() 0
|
|
#endif
|
|
|
|
typedef struct Config Config;
|
|
typedef struct ThreadCtx ThreadCtx;
|
|
|
|
#define THREAD_TIME_INSERT 0
|
|
#define THREAD_TIME_COMMIT 1
|
|
#define THREAD_TIME_ROLLBACK 2
|
|
#define THREAD_TIME_WRITER 3
|
|
#define THREAD_TIME_CKPT 4
|
|
|
|
struct ThreadCtx {
|
|
Config *pConfig;
|
|
Sqlite *pDb;
|
|
Error *pErr;
|
|
sqlite3_int64 aTime[5];
|
|
};
|
|
|
|
struct Config {
|
|
int nIPT; /* --inserts-per-transaction */
|
|
int nThread; /* --threads */
|
|
int nSecond; /* --seconds */
|
|
int bMutex; /* --mutex */
|
|
int nAutoCkpt; /* --autockpt */
|
|
int bRm; /* --rm */
|
|
int bClearCache; /* --clear-cache */
|
|
int nMmap; /* mmap limit in MB */
|
|
char *zFile;
|
|
int bOsinst; /* True to use osinst */
|
|
|
|
ThreadCtx *aCtx; /* Array of size nThread */
|
|
|
|
pthread_cond_t cond;
|
|
pthread_mutex_t mutex;
|
|
int nCondWait; /* Number of threads waiting on hCond */
|
|
sqlite3_vfs *pVfs;
|
|
};
|
|
|
|
|
|
typedef struct VfsWrapperFd VfsWrapperFd;
|
|
struct VfsWrapperFd {
|
|
sqlite3_file base; /* Base class */
|
|
int bWriter; /* True if holding shm WRITER lock */
|
|
int iTid;
|
|
Config *pConfig;
|
|
sqlite3_file *pFd; /* Underlying file descriptor */
|
|
};
|
|
|
|
/* Methods of the wrapper VFS */
|
|
static int vfsWrapOpen(sqlite3_vfs*, const char*, sqlite3_file*, int, int*);
|
|
static int vfsWrapDelete(sqlite3_vfs*, const char*, int);
|
|
static int vfsWrapAccess(sqlite3_vfs*, const char*, int, int*);
|
|
static int vfsWrapFullPathname(sqlite3_vfs*, const char *, int, char*);
|
|
static void *vfsWrapDlOpen(sqlite3_vfs*, const char*);
|
|
static void vfsWrapDlError(sqlite3_vfs*, int, char*);
|
|
static void (*vfsWrapDlSym(sqlite3_vfs*,void*, const char*))(void);
|
|
static void vfsWrapDlClose(sqlite3_vfs*, void*);
|
|
static int vfsWrapRandomness(sqlite3_vfs*, int, char*);
|
|
static int vfsWrapSleep(sqlite3_vfs*, int);
|
|
static int vfsWrapCurrentTime(sqlite3_vfs*, double*);
|
|
static int vfsWrapGetLastError(sqlite3_vfs*, int, char*);
|
|
static int vfsWrapCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
|
|
static int vfsWrapSetSystemCall(sqlite3_vfs*, const char*, sqlite3_syscall_ptr);
|
|
static sqlite3_syscall_ptr vfsWrapGetSystemCall(sqlite3_vfs*, const char*);
|
|
static const char *vfsWrapNextSystemCall(sqlite3_vfs*, const char*);
|
|
|
|
/* Methods of wrapper sqlite3_io_methods object (see vfsWrapOpen()) */
|
|
static int vfsWrapClose(sqlite3_file*);
|
|
static int vfsWrapRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
|
|
static int vfsWrapWrite(sqlite3_file*, const void*, int iAmt, sqlite3_int64);
|
|
static int vfsWrapTruncate(sqlite3_file*, sqlite3_int64 size);
|
|
static int vfsWrapSync(sqlite3_file*, int flags);
|
|
static int vfsWrapFileSize(sqlite3_file*, sqlite3_int64 *pSize);
|
|
static int vfsWrapLock(sqlite3_file*, int);
|
|
static int vfsWrapUnlock(sqlite3_file*, int);
|
|
static int vfsWrapCheckReservedLock(sqlite3_file*, int *pResOut);
|
|
static int vfsWrapFileControl(sqlite3_file*, int op, void *pArg);
|
|
static int vfsWrapSectorSize(sqlite3_file*);
|
|
static int vfsWrapDeviceCharacteristics(sqlite3_file*);
|
|
static int vfsWrapShmMap(sqlite3_file*, int iPg, int, int, void volatile**);
|
|
static int vfsWrapShmLock(sqlite3_file*, int offset, int n, int flags);
|
|
static void vfsWrapShmBarrier(sqlite3_file*);
|
|
static int vfsWrapShmUnmap(sqlite3_file*, int deleteFlag);
|
|
static int vfsWrapFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **);
|
|
static int vfsWrapUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
|
|
|
|
static int vfsWrapOpen(
|
|
sqlite3_vfs *pVfs,
|
|
const char *zName,
|
|
sqlite3_file *pFd,
|
|
int flags,
|
|
int *fout
|
|
){
|
|
static sqlite3_io_methods methods = {
|
|
3,
|
|
vfsWrapClose, vfsWrapRead, vfsWrapWrite,
|
|
vfsWrapTruncate, vfsWrapSync, vfsWrapFileSize,
|
|
vfsWrapLock, vfsWrapUnlock, vfsWrapCheckReservedLock,
|
|
vfsWrapFileControl, vfsWrapSectorSize, vfsWrapDeviceCharacteristics,
|
|
vfsWrapShmMap, vfsWrapShmLock, vfsWrapShmBarrier,
|
|
vfsWrapShmUnmap, vfsWrapFetch, vfsWrapUnfetch
|
|
};
|
|
|
|
Config *pConfig = (Config*)pVfs->pAppData;
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
int rc;
|
|
|
|
memset(pWrapper, 0, sizeof(VfsWrapperFd));
|
|
if( flags & SQLITE_OPEN_MAIN_DB ){
|
|
pWrapper->iTid = (int)sqlite3_uri_int64(zName, "tid", 0);
|
|
}
|
|
|
|
pWrapper->pFd = (sqlite3_file*)&pWrapper[1];
|
|
pWrapper->pConfig = pConfig;
|
|
rc = pConfig->pVfs->xOpen(pConfig->pVfs, zName, pWrapper->pFd, flags, fout);
|
|
if( rc==SQLITE_OK ){
|
|
pWrapper->base.pMethods = &methods;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
static int vfsWrapDelete(sqlite3_vfs *pVfs, const char *a, int b){
|
|
Config *pConfig = (Config*)pVfs->pAppData;
|
|
return pConfig->pVfs->xDelete(pConfig->pVfs, a, b);
|
|
}
|
|
static int vfsWrapAccess(sqlite3_vfs *pVfs, const char *a, int b, int *c){
|
|
Config *pConfig = (Config*)pVfs->pAppData;
|
|
return pConfig->pVfs->xAccess(pConfig->pVfs, a, b, c);
|
|
}
|
|
static int vfsWrapFullPathname(sqlite3_vfs *pVfs, const char *a, int b, char*c){
|
|
Config *pConfig = (Config*)pVfs->pAppData;
|
|
return pConfig->pVfs->xFullPathname(pConfig->pVfs, a, b, c);
|
|
}
|
|
static void *vfsWrapDlOpen(sqlite3_vfs *pVfs, const char *a){
|
|
Config *pConfig = (Config*)pVfs->pAppData;
|
|
return pConfig->pVfs->xDlOpen(pConfig->pVfs, a);
|
|
}
|
|
static void vfsWrapDlError(sqlite3_vfs *pVfs, int a, char *b){
|
|
Config *pConfig = (Config*)pVfs->pAppData;
|
|
return pConfig->pVfs->xDlError(pConfig->pVfs, a, b);
|
|
}
|
|
static void (*vfsWrapDlSym(sqlite3_vfs *pVfs, void *a, const char *b))(void){
|
|
Config *pConfig = (Config*)pVfs->pAppData;
|
|
return pConfig->pVfs->xDlSym(pConfig->pVfs, a, b);
|
|
}
|
|
static void vfsWrapDlClose(sqlite3_vfs *pVfs, void *a){
|
|
Config *pConfig = (Config*)pVfs->pAppData;
|
|
return pConfig->pVfs->xDlClose(pConfig->pVfs, a);
|
|
}
|
|
static int vfsWrapRandomness(sqlite3_vfs *pVfs, int a, char *b){
|
|
Config *pConfig = (Config*)pVfs->pAppData;
|
|
return pConfig->pVfs->xRandomness(pConfig->pVfs, a, b);
|
|
}
|
|
static int vfsWrapSleep(sqlite3_vfs *pVfs, int a){
|
|
Config *pConfig = (Config*)pVfs->pAppData;
|
|
return pConfig->pVfs->xSleep(pConfig->pVfs, a);
|
|
}
|
|
static int vfsWrapCurrentTime(sqlite3_vfs *pVfs, double *a){
|
|
Config *pConfig = (Config*)pVfs->pAppData;
|
|
return pConfig->pVfs->xCurrentTime(pConfig->pVfs, a);
|
|
}
|
|
static int vfsWrapGetLastError(sqlite3_vfs *pVfs, int a, char *b){
|
|
Config *pConfig = (Config*)pVfs->pAppData;
|
|
return pConfig->pVfs->xGetLastError(pConfig->pVfs, a, b);
|
|
}
|
|
static int vfsWrapCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *a){
|
|
Config *pConfig = (Config*)pVfs->pAppData;
|
|
return pConfig->pVfs->xCurrentTimeInt64(pConfig->pVfs, a);
|
|
}
|
|
static int vfsWrapSetSystemCall(
|
|
sqlite3_vfs *pVfs,
|
|
const char *a,
|
|
sqlite3_syscall_ptr b
|
|
){
|
|
Config *pConfig = (Config*)pVfs->pAppData;
|
|
return pConfig->pVfs->xSetSystemCall(pConfig->pVfs, a, b);
|
|
}
|
|
static sqlite3_syscall_ptr vfsWrapGetSystemCall(
|
|
sqlite3_vfs *pVfs,
|
|
const char *a
|
|
){
|
|
Config *pConfig = (Config*)pVfs->pAppData;
|
|
return pConfig->pVfs->xGetSystemCall(pConfig->pVfs, a);
|
|
}
|
|
static const char *vfsWrapNextSystemCall(sqlite3_vfs *pVfs, const char *a){
|
|
Config *pConfig = (Config*)pVfs->pAppData;
|
|
return pConfig->pVfs->xNextSystemCall(pConfig->pVfs, a);
|
|
}
|
|
|
|
static int vfsWrapClose(sqlite3_file *pFd){
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
pWrapper->pFd->pMethods->xClose(pWrapper->pFd);
|
|
pWrapper->pFd = 0;
|
|
return SQLITE_OK;
|
|
}
|
|
static int vfsWrapRead(sqlite3_file *pFd, void *a, int b, sqlite3_int64 c){
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
return pWrapper->pFd->pMethods->xRead(pWrapper->pFd, a, b, c);
|
|
}
|
|
static int vfsWrapWrite(
|
|
sqlite3_file *pFd,
|
|
const void *a, int b,
|
|
sqlite3_int64 c
|
|
){
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
return pWrapper->pFd->pMethods->xWrite(pWrapper->pFd, a, b, c);
|
|
}
|
|
static int vfsWrapTruncate(sqlite3_file *pFd, sqlite3_int64 a){
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
return pWrapper->pFd->pMethods->xTruncate(pWrapper->pFd, a);
|
|
}
|
|
static int vfsWrapSync(sqlite3_file *pFd, int a){
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
return pWrapper->pFd->pMethods->xSync(pWrapper->pFd, a);
|
|
}
|
|
static int vfsWrapFileSize(sqlite3_file *pFd, sqlite3_int64 *a){
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
return pWrapper->pFd->pMethods->xFileSize(pWrapper->pFd, a);
|
|
}
|
|
static int vfsWrapLock(sqlite3_file *pFd, int a){
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
return pWrapper->pFd->pMethods->xLock(pWrapper->pFd, a);
|
|
}
|
|
static int vfsWrapUnlock(sqlite3_file *pFd, int a){
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
return pWrapper->pFd->pMethods->xUnlock(pWrapper->pFd, a);
|
|
}
|
|
static int vfsWrapCheckReservedLock(sqlite3_file *pFd, int *a){
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
return pWrapper->pFd->pMethods->xCheckReservedLock(pWrapper->pFd, a);
|
|
}
|
|
static int vfsWrapFileControl(sqlite3_file *pFd, int a, void *b){
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
return pWrapper->pFd->pMethods->xFileControl(pWrapper->pFd, a, b);
|
|
}
|
|
static int vfsWrapSectorSize(sqlite3_file *pFd){
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
return pWrapper->pFd->pMethods->xSectorSize(pWrapper->pFd);
|
|
}
|
|
static int vfsWrapDeviceCharacteristics(sqlite3_file *pFd){
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
return pWrapper->pFd->pMethods->xDeviceCharacteristics(pWrapper->pFd);
|
|
}
|
|
static int vfsWrapShmMap(
|
|
sqlite3_file *pFd,
|
|
int a, int b, int c,
|
|
void volatile **d
|
|
){
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
return pWrapper->pFd->pMethods->xShmMap(pWrapper->pFd, a, b, c, d);
|
|
}
|
|
static int vfsWrapShmLock(sqlite3_file *pFd, int offset, int n, int flags){
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
Config *pConfig = pWrapper->pConfig;
|
|
int bMutex = 0;
|
|
int rc;
|
|
|
|
if( (offset==0 && n==1)
|
|
&& (flags & SQLITE_SHM_LOCK) && (flags & SQLITE_SHM_EXCLUSIVE)
|
|
){
|
|
pthread_mutex_lock(&pConfig->mutex);
|
|
pWrapper->bWriter = 1;
|
|
bMutex = 1;
|
|
if( pWrapper->iTid ){
|
|
sqlite3_int64 t = vfslog_time();
|
|
pConfig->aCtx[pWrapper->iTid-1].aTime[THREAD_TIME_WRITER] -= t;
|
|
}
|
|
}
|
|
|
|
rc = pWrapper->pFd->pMethods->xShmLock(pWrapper->pFd, offset, n, flags);
|
|
|
|
if( (rc!=SQLITE_OK && bMutex)
|
|
|| (offset==0 && (flags & SQLITE_SHM_UNLOCK) && pWrapper->bWriter)
|
|
){
|
|
assert( pWrapper->bWriter );
|
|
pthread_mutex_unlock(&pConfig->mutex);
|
|
pWrapper->bWriter = 0;
|
|
if( pWrapper->iTid ){
|
|
sqlite3_int64 t = vfslog_time();
|
|
pConfig->aCtx[pWrapper->iTid-1].aTime[THREAD_TIME_WRITER] += t;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
static void vfsWrapShmBarrier(sqlite3_file *pFd){
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
return pWrapper->pFd->pMethods->xShmBarrier(pWrapper->pFd);
|
|
}
|
|
static int vfsWrapShmUnmap(sqlite3_file *pFd, int a){
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
return pWrapper->pFd->pMethods->xShmUnmap(pWrapper->pFd, a);
|
|
}
|
|
static int vfsWrapFetch(sqlite3_file *pFd, sqlite3_int64 a, int b, void **c){
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
return pWrapper->pFd->pMethods->xFetch(pWrapper->pFd, a, b, c);
|
|
}
|
|
static int vfsWrapUnfetch(sqlite3_file *pFd, sqlite3_int64 a, void *b){
|
|
VfsWrapperFd *pWrapper = (VfsWrapperFd*)pFd;
|
|
return pWrapper->pFd->pMethods->xUnfetch(pWrapper->pFd, a, b);
|
|
}
|
|
|
|
static void create_vfs(Config *pConfig){
|
|
static sqlite3_vfs vfs = {
|
|
3, 0, 0, 0, "wrapper", 0,
|
|
vfsWrapOpen, vfsWrapDelete, vfsWrapAccess,
|
|
vfsWrapFullPathname, vfsWrapDlOpen, vfsWrapDlError,
|
|
vfsWrapDlSym, vfsWrapDlClose, vfsWrapRandomness,
|
|
vfsWrapSleep, vfsWrapCurrentTime, vfsWrapGetLastError,
|
|
vfsWrapCurrentTimeInt64, vfsWrapSetSystemCall, vfsWrapGetSystemCall,
|
|
vfsWrapNextSystemCall
|
|
};
|
|
sqlite3_vfs *pVfs;
|
|
|
|
pVfs = sqlite3_vfs_find(0);
|
|
vfs.mxPathname = pVfs->mxPathname;
|
|
vfs.szOsFile = pVfs->szOsFile + sizeof(VfsWrapperFd);
|
|
vfs.pAppData = (void*)pConfig;
|
|
pConfig->pVfs = pVfs;
|
|
|
|
sqlite3_vfs_register(&vfs, 1);
|
|
}
|
|
|
|
|
|
/*
|
|
** Wal hook used by connections in thread_main().
|
|
*/
|
|
static int thread_wal_hook(
|
|
void *pArg, /* Pointer to ThreadCtx object */
|
|
sqlite3 *db,
|
|
const char *zDb,
|
|
int nFrame
|
|
){
|
|
ThreadCtx *pCtx = (ThreadCtx*)pArg;
|
|
Config *pConfig = pCtx->pConfig;
|
|
|
|
if( pConfig->nAutoCkpt && nFrame>=pConfig->nAutoCkpt ){
|
|
pCtx->aTime[THREAD_TIME_CKPT] -= vfslog_time();
|
|
pthread_mutex_lock(&pConfig->mutex);
|
|
if( pConfig->nCondWait>=0 ){
|
|
pConfig->nCondWait++;
|
|
if( pConfig->nCondWait==pConfig->nThread ){
|
|
execsql(pCtx->pErr, pCtx->pDb, "PRAGMA wal_checkpoint");
|
|
pthread_cond_broadcast(&pConfig->cond);
|
|
}else{
|
|
pthread_cond_wait(&pConfig->cond, &pConfig->mutex);
|
|
}
|
|
pConfig->nCondWait--;
|
|
}
|
|
pthread_mutex_unlock(&pConfig->mutex);
|
|
pCtx->aTime[THREAD_TIME_CKPT] += vfslog_time();
|
|
}
|
|
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
|
|
static char *thread_main(int iTid, void *pArg){
|
|
Config *pConfig = (Config*)pArg;
|
|
Error err = {0}; /* Error code and message */
|
|
Sqlite db = {0}; /* SQLite database connection */
|
|
int nAttempt = 0; /* Attempted transactions */
|
|
int nCommit = 0; /* Successful transactions */
|
|
int j;
|
|
ThreadCtx *pCtx = &pConfig->aCtx[iTid-1];
|
|
char *zUri = 0;
|
|
|
|
#ifdef USE_OSINST
|
|
char *zOsinstName = 0;
|
|
char *zLogName = 0;
|
|
if( pConfig->bOsinst ){
|
|
zOsinstName = sqlite3_mprintf("osinst%d", iTid);
|
|
zLogName = sqlite3_mprintf("bc_test1.log.%d.%d", (int)getpid(), iTid);
|
|
zUri = sqlite3_mprintf(
|
|
"file:%s?vfs=%s&tid=%d", pConfig->zFile, zOsinstName, iTid
|
|
);
|
|
sqlite3_vfslog_new(zOsinstName, 0, zLogName);
|
|
opendb(&err, &db, zUri, 0);
|
|
}else
|
|
#endif
|
|
{
|
|
zUri = sqlite3_mprintf("file:%s?tid=%d", pConfig->zFile, iTid);
|
|
opendb(&err, &db, zUri, 0);
|
|
}
|
|
|
|
sqlite3_busy_handler(db.db, 0, 0);
|
|
sql_script_printf(&err, &db,
|
|
"PRAGMA wal_autocheckpoint = 0;"
|
|
"PRAGMA synchronous = 0;"
|
|
"PRAGMA mmap_size = %lld;",
|
|
(i64)(pConfig->nMmap) * 1024 * 1024
|
|
);
|
|
|
|
pCtx->pConfig = pConfig;
|
|
pCtx->pErr = &err;
|
|
pCtx->pDb = &db;
|
|
sqlite3_wal_hook(db.db, thread_wal_hook, (void*)pCtx);
|
|
|
|
while( !timetostop(&err) ){
|
|
execsql(&err, &db, "BEGIN CONCURRENT");
|
|
|
|
pCtx->aTime[THREAD_TIME_INSERT] -= vfslog_time();
|
|
for(j=0; j<pConfig->nIPT; j++){
|
|
execsql(&err, &db,
|
|
"INSERT INTO t1 VALUES"
|
|
"(randomblob(10), randomblob(20), randomblob(30), randomblob(200))"
|
|
);
|
|
}
|
|
pCtx->aTime[THREAD_TIME_INSERT] += vfslog_time();
|
|
|
|
pCtx->aTime[THREAD_TIME_COMMIT] -= vfslog_time();
|
|
execsql(&err, &db, "COMMIT");
|
|
pCtx->aTime[THREAD_TIME_COMMIT] += vfslog_time();
|
|
|
|
pCtx->aTime[THREAD_TIME_ROLLBACK] -= vfslog_time();
|
|
nAttempt++;
|
|
if( err.rc==SQLITE_OK ){
|
|
nCommit++;
|
|
}else{
|
|
clear_error(&err, SQLITE_BUSY);
|
|
execsql(&err, &db, "ROLLBACK");
|
|
}
|
|
pCtx->aTime[THREAD_TIME_ROLLBACK] += vfslog_time();
|
|
|
|
if( pConfig->bClearCache ){
|
|
sqlite3_db_release_memory(db.db);
|
|
}
|
|
}
|
|
|
|
closedb(&err, &db);
|
|
|
|
#ifdef USE_OSINST
|
|
if( pConfig->bOsinst ){
|
|
sqlite3_vfslog_finalize(zOsinstName);
|
|
sqlite3_free(zOsinstName);
|
|
sqlite3_free(zLogName);
|
|
}
|
|
#endif
|
|
sqlite3_free(zUri);
|
|
|
|
pthread_mutex_lock(&pConfig->mutex);
|
|
pConfig->nCondWait = -1;
|
|
pthread_cond_broadcast(&pConfig->cond);
|
|
pthread_mutex_unlock(&pConfig->mutex);
|
|
|
|
return sqlite3_mprintf("commits: %d/%d insert: %dms"
|
|
" commit: %dms"
|
|
" rollback: %dms"
|
|
" writer: %dms"
|
|
" checkpoint: %dms",
|
|
nCommit, nAttempt,
|
|
(int)(pCtx->aTime[THREAD_TIME_INSERT]/1000),
|
|
(int)(pCtx->aTime[THREAD_TIME_COMMIT]/1000),
|
|
(int)(pCtx->aTime[THREAD_TIME_ROLLBACK]/1000),
|
|
(int)(pCtx->aTime[THREAD_TIME_WRITER]/1000),
|
|
(int)(pCtx->aTime[THREAD_TIME_CKPT]/1000)
|
|
);
|
|
}
|
|
|
|
int main(int argc, const char **argv){
|
|
Error err = {0}; /* Error code and message */
|
|
Sqlite db = {0}; /* SQLite database connection */
|
|
Threadset threads = {0}; /* Test threads */
|
|
Config conf = {5, 3, 5};
|
|
int i;
|
|
|
|
CmdlineArg apArg[] = {
|
|
{ "-seconds", CMDLINE_INT, offsetof(Config, nSecond) },
|
|
{ "-inserts", CMDLINE_INT, offsetof(Config, nIPT) },
|
|
{ "-threads", CMDLINE_INT, offsetof(Config, nThread) },
|
|
{ "-mutex", CMDLINE_BOOL, offsetof(Config, bMutex) },
|
|
{ "-rm", CMDLINE_BOOL, offsetof(Config, bRm) },
|
|
{ "-autockpt",CMDLINE_INT, offsetof(Config, nAutoCkpt) },
|
|
{ "-mmap", CMDLINE_INT, offsetof(Config, nMmap) },
|
|
{ "-clear-cache", CMDLINE_BOOL, offsetof(Config, bClearCache) },
|
|
{ "-file", CMDLINE_STRING, offsetof(Config, zFile) },
|
|
{ "-osinst", CMDLINE_BOOL, offsetof(Config, bOsinst) },
|
|
{ 0, 0, 0 }
|
|
};
|
|
|
|
conf.nAutoCkpt = 1000;
|
|
cmdline_process(apArg, argc, argv, (void*)&conf);
|
|
if( err.rc==SQLITE_OK ){
|
|
char *z = cmdline_construct(apArg, (void*)&conf);
|
|
printf("With: %s\n", z);
|
|
sqlite3_free(z);
|
|
}
|
|
if( conf.zFile==0 ){
|
|
conf.zFile = "xyz.db";
|
|
}
|
|
|
|
/* Create the special VFS - "wrapper". And the mutex and condition
|
|
** variable. */
|
|
create_vfs(&conf);
|
|
pthread_mutex_init(&conf.mutex, 0);
|
|
pthread_cond_init(&conf.cond, 0);
|
|
|
|
conf.aCtx = sqlite3_malloc(sizeof(ThreadCtx) * conf.nThread);
|
|
memset(conf.aCtx, 0, sizeof(ThreadCtx) * conf.nThread);
|
|
|
|
/* Ensure the schema has been created */
|
|
opendb(&err, &db, conf.zFile, conf.bRm);
|
|
sql_script(&err, &db,
|
|
"PRAGMA journal_mode = wal;"
|
|
"CREATE TABLE IF NOT EXISTS t1(a PRIMARY KEY, b, c, d) WITHOUT ROWID;"
|
|
"CREATE INDEX IF NOT EXISTS t1b ON t1(b);"
|
|
"CREATE INDEX IF NOT EXISTS t1c ON t1(c);"
|
|
);
|
|
|
|
setstoptime(&err, conf.nSecond*1000);
|
|
if( conf.nThread==1 ){
|
|
char *z = thread_main(1, (void*)&conf);
|
|
printf("Thread 0 says: %s\n", (z==0 ? "..." : z));
|
|
fflush(stdout);
|
|
}else{
|
|
for(i=0; i<conf.nThread; i++){
|
|
launch_thread(&err, &threads, thread_main, (void*)&conf);
|
|
}
|
|
join_all_threads(&err, &threads);
|
|
}
|
|
|
|
if( err.rc==SQLITE_OK ){
|
|
printf("Database is %dK\n", (int)(filesize(&err, conf.zFile) / 1024));
|
|
}
|
|
if( err.rc==SQLITE_OK ){
|
|
char *zWal = sqlite3_mprintf("%s-wal", conf.zFile);
|
|
printf("Wal file is %dK\n", (int)(filesize(&err, zWal) / 1024));
|
|
}
|
|
|
|
closedb(&err, &db);
|
|
print_and_free_err(&err);
|
|
return 0;
|
|
}
|