/ Check-in [84955c2e]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Change the way checksums are calculated.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | wal
Files: files | file ages | folders
SHA1: 84955c2e9ce526c5a3ed479aa09f093a7e37c7d0
User & Date: dan 2010-04-15 10:58:52
Context
2010-04-15
13:33
Merge two leaves on the WAL branch. check-in: c9ed66cc user: dan tags: wal
10:58
Change the way checksums are calculated. check-in: 84955c2e user: dan tags: wal
02:37
Bring over the recent query planner enhancements from the trunk. check-in: 82969f27 user: drh tags: wal
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Changes to src/log.c.

137
138
139
140
141
142
143
144
145
146

147
148
149
150
151
152
153

154
155
156
157
158
159
160
161
162
163
164
165
166
167
....
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270


1271
1272
1273
1274
1275
1276
1277
....
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369




1370
1371
1372
1373
1374
1375
1376
....
1531
1532
1533
1534
1535
1536
1537


1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
/*
** Generate an 8 byte checksum based on the data in array aByte[] and the
** initial values of aCksum[0] and aCksum[1]. The checksum is written into
** aCksum[] before returning.
*/
#define LOG_CKSM_BYTES 8
static void logChecksumBytes(u8 *aByte, int nByte, u32 *aCksum){
  u32 *z32 = (u32 *)aByte;
  int n32 = nByte / sizeof(u32);
  int i;


  assert( LOG_CKSM_BYTES==2*sizeof(u32) );
  assert( (nByte&0x00000003)==0 );

  u32 cksum0 = aCksum[0];
  u32 cksum1 = aCksum[1];


  for(i=0; i<n32; i++){
    cksum0 = (cksum0 >> 8) + (cksum0 ^ z32[i]);
    cksum1 = (cksum1 >> 8) + (cksum1 ^ z32[i]);
  }

  aCksum[0] = cksum0;
  aCksum[1] = cksum1;
}

