| /* |
| ** 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; |
| } |