Index: src/os_unix.c ================================================================== --- src/os_unix.c +++ src/os_unix.c @@ -4143,11 +4143,10 @@ /* ** Constants used for locking */ #define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ #define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ -#define UNIX_SHM_N_DMS 1000000000 /* Size of the DMS */ /* ** Apply posix advisory locks for all bytes from ofst through ofst+n-1. ** ** Locks block if the mask is exactly UNIX_SHM_C and are non-blocking @@ -4165,10 +4164,16 @@ /* Access to the unixShmNode object is serialized by the caller */ pShmNode = pFile->pInode->pShmNode; assert( sqlite3_mutex_held(pShmNode->mutex) || pShmNode->nRef==0 ); + /* Shared locks never span more than one byte */ + assert( n==1 || lockType!=F_RDLCK ); + + /* Locks are within range */ + assert( n>=1 && n<=SQLITE_SHM_NLOCK ); + if( pShmNode->h>=0 ){ /* Initialize the locking parameters */ memset(&f, 0, sizeof(f)); f.l_type = lockType; f.l_whence = SEEK_SET; @@ -4179,48 +4184,40 @@ rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY; } /* Update the global lock state and do debug tracing */ #ifdef SQLITE_DEBUG - if( ofst=1 && n<=SQLITE_SHM_NLOCK ); - - OSTRACE(("SHM-LOCK ")); - mask = ofst>31 ? 0xffff : (1<<(ofst+n)) - (1<exclMask &= ~mask; - pShmNode->sharedMask &= ~mask; - }else if( lockType==F_RDLCK ){ - OSTRACE(("read-lock %d ok", ofst)); - pShmNode->exclMask &= ~mask; - pShmNode->sharedMask |= mask; - }else{ - assert( lockType==F_WRLCK ); - OSTRACE(("write-lock %d ok", ofst)); - pShmNode->exclMask |= mask; - pShmNode->sharedMask &= ~mask; - } - }else{ - if( lockType==F_UNLCK ){ - OSTRACE(("unlock %d failed", ofst)); - }else if( lockType==F_RDLCK ){ - OSTRACE(("read-lock failed")); - }else{ - assert( lockType==F_WRLCK ); - OSTRACE(("write-lock %d failed", ofst)); - } - } - OSTRACE((" - afterwards %03x,%03x\n", - pShmNode->sharedMask, pShmNode->exclMask)); + { u16 mask; + OSTRACE(("SHM-LOCK ")); + mask = ofst>31 ? 0xffff : (1<<(ofst+n)) - (1<exclMask &= ~mask; + pShmNode->sharedMask &= ~mask; + }else if( lockType==F_RDLCK ){ + OSTRACE(("read-lock %d ok", ofst)); + pShmNode->exclMask &= ~mask; + pShmNode->sharedMask |= mask; + }else{ + assert( lockType==F_WRLCK ); + OSTRACE(("write-lock %d ok", ofst)); + pShmNode->exclMask |= mask; + pShmNode->sharedMask &= ~mask; + } + }else{ + if( lockType==F_UNLCK ){ + OSTRACE(("unlock %d failed", ofst)); + }else if( lockType==F_RDLCK ){ + OSTRACE(("read-lock failed")); + }else{ + assert( lockType==F_WRLCK ); + OSTRACE(("write-lock %d failed", ofst)); + } + } + OSTRACE((" - afterwards %03x,%03x\n", + pShmNode->sharedMask, pShmNode->exclMask)); } #endif return rc; } @@ -4390,42 +4387,34 @@ ** is owned by the same user that owns the original database. Otherwise, ** the original owner will not be able to connect. */ robustFchown(pShmNode->h, sStat.st_uid, sStat.st_gid); - /* Do not allow a read-only process to connect if there are no - ** writers, because a read-only process is unable to recover the - ** shm file following a system crash. - */ + /* Check to see if another process is holding the dead-man switch. + ** For a readonly_shm client, if no other process holds the DMS lock, + ** the file cannot be opened and SQLITE_CANTOPEN_DIRTYWAL is returned. + ** Or, for a read-write connection, if no other process holds a + ** DMS lock the file is truncated to zero bytes in size. */ rc = SQLITE_OK; if( pShmNode->isReadonly ){ - if( !unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, UNIX_SHM_N_DMS) ){ + struct flock lock; + lock.l_whence = SEEK_SET; + lock.l_start = UNIX_SHM_DMS; + lock.l_len = 1; + lock.l_type = F_WRLCK; + if( osFcntl(pShmNode->h, F_GETLK, &lockInfo)!=0 ) { + rc = SQLITE_IOERR_LOCK; + }else if( lock.l_type==F_UNLCK ){ rc = SQLITE_CANTOPEN_DIRTYWAL; } - } - - /* If we are able to grab the dead-man switch, that means this is the - ** first (write-enable) process to connect to the database. In that - ** case, truncate the shm file because the contents found on disk might - ** be invalid leftovers from a system crash. The shm will be rebuilt - */ - if( unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){ + }else if( unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){ if( robust_ftruncate(pShmNode->h, 0) ){ rc = unixLogError(SQLITE_IOERR_SHMOPEN, "ftruncate", zShmFilename); } } - - /* Acquires locks to tell other processes that a this process is - ** running and therefore the shm is valid they do not need to run - ** recovery. - */ if( rc==SQLITE_OK ){ - unsigned r; rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1); - sqlite3_randomness(sizeof(r), &r); - r = 1 + (r%(UNIX_SHM_N_DMS-1)); - (void)unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS+r, 1); } if( rc ) goto shm_open_err; } }