/ Check-in [16b34f25]
Login

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: 16b34f2537bbc7846d8e6dc2b35daae5af241c1b
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
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

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