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

Overview
Comment:Fix a problem with skipping past a section of log still in use.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: f96d7603553043f5f93625dfeb290b537ca19077
User & Date: dan 2013-11-02 18:28:39.530
Context
2013-11-04
18:21
Fix various multi-client bugs preventing the multi-threaded tests from passing. check-in: 3c32332c59 user: dan tags: trunk
2013-11-02
18:28
Fix a problem with skipping past a section of log still in use. check-in: f96d760355 user: dan tags: trunk
10:31
Modify the way read-locks are taken to avoid unnecessary SQLITE4_BUSY errors. check-in: 1d06636492 user: dan tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/bt_log.c.
240
241
242
243
244
245
246

247
248

249

250
251
252
253

254
255
256
257
258
259
260
261
262
263
264
  u32 *aOut                       /* OUT: Final checksum value output */
){
  assert( (nByte&0x00000007)==4 && nByte>=8 );
  btLogChecksum(nativeCksum, a, 8, aIn, aOut);
  btLogChecksum(nativeCksum, &a[4], nByte-4, aOut, aOut);
}



static void btDebugTopology(char *zStr, u32 *aLog){

  fprintf(stderr, "%s: %d..%d  %d..%d  %d..%d\n", zStr,

      (int)aLog[0], (int)aLog[1], (int)aLog[2], 
      (int)aLog[3], (int)aLog[4], (int)aLog[5]
  );
  fflush(stderr);

}

#define BT_PAGE_DEBUG 0

#ifndef NDEBUG
static void btDebugCheckSnapshot(BtShmHdr *pHdr){
  u32 *aLog = pHdr->aLog;
  assert( pHdr->iNextFrame!=1 ||
      (aLog[0]==0 && aLog[1]==0 && aLog[2]==0 && aLog[3]==0)
  );
}







>

|
>
|
>




>


<
<







240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259


260
261
262
263
264
265
266
  u32 *aOut                       /* OUT: Final checksum value output */
){
  assert( (nByte&0x00000007)==4 && nByte>=8 );
  btLogChecksum(nativeCksum, a, 8, aIn, aOut);
  btLogChecksum(nativeCksum, &a[4], nByte-4, aOut, aOut);
}

#define BT_PAGE_DEBUG 0

static void btDebugTopology(BtLock *pLock, char *zStr, int iSide, u32 *aLog){
#if BT_PAGE_DEBUG
  fprintf(stderr, "%d:%s: (side=%d) %d..%d  %d..%d  %d..%d\n", 
      pLock->iDebugId, zStr, iSide,
      (int)aLog[0], (int)aLog[1], (int)aLog[2], 
      (int)aLog[3], (int)aLog[4], (int)aLog[5]
  );
  fflush(stderr);
#endif
}



#ifndef NDEBUG
static void btDebugCheckSnapshot(BtShmHdr *pHdr){
  u32 *aLog = pHdr->aLog;
  assert( pHdr->iNextFrame!=1 ||
      (aLog[0]==0 && aLog[1]==0 && aLog[2]==0 && aLog[3]==0)
  );
}
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319











320

321
322
323
324
325
326
327
      nCall++, (int)pgno, aCksum[0], aCksum[1]
  );
  fflush(stderr);
#endif
}
#endif

#ifndef NDEBUG
static void btDebugLogSearch(BtLock *pLock, u32 pgno, u32 iFrame){
#if BT_PAGE_DEBUG
  static int nCall = 0;
  fprintf(stderr, "%d:%d: Search log for page %d - frame %d\n", pLock->iDebugId,
      nCall++, (int)pgno, (int)iFrame
  );
  fflush(stderr);
#endif
}











#endif


/*
** Ensure that shared-memory chunk iChunk is mapped and available in
** the BtLog.apShm[] array. If an error occurs, return an SQLite4 error
** code. Otherwise, SQLITE4_OK.
*/
static int btLogMapShm(BtLog *pLog, int iChunk){







<









>
>
>
>
>
>
>
>
>
>
>

>







305
306
307
308
309
310
311

312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
      nCall++, (int)pgno, aCksum[0], aCksum[1]
  );
  fflush(stderr);
#endif
}
#endif


static void btDebugLogSearch(BtLock *pLock, u32 pgno, u32 iFrame){
#if BT_PAGE_DEBUG
  static int nCall = 0;
  fprintf(stderr, "%d:%d: Search log for page %d - frame %d\n", pLock->iDebugId,
      nCall++, (int)pgno, (int)iFrame
  );
  fflush(stderr);
#endif
}