/*
** Argument zPath must be a nul-terminated string containing a path-name.
** This function modifies the string in-place by removing any "./" or "../" 
** elements in the path. For example, the following input:
**
................................................................................
  if( pLog->isLocked ){
    assert( pLog->isLocked==LOG_REGION_A || pLog->isLocked==LOG_REGION_D );
    logLockRegion(pLog, pLog->isLocked, LOG_UNLOCK);
  }
  pLog->isLocked = 0;
}



/* 
** Read a page from the log, if it is present. 
*/
int sqlite3LogRead(Log *pLog, Pgno pgno, int *pInLog, u8 *pOut){
  u32 iRead = 0;
  u32 *aData = pLog->pSummary->aData;
  int iFrame = (pLog->hdr.iLastPg & 0xFFFFFF00);



  /* Do a linear search of the unindexed block of page-numbers (if any) 
  ** at the end of the log-summary. An alternative to this would be to
  ** build an index in private memory each time a read transaction is
  ** opened on a new snapshot.
  */
  if( pLog->hdr.iLastPg ){
................................................................................

    /* Obtain the writer lock */
    int rc = logLockRegion(pLog, LOG_REGION_C|LOG_REGION_D, LOG_WRLOCK);
    if( rc!=SQLITE_OK ){
      return rc;
    }

    /* If this is connection is a region D, then the SHARED lock on region
    ** D has just been upgraded to EXCLUSIVE. But no lock at all is held on
    ** region A. This means that if the write-transaction is committed
    ** and this connection downgrades to a reader, it will be left with no
    ** lock at all. And its snapshot could get clobbered by a checkpoint
    ** operation. 
    **
    ** To stop this from happening, grab a SHARED lock on region A now.
    ** This should always be successful, as the only time a client holds
    ** an EXCLUSIVE lock on region A, it must also be holding an EXCLUSIVE
    ** lock on region C (a checkpointer does this). This is not possible,
    ** as this connection currently has the EXCLUSIVE lock on region C.
    */
    if( pLog->isLocked==LOG_REGION_D ){
      logLockRegion(pLog, LOG_REGION_A, LOG_RDLOCK);
      pLog->isLocked = LOG_REGION_A;
    }





    if( memcmp(&pLog->hdr, pLog->pSummary->aData, sizeof(pLog->hdr)) ){
      logLockRegion(pLog, LOG_REGION_C|LOG_REGION_D, LOG_UNLOCK);
      return SQLITE_BUSY;
    }
    pLog->isWriteLocked = 1;

  }else if( pLog->isWriteLocked ){
................................................................................
  sqlite3_file *pFd,              /* File descriptor open on db file */
  u8 *zBuf,                       /* Temporary buffer to use */
  int (*xBusyHandler)(void *),    /* Pointer to busy-handler function */
  void *pBusyHandlerArg           /* Argument to pass to xBusyHandler */
){
  int rc;                         /* Return code */



  /* Wait for a write-lock on regions B and C. */
  do {
    rc = logLockRegion(pLog, LOG_REGION_B|LOG_REGION_C, LOG_WRLOCK);
  }while( rc==SQLITE_BUSY && xBusyHandler(pBusyHandlerArg) );
  if( rc!=SQLITE_OK ) return rc;

  /* Wait for a write-lock on region A. */
  do {
    rc = logLockRegion(pLog, LOG_REGION_A, LOG_WRLOCK);
  }while( rc==SQLITE_BUSY && xBusyHandler(pBusyHandlerArg) );
  if( rc!=SQLITE_OK ){
    logLockRegion(pLog, LOG_REGION_B|LOG_REGION_C, LOG_UNLOCK);
    return rc;
  }







|
|
|
>




|
|
<
>
|
<
<
|
<
|
|







 







<
<







>
>







 







|
|
|

|













>
>
>
>







 







>
>
|





|







137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153

154
155


156

157
158
159
160
161
162
163
164
165
....
1253
1254
1255
1256
1257
1258
1259


1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
....
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
....
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
/*
** Generate an 8 byte checksum based on the data in array aByte[] and the
** initial values of aCksum[0] and aCksum[1]. The checksum is written into
** aCksum[] before returning.
*/
#define LOG_CKSM_BYTES 8
static void logChecksumBytes(u8 *aByte, int nByte, u32 *aCksum){
  u64 sum1 = aCksum[0];
  u64 sum2 = aCksum[1];
  u32 *a32 = (u32 *)aByte;
  u32 *aEnd = (u32 *)&aByte[nByte];

  assert( LOG_CKSM_BYTES==2*sizeof(u32) );
  assert( (nByte&0x00000003)==0 );

  do {
    sum1 += (*a32++);

    sum2 += sum1;
  } while( a32<aEnd );




  aCksum[0] = sum1 + (sum1>>24);
  aCksum[1] = sum2 + (sum2>>24);
}

/*
** Argument zPath must be a nul-terminated string containing a path-name.
** This function modifies the string in-place by removing any "./" or "../" 
** elements in the path. For example, the following input:
**
................................................................................
  if( pLog->isLocked ){
    assert( pLog->isLocked==LOG_REGION_A || pLog->isLocked==LOG_REGION_D );
    logLockRegion(pLog, pLog->isLocked, LOG_UNLOCK);
  }
  pLog->isLocked = 0;
}



/* 
** Read a page from the log, if it is present. 
*/
int sqlite3LogRead(Log *pLog, Pgno pgno, int *pInLog, u8 *pOut){
  u32 iRead = 0;
  u32 *aData = pLog->pSummary->aData;
  int iFrame = (pLog->hdr.iLastPg & 0xFFFFFF00);

  assert( pLog->isLocked );

  /* Do a linear search of the unindexed block of page-numbers (if any) 
  ** at the end of the log-summary. An alternative to this would be to
  ** build an index in private memory each time a read transaction is
  ** opened on a new snapshot.
  */
  if( pLog->hdr.iLastPg ){
................................................................................

    /* Obtain the writer lock */
    int rc = logLockRegion(pLog, LOG_REGION_C|LOG_REGION_D, LOG_WRLOCK);
    if( rc!=SQLITE_OK ){
      return rc;
    }

    /* If this is connection is a region D reader, then the SHARED lock on 
    ** region D has just been upgraded to EXCLUSIVE. But no lock at all is 
    ** held on region A. This means that if the write-transaction is committed
    ** and this connection downgrades to a reader, it will be left with no
    ** lock at all. And so its snapshot could get clobbered by a checkpoint
    ** operation. 
    **
    ** To stop this from happening, grab a SHARED lock on region A now.
    ** This should always be successful, as the only time a client holds
    ** an EXCLUSIVE lock on region A, it must also be holding an EXCLUSIVE
    ** lock on region C (a checkpointer does this). This is not possible,
    ** as this connection currently has the EXCLUSIVE lock on region C.
    */
    if( pLog->isLocked==LOG_REGION_D ){
      logLockRegion(pLog, LOG_REGION_A, LOG_RDLOCK);
      pLog->isLocked = LOG_REGION_A;
    }

    /* 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( memcmp(&pLog->hdr, pLog->pSummary->aData, sizeof(pLog->hdr)) ){
      logLockRegion(pLog, LOG_REGION_C|LOG_REGION_D, LOG_UNLOCK);
      return SQLITE_BUSY;
    }
    pLog->isWriteLocked = 1;

  }else if( pLog->isWriteLocked ){
................................................................................
  sqlite3_file *pFd,              /* File descriptor open on db file */
  u8 *zBuf,                       /* Temporary buffer to use */
  int (*xBusyHandler)(void *),    /* Pointer to busy-handler function */
  void *pBusyHandlerArg           /* Argument to pass to xBusyHandler */
){
  int rc;                         /* Return code */

  assert( !pLog->isLocked );

  /* Wait for an EXCLUSIVE lock on regions B and C. */
  do {
    rc = logLockRegion(pLog, LOG_REGION_B|LOG_REGION_C, LOG_WRLOCK);
  }while( rc==SQLITE_BUSY && xBusyHandler(pBusyHandlerArg) );
  if( rc!=SQLITE_OK ) return rc;

  /* Wait for an EXCLUSIVE lock on region A. */
  do {
    rc = logLockRegion(pLog, LOG_REGION_A, LOG_WRLOCK);
  }while( rc==SQLITE_BUSY && xBusyHandler(pBusyHandlerArg) );
  if( rc!=SQLITE_OK ){
    logLockRegion(pLog, LOG_REGION_B|LOG_REGION_C, LOG_UNLOCK);
    return rc;
  }