Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Replace the sqlite3_io_methods.xMremap interface with sqlite3_io_methods.xFetch and xUnfetch. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | experimental-mmap |
Files: | files | file ages | folders |
SHA1: | 1431be95579160fb70408d43e17fc23c |
User & Date: | dan 2013-03-23 21:00:41 |
Context
2013-03-25
| ||
13:50 | Fix a case in the pager where an xFetch() reference was being leaked following an OOM error. check-in: 5885ba6c user: dan tags: experimental-mmap | |
2013-03-23
| ||
21:00 | Replace the sqlite3_io_methods.xMremap interface with sqlite3_io_methods.xFetch and xUnfetch. check-in: 1431be95 user: dan tags: experimental-mmap | |
17:29 | Improve a comment in wal.c. No code changes. check-in: 60b9f5e4 user: dan tags: experimental-mmap | |
Changes
Changes to src/backup.c.
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 |
iOff+=pgszSrc
){
PgHdr *pSrcPg = 0;
const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1);
rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
if( rc==SQLITE_OK ){
u8 *zData = sqlite3PagerGetData(pSrcPg);
rc = sqlite3PagerWriteData(pDestPager, zData, pgszSrc, iOff);
}
sqlite3PagerUnref(pSrcPg);
}
if( rc==SQLITE_OK ){
rc = backupTruncateFile(pFile, iSize);
}
|
| |
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 |
iOff+=pgszSrc
){
PgHdr *pSrcPg = 0;
const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1);
rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
if( rc==SQLITE_OK ){
u8 *zData = sqlite3PagerGetData(pSrcPg);
rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
}
sqlite3PagerUnref(pSrcPg);
}
if( rc==SQLITE_OK ){
rc = backupTruncateFile(pFile, iSize);
}
|
Changes to src/os.c.
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
int pgsz, int bExtend, /* True to extend file if necessary */ void volatile **pp /* OUT: Pointer to mapping */ ){ DO_OS_MALLOC_TEST(id); return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp); } int sqlite3OsMremap( sqlite3_file *id, /* Database file handle */ int flags, /* SQLITE_MREMAP_XXX flags */ i64 iOff, /* Offset at which mapping(s) start */ i64 nOld, /* Size of old mapping */ i64 nNew, /* Size of requested mapping */ void **pp /* IN/OUT: Pointer to mapped region */ ){ return id->pMethods->xMremap(id, flags, iOff, nOld, nNew, pp); } /* ** The next group of routines are convenience wrappers around the ** VFS methods. */ int sqlite3OsOpen( |
| | | | | | < < < |
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
int pgsz, int bExtend, /* True to extend file if necessary */ void volatile **pp /* OUT: Pointer to mapping */ ){ DO_OS_MALLOC_TEST(id); return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp); } int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){ return id->pMethods->xFetch(id, iOff, iAmt, pp); } int sqlite3OsUnfetch(sqlite3_file *id, void *p){ return id->pMethods->xUnfetch(id, p); } /* ** The next group of routines are convenience wrappers around the ** VFS methods. */ int sqlite3OsOpen( |
Changes to src/os.h.
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0 int sqlite3OsSectorSize(sqlite3_file *id); int sqlite3OsDeviceCharacteristics(sqlite3_file *id); int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **); int sqlite3OsShmLock(sqlite3_file *id, int, int, int); void sqlite3OsShmBarrier(sqlite3_file *id); int sqlite3OsShmUnmap(sqlite3_file *id, int); int sqlite3OsMremap(sqlite3_file *id, int, i64, i64, i64, void **); /* ** Functions for accessing sqlite3_vfs methods */ int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *); int sqlite3OsDelete(sqlite3_vfs *, const char *, int); |
| > |
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0 int sqlite3OsSectorSize(sqlite3_file *id); int sqlite3OsDeviceCharacteristics(sqlite3_file *id); int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **); int sqlite3OsShmLock(sqlite3_file *id, int, int, int); void sqlite3OsShmBarrier(sqlite3_file *id); int sqlite3OsShmUnmap(sqlite3_file *id, int); int sqlite3OsFetch(sqlite3_file *id, i64, int, void **); int sqlite3OsUnfetch(sqlite3_file *, void *); /* ** Functions for accessing sqlite3_vfs methods */ int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *); int sqlite3OsDelete(sqlite3_vfs *, const char *, int); |
Changes to src/os_unix.c.
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 .... 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 .... 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 .... 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 .... 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 .... 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 .... 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 .... 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 .... 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 .... 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 .... 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 |
** occur if a file is updated without also updating the transaction ** counter. This test is made to avoid new problems similar to the ** one described by ticket #3584. */ unsigned char transCntrChng; /* True if the transaction counter changed */ unsigned char dbUpdate; /* True if any part of database file changed */ unsigned char inNormalWrite; /* True if in a normal write operation */ sqlite3_int64 mmapSize; /* Size of xMremap() */ void *pMapRegion; /* Area memory mapped */ #endif #ifdef SQLITE_TEST /* In test mode, increase the size of this structure a bit so that ** it is larger than the struct CrashFile defined in test6.c. */ char aPadding[32]; #endif }; ................................................................................ ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. */ static int unixUnlock(sqlite3_file *id, int eFileLock){ return posixUnlock(id, eFileLock, 0); } /* ** This function performs the parts of the "close file" operation ** common to all locking schemes. It closes the directory and file ** handles, if they are valid, and sets all fields of the unixFile ** structure to 0. ** ** It is *not* necessary to hold the mutex when this routine is called, ** even on VxWorks. A mutex will be acquired on VxWorks by the ** vxworksReleaseFileId() routine. */ static int closeUnixFile(sqlite3_file *id){ unixFile *pFile = (unixFile*)id; if( pFile->h>=0 ){ robust_close(pFile, pFile->h, __LINE__); pFile->h = -1; } #if OS_VXWORKS if( pFile->pId ){ if( pFile->ctrlFlags & UNIXFILE_DELETE ){ ................................................................................ void *pBuf, int amt, sqlite3_int64 offset ){ unixFile *pFile = (unixFile *)id; int got; assert( id ); assert( offset>=pFile->mmapSize ); /* Never read from the mmapped region */ /* If this is a database file (not a journal, master-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 assert( pFile->pUnused==0 || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ); #endif got = seekAndRead(pFile, offset, pBuf, amt); if( got==amt ){ return SQLITE_OK; }else if( got<0 ){ /* lastErrno set by seekAndRead */ return SQLITE_IOERR_READ; ................................................................................ int amt, sqlite3_int64 offset ){ unixFile *pFile = (unixFile*)id; int wrote = 0; assert( id ); assert( amt>0 ); assert( offset>=pFile->mmapSize ); /* Never write into the mmapped region */ /* If this is a database file (not a journal, master-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 assert( pFile->pUnused==0 || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ................................................................................ SimulateIOErrorBenign(0); if( rc!=4 || memcmp(oldCntr, &((char*)pBuf)[24-offset], 4)!=0 ){ pFile->transCntrChng = 1; /* The transaction counter has changed */ } } } #endif while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){ amt -= wrote; offset += wrote; pBuf = &((char*)pBuf)[wrote]; } SimulateIOError(( wrote=(-1), amt=1 )); ................................................................................ ** that effectively updates the change counter. This might happen ** when restoring a database using the backup API from a zero-length ** source. */ if( pFile->inNormalWrite && nByte==0 ){ pFile->transCntrChng = 1; } /* If the file was just truncated to a size smaller than the currently ** mapped region, reduce the effective mapping size as well. SQLite will ** use read() and write() to access data beyond this point from now on. */ if( nByte<pFile->mmapSize ){ pFile->mmapSize = nByte; } #endif return SQLITE_OK; } } /* ** Determine the current size of a file in bytes ................................................................................ int nWrite = seekAndWrite(pFile, iWrite, "", 1); if( nWrite!=1 ) return SQLITE_IOERR_WRITE; iWrite += nBlk; } #endif } } return SQLITE_OK; } /* ** If *pArg is inititially negative then this is a query. Set *pArg to ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. ................................................................................ char *zTFile = sqlite3_malloc( pFile->pVfs->mxPathname ); if( zTFile ){ unixGetTempname(pFile->pVfs->mxPathname, zTFile); *(char**)pArg = zTFile; } return SQLITE_OK; } case SQLITE_FCNTL_GETFD: { *(int*)pArg = pFile->h; return SQLITE_OK; } #ifdef SQLITE_DEBUG /* The pager calls this method to signal that it has done ** a rollback and that the database is therefore unchanged and ** it hence it is OK for the transaction change counter to be ** unchanged. ................................................................................ ** ** ROUNDUP(0, 8) -> 0 ** ROUNDUP(13, 8) -> 16 ** ROUNDUP(32, 8) -> 32 */ #define ROUNDUP(x,y) (((x)+y-1)&~(y-1)) /* ** Map, remap or unmap part of the database file. */ static int unixMremap( sqlite3_file *fd, /* Main database file */ int flags, /* Mask of SQLITE_MREMAP_XXX flags */ sqlite3_int64 iOff, /* Offset to start mapping at */ sqlite3_int64 nOld, /* Size of old mapping, or zero */ sqlite3_int64 nNew, /* Size of new mapping, or zero */ void **ppMap /* IN/OUT: Old/new mappings */ ){ unixFile *p = (unixFile *)fd; /* The underlying database file */ int rc = SQLITE_OK; /* Return code */ void *pNew = 0; /* New mapping */ i64 nNewRnd; /* nNew rounded up */ i64 nOldRnd; /* nOld rounded up */ assert( iOff==0 ); /* assert( p->mmapSize==nOld ); */ assert( p->pMapRegion==0 || p->pMapRegion==(*ppMap) ); /* If the SQLITE_MREMAP_EXTEND flag is set, then the size of the requested ** mapping (nNew bytes) may be greater than the size of the database file. ** If this is the case, extend the file on disk using ftruncate(). */ assert( nNew>0 || (flags & SQLITE_MREMAP_EXTEND)==0 ); if( flags & SQLITE_MREMAP_EXTEND ){ struct stat statbuf; /* Low-level file information */ rc = osFstat(p->h, &statbuf); if( rc==SQLITE_OK && nNew>statbuf.st_size ){ rc = robust_ftruncate(p->h, nNew); } if( rc!=SQLITE_OK ) return rc; } /* According to some sources, the effect of changing the size of the ** underlying file on mapped regions that correspond to the added or ** removed pages is undefined. However, there is reason to believe that ** on modern platforms like Linux or OSX, things just work. For example, ** it is possible to create a mapping larger than the file on disk and ** extend the file on disk later on. ** ** Exploit this on Linux and OSX to reduce the number of munmap()/mmap() ** calls required if the file size is changing. In this case all mappings ** are rounded up to the nearest 4MB. And if a new mapping is requested ** that has the same rounded size as an old mapping, the old mapping can ** be reused as is. */ #if defined(__APPLE__) || defined(__linux__) nNewRnd = ROUNDUP(nNew, 4096*1024); nOldRnd = ROUNDUP(nOld, 4096*1024); #else nNewRnd = ROUNDUP(nNew, 4096*1); nOldRnd = ROUNDUP(nOld, 4096*1); #endif /* On OSX or Linux, reuse the old mapping if it is the right size. */ #if defined(__APPLE__) || defined(__linux__) if( nNewRnd==nOldRnd ){ VVA_ONLY( p->mmapSize = nNew; ) return SQLITE_OK; } #endif /* If we get this far, unmap any old mapping. */ if( nOldRnd!=0 ){ void *pOld = *ppMap; munmap(pOld, nOldRnd); VVA_ONLY( p->mmapSize = 0; p->pMapRegion = 0; ); } /* And, if required, use mmap() to create a new mapping. */ if( nNewRnd>0 ){ int flags = PROT_READ; if( (p->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE; pNew = mmap(0, nNewRnd, flags, MAP_SHARED, p->h, iOff); if( pNew==MAP_FAILED ){ pNew = 0; VVA_ONLY( p->mmapSize = 0; p->pMapRegion = 0; ) rc = SQLITE_IOERR_MREMAP; }else{ VVA_ONLY( p->mmapSize = nNew; p->pMapRegion = pNew; ) } } *ppMap = pNew; return rc; } /* ** Here ends the implementation of all sqlite3_file methods. ** ********************** End sqlite3_file Methods ******************************* ******************************************************************************/ ................................................................................ unixFileControl, /* xFileControl */ \ unixSectorSize, /* xSectorSize */ \ unixDeviceCharacteristics, /* xDeviceCapabilities */ \ unixShmMap, /* xShmMap */ \ unixShmLock, /* xShmLock */ \ unixShmBarrier, /* xShmBarrier */ \ unixShmUnmap, /* xShmUnmap */ \ unixMremap, /* xMremap */ \ }; \ static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \ UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \ return &METHOD; \ } \ static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p) \ = FINDER##Impl; ................................................................................ assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 ); OSTRACE(("OPEN %-3d %s\n", h, zFilename)); pNew->h = h; pNew->pVfs = pVfs; pNew->zPath = zFilename; pNew->ctrlFlags = (u8)ctrlFlags; VVA_ONLY( pNew->mmapSize = 0; ) if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0), "psow", SQLITE_POWERSAFE_OVERWRITE) ){ pNew->ctrlFlags |= UNIXFILE_PSOW; } if( strcmp(pVfs->zName,"unix-excl")==0 ){ pNew->ctrlFlags |= UNIXFILE_EXCL; } |
> > | > > | < > > > > > > < > > > > > > > > > > > > > > > < > > > > > > > > > > > > > > > > < > > > > > > > > > > > > > | | | | < > > > > > > > > | < < < < < < < | | < < < < < < > > < < < < < > | > > > | > > > > > | > > | > > > > > > > > > > > > > > > > > > > > > > > > | | > > > | < < < < < < < < < < < < < < < < < < < | < < < < | | < < < < < < > > | > < < < | | < < < < | < > | | < < > | | > < |
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 .... 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 .... 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 .... 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 .... 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 .... 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 .... 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 .... 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 .... 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 .... 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 .... 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 |
** occur if a file is updated without also updating the transaction ** counter. This test is made to avoid new problems similar to the ** one described by ticket #3584. */ unsigned char transCntrChng; /* True if the transaction counter changed */ unsigned char dbUpdate; /* True if any part of database file changed */ unsigned char inNormalWrite; /* True if in a normal write operation */ #endif sqlite3_int64 mmapSize; /* Usable size of mapping at pMapRegion */ sqlite3_int64 mmapOrigsize; /* Actual size of mapping at pMapRegion */ sqlite3_int64 mmapLimit; /* Configured FCNTL_MMAP_SIZE value */ void *pMapRegion; /* Memory mapped region */ int nFetchOut; /* Number of outstanding xFetch refs */ #ifdef SQLITE_TEST /* In test mode, increase the size of this structure a bit so that ** it is larger than the struct CrashFile defined in test6.c. */ char aPadding[32]; #endif }; ................................................................................ ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. */ static int unixUnlock(sqlite3_file *id, int eFileLock){ return posixUnlock(id, eFileLock, 0); } static int unixMapfile(unixFile *pFd, i64 nByte); static void unixUnmapfile(unixFile *pFd); /* ** This function performs the parts of the "close file" operation ** common to all locking schemes. It closes the directory and file ** handles, if they are valid, and sets all fields of the unixFile ** structure to 0. ** ** It is *not* necessary to hold the mutex when this routine is called, ** even on VxWorks. A mutex will be acquired on VxWorks by the ** vxworksReleaseFileId() routine. */ static int closeUnixFile(sqlite3_file *id){ unixFile *pFile = (unixFile*)id; unixUnmapfile(pFile); if( pFile->h>=0 ){ robust_close(pFile, pFile->h, __LINE__); pFile->h = -1; } #if OS_VXWORKS if( pFile->pId ){ if( pFile->ctrlFlags & UNIXFILE_DELETE ){ ................................................................................ void *pBuf, int amt, sqlite3_int64 offset ){ unixFile *pFile = (unixFile *)id; int got; assert( id ); /* If this is a database file (not a journal, master-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 assert( pFile->pUnused==0 || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ); #endif /* Deal with as much of this write request as possible by transfering ** data to 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; } } got = seekAndRead(pFile, offset, pBuf, amt); if( got==amt ){ return SQLITE_OK; }else if( got<0 ){ /* lastErrno set by seekAndRead */ return SQLITE_IOERR_READ; ................................................................................ int amt, sqlite3_int64 offset ){ unixFile *pFile = (unixFile*)id; int wrote = 0; assert( id ); assert( amt>0 ); /* If this is a database file (not a journal, master-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 assert( pFile->pUnused==0 || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ................................................................................ SimulateIOErrorBenign(0); if( rc!=4 || memcmp(oldCntr, &((char*)pBuf)[24-offset], 4)!=0 ){ pFile->transCntrChng = 1; /* The transaction counter has changed */ } } } #endif /* Deal with as much of this write request as possible by transfering ** data from the memory mapping using memcpy(). */ if( offset<pFile->mmapSize ){ if( offset+amt <= pFile->mmapSize ){ memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt); return SQLITE_OK; }else{ int nCopy = pFile->mmapSize - offset; memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy); pBuf = &((u8 *)pBuf)[nCopy]; amt -= nCopy; offset += nCopy; } } while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){ amt -= wrote; offset += wrote; pBuf = &((char*)pBuf)[wrote]; } SimulateIOError(( wrote=(-1), amt=1 )); ................................................................................ ** that effectively updates the change counter. This might happen ** when restoring a database using the backup API from a zero-length ** source. */ if( pFile->inNormalWrite && nByte==0 ){ pFile->transCntrChng = 1; } #endif /* If the file was just truncated to a size smaller than the currently ** mapped region, reduce the effective mapping size as well. SQLite will ** use read() and write() to access data beyond this point from now on. */ if( nByte<pFile->mmapSize ){ pFile->mmapSize = nByte; } return SQLITE_OK; } } /* ** Determine the current size of a file in bytes ................................................................................ int nWrite = seekAndWrite(pFile, iWrite, "", 1); if( nWrite!=1 ) return SQLITE_IOERR_WRITE; iWrite += nBlk; } #endif } } if( pFile->mmapLimit>0 ){ int rc; if( pFile->szChunk<=0 ){ if( robust_ftruncate(pFile->h, nByte) ){ pFile->lastErrno = errno; return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath); } } rc = unixMapfile(pFile, nByte); return rc; } return SQLITE_OK; } /* ** If *pArg is inititially negative then this is a query. Set *pArg to ** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. ................................................................................ char *zTFile = sqlite3_malloc( pFile->pVfs->mxPathname ); if( zTFile ){ unixGetTempname(pFile->pVfs->mxPathname, zTFile); *(char**)pArg = zTFile; } return SQLITE_OK; } case SQLITE_FCNTL_MMAP_SIZE: { pFile->mmapLimit = *(i64*)pArg; return SQLITE_OK; } #ifdef SQLITE_DEBUG /* The pager calls this method to signal that it has done ** a rollback and that the database is therefore unchanged and ** it hence it is OK for the transaction change counter to be ** unchanged. ................................................................................ ** ** ROUNDUP(0, 8) -> 0 ** ROUNDUP(13, 8) -> 16 ** ROUNDUP(32, 8) -> 32 */ #define ROUNDUP(x,y) (((x)+y-1)&~(y-1)) static void unixUnmapfile(unixFile *pFd){ assert( pFd->nFetchOut==0 ); if( pFd->pMapRegion ){ munmap(pFd->pMapRegion, pFd->mmapOrigsize); pFd->pMapRegion = 0; pFd->mmapSize = 0; pFd->mmapOrigsize = 0; } } static int unixMapfile(unixFile *pFd, i64 nByte){ i64 nMap = nByte; int rc; assert( nMap>=0 || pFd->nFetchOut==0 ); if( pFd->nFetchOut>0 ) return SQLITE_OK; if( nMap<0 ){ struct stat statbuf; /* Low-level file information */ rc = osFstat(pFd->h, &statbuf); if( rc!=SQLITE_OK ){ return SQLITE_IOERR_FSTAT; } nMap = statbuf.st_size; } if( nMap>pFd->mmapLimit ){ nMap = pFd->mmapLimit; } if( nMap!=pFd->mmapSize ){ void *pNew; unixUnmapfile(pFd); if( nMap>0 ){ void *pNew; int flags = PROT_READ; if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE; pNew = mmap(0, ROUNDUP(nMap, 4096), flags, MAP_SHARED, pFd->h, 0); if( pNew==MAP_FAILED ){ return SQLITE_IOERR_MREMAP; } pFd->pMapRegion = pNew; pFd->mmapOrigsize = pFd->mmapSize = nMap; } } return SQLITE_OK; } static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){ unixFile *pFd = (unixFile *)fd; /* The underlying database file */ *pp = 0; if( pFd->mmapLimit>0 ){ if( pFd->pMapRegion==0 ){ int rc = unixMapfile(pFd, -1); if( rc!=SQLITE_OK ) return rc; } if( pFd->mmapSize >= iOff+nAmt ){ *pp = &((u8 *)pFd->pMapRegion)[iOff]; pFd->nFetchOut++; } } return SQLITE_OK; } static int unixUnfetch(sqlite3_file *fd, void *p){ unixFile *pFd = (unixFile *)fd; /* The underlying database file */ assert( (p==0)==(pFd->nFetchOut==0) ); if( p ){ pFd->nFetchOut--; }else{ unixUnmapfile(pFd); } assert( pFd->nFetchOut>=0 ); return SQLITE_OK; } /* ** Here ends the implementation of all sqlite3_file methods. ** ********************** End sqlite3_file Methods ******************************* ******************************************************************************/ ................................................................................ unixFileControl, /* xFileControl */ \ unixSectorSize, /* xSectorSize */ \ unixDeviceCharacteristics, /* xDeviceCapabilities */ \ unixShmMap, /* xShmMap */ \ unixShmLock, /* xShmLock */ \ unixShmBarrier, /* xShmBarrier */ \ unixShmUnmap, /* xShmUnmap */ \ unixFetch, /* xFetch */ \ unixUnfetch, /* xUnfetch */ \ }; \ static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \ UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \ return &METHOD; \ } \ static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p) \ = FINDER##Impl; ................................................................................ assert( zFilename!=0 || (ctrlFlags & UNIXFILE_NOLOCK)!=0 ); OSTRACE(("OPEN %-3d %s\n", h, zFilename)); pNew->h = h; pNew->pVfs = pVfs; pNew->zPath = zFilename; pNew->ctrlFlags = (u8)ctrlFlags; if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0), "psow", SQLITE_POWERSAFE_OVERWRITE) ){ pNew->ctrlFlags |= UNIXFILE_PSOW; } if( strcmp(pVfs->zName,"unix-excl")==0 ){ pNew->ctrlFlags |= UNIXFILE_EXCL; } |
Changes to src/pager.c.
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 .... 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 .... 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 .... 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 .... 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 .... 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 .... 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 .... 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 .... 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 .... 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 .... 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 .... 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 .... 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 .... 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 .... 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 .... 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 .... 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 .... 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 .... 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 .... 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 .... 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 |
i64 journalOff; /* Current write offset in the journal file */ i64 journalHdr; /* Byte offset to previous journal header */ sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */ PagerSavepoint *aSavepoint; /* Array of active savepoints */ int nSavepoint; /* Number of elements in aSavepoint[] */ char dbFileVers[16]; /* Changes whenever database file changes */ void *pMap; /* Memory mapped prefix of database file */ i64 nMap; /* Size of mapping at pMap in bytes */ i64 nMapValid; /* Bytes at pMap known to be valid */ i64 nMapLimit; /* Maximum permitted mapping size */ int nMapCfgLimit; /* Configured limit value */ int nMmapOut; /* Number of mmap pages currently outstanding */ PgHdr *pFree; /* List of free mmap page headers (pDirty) */ int bMapResize; /* Check if the mapping should be resized */ /* ** End of the routinely-changing class members ***************************************************************************/ u16 nExtra; /* Add this many bytes to each in-memory page */ i16 nReserve; /* Number of unused bytes at end of each page */ u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */ ................................................................................ (int)pPager->nReserve); } } #else # define pagerReportSize(X) /* No-op if we do not support a codec */ #endif /* ** Write nBuf bytes of data from buffer pBuf to offset iOff of the ** database file. If this part of the database file is memory mapped, ** use memcpy() to do so. Otherwise, call sqlite3OsWrite(). ** ** Return SQLITE_OK if successful, or an SQLite error code if an error ** occurs. */ int sqlite3PagerWriteData(Pager *pPager, const void *pBuf, int nBuf, i64 iOff){ int rc = SQLITE_OK; if( pPager->nMapValid>=(iOff+nBuf) ){ memcpy(&((u8 *)(pPager->pMap))[iOff], pBuf, nBuf); }else{ rc = sqlite3OsWrite(pPager->fd, pBuf, nBuf, iOff); } return rc; } /* ** Read a single page from either the journal file (if isMainJrnl==1) or ** from the sub-journal (if isMainJrnl==0) and playback that page. ** The page begins at offset *pOffset into the file. The *pOffset ** value is increased to the start of the next page in the journal. ** ** The main rollback journal uses checksums - the statement journal does ................................................................................ if( isOpen(pPager->fd) && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) && isSynced ){ i64 ofst = (pgno-1)*(i64)pPager->pageSize; testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 ); assert( !pagerUseWal(pPager) ); rc = sqlite3PagerWriteData(pPager, aData, pPager->pageSize, ofst); if( pgno>pPager->dbFileSize ){ pPager->dbFileSize = pgno; } if( pPager->pBackup ){ CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM); sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM, aData); ................................................................................ assert( pPager->eLock==EXCLUSIVE_LOCK ); /* TODO: Is it safe to use Pager.dbFileSize here? */ rc = sqlite3OsFileSize(pPager->fd, ¤tSize); newSize = szPage*(i64)nPage; if( rc==SQLITE_OK && currentSize!=newSize ){ if( currentSize>newSize ){ rc = sqlite3OsTruncate(pPager->fd, newSize); if( newSize<pPager->nMapValid ){ pPager->nMapValid = newSize; } }else if( (currentSize+szPage)<=newSize ){ char *pTmp = pPager->pTmpSpace; memset(pTmp, 0, szPage); testcase( (newSize-szPage) == currentSize ); testcase( (newSize-szPage) > currentSize ); rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, newSize-szPage); } ................................................................................ } if( iFrame ){ /* Try to pull the page from the write-ahead log. */ rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData); }else{ i64 iOffset = (pgno-1)*(i64)pPager->pageSize; if( pPager->pMap && pPager->nMapValid>=iOffset+pPager->pageSize ){ memcpy(pPg->pData, &((u8 *)(pPager->pMap))[iOffset], pPager->pageSize); }else{ rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset); if( rc==SQLITE_IOERR_SHORT_READ ){ rc = SQLITE_OK; } } } if( pgno==1 ){ if( rc ){ /* If the read is unsuccessful, set the dbFileVers[] to something ** that will never be a valid file version. dbFileVers[] is a copy ** of bytes 24..39 of the database. Bytes 28..31 should always be ** zero or the size of the database in page. Bytes 32..35 and 35..39 ................................................................................ ** the duplicate call is harmless. */ sqlite3WalEndReadTransaction(pPager->pWal); rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed); if( rc!=SQLITE_OK || changed ){ pager_reset(pPager); } return rc; } #endif /* ................................................................................ ** Change the maximum number of in-memory pages that are allowed. */ void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){ sqlite3PcacheSetCachesize(pPager->pPCache, mxPage); } /* ** Set Pager.nMapLimit, the maximum permitted mapping size, based on the ** current values of Pager.nMapCfgLimit and Pager.pageSize. ** ** If this connection should not use mmap at all, set nMapLimit to zero. */ static void pagerFixMaplimit(Pager *pPager){ if( isOpen(pPager->fd)==0 || pPager->fd->pMethods->iVersion<3 || pPager->fd->pMethods->xMremap==0 || pPager->tempFile ){ pPager->nMapLimit = 0; }else if( pPager->nMapCfgLimit<0 ){ pPager->nMapLimit = (i64)pPager->nMapCfgLimit * -1024; }else{ pPager->nMapLimit = (i64)pPager->nMapCfgLimit * pPager->pageSize; } } /* ** Change the maximum size of any memory mapping made of the database file. */ void sqlite3PagerSetMmapsize(Pager *pPager, int nMap){ ................................................................................ } if( rc==SQLITE_OK ){ rc = sqlite3OsFileSize(pPager->jfd, &pPager->journalHdr); } return rc; } /* ** Unmap any memory mapping of the database file. */ static int pagerUnmap(Pager *pPager){ assert( pPager->nMmapOut==0 ); if( pPager->pMap ){ sqlite3OsMremap(pPager->fd, 0, 0, pPager->nMap, 0, &pPager->pMap); pPager->nMap = 0; pPager->nMapValid = 0; } return SQLITE_OK; } /* ** Create, or recreate, the memory mapping of the database file. */ static int pagerMap(Pager *pPager, int bExtend){ int rc = SQLITE_OK; /* Return code */ Pgno nPg; /* Size of mapping to request in pages */ i64 sz; /* Size of mapping to request in bytes */ assert( isOpen(pPager->fd) && pPager->tempFile==0 ); assert( pPager->pMap==0 || pPager->nMap>0 ); /* assert( pPager->eState>=1 ); */ assert( pPager->nMmapOut==0 ); assert( pPager->nMapLimit>0 ); /* Figure out how large a mapping to request. Set variable sz to this ** value in bytes. */ nPg = (pPager->eState==1) ? pPager->dbSize : pPager->dbFileSize; sz = (i64)nPg * pPager->pageSize; if( sz>pPager->nMapLimit ) sz = pPager->nMapLimit; if( sz!=pPager->nMapValid ){ int flags = (bExtend ? SQLITE_MREMAP_EXTEND : 0); rc = sqlite3OsMremap(pPager->fd, flags, 0, pPager->nMap, sz, &pPager->pMap); if( rc==SQLITE_OK ){ assert( pPager->pMap!=0 ); pPager->nMap = sz; }else{ assert( pPager->pMap==0 ); pPager->nMap = 0; } pPager->nMapValid = pPager->nMap; } pPager->bMapResize = 0; return rc; } /* ** Obtain a reference to a memory mapped page object for page number pgno. ** The caller must ensure that page pgno lies within the currently mapped ** region. If successful, set *ppPage to point to the new page reference ** and return SQLITE_OK. Otherwise, return an SQLite error code and set ** *ppPage to zero. ** ** Page references obtained by calling this function should be released ** by calling pagerReleaseMapPage(). */ static int pagerAcquireMapPage(Pager *pPager, Pgno pgno, PgHdr **ppPage){ PgHdr *p; /* Memory mapped page to return */ if( pPager->pFree ){ *ppPage = p = pPager->pFree; pPager->pFree = p->pDirty; p->pDirty = 0; memset(p->pExtra, 0, pPager->nExtra); ................................................................................ assert( p->pExtra==(void *)&p[1] ); assert( p->pPage==0 ); assert( p->flags==PGHDR_MMAP ); assert( p->pPager==pPager ); assert( p->nRef==1 ); p->pData = &((u8 *)pPager->pMap)[(i64)(pgno-1) * pPager->pageSize]; p->pgno = pgno; pPager->nMmapOut++; return SQLITE_OK; } /* ** Release a reference to page pPg. pPg must have been returned by an ................................................................................ ** earlier call to pagerAcquireMapPage(). */ static void pagerReleaseMapPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; pPager->nMmapOut--; pPg->pDirty = pPager->pFree; pPager->pFree = pPg; } /* ** Free all PgHdr objects stored in the Pager.pFree list. */ static void pagerFreeMapHdrs(Pager *pPager){ PgHdr *p; ................................................................................ */ int sqlite3PagerClose(Pager *pPager){ u8 *pTmp = (u8 *)pPager->pTmpSpace; assert( assert_pager_state(pPager) ); disable_simulated_io_errors(); sqlite3BeginBenignMalloc(); pagerUnmap(pPager); pagerFreeMapHdrs(pPager); /* pPager->errCode = 0; */ pPager->exclusiveMode = 0; #ifndef SQLITE_OMIT_WAL sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp); pPager->pWal = 0; #endif ................................................................................ */ sqlite3PcacheClearSyncFlags(pPager->pPCache); pPager->eState = PAGER_WRITER_DBMOD; assert( assert_pager_state(pPager) ); return SQLITE_OK; } /* ** This is called by the wal.c module at the start of a checkpoint. If the ** checkpoint runs to completion, it will set the database file size to ** szReq bytes. This function performs two tasks: ** ** * If the file is currently less than szReq bytes in size, an ** xFileControl(SQLITE_FNCTL_SIZE_HINT) is issued to inform the OS ** layer of the expected file size, and ** ** * If mmap is being used, then the mapping is extended to szReq ** bytes in size. ** ** SQLITE_OK is returned if successful, or an error code if an error occurs. */ int sqlite3PagerSetFilesize(Pager *pPager, i64 szReq){ int rc; i64 sz; /* Size of file on disk in bytes */ assert( pPager->eState==PAGER_OPEN ); assert( pPager->nMmapOut==0 ); rc = sqlite3OsFileSize(pPager->fd, &sz); if( rc==SQLITE_OK ){ if( sz>szReq ){ sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &sz); } } if( rc==SQLITE_OK ){ i64 szMap = (szReq > pPager->nMapLimit) ? pPager->nMapLimit : szReq; if( pPager->nMapValid!=pPager->nMap || szMap!=pPager->nMap ){ pPager->dbFileSize = (szReq / pPager->pageSize); rc = pagerMap(pPager, 1); } } return rc; } /* ** The argument is the first in a linked list of dirty pages connected ** by the PgHdr.pDirty pointer. This function writes each one of the ** in-memory pages in the list to the database file. The argument may ** be NULL, representing an empty list. In this case this function is ** a no-op. ** ................................................................................ assert( rc!=SQLITE_OK || isOpen(pPager->fd) ); if( rc==SQLITE_OK && (pList->pDirty ? pPager->dbSize : pList->pgno+1)>pPager->dbHintSize ){ sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize; sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile); pPager->dbHintSize = pPager->dbSize; if( pPager->nMmapOut==0 && pPager->nMapLimit>0 ){ pPager->dbFileSize = pPager->dbSize; rc = pagerMap(pPager, 1); } } while( rc==SQLITE_OK && pList ){ Pgno pgno = pList->pgno; /* If there are dirty pages in the page cache with page numbers greater ** than Pager.dbSize, this means sqlite3PagerTruncateImage() was called to ................................................................................ assert( (pList->flags&PGHDR_NEED_SYNC)==0 ); if( pList->pgno==1 ) pager_write_changecounter(pList); /* Encode the database */ CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData); /* Write out the page data. */ rc = sqlite3PagerWriteData(pPager, pData, pPager->pageSize, offset); /* If page 1 was just written, update Pager.dbFileVers to match ** the value now stored in the database file. If writing this ** page caused the database file to grow, update dbFileSize. */ if( pgno==1 ){ memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers)); ................................................................................ || (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK) ); } if( !pPager->tempFile && ( pPager->pBackup || sqlite3PcachePagecount(pPager->pPCache)>0 || pPager->pMap )){ /* The shared-lock has just been acquired on the database file ** and there are already pages in the cache (from a previous ** read or write transaction). Check to see if the database ** has been modified. If the database has changed, flush the ** cache. ** ................................................................................ */ Pgno nPage = 0; char dbFileVers[sizeof(pPager->dbFileVers)]; rc = pagerPagecount(pPager, &nPage); if( rc ) goto failed; if( nPage>0 || pPager->pMap ){ IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); if( pPager->pMap ){ memcpy(&dbFileVers, &((u8 *)(pPager->pMap))[24], sizeof(dbFileVers)); }else{ rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24); } if( rc!=SQLITE_OK ){ goto failed; } }else{ memset(dbFileVers, 0, sizeof(dbFileVers)); } ................................................................................ /* Unmap the database file. It is possible that external processes ** may have truncated the database file and then extended it back ** to its original size while this process was not holding a lock. ** In this case there may exist a Pager.pMap mapping that appears ** to be the right size but is not actually valid. Avoid this ** possibility by unmapping the db here. */ pagerUnmap(pPager); }else if( pPager->pMap ){ pPager->bMapResize = 1; } } /* If there is a WAL file in the file-system, open this database in WAL ** mode. Otherwise, the following function call is a no-op. */ rc = pagerOpenWalIfPresent(pPager); ................................................................................ u32 iFrame = 0; /* Frame to read from WAL file */ const int noContent = (flags & PAGER_ACQUIRE_NOCONTENT); /* It is acceptable to use a read-only (mmap) page for any page except ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY ** flag was specified by the caller. And so long as the db is not a ** temporary or in-memory database. */ const int bMmapOk = (pPager->nMapLimit>0 && pgno!=1 && (pPager->eState==PAGER_READER || (flags & PAGER_ACQUIRE_READONLY)) ); assert( pPager->eState>=PAGER_READER ); assert( assert_pager_state(pPager) ); assert( noContent==0 || bMmapOk==0 ); ................................................................................ if( bMmapOk && pagerUseWal(pPager) ){ rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame); if( rc!=SQLITE_OK ) goto pager_acquire_err; } if( iFrame==0 && bMmapOk ){ if( pPager->pMap==0 || (pPager->bMapResize && pPager->nMmapOut==0) ){ rc = pagerMap(pPager, 0); } if( rc==SQLITE_OK && pPager->nMap>=((i64)pgno * pPager->pageSize) ){ if( pPager->eState>PAGER_READER ){ (void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg); } if( pPg==0 ){ rc = pagerAcquireMapPage(pPager, pgno, &pPg); } if( pPg ){ assert( rc==SQLITE_OK ); *ppPage = pPg; return SQLITE_OK; } } ................................................................................ rc = pagerExclusiveLock(pPager); } /* Open the connection to the log file. If this operation fails, ** (e.g. due to malloc() failure), return an error code. */ if( rc==SQLITE_OK ){ rc = sqlite3WalOpen(pPager->pVfs, pPager, pPager->fd, pPager->zWal, pPager->exclusiveMode, pPager->journalSizeLimit, &pPager->pWal ); } pagerFixMaplimit(pPager); return rc; ................................................................................ assert( assert_pager_state(pPager) ); assert( pPager->eState==PAGER_OPEN || pbOpen ); assert( pPager->eState==PAGER_READER || !pbOpen ); assert( pbOpen==0 || *pbOpen==0 ); assert( pbOpen!=0 || (!pPager->tempFile && !pPager->pWal) ); pagerUnmap(pPager); if( !pPager->tempFile && !pPager->pWal ){ if( !sqlite3PagerWalSupported(pPager) ) return SQLITE_CANTOPEN; /* Close any rollback journal previously open */ sqlite3OsClose(pPager->jfd); rc = pagerOpenWal(pPager); |
| < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < > | | | | | | | | | | | | | | | | > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | | > > > > > < > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < < < | < | | < > | | < | > > > > | | > > | < < |
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 .... 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 .... 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 .... 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 .... 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 .... 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 .... 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 .... 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 .... 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 .... 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 .... 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 .... 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 .... 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 .... 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 .... 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 .... 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 .... 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 .... 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 .... 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 .... 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 .... 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 |
i64 journalOff; /* Current write offset in the journal file */ i64 journalHdr; /* Byte offset to previous journal header */ sqlite3_backup *pBackup; /* Pointer to list of ongoing backup processes */ PagerSavepoint *aSavepoint; /* Array of active savepoints */ int nSavepoint; /* Number of elements in aSavepoint[] */ char dbFileVers[16]; /* Changes whenever database file changes */ u8 bUseFetch; /* True to use xFetch() */ int nMapCfgLimit; /* Configured limit value */ int nMmapOut; /* Number of mmap pages currently outstanding */ PgHdr *pFree; /* List of free mmap page headers (pDirty) */ /* ** End of the routinely-changing class members ***************************************************************************/ u16 nExtra; /* Add this many bytes to each in-memory page */ i16 nReserve; /* Number of unused bytes at end of each page */ u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */ ................................................................................ (int)pPager->nReserve); } } #else # define pagerReportSize(X) /* No-op if we do not support a codec */ #endif /* ** Read a single page from either the journal file (if isMainJrnl==1) or ** from the sub-journal (if isMainJrnl==0) and playback that page. ** The page begins at offset *pOffset into the file. The *pOffset ** value is increased to the start of the next page in the journal. ** ** The main rollback journal uses checksums - the statement journal does ................................................................................ if( isOpen(pPager->fd) && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) && isSynced ){ i64 ofst = (pgno-1)*(i64)pPager->pageSize; testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 ); assert( !pagerUseWal(pPager) ); rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); if( pgno>pPager->dbFileSize ){ pPager->dbFileSize = pgno; } if( pPager->pBackup ){ CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM); sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM, aData); ................................................................................ assert( pPager->eLock==EXCLUSIVE_LOCK ); /* TODO: Is it safe to use Pager.dbFileSize here? */ rc = sqlite3OsFileSize(pPager->fd, ¤tSize); newSize = szPage*(i64)nPage; if( rc==SQLITE_OK && currentSize!=newSize ){ if( currentSize>newSize ){ rc = sqlite3OsTruncate(pPager->fd, newSize); }else if( (currentSize+szPage)<=newSize ){ char *pTmp = pPager->pTmpSpace; memset(pTmp, 0, szPage); testcase( (newSize-szPage) == currentSize ); testcase( (newSize-szPage) > currentSize ); rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, newSize-szPage); } ................................................................................ } if( iFrame ){ /* Try to pull the page from the write-ahead log. */ rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData); }else{ i64 iOffset = (pgno-1)*(i64)pPager->pageSize; rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset); if( rc==SQLITE_IOERR_SHORT_READ ){ rc = SQLITE_OK; } } if( pgno==1 ){ if( rc ){ /* If the read is unsuccessful, set the dbFileVers[] to something ** that will never be a valid file version. dbFileVers[] is a copy ** of bytes 24..39 of the database. Bytes 28..31 should always be ** zero or the size of the database in page. Bytes 32..35 and 35..39 ................................................................................ ** the duplicate call is harmless. */ sqlite3WalEndReadTransaction(pPager->pWal); rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed); if( rc!=SQLITE_OK || changed ){ pager_reset(pPager); if( pPager->bUseFetch ) sqlite3OsUnfetch(pPager->fd, 0); } return rc; } #endif /* ................................................................................ ** Change the maximum number of in-memory pages that are allowed. */ void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){ sqlite3PcacheSetCachesize(pPager->pPCache, mxPage); } /* ** Invoke SQLITE_FCNTL_MMAP_SIZE based on the current value of nMapCfgLimit. */ static void pagerFixMaplimit(Pager *pPager){ sqlite3_file *fd = pPager->fd; if( isOpen(fd) ){ pPager->bUseFetch = (fd->pMethods->iVersion>=3) && pPager->nMapCfgLimit!=0; if( pPager->bUseFetch ){ void *p; i64 nMapLimit; if( pPager->nMapCfgLimit<0 ){ nMapLimit = (i64)pPager->nMapCfgLimit * -1024; }else{ nMapLimit = (i64)pPager->nMapCfgLimit * pPager->pageSize; } p = (void *)&nMapLimit; sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, p); } } } /* ** Change the maximum size of any memory mapping made of the database file. */ void sqlite3PagerSetMmapsize(Pager *pPager, int nMap){ ................................................................................ } if( rc==SQLITE_OK ){ rc = sqlite3OsFileSize(pPager->jfd, &pPager->journalHdr); } return rc; } /* ** Obtain a reference to a memory mapped page object for page number pgno. ** The new object will use the pointer pData, obtained from xFetch(). ** If successful, set *ppPage to point to the new page reference ** and return SQLITE_OK. Otherwise, return an SQLite error code and set ** *ppPage to zero. ** ** Page references obtained by calling this function should be released ** by calling pagerReleaseMapPage(). */ static int pagerAcquireMapPage( Pager *pPager, /* Pager object */ Pgno pgno, /* Page number */ void *pData, /* xFetch()'d data for this page */ PgHdr **ppPage /* OUT: Acquired page object */ ){ PgHdr *p; /* Memory mapped page to return */ if( pPager->pFree ){ *ppPage = p = pPager->pFree; pPager->pFree = p->pDirty; p->pDirty = 0; memset(p->pExtra, 0, pPager->nExtra); ................................................................................ assert( p->pExtra==(void *)&p[1] ); assert( p->pPage==0 ); assert( p->flags==PGHDR_MMAP ); assert( p->pPager==pPager ); assert( p->nRef==1 ); p->pgno = pgno; p->pData = pData; pPager->nMmapOut++; return SQLITE_OK; } /* ** Release a reference to page pPg. pPg must have been returned by an ................................................................................ ** earlier call to pagerAcquireMapPage(). */ static void pagerReleaseMapPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; pPager->nMmapOut--; pPg->pDirty = pPager->pFree; pPager->pFree = pPg; assert( pPager->fd->pMethods->iVersion>=3 ); sqlite3OsUnfetch(pPager->fd, pPg->pData); } /* ** Free all PgHdr objects stored in the Pager.pFree list. */ static void pagerFreeMapHdrs(Pager *pPager){ PgHdr *p; ................................................................................ */ int sqlite3PagerClose(Pager *pPager){ u8 *pTmp = (u8 *)pPager->pTmpSpace; assert( assert_pager_state(pPager) ); disable_simulated_io_errors(); sqlite3BeginBenignMalloc(); pagerFreeMapHdrs(pPager); /* pPager->errCode = 0; */ pPager->exclusiveMode = 0; #ifndef SQLITE_OMIT_WAL sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp); pPager->pWal = 0; #endif ................................................................................ */ sqlite3PcacheClearSyncFlags(pPager->pPCache); pPager->eState = PAGER_WRITER_DBMOD; assert( assert_pager_state(pPager) ); return SQLITE_OK; } /* ** The argument is the first in a linked list of dirty pages connected ** by the PgHdr.pDirty pointer. This function writes each one of the ** in-memory pages in the list to the database file. The argument may ** be NULL, representing an empty list. In this case this function is ** a no-op. ** ................................................................................ assert( rc!=SQLITE_OK || isOpen(pPager->fd) ); if( rc==SQLITE_OK && (pList->pDirty ? pPager->dbSize : pList->pgno+1)>pPager->dbHintSize ){ sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize; sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile); pPager->dbHintSize = pPager->dbSize; } while( rc==SQLITE_OK && pList ){ Pgno pgno = pList->pgno; /* If there are dirty pages in the page cache with page numbers greater ** than Pager.dbSize, this means sqlite3PagerTruncateImage() was called to ................................................................................ assert( (pList->flags&PGHDR_NEED_SYNC)==0 ); if( pList->pgno==1 ) pager_write_changecounter(pList); /* Encode the database */ CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData); /* Write out the page data. */ rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset); /* If page 1 was just written, update Pager.dbFileVers to match ** the value now stored in the database file. If writing this ** page caused the database file to grow, update dbFileSize. */ if( pgno==1 ){ memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers)); ................................................................................ || (pPager->exclusiveMode && pPager->eLock>SHARED_LOCK) ); } if( !pPager->tempFile && ( pPager->pBackup || sqlite3PcachePagecount(pPager->pPCache)>0 || pPager->bUseFetch /* TODO: Currently required for xUnfetch(0) only. */ )){ /* The shared-lock has just been acquired on the database file ** and there are already pages in the cache (from a previous ** read or write transaction). Check to see if the database ** has been modified. If the database has changed, flush the ** cache. ** ................................................................................ */ Pgno nPage = 0; char dbFileVers[sizeof(pPager->dbFileVers)]; rc = pagerPagecount(pPager, &nPage); if( rc ) goto failed; if( nPage>0 ){ IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24); if( rc!=SQLITE_OK ){ goto failed; } }else{ memset(dbFileVers, 0, sizeof(dbFileVers)); } ................................................................................ /* Unmap the database file. It is possible that external processes ** may have truncated the database file and then extended it back ** to its original size while this process was not holding a lock. ** In this case there may exist a Pager.pMap mapping that appears ** to be the right size but is not actually valid. Avoid this ** possibility by unmapping the db here. */ if( pPager->bUseFetch ){ sqlite3OsUnfetch(pPager->fd, 0); } } } /* If there is a WAL file in the file-system, open this database in WAL ** mode. Otherwise, the following function call is a no-op. */ rc = pagerOpenWalIfPresent(pPager); ................................................................................ u32 iFrame = 0; /* Frame to read from WAL file */ const int noContent = (flags & PAGER_ACQUIRE_NOCONTENT); /* It is acceptable to use a read-only (mmap) page for any page except ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY ** flag was specified by the caller. And so long as the db is not a ** temporary or in-memory database. */ const int bMmapOk = (pgno!=1 && pPager->bUseFetch && (pPager->eState==PAGER_READER || (flags & PAGER_ACQUIRE_READONLY)) ); assert( pPager->eState>=PAGER_READER ); assert( assert_pager_state(pPager) ); assert( noContent==0 || bMmapOk==0 ); ................................................................................ if( bMmapOk && pagerUseWal(pPager) ){ rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame); if( rc!=SQLITE_OK ) goto pager_acquire_err; } if( iFrame==0 && bMmapOk ){ void *pData = 0; rc = sqlite3OsFetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData ); if( rc==SQLITE_OK && pData ){ if( pPager->eState>PAGER_READER ){ (void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg); } if( pPg==0 ){ rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg); }else{ sqlite3OsUnfetch(pPager->fd, pData); } if( pPg ){ assert( rc==SQLITE_OK ); *ppPage = pPg; return SQLITE_OK; } } ................................................................................ rc = pagerExclusiveLock(pPager); } /* Open the connection to the log file. If this operation fails, ** (e.g. due to malloc() failure), return an error code. */ if( rc==SQLITE_OK ){ rc = sqlite3WalOpen(pPager->pVfs, pPager->fd, pPager->zWal, pPager->exclusiveMode, pPager->journalSizeLimit, &pPager->pWal ); } pagerFixMaplimit(pPager); return rc; ................................................................................ assert( assert_pager_state(pPager) ); assert( pPager->eState==PAGER_OPEN || pbOpen ); assert( pPager->eState==PAGER_READER || !pbOpen ); assert( pbOpen==0 || *pbOpen==0 ); assert( pbOpen!=0 || (!pPager->tempFile && !pPager->pWal) ); if( !pPager->tempFile && !pPager->pWal ){ if( !sqlite3PagerWalSupported(pPager) ) return SQLITE_CANTOPEN; /* Close any rollback journal previously open */ sqlite3OsClose(pPager->jfd); rc = pagerOpenWal(pPager); |
Changes to src/pager.h.
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
void sqlite3PagerClearCache(Pager *); int sqlite3SectorSize(sqlite3_file *); /* Functions used to truncate the database file. */ void sqlite3PagerTruncateImage(Pager*,Pgno); int sqlite3PagerSetFilesize(Pager *, i64); /* Write data to the database file */ int sqlite3PagerWriteData(Pager *pPager, const void *pBuf, int nBuf, i64 iOff); #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) void *sqlite3PagerCodec(DbPage *); #endif /* Functions to support testing and debugging. */ #if !defined(NDEBUG) || defined(SQLITE_TEST) Pgno sqlite3PagerPagenumber(DbPage*); |
< < < |
172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
void sqlite3PagerClearCache(Pager *); int sqlite3SectorSize(sqlite3_file *); /* Functions used to truncate the database file. */ void sqlite3PagerTruncateImage(Pager*,Pgno); int sqlite3PagerSetFilesize(Pager *, i64); #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) void *sqlite3PagerCodec(DbPage *); #endif /* Functions to support testing and debugging. */ #if !defined(NDEBUG) || defined(SQLITE_TEST) Pgno sqlite3PagerPagenumber(DbPage*); |
Changes to src/sqlite.h.in.
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 ... 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 ... 902 903 904 905 906 907 908 909 910 911 912 913 914 915 ... 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 |
** to xWrite(). ** ** If xRead() returns SQLITE_IOERR_SHORT_READ it must also fill ** in the unread portions of the buffer with zeros. A VFS that ** fails to zero-fill short reads might seem to work. However, ** failure to zero-fill short reads will eventually lead to ** database corruption. ** ** Assuming parameter nNew is non-zero, the xMremap method should attempt ** to memory map a region nNew bytes in size starting at offset iOffset ** of the file. If successful, it should set *ppMap to point to the ** mapping and return SQLITE_OK. If the file is opened for read-write ** access, then the mapping should also be read-write. ** ** If nOld is non-zero, then the initial value of *ppMap points to a ** mapping returned by a previous call to xMremap. The existing mapping ** is nOld bytes in size and starts at offset iOffset of the file. In ** this case the xMremap method is expected to unmap the existing mapping ** and overwrite *ppMap with the pointer to the new mapping. If nOld is ** zero, then the initial value of *ppMap is undefined. ** ** If nNew is zero, then no new mapping should be created. Any old ** mapping must still be unmapped if nOld is non-zero. If the nOld ** parameter is non-zero, then the existing mapping is always unmapped - ** even if an error occurs. */ typedef struct sqlite3_io_methods sqlite3_io_methods; struct sqlite3_io_methods { int iVersion; int (*xClose)(sqlite3_file*); int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); ................................................................................ int (*xDeviceCharacteristics)(sqlite3_file*); /* Methods above are valid for version 1 */ int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**); int (*xShmLock)(sqlite3_file*, int offset, int n, int flags); void (*xShmBarrier)(sqlite3_file*); int (*xShmUnmap)(sqlite3_file*, int deleteFlag); /* Methods above are valid for version 2 */ int (*xMremap)(sqlite3_file *fd, int flags, sqlite3_int64 iOff, sqlite3_int64 nOld, sqlite3_int64 nNew, void **ppMap); /* Methods above are valid for version 3 */ /* Additional methods may be added in future releases */ }; #define SQLITE_MREMAP_EXTEND 0x0001 /* xMremap call may extend file */ /* ** CAPI3REF: Standard File Control Opcodes ** ** These integer constants are opcodes for the xFileControl method ** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] ** interface. ** ................................................................................ ** ^Application can invoke this file-control to have SQLite generate a ** temporary filename using the same algorithm that is followed to generate ** temporary filenames for TEMP tables and other internal uses. The ** argument should be a char** which will be filled with the filename ** written into memory obtained from [sqlite3_malloc()]. The caller should ** invoke [sqlite3_free()] on the result to avoid a memory leak. ** ** </ul> */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_GET_LOCKPROXYFILE 2 #define SQLITE_SET_LOCKPROXYFILE 3 #define SQLITE_LAST_ERRNO 4 #define SQLITE_FCNTL_SIZE_HINT 5 ................................................................................ #define SQLITE_FCNTL_PERSIST_WAL 10 #define SQLITE_FCNTL_OVERWRITE 11 #define SQLITE_FCNTL_VFSNAME 12 #define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13 #define SQLITE_FCNTL_PRAGMA 14 #define SQLITE_FCNTL_BUSYHANDLER 15 #define SQLITE_FCNTL_TEMPFILENAME 16 #define SQLITE_FCNTL_GETFD 17 /* ** CAPI3REF: Mutex Handle ** ** The mutex module within SQLite defines [sqlite3_mutex] to be an ** abstract type for a mutex object. The SQLite core never looks ** at the internal representation of an [sqlite3_mutex]. It only |
< < < < < < < < < < < < < < < < < < | | < < > > > > | |
703 704 705 706 707 708 709 710 711 712 713 714 715 716 ... 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 ... 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 ... 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 |
** to xWrite(). ** ** If xRead() returns SQLITE_IOERR_SHORT_READ it must also fill ** in the unread portions of the buffer with zeros. A VFS that ** fails to zero-fill short reads might seem to work. However, ** failure to zero-fill short reads will eventually lead to ** database corruption. */ typedef struct sqlite3_io_methods sqlite3_io_methods; struct sqlite3_io_methods { int iVersion; int (*xClose)(sqlite3_file*); int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); ................................................................................ int (*xDeviceCharacteristics)(sqlite3_file*); /* Methods above are valid for version 1 */ int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**); int (*xShmLock)(sqlite3_file*, int offset, int n, int flags); void (*xShmBarrier)(sqlite3_file*); int (*xShmUnmap)(sqlite3_file*, int deleteFlag); /* Methods above are valid for version 2 */ int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); int (*xUnfetch)(sqlite3_file*, void *p); /* Methods above are valid for version 3 */ /* Additional methods may be added in future releases */ }; /* ** CAPI3REF: Standard File Control Opcodes ** ** These integer constants are opcodes for the xFileControl method ** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] ** interface. ** ................................................................................ ** ^Application can invoke this file-control to have SQLite generate a ** temporary filename using the same algorithm that is followed to generate ** temporary filenames for TEMP tables and other internal uses. The ** argument should be a char** which will be filled with the filename ** written into memory obtained from [sqlite3_malloc()]. The caller should ** invoke [sqlite3_free()] on the result to avoid a memory leak. ** ** <li>[[SQLITE_FCNTL_MMAP_SIZE]] ** The argument is assumed to point to a value of type sqlite3_int64. An ** advisory maximum amount of this file to memory map in bytes. ** ** </ul> */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_GET_LOCKPROXYFILE 2 #define SQLITE_SET_LOCKPROXYFILE 3 #define SQLITE_LAST_ERRNO 4 #define SQLITE_FCNTL_SIZE_HINT 5 ................................................................................ #define SQLITE_FCNTL_PERSIST_WAL 10 #define SQLITE_FCNTL_OVERWRITE 11 #define SQLITE_FCNTL_VFSNAME 12 #define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13 #define SQLITE_FCNTL_PRAGMA 14 #define SQLITE_FCNTL_BUSYHANDLER 15 #define SQLITE_FCNTL_TEMPFILENAME 16 #define SQLITE_FCNTL_MMAP_SIZE 18 /* ** CAPI3REF: Mutex Handle ** ** The mutex module within SQLite defines [sqlite3_mutex] to be an ** abstract type for a mutex object. The SQLite core never looks ** at the internal representation of an [sqlite3_mutex]. It only |
Changes to src/wal.c.
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 .... 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 .... 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 .... 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 |
** An open write-ahead log file is represented by an instance of the ** following object. */ struct Wal { sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */ sqlite3_file *pDbFd; /* File handle for the database file */ sqlite3_file *pWalFd; /* File handle for WAL file */ Pager *pPager; /* Pager object */ u32 iCallback; /* Value to pass to log callback (or 0) */ i64 mxWalSize; /* Truncate WAL to this size upon reset */ int nWiData; /* Size of array apWiData */ int szFirstBlock; /* Size of first block written to WAL file */ volatile u32 **apWiData; /* Pointer to wal-index content in memory */ u32 szPage; /* Database page size */ i16 readLock; /* Which read lock is being held. -1 for none */ ................................................................................ ** ** If the log file is successfully opened, SQLITE_OK is returned and ** *ppWal is set to point to a new WAL handle. If an error occurs, ** an SQLite error code is returned and *ppWal is left unmodified. */ int sqlite3WalOpen( sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */ Pager *pPager, /* Pager object handle */ sqlite3_file *pDbFd, /* The open database file */ const char *zWalName, /* Name of the WAL file */ int bNoShm, /* True to run in heap-memory mode */ i64 mxWalSize, /* Truncate WAL to this size on reset */ Wal **ppWal /* OUT: Allocated Wal handle */ ){ int rc; /* Return Code */ ................................................................................ pRet->pWalFd = (sqlite3_file *)&pRet[1]; pRet->pDbFd = pDbFd; pRet->readLock = -1; pRet->mxWalSize = mxWalSize; pRet->zWalName = zWalName; pRet->syncHeader = 1; pRet->padToSectorBoundary = 1; pRet->pPager = pPager; pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE); /* Open file handle on the write-ahead log file. */ flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL); rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags); if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){ pRet->readOnly = WAL_RDONLY; ................................................................................ u32 nBackfill = pInfo->nBackfill; /* Sync the WAL to disk */ if( sync_flags ){ rc = sqlite3OsSync(pWal->pWalFd, sync_flags); } /* If the database file is currently smaller than mxPage pages in size, ** the call below issues an SQLITE_FCNTL_SIZE_HINT to the OS layer to ** inform it that it is likely to grow to that size. ** ** Additionally, if the pager is using mmap(), then the call to ** SetFilesize() guarantees that the mapping is not larger than mxPage ** pages. This makes the sqlite3OsTruncate() call below safe - no pages ** that are part of the mapped region will be truncated away. */ if( rc==SQLITE_OK ){ i64 nReq = ((i64)mxPage * szPage); rc = sqlite3PagerSetFilesize(pWal->pPager, nReq); } /* Iterate through the contents of the WAL, copying data to the db file. */ while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){ i64 iOffset; assert( walFramePgno(pWal, iFrame)==iDbpage ); if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue; iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE; /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */ rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset); if( rc!=SQLITE_OK ) break; iOffset = (iDbpage-1)*(i64)szPage; testcase( IS_BIG_INT(iOffset) ); rc = sqlite3PagerWriteData(pWal->pPager, zBuf, szPage, iOffset); if( rc!=SQLITE_OK ) break; } /* If work was actually accomplished... */ if( rc==SQLITE_OK ){ if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){ i64 szDb = pWal->hdr.nPage*(i64)szPage; |
< < < | | < | < < < < < > > > | > > | |
408 409 410 411 412 413 414 415 416 417 418 419 420 421 .... 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 .... 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 .... 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 |
** An open write-ahead log file is represented by an instance of the ** following object. */ struct Wal { sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */ sqlite3_file *pDbFd; /* File handle for the database file */ sqlite3_file *pWalFd; /* File handle for WAL file */ u32 iCallback; /* Value to pass to log callback (or 0) */ i64 mxWalSize; /* Truncate WAL to this size upon reset */ int nWiData; /* Size of array apWiData */ int szFirstBlock; /* Size of first block written to WAL file */ volatile u32 **apWiData; /* Pointer to wal-index content in memory */ u32 szPage; /* Database page size */ i16 readLock; /* Which read lock is being held. -1 for none */ ................................................................................ ** ** If the log file is successfully opened, SQLITE_OK is returned and ** *ppWal is set to point to a new WAL handle. If an error occurs, ** an SQLite error code is returned and *ppWal is left unmodified. */ int sqlite3WalOpen( sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */ sqlite3_file *pDbFd, /* The open database file */ const char *zWalName, /* Name of the WAL file */ int bNoShm, /* True to run in heap-memory mode */ i64 mxWalSize, /* Truncate WAL to this size on reset */ Wal **ppWal /* OUT: Allocated Wal handle */ ){ int rc; /* Return Code */ ................................................................................ pRet->pWalFd = (sqlite3_file *)&pRet[1]; pRet->pDbFd = pDbFd; pRet->readLock = -1; pRet->mxWalSize = mxWalSize; pRet->zWalName = zWalName; pRet->syncHeader = 1; pRet->padToSectorBoundary = 1; pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE); /* Open file handle on the write-ahead log file. */ flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL); rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags); if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){ pRet->readOnly = WAL_RDONLY; ................................................................................ u32 nBackfill = pInfo->nBackfill; /* Sync the WAL to disk */ if( sync_flags ){ rc = sqlite3OsSync(pWal->pWalFd, sync_flags); } /* If the database may grow as a result of this checkpoint, hint ** about the eventual size of the db file to the VFS layer. */ if( rc==SQLITE_OK ){ i64 nReq = ((i64)mxPage * szPage); rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); if( rc==SQLITE_OK && nSize<nReq ){ sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq); } } /* Iterate through the contents of the WAL, copying data to the db file. */ while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){ i64 iOffset; assert( walFramePgno(pWal, iFrame)==iDbpage ); if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue; iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE; /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */ rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset); if( rc!=SQLITE_OK ) break; iOffset = (iDbpage-1)*(i64)szPage; testcase( IS_BIG_INT(iOffset) ); rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); if( rc!=SQLITE_OK ) break; } /* If work was actually accomplished... */ if( rc==SQLITE_OK ){ if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){ i64 szDb = pWal->hdr.nPage*(i64)szPage; |
Changes to src/wal.h.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
/* Connection to a write-ahead log (WAL) file. ** There is one object of this type for each pager. */ typedef struct Wal Wal; /* Open and close a connection to a write-ahead log. */ int sqlite3WalOpen( sqlite3_vfs*, Pager *, sqlite3_file*, const char *, int, i64, Wal**); int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *); /* Set the limiting size of a WAL file. */ void sqlite3WalLimit(Wal*, i64); /* Used by readers to open (lock) and close (unlock) a snapshot. A ** snapshot is like a read-transaction. It is the state of the database |
< | |
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
/* Connection to a write-ahead log (WAL) file.
** There is one object of this type for each pager.
*/
typedef struct Wal Wal;
/* Open and close a connection to a write-ahead log. */
int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**);
int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
/* Set the limiting size of a WAL file. */
void sqlite3WalLimit(Wal*, i64);
/* Used by readers to open (lock) and close (unlock) a snapshot. A
** snapshot is like a read-transaction. It is the state of the database
|