static void btDebugSetPgno(
    BtLock *pLock, int iHash, u32 *aPgno, int iFrame, int iZero, u32 pgno
){
#if BT_PAGE_DEBUG
  static int nCall = 0;
  fprintf(stderr, "%d:%d: Set iHash=%d aPgno=%p iFrame=%d iZero=%d pgno=%d\n",
      pLock->iDebugId, nCall++, iHash,
      (void*)aPgno, iFrame, iZero, (int)pgno
  );
  fflush(stderr);
#endif
}

/*
** Ensure that shared-memory chunk iChunk is mapped and available in
** the BtLog.apShm[] array. If an error occurs, return an SQLite4 error
** code. Otherwise, SQLITE4_OK.
*/
static int btLogMapShm(BtLog *pLog, int iChunk){
536
537
538
539
540
541
542

543
544
545
546
547
548
549
  rc = btLogFindHash(pLog, iSide, iHash, &aHash, &aPgno, &iZero);

  /* Update the hash table */
  if( rc==SQLITE4_OK ){
    int iSlot;
    int nCollide = HASHTABLE_NSLOT*2;
    aPgno[iFrame-iZero] = pgno;


    if( iFrame==iZero ){
      memset(aHash, 0, sizeof(ht_slot) * HASHTABLE_NSLOT);
    }

    for(iSlot=btLogHashKey(pLog,pgno); ; iSlot=btLogHashNext(pLog, iSlot)){
      if( aHash[iSlot]==0 ){







>







549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
  rc = btLogFindHash(pLog, iSide, iHash, &aHash, &aPgno, &iZero);

  /* Update the hash table */
  if( rc==SQLITE4_OK ){
    int iSlot;
    int nCollide = HASHTABLE_NSLOT*2;
    aPgno[iFrame-iZero] = pgno;
btDebugSetPgno(pLog->pLock, iHash, aPgno, iFrame, iZero, pgno);

    if( iFrame==iZero ){
      memset(aHash, 0, sizeof(ht_slot) * HASHTABLE_NSLOT);
    }

    for(iSlot=btLogHashKey(pLog,pgno); ; iSlot=btLogHashNext(pLog, iSlot)){
      if( aHash[iSlot]==0 ){
982
983
984
985
986
987
988














989
990
991
992
993
994
995
**
** If any other error occurs, an SQLite4 error code is returned. The final
** state of buffer aData[] is undefined in this case.
*/
int sqlite4BtLogRead(BtLog *pLog, u32 pgno, u8 *aData){
  return btLogRead(pLog, pgno, aData, 0);
}















/*
** Write a frame to the log file.
*/
int sqlite4BtLogWrite(BtLog *pLog, u32 pgno, u8 *aData, u32 nPg){
  const int pgsz = sqlite4BtPagerPagesize((BtPager*)(pLog->pLock));
  int rc = SQLITE4_OK;







>
>
>
>
>
>
>
>
>
>
>
>
>
>







996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
**
** If any other error occurs, an SQLite4 error code is returned. The final
** state of buffer aData[] is undefined in this case.
*/
int sqlite4BtLogRead(BtLog *pLog, u32 pgno, u8 *aData){
  return btLogRead(pLog, pgno, aData, 0);
}

static int btLogZeroHash(BtLog *pLog, int iHash){
  int iSide = pLog->snapshot.iHashSide;
  ht_slot *aHash;
  u32 *aPgno;
  u32 iZero;
  int rc;

  rc = btLogFindHash(pLog, iSide, iHash, &aHash, &aPgno, &iZero);
  if( rc==SQLITE4_OK ){
    memset(aHash, 0, sizeof(ht_slot)*HASHTABLE_NSLOT);
  }
  return rc;
}

/*
** Write a frame to the log file.
*/
int sqlite4BtLogWrite(BtLog *pLog, u32 pgno, u8 *aData, u32 nPg){
  const int pgsz = sqlite4BtPagerPagesize((BtPager*)(pLog->pLock));
  int rc = SQLITE4_OK;
1059
1060
1061
1062
1063
1064
1065
1066


1067



1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086

1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099

1100
1101
1102
1103
1104
1105
1106
  ){
    /* Case 2) It is possible to wrap the log around */
    iNextFrame = 1;
  }else if( iNextFrame==aLog[0] ){
    /* Case 3) It is necessary to jump over some existing log. */
    iNextFrame = aLog[1]+1;
    assert( iNextFrame!=1 );
  }






  if( iNextFrame & 0x80000000 ){
    rc = SQLITE4_FULL;
  }else{

    /* Populate the frame header object. */
    memset(&frame, 0, sizeof(frame));
    frame.pgno = pgno;
    frame.iNext = iNextFrame;
    frame.nPg = nPg;
    a = pLog->snapshot.aFrameCksum;
    btLogChecksum32(1, (u8*)&frame, offsetof(BtFrameHdr,aCksum),a,frame.aCksum);
    btLogChecksum(1, aData, pgsz, frame.aCksum, frame.aCksum);

    btDebugLogPage(pLog->pLock, pgno, iFrame, aData, pgsz, nPg);

    /* Write the frame header to the log file. */
    rc = btLogWriteData(pLog, iOff, (u8*)&frame, sizeof(frame));
  }
  pLog->snapshot.iNextFrame = iNextFrame;


  /* Write the frame contents to the log file. */
  if( rc==SQLITE4_OK ){
    rc = btLogWriteData(pLog, iOff+sizeof(frame), aData, pgsz);
  }

  /* Update the wal index hash tables with the (pgno -> iFrame) record. 
  ** If this is a commit frame, update the nPg field as well. */
  if( rc==SQLITE4_OK ){
    if( iFrame==1 ){
      pLog->snapshot.iHashSide = (pLog->snapshot.iHashSide+1) %2;
    }
    if( nPg ) pLog->snapshot.nPg = nPg;

    rc = btLogHashInsert(pLog, pgno, iFrame);
  }

  /* Update the private copy of the shm-header */
  btDebugCheckSnapshot(&pLog->snapshot);
  BtShmHdr hdr;
  memcpy(&hdr, &pLog->snapshot, sizeof(BtShmHdr));







|
>
>
|
>
>
>
|
|
|

|
|
|
|
|
|
|
|

|

|
|
|
|
>










|


>







1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
  ){
    /* Case 2) It is possible to wrap the log around */
    iNextFrame = 1;
  }else if( iNextFrame==aLog[0] ){
    /* Case 3) It is necessary to jump over some existing log. */
    iNextFrame = aLog[1]+1;
    assert( iNextFrame!=1 );

    if( btLogFrameHash(pLog, iNextFrame)!=btLogFrameHash(pLog, iFrame) ){
      rc = btLogZeroHash(pLog, btLogFrameHash(pLog, iNextFrame));
    }
  }

  if( rc==SQLITE4_OK ){
    if( iNextFrame & 0x80000000 ){
      rc = SQLITE4_FULL;
    }else{

      /* Populate the frame header object. */
      memset(&frame, 0, sizeof(frame));
      frame.pgno = pgno;
      frame.iNext = iNextFrame;
      frame.nPg = nPg;
      a = pLog->snapshot.aFrameCksum;
      btLogChecksum32(1,(u8*)&frame,offsetof(BtFrameHdr,aCksum),a,frame.aCksum);
      btLogChecksum(1, aData, pgsz, frame.aCksum, frame.aCksum);

      btDebugLogPage(pLog->pLock, pgno, iFrame, aData, pgsz, nPg);

      /* Write the frame header to the log file. */
      rc = btLogWriteData(pLog, iOff, (u8*)&frame, sizeof(frame));
    }
    pLog->snapshot.iNextFrame = iNextFrame;
  }

  /* Write the frame contents to the log file. */
  if( rc==SQLITE4_OK ){
    rc = btLogWriteData(pLog, iOff+sizeof(frame), aData, pgsz);
  }

  /* Update the wal index hash tables with the (pgno -> iFrame) record. 
  ** If this is a commit frame, update the nPg field as well. */
  if( rc==SQLITE4_OK ){
    if( iFrame==1 ){
      pLog->snapshot.iHashSide = (pLog->snapshot.iHashSide+1) % 2;
    }
    if( nPg ) pLog->snapshot.nPg = nPg;

    rc = btLogHashInsert(pLog, pgno, iFrame);
  }

  /* Update the private copy of the shm-header */
  btDebugCheckSnapshot(&pLog->snapshot);
  BtShmHdr hdr;
  memcpy(&hdr, &pLog->snapshot, sizeof(BtShmHdr));
1219
1220
1221
1222
1223
1224
1225






1226
1227
1228
1229
1230
1231
1232
        }else{
          aLog[iRegion*2] = 0;
          aLog[iRegion*2+1] = 0;
        }
      }
    }
  }







  return rc;
}

int sqlite4BtLogSnapshotClose(BtLog *pLog){
  sqlite4BtLockReaderUnlock(pLog->pLock);
  return SQLITE4_OK;







>
>
>
>
>
>







1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
        }else{
          aLog[iRegion*2] = 0;
          aLog[iRegion*2+1] = 0;
        }
      }
    }
  }

if( rc==SQLITE4_OK ){
  btDebugTopology(
      pLog->pLock, "snapshot", pLog->snapshot.iHashSide, pLog->snapshot.aLog
  );
}

  return rc;
}

int sqlite4BtLogSnapshotClose(BtLog *pLog){
  sqlite4BtLockReaderUnlock(pLog->pLock);
  return SQLITE4_OK;