Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | If it is known that checksums will be recalculated on transaction commit, skip calculating checksums when appending frames to the wal file. When recalculating checksums, recalculate them starting with the first overwritten frame - not the first frame in the transaction. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | wal-overwrite-frames |
Files: | files | file ages | folders |
SHA1: |
16b34f2537bbc7846d8e6dc2b35daae5 |
User & Date: | dan 2016-01-09 18:57:35 |
Context
2016-01-09
| ||
23:55 | All WAL frame overwrites even if there are active savepoints. This is safe because a ROLLBACK TO will cause all reverted pages to be rewritten to the WAL file prior to COMMIT. check-in: 99b31a6b user: drh tags: wal-overwrite-frames | |
18:57 | If it is known that checksums will be recalculated on transaction commit, skip calculating checksums when appending frames to the wal file. When recalculating checksums, recalculate them starting with the first overwritten frame - not the first frame in the transaction. check-in: 16b34f25 user: dan tags: wal-overwrite-frames | |
16:39 | If a single page is written to the wal file more than once, have each subsequent copy overwrite the original frame. check-in: 5d113aef user: dan tags: wal-overwrite-frames | |
Changes
Changes to src/wal.c.
441 441 u8 ckptLock; /* True if holding a checkpoint lock */ 442 442 u8 readOnly; /* WAL_RDWR, WAL_RDONLY, or WAL_SHM_RDONLY */ 443 443 u8 truncateOnCommit; /* True to truncate WAL file on commit */ 444 444 u8 syncHeader; /* Fsync the WAL header if true */ 445 445 u8 padToSectorBoundary; /* Pad transactions out to the next sector */ 446 446 WalIndexHdr hdr; /* Wal-index header for current transaction */ 447 447 u32 minFrame; /* Ignore wal frames before this one */ 448 + u32 iReCksum; /* On commit, recalculate checksums from here */ 448 449 const char *zWalName; /* Name of WAL file */ 449 450 u32 nCkpt; /* Checkpoint sequence counter in the wal-header */ 450 451 #ifdef SQLITE_DEBUG 451 452 u8 lockError; /* True if a locking error has occurred */ 452 453 #endif 453 454 #ifdef SQLITE_ENABLE_SNAPSHOT 454 455 WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */ ................................................................................ 458 459 /* 459 460 ** Candidate values for Wal.exclusiveMode. 460 461 */ 461 462 #define WAL_NORMAL_MODE 0 462 463 #define WAL_EXCLUSIVE_MODE 1 463 464 #define WAL_HEAPMEMORY_MODE 2 464 465 465 -/* 466 -** Values for Wal.writeLock. 467 -*/ 468 -#define WAL_WRITELOCK_UNLOCKED 0 469 -#define WAL_WRITELOCK_LOCKED 1 470 -#define WAL_WRITELOCK_RECKSUM 2 471 - 472 466 /* 473 467 ** Possible values for WAL.readOnly 474 468 */ 475 469 #define WAL_RDWR 0 /* Normal read/write connection */ 476 470 #define WAL_RDONLY 1 /* The WAL file is readonly */ 477 471 #define WAL_SHM_RDONLY 2 /* The SHM file is readonly */ 478 472 ................................................................................ 701 695 u8 *aFrame /* OUT: Write encoded frame here */ 702 696 ){ 703 697 int nativeCksum; /* True for native byte-order checksums */ 704 698 u32 *aCksum = pWal->hdr.aFrameCksum; 705 699 assert( WAL_FRAME_HDRSIZE==24 ); 706 700 sqlite3Put4byte(&aFrame[0], iPage); 707 701 sqlite3Put4byte(&aFrame[4], nTruncate); 708 - memcpy(&aFrame[8], pWal->hdr.aSalt, 8); 702 + if( pWal->iReCksum==0 ){ 703 + memcpy(&aFrame[8], pWal->hdr.aSalt, 8); 709 704 710 - nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN); 711 - walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum); 712 - walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum); 705 + nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN); 706 + walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum); 707 + walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum); 713 708 714 - sqlite3Put4byte(&aFrame[16], aCksum[0]); 715 - sqlite3Put4byte(&aFrame[20], aCksum[1]); 709 + sqlite3Put4byte(&aFrame[16], aCksum[0]); 710 + sqlite3Put4byte(&aFrame[20], aCksum[1]); 711 + } 716 712 } 717 713 718 714 /* 719 715 ** Check to see if the frame with header in aFrame[] and content 720 716 ** in aData[] is valid. If it is a valid frame, fill *piPage and 721 717 ** *pnTruncate and return true. Return if the frame is not valid. 722 718 */ ................................................................................ 2635 2631 */ 2636 2632 int sqlite3WalBeginWriteTransaction(Wal *pWal){ 2637 2633 int rc; 2638 2634 2639 2635 /* Cannot start a write transaction without first holding a read 2640 2636 ** transaction. */ 2641 2637 assert( pWal->readLock>=0 ); 2638 + assert( pWal->writeLock==0 && pWal->iReCksum==0 ); 2642 2639 2643 2640 if( pWal->readOnly ){ 2644 2641 return SQLITE_READONLY; 2645 2642 } 2646 2643 2647 2644 /* Only one writer allowed at a time. Get the write lock. Return 2648 2645 ** SQLITE_BUSY if unable. ................................................................................ 2670 2667 ** End a write transaction. The commit has already been done. This 2671 2668 ** routine merely releases the lock. 2672 2669 */ 2673 2670 int sqlite3WalEndWriteTransaction(Wal *pWal){ 2674 2671 if( pWal->writeLock ){ 2675 2672 walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); 2676 2673 pWal->writeLock = 0; 2674 + pWal->iReCksum = 0; 2677 2675 pWal->truncateOnCommit = 0; 2678 2676 } 2679 2677 return SQLITE_OK; 2680 2678 } 2681 2679 2682 2680 /* 2683 2681 ** If any data has been written (but not committed) to the log file, this ................................................................................ 2891 2889 rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame)); 2892 2890 return rc; 2893 2891 } 2894 2892 2895 2893 /* 2896 2894 ** This function is called as part of committing a transaction within which 2897 2895 ** one or more frames have been overwritten. It updates the checksums for 2898 -** all frames written to the wal file by the current transaction. 2899 -** 2900 -** Argument pLive is a pointer to the first wal-index header in shared 2901 -** memory (the copy readers will see if they open a read-transaction now, 2902 -** before the current commit is finished). This is safe to use because the 2903 -** caller holds the WRITER lock. The first frame to update the checksum 2904 -** for is (pLive->mxFrame+1). The last is argument iLast. 2896 +** all frames written to the wal file by the current transaction starting 2897 +** with the earliest to have been overwritten. 2905 2898 ** 2906 2899 ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. 2907 2900 */ 2908 -static int walRewriteChecksums(Wal *pWal, WalIndexHdr *pLive, u32 iLast){ 2901 +static int walRewriteChecksums(Wal *pWal, u32 iLast){ 2909 2902 const int szPage = pWal->szPage;/* Database page size */ 2910 2903 int rc = SQLITE_OK; /* Return code */ 2911 2904 u8 *aBuf; /* Buffer to load data from wal file into */ 2912 2905 u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-headers in */ 2913 2906 u32 iRead; /* Next frame to read from wal file */ 2907 + i64 iCksumOff; 2914 2908 2915 2909 aBuf = sqlite3_malloc(szPage + WAL_FRAME_HDRSIZE); 2916 2910 if( aBuf==0 ) return SQLITE_NOMEM; 2917 2911 2918 - /* Find the checksum values to use as input for the checksum of the 2919 - ** first frame written by this transaction. If that frame is frame 1 2920 - ** (implying that the current transaction restarted the wal file), 2921 - ** these values must be read from the wal-file header. If the first 2922 - ** frame to update the checksum of is not frame 1, then the initial 2923 - ** checksum values can be copied from pLive. */ 2924 - if( pLive->mxFrame==0 ){ 2925 - rc = sqlite3OsRead(pWal->pWalFd, aBuf, sizeof(u32)*2, 24); 2926 - pWal->hdr.aFrameCksum[0] = sqlite3Get4byte(aBuf); 2927 - pWal->hdr.aFrameCksum[1] = sqlite3Get4byte(&aBuf[sizeof(u32)]); 2912 + /* Find the checksum values to use as input for the recalculating the 2913 + ** first checksum. If the first frame is frame 1 (implying that the current 2914 + ** transaction restarted the wal file), these values must be read from the 2915 + ** wal-file header. Otherwise, read them from the frame header of the 2916 + ** previous frame. */ 2917 + assert( pWal->iReCksum>0 ); 2918 + if( pWal->iReCksum==1 ){ 2919 + iCksumOff = 24; 2928 2920 }else{ 2929 - memcpy(pWal->hdr.aFrameCksum, pLive->aFrameCksum, sizeof(u32)*2); 2921 + iCksumOff = walFrameOffset(pWal->iReCksum-1, szPage) + 16; 2930 2922 } 2923 + rc = sqlite3OsRead(pWal->pWalFd, aBuf, sizeof(u32)*2, iCksumOff); 2924 + pWal->hdr.aFrameCksum[0] = sqlite3Get4byte(aBuf); 2925 + pWal->hdr.aFrameCksum[1] = sqlite3Get4byte(&aBuf[sizeof(u32)]); 2931 2926 2932 - for(iRead=pLive->mxFrame+1; rc==SQLITE_OK && iRead<=iLast; iRead++){ 2927 + iRead = pWal->iReCksum; 2928 + pWal->iReCksum = 0; 2929 + for(; rc==SQLITE_OK && iRead<=iLast; iRead++){ 2933 2930 i64 iOff = walFrameOffset(iRead, szPage); 2934 2931 rc = sqlite3OsRead(pWal->pWalFd, aBuf, szPage+WAL_FRAME_HDRSIZE, iOff); 2935 2932 if( rc==SQLITE_OK ){ 2936 2933 u32 iPgno, nDbSize; 2937 2934 iPgno = sqlite3Get4byte(aBuf); 2938 2935 nDbSize = sqlite3Get4byte(&aBuf[4]); 2939 2936 ................................................................................ 3061 3058 ** checksums must be recomputed when the transaction is committed. */ 3062 3059 if( iFirst && (p->pDirty || isCommit==0) ){ 3063 3060 u32 iWrite = 0; 3064 3061 rc = sqlite3WalFindFrame(pWal, p->pgno, &iWrite); 3065 3062 if( rc ) return rc; 3066 3063 if( iWrite>=iFirst ){ 3067 3064 i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE; 3068 - pWal->writeLock = WAL_WRITELOCK_RECKSUM; 3065 + if( pWal->iReCksum==0 || iWrite<pWal->iReCksum ){ 3066 + pWal->iReCksum = iWrite; 3067 + } 3069 3068 rc = sqlite3OsWrite(pWal->pWalFd, p->pData, szPage, iOff); 3070 3069 if( rc ) return rc; 3071 3070 p->flags &= ~PGHDR_WAL_APPEND; 3072 3071 continue; 3073 3072 } 3074 3073 } 3075 3074 ................................................................................ 3080 3079 if( rc ) return rc; 3081 3080 pLast = p; 3082 3081 iOffset += szFrame; 3083 3082 p->flags |= PGHDR_WAL_APPEND; 3084 3083 } 3085 3084 3086 3085 /* Recalculate checksums within the wal file if required. */ 3087 - if( isCommit && pWal->writeLock==WAL_WRITELOCK_RECKSUM ){ 3088 - rc = walRewriteChecksums(pWal, pLive, iFrame); 3086 + if( isCommit && pWal->iReCksum ){ 3087 + rc = walRewriteChecksums(pWal, iFrame); 3089 3088 if( rc ) return rc; 3090 3089 } 3091 3090 3092 3091 /* If this is the end of a transaction, then we might need to pad 3093 3092 ** the transaction and/or sync the WAL file. 3094 3093 ** 3095 3094 ** Padding and syncing only occur if this set of frames complete a