Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Change the semantics of xShmGet() such that it will never increase the size of shared memory. xShmSize() must be used to grow the size of shared memory. A shared memory segment size cannot be shrunk (except by dropping it). |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
72de00731245277b2209103ec0a76e3d |
User & Date: | drh 2010-05-26 15:06:38.000 |
Context
2010-05-26
| ||
17:31 | Make sure the wal-index mapping is always large enough to cover the entire active area of the wal-index. (check-in: 42705babba user: drh tags: trunk) | |
15:06 | Change the semantics of xShmGet() such that it will never increase the size of shared memory. xShmSize() must be used to grow the size of shared memory. A shared memory segment size cannot be shrunk (except by dropping it). (check-in: 72de007312 user: drh tags: trunk) | |
2010-05-25
| ||
15:53 | Updated header comments in wal.c. No functional code changes. (check-in: 687632a6b3 user: drh tags: trunk) | |
Changes
Changes to src/os_unix.c.
︙ | ︙ | |||
3598 3599 3600 3601 3602 3603 3604 | } unixLeaveMutex(); return SQLITE_OK; } /* | | < < < < > > > | < < < < < < < | < < < | > | | < > > | > > > | | 3598 3599 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 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 | } unixLeaveMutex(); return SQLITE_OK; } /* ** Changes the size of the underlying storage for a shared-memory segment. ** ** The reqSize parameter is the new requested size of the shared memory. ** This implementation is free to increase the shared memory size to ** any amount greater than or equal to reqSize. If the shared memory is ** already as big or bigger as reqSize, this routine is a no-op. ** ** 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_file *fd, /* The open database file holding SHM */ int reqSize, /* Requested size. -1 for query only */ int *pNewSize /* Write new size here */ ){ unixFile *pDbFd = (unixFile*)fd; unixShm *p = pDbFd->pShm; unixShmNode *pShmNode = p->pShmNode; int rc = SQLITE_OK; struct stat sStat; assert( pShmNode==pDbFd->pInode->pShmNode ); assert( pShmNode->pInode==pDbFd->pInode ); while( 1 ){ if( fstat(pShmNode->h, &sStat)==0 ){ *pNewSize = (int)sStat.st_size; if( reqSize<=(int)sStat.st_size ) break; }else{ *pNewSize = 0; rc = SQLITE_IOERR; break; } rc = ftruncate(pShmNode->h, reqSize); reqSize = -1; } return rc; } /* ** Map the shared storage into memory. ** ** If reqMapSize is positive, then an attempt is made to make the ** mapping at least reqMapSize bytes in size. However, the mapping ** will never be larger than the size of the underlying shared memory ** as set by prior calls to xShmSize(). ** ** *ppBuf is made to point to the memory which is a mapping of the ** underlying storage. A mutex is acquired to prevent other threads ** from running while *ppBuf is in use in order to prevent other threads ** remapping *ppBuf out from under this thread. The unixShmRelease() ** call will release the mutex. However, if the lock state is CHECKPOINT, ** the mutex is not acquired because CHECKPOINT will never remap the ** buffer. RECOVER might remap, though, so CHECKPOINT will acquire ** the mutex if and when it promotes to RECOVER. ** ** RECOVER needs to be atomic. The same mutex that prevents *ppBuf from ** being remapped also prevents more than one thread from being in ** RECOVER at a time. But, RECOVER sometimes wants to remap itself. ** To prevent RECOVER from losing its lock while remapping, the ** mutex is not released by unixShmRelease() when in RECOVER. ** ** *pNewMapSize is set to the size of the mapping. Usually *pNewMapSize ** will be reqMapSize or larger, though it could be smaller if the ** underlying shared memory has never been enlarged to reqMapSize bytes ** by prior calls to xShmSize(). ** ** *ppBuf might be NULL and zero if no space has ** yet been allocated to the underlying storage. */ static int unixShmGet( sqlite3_file *fd, /* Database file holding shared memory */ int reqMapSize, /* Requested size of mapping. -1 means don't care */ int *pNewMapSize, /* Write new size of mapping here */ void volatile **ppBuf /* Write mapping buffer origin here */ |
︙ | ︙ | |||
3697 3698 3699 3700 3701 3702 3703 | assert( sqlite3_mutex_notheld(pShmNode->mutex) ); sqlite3_mutex_enter(pShmNode->mutexBuf); p->hasMutexBuf = 1; } sqlite3_mutex_enter(pShmNode->mutex); if( pShmNode->szMap==0 || reqMapSize>pShmNode->szMap ){ int actualSize; | | | < < > | > | | | > > > > | 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 | assert( sqlite3_mutex_notheld(pShmNode->mutex) ); sqlite3_mutex_enter(pShmNode->mutexBuf); p->hasMutexBuf = 1; } sqlite3_mutex_enter(pShmNode->mutex); if( pShmNode->szMap==0 || reqMapSize>pShmNode->szMap ){ int actualSize; if( unixShmSize(fd, -1, &actualSize)!=SQLITE_OK ){ actualSize = 0; } reqMapSize = actualSize; if( pShmNode->pMMapBuf || reqMapSize<=0 ){ munmap(pShmNode->pMMapBuf, pShmNode->szMap); } if( reqMapSize>0 ){ pShmNode->pMMapBuf = mmap(0, reqMapSize, PROT_READ|PROT_WRITE, MAP_SHARED, pShmNode->h, 0); pShmNode->szMap = pShmNode->pMMapBuf ? reqMapSize : 0; }else{ pShmNode->pMMapBuf = 0; pShmNode->szMap = 0; } } *pNewMapSize = pShmNode->szMap; *ppBuf = pShmNode->pMMapBuf; sqlite3_mutex_leave(pShmNode->mutex); return rc; } |
︙ | ︙ |
Changes to src/os_win.c.
︙ | ︙ | |||
1754 1755 1756 1757 1758 1759 1760 | } winShmLeaveMutex(); return SQLITE_OK; } /* | | < < < < < | > | > < < > > | 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 | } winShmLeaveMutex(); return SQLITE_OK; } /* ** Increase the size of the underlying storage for a shared-memory segment. ** ** The reqSize parameter is the new requested minimum size of the underlying ** shared memory. This routine may choose to make the shared memory larger ** than this value (for example to round the shared memory size up to an ** operating-system dependent page size.) ** ** This routine will only grow the size of shared memory. A request for ** a smaller size is a no-op. */ static int winShmSize( sqlite3_file *fd, /* Database holding the shared memory */ int reqSize, /* Requested size. -1 for query only */ int *pNewSize /* Write new size here */ ){ winFile *pDbFd = (winFile*)fd; |
︙ | ︙ |
Changes to src/wal.c.
︙ | ︙ | |||
240 241 242 243 244 245 246 247 248 249 250 251 252 253 | /* A block of WALINDEX_LOCK_RESERVED bytes beginning at ** WALINDEX_LOCK_OFFSET is reserved for locks. Since some systems ** only support mandatory file-locks, we do not read or write data ** from the region of the file on which locks are applied. */ #define WALINDEX_LOCK_OFFSET (sizeof(WalIndexHdr)*2) #define WALINDEX_LOCK_RESERVED 8 /* Size of header before each frame in wal */ #define WAL_FRAME_HDRSIZE 24 /* Size of write ahead log header */ #define WAL_HDRSIZE 24 | > | 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | /* A block of WALINDEX_LOCK_RESERVED bytes beginning at ** WALINDEX_LOCK_OFFSET is reserved for locks. Since some systems ** only support mandatory file-locks, we do not read or write data ** from the region of the file on which locks are applied. */ #define WALINDEX_LOCK_OFFSET (sizeof(WalIndexHdr)*2) #define WALINDEX_LOCK_RESERVED 8 #define WALINDEX_HDR_SIZE (WALINDEX_LOCK_OFFSET+WALINDEX_LOCK_RESERVED) /* Size of header before each frame in wal */ #define WAL_FRAME_HDRSIZE 24 /* Size of write ahead log header */ #define WAL_HDRSIZE 24 |
︙ | ︙ | |||
558 559 560 561 562 563 564 | /* ** Release our reference to the wal-index memory map, if we are holding ** it. */ static void walIndexUnmap(Wal *pWal){ if( pWal->pWiData ){ sqlite3OsShmRelease(pWal->pDbFd); | < > > | | > > < < < < < < > > > < < < < < < | 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 | /* ** Release our reference to the wal-index memory map, if we are holding ** it. */ static void walIndexUnmap(Wal *pWal){ if( pWal->pWiData ){ sqlite3OsShmRelease(pWal->pDbFd); } pWal->pWiData = 0; pWal->szWIndex = -1; } /* ** Map the wal-index file into memory if it isn't already. ** ** The reqSize parameter is the requested size of the mapping. The ** mapping will be at least this big if the underlying storage is ** that big. But the mapping will never grow larger than the underlying ** storage. Use the walIndexRemap() to enlarget the storage space. */ static int walIndexMap(Wal *pWal, int reqSize){ int rc = SQLITE_OK; if( pWal->pWiData==0 || reqSize>pWal->szWIndex ){ walIndexUnmap(pWal); rc = sqlite3OsShmGet(pWal->pDbFd, reqSize, &pWal->szWIndex, (void volatile**)(char volatile*)&pWal->pWiData); if( rc!=SQLITE_OK ){ walIndexUnmap(pWal); } } return rc; } /* ** Enlarge the wal-index to be at least enlargeTo bytes in size and ** 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 walIndexRemap(Wal *pWal, int enlargeTo){ int rc; int sz; assert( pWal->lockState>=SQLITE_SHM_WRITE ); rc = sqlite3OsShmSize(pWal->pDbFd, enlargeTo, &sz); if( rc==SQLITE_OK && sz>pWal->szWIndex ){ walIndexUnmap(pWal); rc = walIndexMap(pWal, sz); } assert( pWal->szWIndex>=enlargeTo || rc!=SQLITE_OK ); return rc; } /* ** Compute a hash on a page number. The resulting hash value must land ** between 0 and (HASHTABLE_NSLOT-1). */ static int walHash(u32 iPage){ assert( iPage>0 ); |
︙ | ︙ | |||
734 735 736 737 738 739 740 | */ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ int rc; /* Return code */ int nMapping; /* Required mapping size in bytes */ /* Make sure the wal-index is mapped. Enlarge the mapping if required. */ nMapping = walMappingSize(iFrame); | | < | | 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 | */ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ int rc; /* Return code */ int nMapping; /* Required mapping size in bytes */ /* Make sure the wal-index is mapped. Enlarge the mapping if required. */ nMapping = walMappingSize(iFrame); rc = walIndexMap(pWal, nMapping); while( rc==SQLITE_OK && nMapping>pWal->szWIndex ){ rc = walIndexRemap(pWal, nMapping); } /* Assuming the wal-index file was successfully mapped, find the hash ** table and section of of the page number array that pertain to frame ** iFrame of the WAL. Then populate the page number array and the hash ** table entry. */ |
︙ | ︙ | |||
903 904 905 906 907 908 909 | } sqlite3_free(aFrame); } finished: if( rc==SQLITE_OK && pWal->hdr.mxFrame==0 ){ | | | 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 | } sqlite3_free(aFrame); } finished: if( rc==SQLITE_OK && pWal->hdr.mxFrame==0 ){ rc = walIndexRemap(pWal, walMappingSize(1)); } if( rc==SQLITE_OK ){ pWal->hdr.aFrameCksum[0] = aFrameCksum[0]; pWal->hdr.aFrameCksum[1] = aFrameCksum[1]; walIndexWriteHdr(pWal); } return rc; |
︙ | ︙ | |||
979 980 981 982 983 984 985 986 987 988 989 990 991 992 | if( !pRet ){ return SQLITE_NOMEM; } pRet->pVfs = pVfs; pRet->pWalFd = (sqlite3_file *)&pRet[1]; pRet->pDbFd = pDbFd; sqlite3_randomness(8, &pRet->hdr.aSalt); pRet->zWalName = zWal = pVfs->szOsFile + (char*)pRet->pWalFd; sqlite3_snprintf(nWal, zWal, "%s-wal", zDbName); rc = sqlite3OsShmOpen(pDbFd); /* Open file handle on the write-ahead log file. */ if( rc==SQLITE_OK ){ | > | 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 | if( !pRet ){ return SQLITE_NOMEM; } pRet->pVfs = pVfs; pRet->pWalFd = (sqlite3_file *)&pRet[1]; pRet->pDbFd = pDbFd; pRet->szWIndex = -1; sqlite3_randomness(8, &pRet->hdr.aSalt); pRet->zWalName = zWal = pVfs->szOsFile + (char*)pRet->pWalFd; sqlite3_snprintf(nWal, zWal, "%s-wal", zDbName); rc = sqlite3OsShmOpen(pDbFd); /* Open file handle on the write-ahead log file. */ if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
1305 1306 1307 1308 1309 1310 1311 | ** is read successfully and the checksum verified, return zero. */ int walIndexTryHdr(Wal *pWal, int *pChanged){ u32 aCksum[2]; /* Checksum on the header content */ WalIndexHdr h1, h2; /* Two copies of the header content */ WalIndexHdr *aHdr; /* Header in shared memory */ | < | | | < < > | 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 | ** is read successfully and the checksum verified, return zero. */ int walIndexTryHdr(Wal *pWal, int *pChanged){ u32 aCksum[2]; /* Checksum on the header content */ WalIndexHdr h1, h2; /* Two copies of the header content */ WalIndexHdr *aHdr; /* Header in shared memory */ if( pWal->szWIndex < WALINDEX_HDR_SIZE ){ /* The wal-index is not large enough to hold the header, then assume ** header is invalid. */ return 1; } assert( pWal->pWiData ); /* Read the header. The caller may or may not have an exclusive ** (WRITE, PENDING, CHECKPOINT or RECOVER) lock on the wal-index ** file, meaning it is possible that an inconsistent snapshot is read ** from the file. If this happens, return non-zero. ** ** There are two copies of the header at the beginning of the wal-index. |
︙ | ︙ | |||
1374 1375 1376 1377 1378 1379 1380 | */ static int walIndexReadHdr(Wal *pWal, int *pChanged){ int rc; /* Return code */ int lockState; /* pWal->lockState before running recovery */ assert( pWal->lockState>=SQLITE_SHM_READ ); assert( pChanged ); | | | 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 | */ static int walIndexReadHdr(Wal *pWal, int *pChanged){ int rc; /* Return code */ int lockState; /* pWal->lockState before running recovery */ assert( pWal->lockState>=SQLITE_SHM_READ ); assert( pChanged ); rc = walIndexMap(pWal, walMappingSize(1)); if( rc!=SQLITE_OK ){ return rc; } /* First attempt to read the wal-index header. This may fail for one ** of two reasons: (a) the wal-index does not yet exist or has been ** corrupted and needs to be constructed by running recovery, or (b) |
︙ | ︙ | |||
1624 1625 1626 1627 1628 1629 1630 | rc = walSetLock(pWal, SQLITE_SHM_WRITE); /* If this connection is not reading the most recent database snapshot, ** it is not possible to write to the database. In this case release ** the write locks and return SQLITE_BUSY. */ if( rc==SQLITE_OK ){ | | > | 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 | rc = walSetLock(pWal, SQLITE_SHM_WRITE); /* If this connection is not reading the most recent database snapshot, ** it is not possible to write to the database. In this case release ** the write locks and return SQLITE_BUSY. */ if( rc==SQLITE_OK ){ rc = walIndexMap(pWal, walMappingSize(1)); assert( pWal->szWIndex>=WALINDEX_HDR_SIZE || rc!=SQLITE_OK ); if( rc==SQLITE_OK && memcmp(&pWal->hdr, (void*)pWal->pWiData, sizeof(WalIndexHdr)) ){ rc = SQLITE_BUSY; } walIndexUnmap(pWal); if( rc!=SQLITE_OK ){ |
︙ | ︙ |