diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/os_unix.c | 100 | ||||
-rw-r--r-- | src/sqlite.h.in | 3 | ||||
-rw-r--r-- | src/wal.c | 69 |
3 files changed, 113 insertions, 59 deletions
diff --git a/src/os_unix.c b/src/os_unix.c index d991ec9d5..006b0d182 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -4594,11 +4594,9 @@ struct unixShmFile { sqlite3_mutex *mutexBuf; /* Mutex to access zBuf[] */ sqlite3_mutex *mutexRecov; /* The RECOVER mutex */ char *zFilename; /* Name of the file */ - int size; /* Size of the file */ int h; /* Open file descriptor */ - char *pMMapBuf; /* Where currently mmapped() */ - int nReadPrefix; /* Number of SQLITE_SHM_READ_PREFIX locks */ - int nReadFull; /* Number of SQLITE_SHM_READ_FULL locks */ + int szMap; /* Size of the mapping of file into memory */ + char *pMMapBuf; /* Where currently mmapped(). NULL if unmapped */ int nRef; /* Number of unixShm objects pointing to this */ unixShm *pFirst; /* All unixShm objects pointing to this */ unixShmFile *pNext; /* Next in list of all unixShmFile objects */ @@ -4995,8 +4993,6 @@ static int unixShmOpen( } pFile->fid.dev = sStat.st_dev; pFile->fid.ino = sStat.st_ino; - pFile->size = (int)sStat.st_size; - pFile->size = (pFile->size/SQLITE_UNIX_SHM_INCR)*SQLITE_UNIX_SHM_INCR; /* Check to see if another process is holding the dead-man switch. ** If not, truncate the file to zero length. @@ -5010,7 +5006,6 @@ static int unixShmOpen( rc = SQLITE_IOERR; goto shm_open_err; } - pFile->size = 0; } rc = unixShmSystemLock(pFile, F_RDLCK, UNIX_SHM_DMS); if( rc ) goto shm_open_err; @@ -5078,46 +5073,86 @@ static int unixShmClose(sqlite3_shm *pSharedMem){ } /* -** Query and/or changes the size of a shared-memory segment. -** The reqSize parameter is the new size of the segment, or -1 to -** do just a query. The size of the segment after resizing is -** written into pNewSize. A writer lock is held on the shared memory -** segment while resizing it. +** Query and/or changes the size of the underlying storage for +** a shared-memory segment. The reqSize parameter is the new size +** of the underlying storage, or -1 to do just a query. The size +** of the underlying storage (after resizing if resizing occurs) is +** written into pNewSize. ** -** If ppBuffer is not NULL, the a reader lock is acquired on the shared -** memory segment and *ppBuffer is made to point to the start of the -** shared memory segment. xShmRelease() must be called to release the -** lock. +** This routine does not (necessarily) change the size of the mapping +** of the underlying storage into memory. Use xShmGet() to change +** the mapping size. +** +** The reqSize parameter is the minimum size requested. The implementation +** is free to expand the storage to some larger amount if it chooses. */ static int unixShmSize( sqlite3_shm *pSharedMem, /* Pointer returned by unixShmOpen() */ int reqSize, /* Requested size. -1 for query only */ - int *pNewSize, /* Write new size here */ - void **ppBuf /* Write new buffer origin here */ + int *pNewSize /* Write new size here */ ){ unixShm *p = (unixShm*)pSharedMem; unixShmFile *pFile = p->pFile; int rc = SQLITE_OK; + struct stat sStat; - sqlite3_mutex_enter(pFile->mutexBuf); - sqlite3_mutex_enter(pFile->mutex); if( reqSize>=0 ){ reqSize = (reqSize + SQLITE_UNIX_SHM_INCR - 1)/SQLITE_UNIX_SHM_INCR; reqSize *= SQLITE_UNIX_SHM_INCR; - if( reqSize!=pFile->size ){ - if( pFile->pMMapBuf ) munmap(pFile->pMMapBuf, pFile->size); - rc = ftruncate(pFile->h, reqSize); - if( rc ){ - pFile->pMMapBuf = 0; - pFile->size = 0; - }else{ - pFile->pMMapBuf = mmap(0, reqSize, PROT_READ|PROT_WRITE, MAP_SHARED, - pFile->h, 0); - pFile->size = pFile->pMMapBuf ? reqSize : 0; - } + rc = ftruncate(pFile->h, reqSize); + } + if( fstat(pFile->h, &sStat)==0 ){ + *pNewSize = (int)sStat.st_size; + }else{ + *pNewSize = 0; + rc = SQLITE_IOERR; + } + return rc; +} + + +/* +** Map the shared storage into memory. The minimum size of the +** mapping should be reqMapSize if reqMapSize is positive. If +** reqMapSize is zero or negative, the implementation can choose +** whatever mapping size is convenient. +** +** *ppBuf is made to point to the memory which is a mapping of the +** underlying storage. This segment is locked. unixShmRelease() +** must be called to release the lock. +** +** *pNewMapSize is set to the size of the mapping. +** +** *ppBuf and *pNewMapSize might be NULL and zero if no space has +** yet been allocated to the underlying storage. +*/ +static int unixShmGet( + sqlite3_shm *pSharedMem, /* Pointer returned by unixShmOpen() */ + int reqMapSize, /* Requested size of mapping. -1 means don't care */ + int *pNewMapSize, /* Write new size of mapping here */ + void **ppBuf /* Write mapping buffer origin here */ +){ + unixShm *p = (unixShm*)pSharedMem; + unixShmFile *pFile = p->pFile; + int rc = SQLITE_OK; + + sqlite3_mutex_enter(pFile->mutexBuf); + sqlite3_mutex_enter(pFile->mutex); + if( pFile->szMap==0 || reqMapSize>pFile->szMap ){ + int actualSize; + if( unixShmSize(pSharedMem, -1, &actualSize)==SQLITE_OK + && reqMapSize<actualSize + ){ + reqMapSize = actualSize; + } + if( pFile->pMMapBuf ){ + munmap(pFile->pMMapBuf, pFile->szMap); } + pFile->pMMapBuf = mmap(0, reqMapSize, PROT_READ|PROT_WRITE, MAP_SHARED, + pFile->h, 0); + pFile->szMap = pFile->pMMapBuf ? reqMapSize : 0; } - *pNewSize = pFile->size; + *pNewMapSize = pFile->szMap; *ppBuf = pFile->pMMapBuf; sqlite3_mutex_leave(pFile->mutex); return rc; @@ -6490,6 +6525,7 @@ int sqlite3_os_init(void){ unixGetLastError, /* xGetLastError */ \ unixShmOpen, /* xShmOpen */ \ unixShmSize, /* xShmSize */ \ + unixShmGet, /* xShmGet */ \ unixShmRelease, /* xShmRelease */ \ 0, /* xShmPush */ \ 0, /* xShmPull */ \ diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 35ac5bd00..d2ce5396f 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -844,7 +844,8 @@ struct sqlite3_vfs { ** definition. Those that follow are added in version 2 or later */ int (*xShmOpen)(sqlite3_vfs*, const char *zName, sqlite3_shm**); - int (*xShmSize)(sqlite3_shm*, int reqSize, int *pNewSize, void**); + int (*xShmSize)(sqlite3_shm*, int reqSize, int *pNewSize); + int (*xShmGet)(sqlite3_shm*, int reqMapSize, int *pMapSize, void**); int (*xShmRelease)(sqlite3_shm*); int (*xShmPush)(sqlite3_shm*); int (*xShmPull)(sqlite3_shm*); @@ -126,7 +126,7 @@ struct Wal { sqlite3_file *pFd; /* File handle for WAL file */ u32 iCallback; /* Value to pass to log callback (or 0) */ sqlite3_shm *pWIndex; /* The open wal-index file */ - int szWIndex; /* Size of the wal-index */ + int szWIndex; /* Size of the wal-index that is mapped in mem */ u32 *pWiData; /* Pointer to wal-index content in memory */ u8 lockState; /* SQLITE_SHM_xxxx constant showing lock state */ u8 readerType; /* SQLITE_SHM_READ or SQLITE_SHM_READ_FULL */ @@ -368,7 +368,8 @@ static int walIndexEntry(u32 iFrame){ } /* -** Release our reference to the wal-index memory map. +** Release our reference to the wal-index memory map, if we are holding +** it. */ static void walIndexUnmap(Wal *pWal){ if( pWal->pWiData ){ @@ -378,26 +379,42 @@ static void walIndexUnmap(Wal *pWal){ } /* -** Resize the wal-index file. If newSize is negative, leave the size -** unchanged. +** Map the wal-index file into memory if it isn't already. +** +** The reqSize parameter is the minimum required size of the mapping. +** A value of -1 means "don't care". The reqSize parameter is ignored +** if the mapping is already held. */ -static int walIndexRemap(Wal *pWal, int newSize){ - int rc; - walIndexUnmap(pWal); - rc = pWal->pVfs->xShmSize(pWal->pWIndex, newSize, - &pWal->szWIndex, (void**)(char*)&pWal->pWiData); - if( rc==SQLITE_OK && pWal->pWiData==0 ){ - assert( pWal->szWIndex==0 ); - pWal->pWiData = &pWal->iCallback; +static int walIndexMap(Wal *pWal, int reqSize){ + int rc = SQLITE_OK; + if( pWal->pWiData==0 ){ + rc = pWal->pVfs->xShmGet(pWal->pWIndex, reqSize, &pWal->szWIndex, + (void**)(char*)&pWal->pWiData); + if( rc==SQLITE_OK && pWal->pWiData==0 ){ + /* Make sure pWal->pWiData is not NULL while we are holding the + ** lock on the mapping. */ + assert( pWal->szWIndex==0 ); + pWal->pWiData = &pWal->iCallback; + } } return rc; } /* -** Map the wal-index file into memory if it isn't already. +** Remap the wal-index so that the mapping covers the full size +** of the underlying file. +** +** If enlargeTo is non-negative, then increase the size of the underlying +** storage to be at least as big as enlargeTo before remapping. */ -static int walIndexMap(Wal *pWal){ - int rc = walIndexRemap(pWal, -1); +static int walIndexRemap(Wal *pWal, int enlargeTo){ + int rc; + int sz; + rc = pWal->pVfs->xShmSize(pWal->pWIndex, enlargeTo, &sz); + if( rc==SQLITE_OK && sz>pWal->szWIndex ){ + walIndexUnmap(pWal); + rc = walIndexMap(pWal, sz); + } return rc; } @@ -416,12 +433,12 @@ static int walIndexMap(Wal *pWal){ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ u32 iSlot = walIndexEntry(iFrame); - walIndexMap(pWal); + walIndexMap(pWal, -1); while( (iSlot+128)>=pWal->szWIndex ){ int rc; int nByte = pWal->szWIndex*4 + WALINDEX_MMAP_INCREMENT; - /* Unmap and remap the wal-index file. */ + /* Enlarge the storage, then remap it. */ rc = walIndexRemap(pWal, nByte); if( rc!=SQLITE_OK ){ return rc; @@ -640,7 +657,7 @@ static WalIterator *walIteratorInit(Wal *pWal){ struct WalSegment *pFinal; /* Final (unindexed) segment */ u8 *aTmp; /* Temp space used by merge-sort */ - walIndexMap(pWal); + walIndexMap(pWal, -1); aData = pWal->pWiData; iLast = pWal->hdr.iLastPg; nSegment = (iLast >> 8) + 1; @@ -789,7 +806,8 @@ int walIndexTryHdr(Wal *pWal, int *pChanged){ u32 aHdr[WALINDEX_HDR_NFIELD+2]; if( pWal->szWIndex==0 ){ - int rc = walIndexRemap(pWal, WALINDEX_MMAP_INCREMENT); + int rc; + rc = walIndexRemap(pWal, WALINDEX_MMAP_INCREMENT); if( rc ) return rc; } @@ -830,7 +848,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ int rc; assert( pWal->lockState>=SQLITE_SHM_READ ); - walIndexMap(pWal); + walIndexMap(pWal, -1); /* First try to read the header without a lock. Verify the checksum ** before returning. This will almost always work. @@ -881,11 +899,10 @@ int sqlite3WalOpenSnapshot(Wal *pWal, int *pChanged){ sqlite3WalCloseSnapshot(pWal); }else{ /* Check if the mapping needs to grow. */ - if( pWal->hdr.iLastPg - && walIndexEntry(pWal->hdr.iLastPg)>=pWal->szWIndex - ){ - rc = walIndexRemap(pWal, 0); - assert( rc || walIndexEntry(pWal->hdr.iLastPg)<pWal->szWIndex ); + if( pWal->hdr.iLastPg + && walIndexEntry(pWal->hdr.iLastPg)>=pWal->szWIndex + ){ + walIndexRemap(pWal, -1); } } } @@ -913,7 +930,7 @@ int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, u8 *pOut){ int iFrame = (pWal->hdr.iLastPg & 0xFFFFFF00); assert( pWal->lockState==SQLITE_SHM_READ||pWal->lockState==SQLITE_SHM_WRITE ); - walIndexMap(pWal); + walIndexMap(pWal, -1); /* Do a linear search of the unindexed block of page-numbers (if any) ** at the end of the wal-index. An alternative to this would be to |