/ Check-in [7aade899]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Add several EXPENSIVE_ASSERT code blocks to validate the wal-index hash table. Fix the bugs that these code blocks fine. Rename walClearHash() to walCleanupHash() and simplify its interface.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 7aade899e55f4565f02d301e1e83fb0bac2ea500
User & Date: drh 2010-05-22 00:55:40
Context
2010-05-22
08:22
Add a couple of missing methods to test_osinst.c.. check-in: 5c9e9c06 user: dan tags: trunk
00:55
Add several EXPENSIVE_ASSERT code blocks to validate the wal-index hash table. Fix the bugs that these code blocks fine. Rename walClearHash() to walCleanupHash() and simplify its interface. check-in: 7aade899 user: drh tags: trunk
2010-05-21
19:15
Fix another bug in walClearHash(). check-in: 40f80ffe user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/wal.c.

648
649
650
651
652
653
654
655




























656
657
658
659
660
661
662
....
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486

1487
1488
1489
1490
1491



1492
1493
1494
1495
1496
1497
1498
1499
1500















1501
1502
1503
1504
1505
1506
1507
....
1517
1518
1519
1520
1521
1522
1523


1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
....
1544
1545
1546
1547
1548
1549
1550


1551

1552
1553

1554
1555
1556

1557
1558
1559
1560
1561
1562
1563
    if( idx==1 ) memset((void*)aHash, 0, HASHTABLE_NBYTE);
    assert( idx <= HASHTABLE_NSLOT/2 + 1 );
    aPgno[iFrame] = iPage;
    for(iKey=walHash(iPage); aHash[iKey]; iKey=walNextHash(iKey)){
      assert( nCollide++ < idx );
    }
    aHash[iKey] = idx;
  }





























  return rc;
}


/*
** Recover the wal-index by reading the write-ahead log file. 
................................................................................
  }else if( pWal->lockState==SQLITE_SHM_WRITE ){
    rc = walSetLock(pWal, SQLITE_SHM_READ);
  }
  return rc;
}

/*
** Remove entries from zero or more hash-table indexes in the wal-index 
** file.
**
** This function is called when rolling back a transaction or savepoint
** transaction in WAL mode. Argument iNewMx is the value that 
** Wal.hdr.mxFrame will be set to following the rollback. Argument iOldMx
** is the value that it had before the rollback. This function removes 
** entries that refer to frames with frame numbers greater than iNewMx 
** from the hash table that contains the entry associated with iNewMx.
** It is not necessary to remove any entries from any subsequent hash
** tables, as they will be zeroed by walIndexAppend() before they are
** next used.
*/
static void walClearHash(Wal *pWal, u32 iOldMx, u32 iNewMx){
  if( iOldMx>iNewMx ){
    volatile HASHTABLE_DATATYPE *aHash;     /* Pointer to hash table to clear */
    volatile u32 *unused1;                  /* Only to satisfy walHashFind() */

    u32 iZero;                              /* frame == (aHash[x]+iZero) */
    int iLimit;                             /* Zero values greater than this */

    walHashFind(pWal, iNewMx+1, &aHash, &unused1, &iZero);
    iLimit = iNewMx - iZero;



    if( iLimit>0 ){
      int i;                      /* Used to iterate through aHash[] */
      for(i=0; i<HASHTABLE_NSLOT; i++){
        if( aHash[i]>iLimit ){
          aHash[i] = 0;
        }
      }
    }
  }















}

/*
** If any data has been written (but not committed) to the log file, this
** function moves the write-pointer back to the start of the transaction.
**
** Additionally, the callback function is invoked for each frame written
................................................................................
  if( pWal->lockState==SQLITE_SHM_WRITE ){
    int unused;
    Pgno iMax = pWal->hdr.mxFrame;
    Pgno iFrame;
  
    assert( pWal->pWiData==0 );
    rc = walIndexReadHdr(pWal, &unused);


    for(iFrame=pWal->hdr.mxFrame+1; rc==SQLITE_OK && iFrame<=iMax; iFrame++){
      assert( pWal->lockState==SQLITE_SHM_WRITE );
      rc = xUndo(pUndoCtx, pWal->pWiData[walIndexEntry(iFrame)]);
    }
    if( rc==SQLITE_OK ){
      walClearHash(pWal, iMax, pWal->hdr.mxFrame);
    }
    walIndexUnmap(pWal);
  }
  return rc;
}

/* Return an integer that records the current (uncommitted) write
................................................................................
/* Move the write position of the WAL back to iFrame.  Called in
** response to a ROLLBACK TO command.
*/
int sqlite3WalSavepointUndo(Wal *pWal, u32 iFrame){
  int rc = SQLITE_OK;
  assert( pWal->lockState==SQLITE_SHM_WRITE );



  rc = walIndexMap(pWal, walMappingSize(pWal->hdr.mxFrame));

  if( rc==SQLITE_OK ){
    walClearHash(pWal, pWal->hdr.mxFrame, iFrame);

    walIndexUnmap(pWal);
  }
  pWal->hdr.mxFrame = iFrame;

  return rc;
}

/* 
** Write a set of frames to the log. The caller must hold the write-lock
** on the log file (obtained using sqlite3WalWriteLock()).
*/







|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
|

|
|
|
|
|
|
<
<
<

|
<
|
<
>
|
|

<
<
>
>
>
|
|
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
|
|
|
|
<
<







 







>
>
|
>
|
<
>
|
|
<
>







