-C Remove\scode\sfor\sPLL\ssupport\sin\swal\smode\sfrom\sthis\sbranch.
-D 2017-08-14T07:16:18.805
+C Enhance\sthis\sbranch\sto\ssupport\spage-level-locking\s(without\sMVCC)\sfor\nmulti-process\sdeployments.
+D 2017-08-16T16:52:14.156
F Makefile.in d9873c9925917cca9990ee24be17eb9613a668012c85a343aef7e5536ae266e8
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 02b469e9dcd5b7ee63fc1fb05babc174260ee4cfa4e0ef2e48c3c6801567a016
F src/os.h 8e976e59eb4ca1c0fca6d35ee803e38951cb0343
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
-F src/os_unix.c 24e4b7f6f89b742357068959255c4530014254579c09c1b56beff1014eb0c0c1
+F src/os_unix.c 6947c0fccc1b68404def7161553881b2efab6fcac4a58bf9f4ce36a4ad27d325
F src/os_win.c 964165b66cde03abc72fe948198b01be608436894732eadb94c8720d2467f223
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
-F src/pager.c 0cfac2557de08ac12ec8d2edd3c4cb69f96ad49b923f1390619c310aa684366e
+F src/pager.c e53f35d61f266c47cc3883e34c7d01eaca38a71451dd72efb3cf21e043b471a7
F src/pager.h 316dac0671fd7555af9e73d4357febd5f2d3ce6a185ffd8d77b7fc0423ac8b1a
F src/parse.y 58a2de13e855aece3d7709440e6e86849f4cde97f5227c6a25e6bba2fc5e2976
F src/pcache.c 62835bed959e2914edd26afadfecce29ece0e870
F src/resolve.c 4324a94573b1e29286f8121e4881db59eaedc014afeb274c8d3e07ed282e0e20
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c ea8921065512650a9df3f5bf9a9b531c6ef4fb193c0d57e09d7a479ef9b13992
-F src/server.c d69efa7284074e69d43c38d5d649ef3b20add1db31c9d8e7f01cabd95d0ee72b
-F src/server.h d7555e68ee34008ca02705e44f861938a67b85a97ffe64d9326e03bd15dcd06b
+F src/server.c e8d1c1a0e39d508c75e11eafa9a20edc85f5b619b27f7218950f3a77431f5a71
+F src/server.h cf1ede28aaa07a30550228582f211327b5ebe5517d2334e35ec09d00fd6d230d
F src/shell.c bd6a37cbe8bf64ef6a6a74fdc50f067d3148149b4ce2b4d03154663e66ded55f
F src/shell.c.in b5725acacba95ccefa57b6d068f710e29ba8239c3aa704628a1902a1f729c175
-F src/sqlite.h.in 0ebbd0299e4bd03841c0e24ea86c74a42082b20533b86b0f360424a3b3c145a5
+F src/sqlite.h.in 9dacf9a0959630bf5d286c0fbdaf2bb4bf408a9477f6d61db8edab3a859714d7
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h a1fd3aa82f967da436164e0728a7d6841651fd0c6e27b9044e0eb9f6c8462e47
F src/sqliteInt.h eaa2c5e52a29da629bd50521a6b67cce7f952128a95ba4f20aac62c78d41b04d
F src/vtab.c f1d5c23132fb0247af3e86146404112283ddedb6c518de0d4edc91cfb36970ef
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 40c543f0a2195d1b0dc88ef12142bea690009344
-F src/wal.h 739d92494eb18b6d8f3e353e66c10eb8f94534bafd336ece9f3f60235317ea08
+F src/wal.h 06b2a0b599cc0f53ea97f497cf8c6b758c999f71
F src/walker.c a7ca64ce08a83a20d32186fbe06bca9234e348cfcf07959ee322fdc3e8a6173a
F src/where.c cbe8ddffbcec7ce86f7a800fe8fd10aee412c76c87e0dd3732a1682e68d74cd9
F src/whereInt.h 93bb90b77d39901eda31b44d8e90da1351193ccfe96876f89b58a93a33b84c3d
F test/selectF.test 21c94e6438f76537b72532fa9fd4710cdd455fc3
F test/selectG.test e8600e379589e85e9fefd2fe4d44a4cdd63f6982
F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118
-F test/server2.test 38a33c71963d72aad64c6f4e89ed8f7de129b3b5bf75c5785e363dee8deabd35
-F test/server3.test ba6428594bbe32eafa015782a039dcacbf0f42db967e4093e4d2f6f74178a02d
+F test/server2.test e7890fb1eb9a11a0f94cd0892279e0f3cd1ba8c3006fa343637ee9ff3c4689f6
+F test/server3.test c3ae4ca7a6e7df870bfcd2450a9815507eaa80b9cdc44ee6c7975d48311505d4
F test/server4.test 97040670597948a695b1973537d770417589f1998bcbb3959302aaee3c211250
F test/server5.test 2e554001145170094a19731a8ce2981d040cf44c947542b35d130e6e31256fca
-F test/server_common.tcl 6e0e0348a87381770b548fcf8faf2d8c7b910120b08a1bfb565546f77293fa81
+F test/server_common.tcl 551923cf8d51fefcdb4444bfd72b88ca5c5228fe1525da5b6528ae4edb7a2f2e
F test/servercrash.test 816c132b26af008067cab2913783f67006d4003e3988f3f3ee1075742f6e0a6c
F test/session.test 78fa2365e93d3663a6e933f86e7afc395adf18be
F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P bc2498d60fa22b587ad463ec697abe82d1c87abb7fd0d2cb60cc7316cfd7cec7
-R 97b8be53027d87f1df1370ba323e39a9
+P 8e1b28ed3e83eba0b2113316a40ed1165e0e051220b68863cb70734c95a82c2a
+R 0a18526bebbb88ed2fe197ff12475de8
U dan
-Z cc211de634879a22eac42d92c4a3bb35
+Z 121a6646ee66bffdec0d5750ccf213ab
-8e1b28ed3e83eba0b2113316a40ed1165e0e051220b68863cb70734c95a82c2a
\ No newline at end of file
+04e0cb571dbed00e269a890a755e252d7e8204d6d2ed5a7cfdb3d78d990a2876
\ No newline at end of file
/* Forward declaration */
static int unixGetTempname(int nBuf, char *zBuf);
+#ifdef SQLITE_SERVER_EDITION
+
/*
-** Information and control of an open file handle.
+** Structure passed by SQLite through the (void*) argument to various
+** fcntl operations.
*/
-static int unixFileControl(sqlite3_file *id, int op, void *pArg){
- unixFile *pFile = (unixFile*)id;
- switch( op ){
- case SQLITE_FCNTL_SERVER_MODE: {
- int rc = SQLITE_OK;
- int eServer = 0;
- if( pFile->ctrlFlags | UNIXFILE_EXCL ){
- char *zJrnl = sqlite3_mprintf("%s-journal", pFile->zPath);
- if( zJrnl==0 ){
- rc = SQLITE_NOMEM;
- }else{
- struct stat buf; /* Used to hold return values of stat() */
- if( osStat(zJrnl, &buf) ){
- rc = SQLITE_IOERR_FSTAT;
- }else{
- eServer = ((buf.st_mode & S_IFDIR) ? 1 : 0);
- }
+struct UnixServerArg {
+ void *h; /* Handle from SHMOPEN */
+ void *p; /* Mapping */
+ int i1; /* Integer value 1 */
+ int i2; /* Integer value 2 */
+};
+typedef struct UnixServerArg UnixServerArg;
+
+/*
+** Structure used as a server-shm handle.
+*/
+struct UnixServerShm {
+ void *pMap; /* Pointer to mapping */
+ int nMap; /* Size of mapping in bytes */
+ int fd; /* File descriptor open on *-hma file */
+};
+typedef struct UnixServerShm UnixServerShm;
+
+/*
+** Implementation of SQLITE_FCNTL_FILEID
+*/
+static int unixFcntlServerFileid(unixFile *pFile, void *pArg){
+ i64 *aId = (i64*)pArg;
+ aId[0] = (i64)(pFile->pInode->fileId.dev);
+ aId[1] = (i64)(pFile->pInode->fileId.ino);
+ return SQLITE_OK;
+}
+
+/*
+** Implementation of SQLITE_FCNTL_SERVER_MODE
+*/
+static int unixFcntlServerMode(unixFile *pFile, void *pArg){
+ int rc = SQLITE_OK;
+ int eServer = 0;
+ char *zJrnl = sqlite3_mprintf("%s-journal", pFile->zPath);
+ if( zJrnl==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ struct stat buf; /* Used to hold return values of stat() */
+ if( osStat(zJrnl, &buf) ){
+ rc = SQLITE_IOERR_FSTAT;
+ }else if( buf.st_mode & S_IFDIR ){
+ eServer = (pFile->ctrlFlags & UNIXFILE_EXCL) ? 1 : 2;
+ }
+ }
+ sqlite3_free(zJrnl);
+ *((int*)pArg) = eServer;
+ return rc;
+}
+
+/*
+** Implementation of SQLITE_FCNTL_SERVER_SHMOPEN.
+**
+** The (void*) argument passed to this file control should actually be
+** a pointer to a UnixServerArg or equivalent structure. Arguments are
+** interpreted as follows:
+**
+** UnixServerArg.h - OUT: New server shm handle.
+** UnixServerArg.p - OUT: New server shm mapping.
+** UnixServerArg.i1 - Size of requested mapping in bytes.
+** UnixServerArg.i2 - OUT: True if journal rollback + SHMOPEN2 are required.
+*/
+static int unixFcntlServerShmopen(unixFile *pFd, void *pArg){
+ int rc = SQLITE_OK;
+ UnixServerArg *pSArg = (UnixServerArg*)pArg;
+ UnixServerShm *p;
+ char *zHma;
+
+ p = sqlite3_malloc(sizeof(UnixServerShm));
+ if( p==0 ) return SQLITE_NOMEM;
+ memset(p, 0, sizeof(UnixServerShm));
+ p->fd = -1;
+
+ zHma = sqlite3_mprintf("%s-journal/hma", pFd->zPath);
+ if( zHma==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ p->fd = osOpen(zHma, O_RDWR|O_CREAT, 0644);
+ p->nMap = pSArg->i1;
+
+ if( p->fd<0 ){
+ rc = SQLITE_CANTOPEN;
+ }else{
+ int res = ftruncate(p->fd, p->nMap);
+ if( res!=0 ){
+ rc = SQLITE_IOERR_TRUNCATE;
+ }else{
+ p->pMap = osMmap(0, p->nMap, PROT_READ|PROT_WRITE, MAP_SHARED, p->fd,0);
+ if( p->pMap==0 ){
+ rc = SQLITE_IOERR_MMAP;
}
- sqlite3_free(zJrnl);
}
- *((int*)pArg) = eServer;
- return rc;
}
- case SQLITE_FCNTL_FILEID: {
- i64 *aId = (i64*)pArg;
- aId[0] = (i64)(pFile->pInode->fileId.dev);
- aId[1] = (i64)(pFile->pInode->fileId.ino);
- return SQLITE_OK;
+ sqlite3_free(zHma);
+ }
+
+ if( rc==SQLITE_OK ){
+ int res;
+ struct flock lock;
+ memset(&lock, 0, sizeof(struct flock));
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = p->nMap;
+ lock.l_len = 1;
+
+ res = osFcntl(p->fd, F_SETLK, &lock);
+ if( res==0 ){
+ pSArg->i2 = 1;
+ memset(p->pMap, 0, p->nMap);
+ }else{
+ pSArg->i2 = 0;
+ lock.l_type = F_RDLCK;
+ res = osFcntl(p->fd, F_SETLKW, &lock);
+ if( res!=0 ){
+ rc = SQLITE_IOERR_LOCK;
+ }
}
+ }
+
+ if( rc!=SQLITE_OK ){
+ if( p->pMap ) osMunmap(p->pMap, p->nMap);
+ if( p->fd>=0 ) close(p->fd);
+ sqlite3_free(p);
+ pSArg->h = pSArg->p = 0;
+ }else{
+ pSArg->h = (void*)p;
+ pSArg->p = (void*)(p->pMap);
+ }
+
+ return rc;
+}
+
+/*
+** Implementation of SQLITE_FCNTL_SERVER_SHMOPEN2.
+**
+** The (void*) argument passed to this file control should actually be
+** a pointer to a UnixServerArg or equivalent structure. Arguments are
+** interpreted as follows:
+**
+** UnixServerArg.h - Server shm handle (from SHMOPEN).
+** UnixServerArg.p - unused.
+** UnixServerArg.i1 - unused.
+** UnixServerArg.i2 - unused.
+*/
+static int unixFcntlServerShmopen2(unixFile *pFd, void *pArg){
+ UnixServerArg *pSArg = (UnixServerArg*)pArg;
+ UnixServerShm *p = (UnixServerShm*)pSArg->h;
+ int res;
+ struct flock lock;
+
+ memset(&lock, 0, sizeof(struct flock));
+ lock.l_type = F_RDLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = p->nMap;
+ lock.l_len = 1;
+ res = osFcntl(p->fd, F_SETLK, &lock);
+
+ return res ? SQLITE_IOERR_LOCK : SQLITE_OK;
+}
+
+/*
+** Implementation of SQLITE_FCNTL_SERVER_SHMCLOSE.
+**
+** The (void*) argument passed to this file control should actually be
+** a pointer to a UnixServerArg or equivalent structure. Arguments are
+** interpreted as follows:
+**
+** UnixServerArg.h - Server shm handle (from SHMOPEN).
+** UnixServerArg.p - unused.
+** UnixServerArg.i1 - unused.
+** UnixServerArg.i2 - unused.
+*/
+static int unixFcntlServerShmclose(unixFile *pFd, void *pArg){
+ UnixServerArg *pSArg = (UnixServerArg*)pArg;
+ UnixServerShm *p = (UnixServerShm*)pSArg->h;
+
+ if( p->pMap ) osMunmap(p->pMap, p->nMap);
+ if( p->fd>=0 ) close(p->fd);
+ sqlite3_free(p);
+
+ return SQLITE_OK;
+}
+
+/*
+** Implementation of SQLITE_FCNTL_SERVER_SHMLOCK.
+**
+** The (void*) argument passed to this file control should actually be
+** a pointer to a UnixServerArg or equivalent structure. Arguments are
+** interpreted as follows:
+**
+** UnixServerArg.h - Server shm handle (from SHMOPEN).
+** UnixServerArg.p - unused.
+** UnixServerArg.i1 - slot to lock.
+** UnixServerArg.i2 - true to take the lock, false to release it.
+*/
+static int unixFcntlServerShmlock(unixFile *pFd, void *pArg){
+ UnixServerArg *pSArg = (UnixServerArg*)pArg;
+ UnixServerShm *p = (UnixServerShm*)pSArg->h;
+ int res;
+
+ struct flock lock;
+ memset(&lock, 0, sizeof(struct flock));
+ lock.l_type = pSArg->i2 ? F_WRLCK : F_UNLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = p->nMap + pSArg->i1 + 1;
+ lock.l_len = 1;
+
+ res = osFcntl(p->fd, F_SETLK, &lock);
+
+ return (res==0 ? SQLITE_OK : SQLITE_BUSY);
+}
+#endif
+
+/*
+** Information and control of an open file handle.
+*/
+static int unixFileControl(sqlite3_file *id, int op, void *pArg){
+ unixFile *pFile = (unixFile*)id;
+ switch( op ){
+
+#ifdef SQLITE_SERVER_EDITION
+ case SQLITE_FCNTL_FILEID:
+ return unixFcntlServerFileid(pFile, pArg);
+ case SQLITE_FCNTL_SERVER_MODE:
+ return unixFcntlServerMode(pFile, pArg);
+ case SQLITE_FCNTL_SERVER_SHMOPEN:
+ return unixFcntlServerShmopen(pFile, pArg);
+ case SQLITE_FCNTL_SERVER_SHMOPEN2:
+ return unixFcntlServerShmopen2(pFile, pArg);
+ case SQLITE_FCNTL_SERVER_SHMCLOSE:
+ return unixFcntlServerShmclose(pFile, pArg);
+ case SQLITE_FCNTL_SERVER_SHMLOCK:
+ return unixFcntlServerShmlock(pFile, pArg);
+#endif
+
#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: {
int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE);
#ifdef SQLITE_SERVER_EDITION
# define pagerIsServer(x) ((x)->pServer!=0)
+# define pagerIsProcessServer(x) sqlite3ServerIsSingleProcess((x)->pServer)
#else
# define pagerIsServer(x) 0
#endif
}
#ifdef SQLITE_SERVER_EDITION
+/*
+** Free the linked list of ServerPage objects headed at Pager.pServerPage.
+*/
static void pagerFreeServerPage(Pager *pPager){
ServerPage *pPg;
ServerPage *pNext;
assert( isOpen(pPager->fd) || pList->pDirty==0 );
#ifdef SQLITE_SERVER_EDITION
- if( pagerIsServer(pPager) ){
+ if( pagerIsProcessServer(pPager) ){
rc = sqlite3ServerPreCommit(pPager->pServer, pPager->pServerPage);
pPager->pServerPage = 0;
if( rc!=SQLITE_OK ) return rc;
}
#ifdef SQLITE_SERVER_EDITION
-static int pagerServerConnect(Pager *pPager){
+static int pagerServerConnect(Pager *pPager, int eServer){
int rc = SQLITE_OK;
if( pPager->tempFile==0 ){
pPager->noLock = 1;
pPager->journalMode = PAGER_JOURNALMODE_PERSIST;
- rc = sqlite3ServerConnect(pPager, &pPager->pServer);
+ rc = sqlite3ServerConnect(pPager, eServer, &pPager->pServer);
}
return rc;
}
#ifdef SQLITE_SERVER_EDITION
if( eServer ){
- rc = pagerServerConnect(pPager);
+ rc = pagerServerConnect(pPager, eServer);
}
#endif
i64 iOff = pPager->journalOff;
#ifdef SQLITE_SERVER_EDITION
- if( pagerIsServer(pPager) ){
+ if( pagerIsProcessServer(pPager) ){
ServerPage *p = sqlite3ServerBuffer(pPager->pServer);
if( p==0 ){
int nByte = sizeof(ServerPage) + pPager->pageSize;
#define HMA_SLOT_RLWL_BITS (HMA_SLOT_RL_BITS + HMA_SLOT_WL_BITS)
-
#define HMA_SLOT_RL_MASK ((1 << HMA_SLOT_RL_BITS)-1)
#define HMA_SLOT_WL_MASK (((1 << HMA_SLOT_WL_BITS)-1) << HMA_SLOT_RL_BITS)
#define HMA_SLOT_TR_MASK (((1 << HMA_SLOT_TR_BITS)-1) << HMA_SLOT_RLWL_BITS)
/* Maximum concurrent read/write transactions */
#define HMA_MAX_TRANSACTIONID 16
-
+/* Number of buckets in hash table used for MVCC in single-process mode */
#define HMA_HASH_SIZE 512
/*
#define slotReaderMask(v) ((v) & HMA_SLOT_RL_MASK)
-#include "unistd.h"
-#include "fcntl.h"
-#include "sys/mman.h"
-#include "sys/types.h"
-#include "sys/stat.h"
-#include "errno.h"
+
+/*
+** Atomic CAS primitive used in multi-process mode. Equivalent to:
+**
+** int serverCompareAndSwap(u32 *ptr, u32 oldval, u32 newval){
+** if( *ptr==oldval ){
+** *ptr = newval;
+** return 1;
+** }
+** return 0;
+** }
+*/
+#define serverCompareAndSwap(ptr,oldval,newval) \
+ __sync_bool_compare_and_swap(ptr,oldval,newval)
+
typedef struct ServerDb ServerDb;
typedef struct ServerJournal ServerJournal;
struct ServerGlobal {
- ServerDb *pDb; /* Linked list of all ServerHMA objects */
+ ServerDb *pDb; /* Linked list of all ServerDb objects */
};
static struct ServerGlobal g_server;
ServerJournal aJrnl[HMA_MAX_TRANSACTIONID];
u8 *aJrnlFdSpace;
+ void *pServerShm;
+
int iNextCommit; /* Commit id for next pre-commit call */
Server *pCommit; /* List of connections currently commiting */
Server *pReader; /* Connections in slower-reader transaction */
ServerPage *pPgFirst; /* First (oldest) in list of pages */
ServerPage *pPgLast; /* Last (newest) in list of pages */
- ServerPage *apPg[HMA_HASH_SIZE];
-
+ ServerPage *apPg[HMA_HASH_SIZE];/* Hash table of "old" page data */
ServerPage *pFree; /* List of free page buffers */
};
int iCommitId; /* Current commit id (or 0) */
int nAlloc; /* Allocated size of aLock[] array */
int nLock; /* Number of entries in aLock[] */
- u32 *aLock; /* Mapped lock file */
+ u32 *aLock; /* Array of held locks */
Server *pNext; /* Next in pCommit or pReader list */
};
+struct ServerFcntlArg {
+ void *h; /* Handle from SHMOPEN */
+ void *p; /* Mapping */
+ int i1; /* Integer value 1 */
+ int i2; /* Integer value 2 */
+};
+typedef struct ServerFcntlArg ServerFcntlArg;
+
/*
** Possible values for Server.eTrans.
*/
assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_APP1)) );
}
+/*
+** Locate the ServerDb object shared by all connections to the db identified
+** by aFileId[2], increment its ref count and set pNew->pDb to point to it.
+** In this context "locate" may mean to find an existing object or to
+** allocate a new one.
+*/
static int serverFindDatabase(Server *pNew, i64 *aFileId){
ServerDb *p;
int rc = SQLITE_OK;
if( p==0 ){
p = (ServerDb*)sqlite3MallocZero(sizeof(ServerDb));
if( p ){
- p->aSlot = (u32*)sqlite3MallocZero(sizeof(u32)*HMA_PAGELOCK_SLOTS);
- if( p->aSlot==0 ){
- rc = SQLITE_NOMEM_BKPT;
- }else{
- p->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ p->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
#if SQLITE_THREADSAFE!=0
- if( p->mutex==0 ) rc = SQLITE_NOMEM_BKPT;
+ if( p->mutex==0 ) rc = SQLITE_NOMEM_BKPT;
#endif
- }
-
if( rc==SQLITE_NOMEM ){
- sqlite3_free(p->aSlot);
sqlite3_free(p);
p = 0;
}else{
** Free all resources allocated by serverInitDatabase() associated with the
** object passed as the only argument.
*/
-static void serverShutdownDatabase(ServerDb *pDb){
+static void serverShutdownDatabase(
+ ServerDb *pDb,
+ sqlite3_file *dbfd,
+ int bDelete
+){
int i;
for(i=0; i<HMA_MAX_TRANSACTIONID; i++){
ServerJournal *pJ = &pDb->aJrnl[i];
if( pJ->jfd ){
sqlite3OsClose(pJ->jfd);
- sqlite3OsDelete(pDb->pVfs, pJ->zJournal, 0);
+ if( bDelete ) sqlite3OsDelete(pDb->pVfs, pJ->zJournal, 0);
}
sqlite3_free(pJ->zJournal);
}
pDb->aJrnlFdSpace = 0;
}
- sqlite3_free(pDb->aSlot);
+ if( pDb->pServerShm ){
+ ServerFcntlArg arg;
+ memset(&arg, 0, sizeof(ServerFcntlArg));
+ arg.h = pDb->pServerShm;
+ sqlite3OsFileControl(dbfd, SQLITE_FCNTL_SERVER_SHMCLOSE, (void*)&arg);
+ }else{
+ sqlite3_free(pDb->aSlot);
+ }
+ pDb->aSlot = 0;
pDb->bInit = 0;
}
** is established. It is responsible for rolling back any hot journal
** files found in the file-system.
*/
-static int serverInitDatabase(Server *pNew){
+static int serverInitDatabase(Server *pNew, int eServer){
int nByte;
int rc = SQLITE_OK;
ServerDb *pDb = pNew->pDb;
sqlite3_vfs *pVfs;
+ sqlite3_file *dbfd = sqlite3PagerFile(pNew->pPager);
const char *zFilename = sqlite3PagerFilename(pNew->pPager, 0);
+ int bRollback = 0;
assert( zFilename );
+ assert( eServer==1 || eServer==2 );
+
pVfs = pDb->pVfs = sqlite3PagerVfs(pNew->pPager);
nByte = ROUND8(pVfs->szOsFile) * HMA_MAX_TRANSACTIONID;
pDb->aJrnlFdSpace = (u8*)sqlite3MallocZero(nByte);
if( pDb->aJrnlFdSpace==0 ){
rc = SQLITE_NOMEM_BKPT;
}else{
+ if( eServer==2 ){
+ ServerFcntlArg arg;
+ arg.h = 0;
+ arg.p = 0;
+ arg.i1 = sizeof(u32)*HMA_PAGELOCK_SLOTS;
+ arg.i2 = 0;
+
+ rc = sqlite3OsFileControl(dbfd, SQLITE_FCNTL_SERVER_SHMOPEN, (void*)&arg);
+ if( rc==SQLITE_OK ){
+ pDb->aSlot = (u32*)arg.p;
+ pDb->pServerShm = arg.h;
+ bRollback = arg.i2;
+ }
+ }else{
+ pDb->aSlot = (u32*)sqlite3MallocZero(sizeof(u32)*HMA_PAGELOCK_SLOTS);
+ if( pDb->aSlot==0 ) rc = SQLITE_NOMEM_BKPT;
+ bRollback = 1;
+ }
+ }
+
+ if( rc==SQLITE_OK ){
u8 *a = pDb->aJrnlFdSpace;
int i;
for(i=0; rc==SQLITE_OK && i<HMA_MAX_TRANSACTIONID; i++){
- int bExists = 0;
ServerJournal *pJ = &pDb->aJrnl[i];
pJ->jfd = (sqlite3_file*)&a[ROUND8(pVfs->szOsFile)*i];
pJ->zJournal = sqlite3_mprintf("%s-journal/%d-journal", zFilename, i);
break;
}
- rc = sqlite3OsAccess(pVfs, pJ->zJournal, SQLITE_ACCESS_EXISTS, &bExists);
- if( rc==SQLITE_OK && bExists ){
- int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
- rc = sqlite3OsOpen(pVfs, pJ->zJournal, pJ->jfd, flags, &flags);
- if( rc==SQLITE_OK ){
- rc = sqlite3PagerRollbackJournal(pNew->pPager, pJ->jfd);
+ if( bRollback ){
+ int bExist = 0;
+ rc = sqlite3OsAccess(pVfs, pJ->zJournal, SQLITE_ACCESS_EXISTS, &bExist);
+ if( rc==SQLITE_OK && bExist ){
+ int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL;
+ rc = sqlite3OsOpen(pVfs, pJ->zJournal, pJ->jfd, flags, &flags);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerRollbackJournal(pNew->pPager, pJ->jfd);
+ }
}
}
}
}
+ if( rc==SQLITE_OK && pDb->pServerShm && bRollback ){
+ ServerFcntlArg arg;
+ arg.h = pDb->pServerShm;
+ arg.p = 0;
+ arg.p = 0;
+ arg.i2 = 0;
+ rc = sqlite3OsFileControl(dbfd, SQLITE_FCNTL_SERVER_SHMOPEN2, (void*)&arg);
+ }
+
if( rc==SQLITE_OK ){
pDb->bInit = 1;
}else{
- serverShutdownDatabase(pNew->pDb);
+ serverShutdownDatabase(pNew->pDb, dbfd, eServer==1);
}
return rc;
}
+/*
+** Take (bLock==1) or release (bLock==0) a server shmlock on slot iSlot.
+** Return SQLITE_OK if successful, or SQLITE_BUSY if the lock cannot be
+** obtained.
+*/
+static int serverFcntlLock(Server *p, int iSlot, int bLock){
+ sqlite3_file *dbfd = sqlite3PagerFile(p->pPager);
+ int rc;
+ ServerFcntlArg arg;
+ arg.h = p->pDb->pServerShm;
+ arg.p = 0;
+ arg.i1 = iSlot;
+ arg.i2 = bLock;
+ rc = sqlite3OsFileControl(dbfd, SQLITE_FCNTL_SERVER_SHMLOCK, (void*)&arg);
+ return rc;
+}
+
/*
** Close the connection.
*/
void sqlite3ServerDisconnect(Server *p, sqlite3_file *dbfd){
ServerDb *pDb = p->pDb;
+ /* In a multi-process setup, release the lock on the client slot and
+ ** clear the bit in the ServerDb.transmask bitmask. */
+ if( pDb->pServerShm && p->iTransId>=0 ){
+ sqlite3_mutex_enter(pDb->mutex);
+ pDb->transmask &= ~((u32)1 << p->iTransId);
+ sqlite3_mutex_leave(pDb->mutex);
+ serverFcntlLock(p, p->iTransId, 0);
+ }
+
serverEnterMutex();
pDb->nClient--;
if( pDb->nClient==0 ){
+ sqlite3_file *dbfd = sqlite3PagerFile(p->pPager);
ServerPage *pFree;
ServerDb **pp;
- serverShutdownDatabase(pDb);
+
+ /* Delete the journal files on shutdown if an EXCLUSIVE lock is already
+ ** held (single process mode) or can be obtained (multi process mode)
+ ** on the database file.
+ **
+ ** TODO: Need to account for disk-full errors and the like here. It
+ ** is not necessarily safe to delete journal files here. */
+ int bDelete = 0;
+ if( pDb->pServerShm ){
+ int res;
+ res = sqlite3OsLock(dbfd, EXCLUSIVE_LOCK);
+ if( res==SQLITE_OK ) bDelete = 1;
+ }else{
+ bDelete = 1;
+ }
+ serverShutdownDatabase(pDb, dbfd, bDelete);
+
for(pp=&g_server.pDb; *pp!=pDb; pp=&((*pp)->pNext));
*pp = pDb->pNext;
sqlite3_mutex_free(pDb->mutex);
** Connect to the system.
*/
int sqlite3ServerConnect(
- Pager *pPager,
+ Pager *pPager, /* Pager object */
+ int eServer, /* 1 -> single process, 2 -> multi process */
Server **ppOut /* OUT: Server handle */
){
Server *pNew = 0;
sqlite3_free(pNew);
pNew = 0;
}else{
+ ServerDb *pDb = pNew->pDb;
sqlite3_mutex_enter(pNew->pDb->mutex);
- if( pNew->pDb->bInit==0 ){
- rc = serverInitDatabase(pNew);
+ if( pDb->bInit==0 ){
+ rc = serverInitDatabase(pNew, eServer);
+ }
+
+ /* If this is a multi-process connection, need to lock a
+ ** client locking-slot before continuing. */
+ if( rc==SQLITE_OK && pDb->pServerShm ){
+ int i;
+ rc = SQLITE_BUSY;
+ for(i=0; rc==SQLITE_BUSY && i<HMA_MAX_TRANSACTIONID; i++){
+ if( 0==(pDb->transmask & ((u32)1 << i)) ){
+ rc = serverFcntlLock(pNew, i, 1);
+ if( rc==SQLITE_OK ){
+ pNew->iTransId = i;
+ pDb->transmask |= ((u32)1 << i);
+ }
+ }
+ }
}
sqlite3_mutex_leave(pNew->pDb->mutex);
}
}
}
+ if( rc!=SQLITE_OK && pNew ){
+ sqlite3ServerDisconnect(pNew, dbfd);
+ pNew = 0;
+ }
+
*ppOut = pNew;
return rc;
}
int rc = SQLITE_OK;
if( p->eTrans==SERVER_TRANS_NONE ){
- int id;
ServerDb *pDb = p->pDb;
u32 t;
- assert( p->iTransId<0 );
assert( p->pNext==0 );
- sqlite3_mutex_enter(pDb->mutex);
-
- if( bReadonly ){
- Server *pIter;
- p->iCommitId = pDb->iNextCommit;
- for(pIter=pDb->pCommit; pIter; pIter=pIter->pNext){
- if( pIter->iCommitId<p->iCommitId ){
- p->iCommitId = pIter->iCommitId;
- }
- }
- p->pNext = pDb->pReader;
- pDb->pReader = p;
- p->eTrans = SERVER_TRANS_READONLY;
+ if( pDb->pServerShm ){
+ p->eTrans = SERVER_TRANS_READWRITE;
}else{
- /* Find a transaction id to use */
- rc = SQLITE_BUSY;
- t = pDb->transmask;
- for(id=0; id<HMA_MAX_TRANSACTIONID; id++){
- if( (t & (1 << id))==0 ){
- t = t | (1 << id);
- rc = SQLITE_OK;
- break;
+ assert( p->iTransId<0 );
+ sqlite3_mutex_enter(pDb->mutex);
+ if( bReadonly ){
+ Server *pIter;
+ p->iCommitId = pDb->iNextCommit;
+ for(pIter=pDb->pCommit; pIter; pIter=pIter->pNext){
+ if( pIter->iCommitId<p->iCommitId ){
+ p->iCommitId = pIter->iCommitId;
+ }
+ }
+ p->pNext = pDb->pReader;
+ pDb->pReader = p;
+ p->eTrans = SERVER_TRANS_READONLY;
+ }else{
+ int id;
+
+ /* Find a transaction id to use */
+ rc = SQLITE_BUSY;
+ t = pDb->transmask;
+ for(id=0; id<HMA_MAX_TRANSACTIONID; id++){
+ if( (t & (1 << id))==0 ){
+ t = t | (1 << id);
+ rc = SQLITE_OK;
+ break;
+ }
+ }
+ pDb->transmask = t;
+ p->eTrans = SERVER_TRANS_READWRITE;
+ if( rc==SQLITE_OK ){
+ p->iTransId = id;
}
}
- pDb->transmask = t;
- p->eTrans = SERVER_TRANS_READWRITE;
+ sqlite3_mutex_leave(pDb->mutex);
}
- sqlite3_mutex_leave(pDb->mutex);
-
- if( rc==SQLITE_OK && bReadonly==0 ){
- ServerJournal *pJrnl = &pDb->aJrnl[id];
+ if( rc==SQLITE_OK && p->eTrans==SERVER_TRANS_READWRITE ){
+ ServerJournal *pJrnl = &pDb->aJrnl[p->iTransId];
sqlite3PagerServerJournal(p->pPager, pJrnl->jfd, pJrnl->zJournal);
- p->iTransId = id;
}
}
return rc;
}
+static u32 *serverLockingSlot(ServerDb *pDb, u32 pgno){
+ return &pDb->aSlot[pgno % HMA_PAGELOCK_SLOTS];
+}
+
static void serverReleaseLocks(Server *p){
ServerDb *pDb = p->pDb;
int i;
- assert( sqlite3_mutex_held(pDb->mutex) );
+
+ assert( pDb->pServerShm || sqlite3_mutex_held(pDb->mutex) );
for(i=0; i<p->nLock; i++){
- u32 *pSlot = &pDb->aSlot[p->aLock[i] % HMA_PAGELOCK_SLOTS];
- if( slotGetWriter(*pSlot)==p->iTransId ){
- *pSlot -= ((p->iTransId + 1) << HMA_MAX_TRANSACTIONID);
+ while( 1 ){
+ u32 *pSlot = serverLockingSlot(pDb, p->aLock[i]);
+ u32 o = *pSlot;
+ u32 n = o & ~((u32)1 << p->iTransId);
+ if( slotGetWriter(n)==p->iTransId ){
+ n -= ((p->iTransId + 1) << HMA_MAX_TRANSACTIONID);
+ }
+ if( serverCompareAndSwap(pSlot, o, n) ) break;
}
- *pSlot &= ~((u32)1 << p->iTransId);
}
p->nLock = 0;
}
/*
-** End a transaction (and release all locks).
+** End a transaction (and release all locks). This version runs in
+** single process mode only.
*/
-int sqlite3ServerEnd(Server *p){
- int rc = SQLITE_OK;
- if( p->eTrans!=SERVER_TRANS_NONE ){
- Server **pp;
- ServerDb *pDb = p->pDb;
- ServerPage *pPg = 0;
+static void serverEndSingle(Server *p){
+ Server **pp;
+ ServerDb *pDb = p->pDb;
+ ServerPage *pPg = 0;
- sqlite3_mutex_enter(pDb->mutex);
+ assert( p->eTrans!=SERVER_TRANS_NONE );
+ assert( pDb->pServerShm==0 );
- if( p->eTrans==SERVER_TRANS_READONLY ){
- /* Remove the connection from the readers list */
- for(pp=&pDb->pReader; *pp!=p; pp = &((*pp)->pNext));
- *pp = p->pNext;
- }else{
- serverReleaseLocks(p);
+ sqlite3_mutex_enter(pDb->mutex);
- /* Clear the bit in the transaction mask. */
- pDb->transmask &= ~((u32)1 << p->iTransId);
+ if( p->eTrans==SERVER_TRANS_READONLY ){
+ /* Remove the connection from the readers list */
+ for(pp=&pDb->pReader; *pp!=p; pp = &((*pp)->pNext));
+ *pp = p->pNext;
+ }else{
+ serverReleaseLocks(p);
- /* If this connection is in the committers list, remove it. */
- for(pp=&pDb->pCommit; *pp; pp = &((*pp)->pNext)){
- if( *pp==p ){
- *pp = p->pNext;
- break;
- }
+ /* Clear the bit in the transaction mask. */
+ pDb->transmask &= ~((u32)1 << p->iTransId);
+
+ /* If this connection is in the committers list, remove it. */
+ for(pp=&pDb->pCommit; *pp; pp = &((*pp)->pNext)){
+ if( *pp==p ){
+ *pp = p->pNext;
+ break;
}
}
+ }
- /* See if it is possible to free any ServerPage records. If so, remove
- ** them from the linked list and hash table, but do not call sqlite3_free()
- ** on them until the mutex has been released. */
- if( pDb->pPgFirst ){
- ServerPage *pLast = 0;
- Server *pIter;
- int iOldest = 0x7FFFFFFF;
- for(pIter=pDb->pReader; pIter; pIter=pIter->pNext){
- iOldest = MIN(iOldest, pIter->iCommitId);
- }
- for(pIter=pDb->pCommit; pIter; pIter=pIter->pNext){
- iOldest = MIN(iOldest, pIter->iCommitId);
- }
+ /* See if it is possible to free any ServerPage records. If so, remove
+ ** them from the linked list and hash table, but do not call sqlite3_free()
+ ** on them until the mutex has been released. */
+ if( pDb->pPgFirst ){
+ ServerPage *pLast = 0;
+ Server *pIter;
+ int iOldest = 0x7FFFFFFF;
+ for(pIter=pDb->pReader; pIter; pIter=pIter->pNext){
+ iOldest = MIN(iOldest, pIter->iCommitId);
+ }
+ for(pIter=pDb->pCommit; pIter; pIter=pIter->pNext){
+ iOldest = MIN(iOldest, pIter->iCommitId);
+ }
- for(pPg=pDb->pPgFirst; pPg && pPg->iCommitId<iOldest; pPg=pPg->pNext){
- if( pPg->pHashPrev ){
- pPg->pHashPrev->pHashNext = pPg->pHashNext;
- }else{
- int iHash = pPg->pgno % HMA_HASH_SIZE;
- assert( pDb->apPg[iHash]==pPg );
- pDb->apPg[iHash] = pPg->pHashNext;
- }
- if( pPg->pHashNext ){
- pPg->pHashNext->pHashPrev = pPg->pHashPrev;
- }
- pLast = pPg;
+ for(pPg=pDb->pPgFirst; pPg && pPg->iCommitId<iOldest; pPg=pPg->pNext){
+ if( pPg->pHashPrev ){
+ pPg->pHashPrev->pHashNext = pPg->pHashNext;
+ }else{
+ int iHash = pPg->pgno % HMA_HASH_SIZE;
+ assert( pDb->apPg[iHash]==pPg );
+ pDb->apPg[iHash] = pPg->pHashNext;
}
-
- if( pLast ){
- assert( pLast->pNext==pPg );
- pLast->pNext = pDb->pFree;
- pDb->pFree = pDb->pPgFirst;
+ if( pPg->pHashNext ){
+ pPg->pHashNext->pHashPrev = pPg->pHashPrev;
}
+ pLast = pPg;
+ }
- if( pPg==0 ){
- pDb->pPgFirst = pDb->pPgLast = 0;
- }else{
- pDb->pPgFirst = pPg;
- }
+ if( pLast ){
+ assert( pLast->pNext==pPg );
+ pLast->pNext = pDb->pFree;
+ pDb->pFree = pDb->pPgFirst;
}
- sqlite3_mutex_leave(pDb->mutex);
+ if( pPg==0 ){
+ pDb->pPgFirst = pDb->pPgLast = 0;
+ }else{
+ pDb->pPgFirst = pPg;
+ }
+ }
- p->pNext = 0;
- p->eTrans = SERVER_TRANS_NONE;
- p->iTransId = -1;
- p->iCommitId = 0;
+ sqlite3_mutex_leave(pDb->mutex);
+
+ p->pNext = 0;
+ p->eTrans = SERVER_TRANS_NONE;
+ p->iTransId = -1;
+ p->iCommitId = 0;
+}
+
+/*
+** End a transaction (and release all locks).
+*/
+int sqlite3ServerEnd(Server *p){
+ if( p->eTrans!=SERVER_TRANS_NONE ){
+ if( p->pDb->pServerShm ){
+ serverReleaseLocks(p);
+ }else{
+ serverEndSingle(p);
+ }
}
- return rc;
+ return SQLITE_OK;
}
int sqlite3ServerPreCommit(Server *p, ServerPage *pPg){
int rc = SQLITE_OK;
ServerPage *pIter;
+ /* This should never be called in multi-process mode */
+ assert( pDb->pServerShm==0 );
if( pPg==0 ) return SQLITE_OK;
sqlite3_mutex_enter(pDb->mutex);
int rc = SQLITE_OK;
assert( p->eTrans==SERVER_TRANS_READWRITE
- || p->eTrans==SERVER_TRANS_READONLY
+ || (p->eTrans==SERVER_TRANS_READONLY && p->pDb->pServerShm==0)
);
if( p->eTrans==SERVER_TRANS_READWRITE ){
ServerDb *pDb = p->pDb;
int bSkip = 0;
u32 *pSlot;
+ /* Grow the aLock[] array if required */
assert( p->iTransId>=0 );
assert( p->nLock<=p->nAlloc );
if( p->nLock==p->nAlloc ){
p->aLock = aNew;
}
- sqlite3_mutex_enter(pDb->mutex);
+ /* Find the locking slot for the page in question */
+ pSlot = serverLockingSlot(pDb, pgno);
- pSlot = &pDb->aSlot[pgno % HMA_PAGELOCK_SLOTS];
- assert( slotGetWriter(*pSlot)<0
- || slotReaderMask(*pSlot)==0
- || slotReaderMask(*pSlot)==(1 << slotGetWriter(*pSlot))
- );
-
- iWriter = slotGetWriter(*pSlot);
- if( iWriter==p->iTransId || (bWrite==0 && (*pSlot & (1<<p->iTransId))) ){
- bSkip = 1;
- }else if( iWriter>=0 ){
- rc = SQLITE_BUSY_DEADLOCK;
- }else if( bWrite ){
- if( (slotReaderMask(*pSlot) & ~(1 << p->iTransId))==0 ){
- *pSlot += ((p->iTransId + 1) << HMA_MAX_TRANSACTIONID);
- }else{
+ if( pDb->pServerShm==0 ) sqlite3_mutex_enter(pDb->mutex);
+
+ while( 1 ){
+ u32 o = *pSlot;
+ u32 n = o;
+
+ assert( slotGetWriter(o)<0
+ || slotReaderMask(o)==0
+ || slotReaderMask(o)==(1 << slotGetWriter(o))
+ );
+
+ iWriter = slotGetWriter(o);
+ if( iWriter==p->iTransId || (bWrite==0 && (o & (1<<p->iTransId))) ){
+ bSkip = 1;
+ break;
+ }else if( iWriter>=0 ){
rc = SQLITE_BUSY_DEADLOCK;
+ }else if( bWrite ){
+ if( (slotReaderMask(o) & ~(1 << p->iTransId))==0 ){
+ n += ((p->iTransId + 1) << HMA_MAX_TRANSACTIONID);
+ }else{
+ rc = SQLITE_BUSY_DEADLOCK;
+ }
+ }else{
+ n |= (1 << p->iTransId);
}
- }else{
- *pSlot |= (1 << p->iTransId);
- }
- assert( slotGetWriter(*pSlot)<0
- || slotReaderMask(*pSlot)==0
- || slotReaderMask(*pSlot)==(1 << slotGetWriter(*pSlot))
- );
+ assert( slotGetWriter(n)<0
+ || slotReaderMask(n)==0
+ || slotReaderMask(n)==(1 << slotGetWriter(n))
+ );
+ if( rc!=SQLITE_OK || serverCompareAndSwap(pSlot, o, n) ) break;
+ }
- sqlite3_mutex_leave(pDb->mutex);
+ if( pDb->pServerShm==0 ){
+ sqlite3_mutex_leave(pDb->mutex);
+ }
- if( bSkip==0 ){
+ if( bSkip==0 && rc==SQLITE_OK ){
p->aLock[p->nLock++] = pgno;
}
}
ServerPage *pBest = 0;
int iHash = pgno % HMA_HASH_SIZE;
+ /* There are no READONLY transactions in a multi process system */
+ assert( pDb->pServerShm==0 );
sqlite3_mutex_enter(pDb->mutex);
/* Search the hash table for the oldest version of page pgno with
if( p->eTrans==SERVER_TRANS_READONLY ){
ServerDb *pDb = p->pDb;
u32 *pSlot = &pDb->aSlot[pgno % HMA_PAGELOCK_SLOTS];
+ assert( pDb->pServerShm==0 );
sqlite3_mutex_enter(pDb->mutex);
serverIncrSlowReader(pSlot, -1);
assert( slotGetSlowReaders(*pSlot)>=0 );
ServerPage *sqlite3ServerBuffer(Server *p){
ServerDb *pDb = p->pDb;
ServerPage *pRet = 0;
+ assert( pDb->pServerShm==0 );
sqlite3_mutex_enter(pDb->mutex);
if( pDb->pFree ){
pRet = pDb->pFree;
return (p && p->eTrans==SERVER_TRANS_READONLY);
}
+/*
+** Return true if the argument is non-NULL and connects to a single-process
+** server system. Return false if the argument is NULL or the system supports
+** multiple processes.
+*/
+int sqlite3ServerIsSingleProcess(Server *p){
+ return (p && p->pDb->pServerShm==0);
+}
+
#endif /* ifdef SQLITE_SERVER_EDITION */
ServerPage *pHashPrev;
};
-int sqlite3ServerConnect(Pager *pPager, Server **ppOut);
+int sqlite3ServerConnect(Pager *pPager, int eServer, Server **ppOut);
void sqlite3ServerDisconnect(Server *p, sqlite3_file *dbfd);
int sqlite3ServerBegin(Server *p, int bReadonly);
ServerPage *sqlite3ServerBuffer(Server*);
+int sqlite3ServerIsSingleProcess(Server*);
+
/* For "BEGIN READONLY" clients. */
int sqlite3ServerIsReadonly(Server*);
void sqlite3ServerReadPage(Server*, Pgno, u8**);
#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33
#define SQLITE_FCNTL_FILEID 34
#define SQLITE_FCNTL_SERVER_MODE 35
+#define SQLITE_FCNTL_SERVER_SHMOPEN 36
+#define SQLITE_FCNTL_SERVER_SHMOPEN2 37
+#define SQLITE_FCNTL_SERVER_SHMLOCK 38
+#define SQLITE_FCNTL_SERVER_SHMCLOSE 39
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
/* Return the sqlite3_file object for the WAL file */
sqlite3_file *sqlite3WalFile(Wal *pWal);
-#ifdef SQLITE_SERVER_EDITION
-int sqlite3WalServer(Wal *pWal, Server *pServer);
-#endif
-
#endif /* ifndef SQLITE_OMIT_WAL */
#endif /* SQLITE_WAL_H */
source $testdir/server_common.tcl
return_if_no_server
-
db close
-foreach f [glob -nocomplain test.db*] {
- forcedelete $f
-}
-
-#-------------------------------------------------------------------------
-# Check that the *-journal* files are deleted correctly.
-#
-server_reset_db
-do_execsql_test 1.0 {
- CREATE TABLE t1(a, b);
-} {}
-
-do_test 1.1 {
- lsort [glob -nocomplain test.db-journal/*]
-} {test.db-journal/0-journal}
-
-do_test 1.2 {
- db close
- lsort [glob -nocomplain test.db-journal/*]
-} {}
-server_sqlite3 db test.db
-do_execsql_test 1.3 {
- CREATE TABLE t2(a, b);
-} {}
+foreach {tn vfs} {1 unix-excl 2 unix} {
+ server_set_vfs $vfs
-server_sqlite3 db2 test.db
-do_test 1.4 {
- db eval {
- BEGIN;
- INSERT INTO t1 VALUES(1, 2);
+ foreach f [glob -nocomplain test.db*] {
+ forcedelete $f
}
- db2 eval {
- BEGIN;
- INSERT INTO t2 VALUES(3, 4);
- }
-} {}
-
-do_test 1.5 {
- db2 eval COMMIT
- db eval COMMIT
- lsort [glob -nocomplain test.db-journal/*]
-} {test.db-journal/0-journal test.db-journal/1-journal}
-
-do_test 1.6 {
- db close
- lsort [glob -nocomplain test.db-journal/*]
-} {test.db-journal/0-journal test.db-journal/1-journal}
-
-do_test 1.7 {
- db2 close
- lsort [glob -nocomplain test.db-journal/*]
-} {}
-#-------------------------------------------------------------------------
-#
-server_reset_db
-server_sqlite3 db2 test.db
-
-do_execsql_test 2.0 {
- CREATE TABLE t1(a, b);
- CREATE TABLE t2(c, d);
-}
-
-# Two concurrent transactions committed.
-#
-do_test 2.1 {
- db eval {
- BEGIN;
- INSERT INTO t1 VALUES(1, 2);
+ #-------------------------------------------------------------------------
+ # Check that the *-journal* files are deleted correctly.
+ #
+ server_reset_db
+ do_execsql_test 1.0 {
+ CREATE TABLE t1(a, b);
+ } {}
+
+ do_test $tn.1.1 {
+ lsort [glob -nocomplain test.db-journal/*-journal]
+ } {test.db-journal/0-journal}
+
+ do_test $tn.1.2 {
+ db close
+ lsort [glob -nocomplain test.db-journal/*-journal]
+ } {}
+
+ server_sqlite3 db test.db
+ do_execsql_test $tn.1.3 {
+ CREATE TABLE t2(a, b);
+ } {}
+
+ server_sqlite3 db2 test.db
+ do_test $tn.1.4 {
+ db eval {
+ BEGIN;
+ INSERT INTO t1 VALUES(1, 2);
+ }
+ db2 eval {
+ BEGIN;
+ INSERT INTO t2 VALUES(3, 4);
+ }
+ } {}
+
+ do_test $tn.1.5 {
+ db2 eval COMMIT
+ db eval COMMIT
+ lsort [glob -nocomplain test.db-journal/*-journal]
+ } {test.db-journal/0-journal test.db-journal/1-journal}
+
+ do_test $tn.1.6 {
+ db close
+ lsort [glob -nocomplain test.db-journal/*-journal]
+ } {test.db-journal/0-journal test.db-journal/1-journal}
+
+ do_test $tn.1.7 {
+ db2 close
+ lsort [glob -nocomplain test.db-journal/*-journal]
+ } {}
+
+ #-------------------------------------------------------------------------
+ #
+ server_reset_db
+ server_sqlite3 db2 test.db
+
+ do_execsql_test $tn.2.0 {
+ CREATE TABLE t1(a, b);
+ CREATE TABLE t2(c, d);
}
- db2 eval {
- BEGIN;
- INSERT INTO t2 VALUES(3, 4);
+
+ # Two concurrent transactions committed.
+ #
+ do_test $tn.2.1 {
+ db eval {
+ BEGIN;
+ INSERT INTO t1 VALUES(1, 2);
+ }
+ db2 eval {
+ BEGIN;
+ INSERT INTO t2 VALUES(3, 4);
+ }
+ } {}
+ do_test $tn.2.2 {
+ lsort [glob -nocomplain test.db-journal/*-journal]
+ } {test.db-journal/0-journal test.db-journal/1-journal}
+ do_test $tn.2.3.1 { db eval COMMIT } {}
+ do_test $tn.2.3.2 { db2 eval COMMIT } {}
+ do_execsql_test 2.4 {SELECT * FROM t1, t2} {1 2 3 4}
+ do_test $tn.2.5 {
+ lsort [glob -nocomplain test.db-journal/*-journal]
+ } {test.db-journal/0-journal test.db-journal/1-journal}
+
+ do_test $tn.2.6 {
+ execsql {BEGIN}
+ execsql {INSERT INTO t1 VALUES(5, 6)}
+
+ execsql {BEGIN} db2
+ catchsql {INSERT INTO t1 VALUES(7, 8)} db2
+ } {1 {database is locked}}
+ do_test $tn.2.7 {
+ # Transaction is automatically rolled back in this case.
+ sqlite3_get_autocommit db2
+ } {1}
+ do_test $tn.2.8 {
+ execsql COMMIT
+ execsql { SELECT * FROM t1 } db2
+ } {1 2 5 6}
+ db2 close
+
+ #-------------------------------------------------------------------------
+ #
+ server_reset_db
+ do_execsql_test $tn.3.0 {
+ CREATE TABLE t1(a, b);
}
-} {}
-do_test 2.2 {
- lsort [glob -nocomplain test.db-journal/*]
-} {test.db-journal/0-journal test.db-journal/1-journal}
-do_test 2.3.1 { db eval COMMIT } {}
-do_test 2.3.2 { db2 eval COMMIT } {}
-do_execsql_test 2.4 {SELECT * FROM t1, t2} {1 2 3 4}
-do_test 2.5 {
- lsort [glob -nocomplain test.db-journal/*]
-} {test.db-journal/0-journal test.db-journal/1-journal}
-
-do_test 2.6 {
- execsql {BEGIN}
- execsql {INSERT INTO t1 VALUES(5, 6)}
-
- execsql {BEGIN} db2
- catchsql {INSERT INTO t1 VALUES(7, 8)} db2
-} {1 {database is locked}}
-do_test 2.7 {
- # Transaction is automatically rolled back in this case.
- sqlite3_get_autocommit db2
-} {1}
-do_test 2.8 {
- execsql COMMIT
- execsql { SELECT * FROM t1 } db2
-} {1 2 5 6}
-db2 close
-
-#-------------------------------------------------------------------------
-#
-server_reset_db
-do_execsql_test 3.0 {
- CREATE TABLE t1(a, b);
+
+ do_test $tn.3.1 {
+ lsort [glob -nocomplain test.db-journal/*-journal]
+ } {test.db-journal/0-journal}
+
+ do_test $tn.3.2 {
+ db close
+ lsort [glob -nocomplain test.db-journal/*-journal]
+ } {}
}
-do_test 3.1 {
- lsort [glob -nocomplain test.db-journal/*]
-} {test.db-journal/0-journal}
-
-do_test 3.2 {
- db close
- lsort [glob -nocomplain test.db-journal/*]
-} {}
finish_test
source $testdir/server_common.tcl
return_if_no_server
-server_reset_db
-server_sqlite3 db2 test.db
-
-do_test 1.1 {
- db eval { CREATE TABLE t1(a, b) }
- db2 eval { CREATE TABLE t2(a, b) }
-} {}
-
-do_test 1.2 {
- db eval {
- INSERT INTO t2 VALUES(1, 2);
- BEGIN;
- INSERT INTO t1 VALUES(1, 2);
- }
-} {}
-
-do_test 1.3 {
- list [catch { db2 eval { SELECT * FROM t1 } } msg] $msg
-} {1 {database is locked}}
-do_test 1.4 {
- list [catch { db2 eval { SELECT * FROM t1 } } msg] $msg
-} {1 {database is locked}}
-
-do_test 1.4 {
- db2 eval { SELECT * FROM t2 }
-} {1 2}
+foreach {tn vfs} {1 unix-excl 2 unix} {
+ server_set_vfs $vfs
+
+ server_reset_db
+ server_sqlite3 db2 test.db
+
+ do_test 1.1 {
+ db eval { CREATE TABLE t1(a, b) }
+ db2 eval { CREATE TABLE t2(a, b) }
+ } {}
+
+ do_test 1.2 {
+ db eval {
+ INSERT INTO t2 VALUES(1, 2);
+ BEGIN;
+ INSERT INTO t1 VALUES(1, 2);
+ }
+ } {}
+
+ do_test 1.3 {
+ list [catch { db2 eval { SELECT * FROM t1 } } msg] $msg
+ } {1 {database is locked}}
+ do_test 1.4 {
+ list [catch { db2 eval { SELECT * FROM t1 } } msg] $msg
+ } {1 {database is locked}}
+
+ do_test 1.4 {
+ db2 eval { SELECT * FROM t2 }
+ } {1 2}
+}
+
finish_test
}
proc server_sqlite3 {cmd file} {
- sqlite3 $cmd $file -vfs unix-excl
+ sqlite3 $cmd $file -vfs $::server_vfs
}
proc server_reset_db {} {
server_sqlite3 db test.db
}
+set ::server_vfs unix-excl
+proc server_set_vfs {vfs} {
+ set ::server_vfs $vfs
+}