-C Allow\sthe\squery\splanner\saccess\sto\sthe\sargument\sof\sLIMIT\seven\sif\sthat\nargument\sis\sa\sbound\sparameter.
-D 2024-06-06T23:56:36.923
+C At\sattempt\sat\simproving\sthe\sperformance\sof\sunixRead().\s\sPartly\ssuccessfuly,\nbut\sthe\simprovement\sis\snot\sthat\smuch\sand\sthere\sis\squestion\swhether\sor\snot\nthe\simprovement\sis\sworth\sthe\sextra\scomplication\sand\scode\sspace.
+D 2024-06-07T19:48:05.236
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06
F src/os_kv.c 4d39e1f1c180b11162c6dc4aa8ad34053873a639bac6baae23272fc03349986a
F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d872107
-F src/os_unix.c 08ca53844f4bf8eafb18b0a9076c84afac41da912315a5cfbe9e704d4c10c090
+F src/os_unix.c c4ad2db8265be042eda2ba14ff4f1497b40be0f0f20829cddabf2062bcd843f8
F src/os_win.c 6ff43bac175bd9ed79e7c0f96840b139f2f51d01689a638fd05128becf94908a
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 9beb80f6e330dd63c5d8ba0f7a7f3a55fff22067a68d424949c389bfc6fa0c56
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P f66608bd356efe492d1003663c2e1ccd7cfbf2d40393d256f8720149904ad2d5 e94dfe9928750dd98145d4d9920b298f7b0868703b487f86e0db77a41d53ccf9
-R f3d6aba1cc68a2224dd6f7df935a2c23
+P c4a9dda2809c6e0e3d928e11e5553ead82cd9df551bcd35b11a7d869ef80ab8e
+R 1e97a9b24bcfd905372f808facc9498c
+T *branch * fast-read
+T *sym-fast-read *
+T -sym-trunk *
U drh
-Z b92cbf17475d91065d48b9fdd285839c
+Z fcb5924181490f13936092bbea843f28
# Remove this line to create a well-formed Fossil manifest.
** Seek to the offset passed as the second argument, then read cnt
** bytes into pBuf. Return the number of bytes actually read.
**
-** To avoid stomping the errno value on a failed read the lastErrno value
-** is set before returning.
+** To avoid stomping the errno value on a failed read() call,
+** the lastErrno value is set before returning.
*/
-static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
+static SQLITE_NOINLINE int seekAndRead(
+ unixFile *id,
+ sqlite3_int64 offset,
+ void *pBuf,
+ int cnt
+){
int got;
int prior = 0;
#if (!defined(USE_PREAD) && !defined(USE_PREAD64))
return got+prior;
}
+/* Forward reference */
+static int unixRead(sqlite3_file*,void*,int,sqlite3_int64);
+
+#if SQLITE_MAX_MMAP_SIZE>0
+/*
+** Helper subroutine to unixRead(): Handle the case of reading
+** from a memory-mapped file.
+*/
+static SQLITE_NOINLINE int unixReadMMap(
+ unixFile *pFile, /* File from which we are reading */
+ void *pBuf, /* Store content here */
+ int amt, /* Number of bytes to read */
+ sqlite3_int64 offset /* Begin reading at this offset into the file */
+){
+ assert( offset < pFile->mmapSize );
+ if( offset+amt <= pFile->mmapSize ){
+ memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt);
+ return SQLITE_OK;
+ }else{
+ int nCopy = pFile->mmapSize - offset;
+ assert( nCopy>0 );
+ testcase( nCopy>amt/2 );
+ memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy);
+ return unixRead((sqlite3_file*)pFile,&((u8*)pBuf)[nCopy],
+ amt-nCopy,offset+nCopy);
+ }
+}
+#endif /* SQLITE_MAX_MMAP_SIZE>0 */
+
+/*
+** Helper subroutine to unixRead(): Handle the rare case where
+** the number of bytes returned by pread() or read() is different
+** from the number of bytes requested.
+*/
+static SQLITE_NOINLINE int unixReadDealWithIssue(
+ unixFile *pFile, /* Tried to read from this file */
+ void *pBuf, /* Results written here */
+ int amt, /* Bytes requested */
+ sqlite3_int64 offset, /* Offset of first byte to read */
+ int got /* Result from the first read attempt */
+){
+ while( 1 /*exit-by-return-or-break*/ ){
+ if( got<0 ){
+ if( errno==EINTR ){
+ got = seekAndRead(pFile, offset, pBuf, amt);
+ if( got==amt ) return SQLITE_OK;
+ continue;
+ }else{
+ storeLastErrno(pFile, errno);
+ /*
+ ** Usually we return SQLITE_IOERR_READ here, though for some
+ ** kinds of errors we return SQLITE_IOERR_CORRUPTFS. The
+ ** SQLITE_IOERR_CORRUPTFS will be converted into SQLITE_CORRUPT
+ ** prior to returning to the application by the sqlite3ApiExit()
+ ** routine.
+ */
+ switch( pFile->lastErrno ){
+ case ERANGE:
+ case EIO:
+#ifdef ENXIO
+ case ENXIO:
+#endif
+#ifdef EDEVERR
+ case EDEVERR:
+#endif
+ return SQLITE_IOERR_CORRUPTFS;
+ }
+ return SQLITE_IOERR_READ;
+ }
+ }else if( got>0 ){
+ offset += got;
+ pBuf = (void*)(got + (char*)pBuf);
+ amt -= got;
+ got = seekAndRead(pFile, offset, pBuf, amt);
+ if( got==amt ) return SQLITE_OK;
+ continue;
+ }else{
+ storeLastErrno(pFile, 0); /* not a system error */
+ /* Unread parts of the buffer must be zero-filled */
+ memset(&((char*)pBuf)[got], 0, amt-got);
+ break;
+ }
+ }
+ return SQLITE_IOERR_SHORT_READ;
+}
+
+
/*
** Read data from a file into a buffer. Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
** wrong.
+**
+** The most common case (by far) is that this routine does a single
+** call to pread() to get the content request and then returns.
+** This routine is coded so that that is the fast path. If anything
+** unusual happens (an I/O error, the read comes back in smaller
+** pieces, memory-mapped I/O, etc) then that processing is handled
+** by subroutines so as not to burden the fast path.
*/
static int unixRead(
sqlite3_file *id,
){
unixFile *pFile = (unixFile *)id;
int got;
+#if (!defined(USE_PREAD) && !defined(USE_PREAD64))
+ i64 newOffset;
+#endif
+
assert( id );
assert( offset>=0 );
assert( amt>0 );
- /* If this is a database file (not a journal, super-journal or temp
- ** file), the bytes in the locking range should never be read or written. */
-#if 0
- assert( pFile->pPreallocatedUnused==0
- || offset>=PENDING_BYTE+512
- || offset+amt<=PENDING_BYTE
- );
-#endif
-
#if SQLITE_MAX_MMAP_SIZE>0
/* Deal with as much of this read request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
- if( offset+amt <= pFile->mmapSize ){
- memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt);
- return SQLITE_OK;
- }else{
- int nCopy = pFile->mmapSize - offset;
- memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy);
- pBuf = &((u8 *)pBuf)[nCopy];
- amt -= nCopy;
- offset += nCopy;
- }
+ return unixReadMMap(pFile, pBuf, amt, offset);
}
#endif
- got = seekAndRead(pFile, offset, pBuf, amt);
- if( got==amt ){
- return SQLITE_OK;
- }else if( got<0 ){
- /* pFile->lastErrno has been set by seekAndRead().
- ** Usually we return SQLITE_IOERR_READ here, though for some
- ** kinds of errors we return SQLITE_IOERR_CORRUPTFS. The
- ** SQLITE_IOERR_CORRUPTFS will be converted into SQLITE_CORRUPT
- ** prior to returning to the application by the sqlite3ApiExit()
- ** routine.
- */
- switch( pFile->lastErrno ){
- case ERANGE:
- case EIO:
-#ifdef ENXIO
- case ENXIO:
-#endif
-#ifdef EDEVERR
- case EDEVERR:
+#if defined(USE_PREAD)
+ got = osPread(pFile->h, pBuf, amt, offset);
+ SimulateIOError( got = -1 );
+#elif defined(USE_PREAD64)
+ got = osPread64(pFile->h, pBuf, amt, offset);
+ SimulateIOError( got = -1 );
+#else
+ newOffset = lseek(pFile->h, offset, SEEK_SET);
+ SimulateIOError( newOffset = -1 );
+ if( newOffset<0 ){
+ return unixReadDealWithIssue(pFile, pBuf, amt, offset, -1);
+ }
+ got = osRead(id->h, pBuf, amt);
#endif
- return SQLITE_IOERR_CORRUPTFS;
- }
- return SQLITE_IOERR_READ;
+
+ if( got!=amt ){
+ return unixReadDealWithIssue(pFile, pBuf, amt, offset, got);
}else{
- storeLastErrno(pFile, 0); /* not a system error */
- /* Unread parts of the buffer must be zero-filled */
- memset(&((char*)pBuf)[got], 0, amt-got);
- return SQLITE_IOERR_SHORT_READ;
+ return SQLITE_OK;
}
}
#endif
/* The attempt to extend the existing mapping failed. Free it. */
- if( pNew==MAP_FAILED || pNew==0 ){
+ if( pNew==MAP_FAILED || NEVER(pNew==0) ){
osMunmap(pOrig, nReuse);
}
}