648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
....
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506



1507
1508

1509

1510
1511
1512
1513


1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
....
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569


1570
1571
1572
1573
1574
1575
1576
....
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595

1596
1597
1598

1599
1600
1601
1602
1603
1604
1605
1606
    if( idx==1 ) memset((void*)aHash, 0, HASHTABLE_NBYTE);
    assert( idx <= HASHTABLE_NSLOT/2 + 1 );
    aPgno[iFrame] = iPage;
    for(iKey=walHash(iPage); aHash[iKey]; iKey=walNextHash(iKey)){
      assert( nCollide++ < idx );
    }
    aHash[iKey] = idx;

#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
    /* Verify that the number of entries in the hash table exactly equals
    ** the number of entries in the mapping region.
    */
    {
      int i;           /* Loop counter */
      int nEntry = 0;  /* Number of entries in the hash table */
      for(i=0; i<HASHTABLE_NSLOT; i++){ if( aHash[i] ) nEntry++; }
      assert( nEntry==idx );
    }

    /* Verify that the every entry in the mapping region is reachable
    ** via the hash table.  This turns out to be a really, really expensive
    ** thing to check, so only do this occasionally - not on every
    ** iteration.
    */
    if( (idx&0x3ff)==0 ){
      int i;           /* Loop counter */
      for(i=1; i<=idx; i++){
        for(iKey=walHash(aPgno[i+iZero]); aHash[iKey]; iKey=walNextHash(iKey)){
          if( aHash[iKey]==i ) break;
        }
        assert( aHash[iKey]==i );
      }
    }
#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
  }


  return rc;
}


/*
** Recover the wal-index by reading the write-ahead log file. 
................................................................................
  }else if( pWal->lockState==SQLITE_SHM_WRITE ){
    rc = walSetLock(pWal, SQLITE_SHM_READ);
  }
  return rc;
}

/*
** Remove entries from the hash table that point to WAL slots greater
** than pWal->hdr.mxFrame.
**
** This function is called whenever pWal->hdr.mxFrame is decreased due
** to a rollback or savepoint.
**
** At most only the very last hash table needs to be updated.  Any
** later hash tables will be automatically cleared when pWal->hdr.mxFrame
** advances to the point where those hash tables are actually needed.



*/
static void walCleanupHash(Wal *pWal){

  volatile HASHTABLE_DATATYPE *aHash;  /* Pointer to hash table to clear */

  volatile u32 *aPgno;                 /* Unused return from walHashFind() */
  u32 iZero;                           /* frame == (aHash[x]+iZero) */
  int iLimit;                          /* Zero values greater than this */



  assert( pWal->lockState==SQLITE_SHM_WRITE );
  walHashFind(pWal, pWal->hdr.mxFrame+1, &aHash, &aPgno, &iZero);
  iLimit = pWal->hdr.mxFrame - iZero;
  if( iLimit>0 ){
    int i;                      /* Used to iterate through aHash[] */
    for(i=0; i<HASHTABLE_NSLOT; i++){
      if( aHash[i]>iLimit ){
        aHash[i] = 0;
      }
    }
  }

#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
  /* Verify that the every entry in the mapping region is still reachable
  ** via the hash table even after the cleanup.
  */
  {
    int i;           /* Loop counter */
    int iKey;        /* Hash key */
    for(i=1; i<=iLimit; i++){
      for(iKey=walHash(aPgno[i+iZero]); aHash[iKey]; iKey=walNextHash(iKey)){
        if( aHash[iKey]==i ) break;
      }
      assert( aHash[iKey]==i );
    }
  }
#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
}

/*
** If any data has been written (but not committed) to the log file, this
** function moves the write-pointer back to the start of the transaction.
**
** Additionally, the callback function is invoked for each frame written
................................................................................
  if( pWal->lockState==SQLITE_SHM_WRITE ){
    int unused;
    Pgno iMax = pWal->hdr.mxFrame;
    Pgno iFrame;
  
    assert( pWal->pWiData==0 );
    rc = walIndexReadHdr(pWal, &unused);
    if( rc==SQLITE_OK ){
      walCleanupHash(pWal);
      for(iFrame=pWal->hdr.mxFrame+1; rc==SQLITE_OK && iFrame<=iMax; iFrame++){
        assert( pWal->lockState==SQLITE_SHM_WRITE );
        rc = xUndo(pUndoCtx, pWal->pWiData[walIndexEntry(iFrame)]);
      }


    }
    walIndexUnmap(pWal);
  }
  return rc;
}

/* Return an integer that records the current (uncommitted) write
................................................................................
/* Move the write position of the WAL back to iFrame.  Called in
** response to a ROLLBACK TO command.
*/
int sqlite3WalSavepointUndo(Wal *pWal, u32 iFrame){
  int rc = SQLITE_OK;
  assert( pWal->lockState==SQLITE_SHM_WRITE );

  assert( iFrame<=pWal->hdr.mxFrame );
  if( iFrame<pWal->hdr.mxFrame ){
    rc = walIndexMap(pWal, walMappingSize(pWal->hdr.mxFrame));
    pWal->hdr.mxFrame = iFrame;
    if( rc==SQLITE_OK ){

      walCleanupHash(pWal);
      walIndexUnmap(pWal);
    }

  }
  return rc;
}

/* 
** Write a set of frames to the log. The caller must hold the write-lock
** on the log file (obtained using sqlite3WalWriteLock()).
*/