SQLite

Check-in [bebd967f36]
Login

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

Overview
Comment:Add code to create/update the btree 'pointer-map' for auto-vacuum mode. (CVS 2035)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: bebd967f3627220c3ce0352c8ca9c7c17b722ce6
User & Date: danielk1977 2004-10-31 16:25:43.000
Context
2004-11-01
16:03
Updates to the support.html page. (CVS 2036) (check-in: 5515accee3 user: drh tags: trunk)
2004-10-31
16:25
Add code to create/update the btree 'pointer-map' for auto-vacuum mode. (CVS 2035) (check-in: bebd967f36 user: danielk1977 tags: trunk)
02:22
Insert #ifdefs that can optionally remove features at compiletime resulting in a database engine with a smaller footprint. (CVS 2034) (check-in: be661acfa8 user: drh tags: trunk)
Changes
Side-by-Side Diff Ignore Whitespace Patch
Changes to src/btree.c.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
19











-
+







/*
** 2004 April 6
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.194 2004/10/31 02:22:49 drh Exp $
** $Id: btree.c,v 1.195 2004/10/31 16:25:43 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
**
**     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
**     "Sorting And Searching", pages 473-480. Addison-Wesley
**     Publishing Company, Reading, Massachusetts.
307
308
309
310
311
312
313



314
315
316
317
318
319
320
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323







+
+
+







  u16 pageSize;         /* Total number of bytes on a page */
  u16 psAligned;        /* pageSize rounded up to a multiple of 8 */
  u16 usableSize;       /* Number of usable bytes on each page */
  int maxLocal;         /* Maximum local payload in non-LEAFDATA tables */
  int minLocal;         /* Minimum local payload in non-LEAFDATA tables */
  int maxLeaf;          /* Maximum local payload in a LEAFDATA table */
  int minLeaf;          /* Minimum local payload in a LEAFDATA table */
#ifndef SQLITE_OMIT_AUTOVACUUM
  u8 autoVacuum;        /* True if database supports auto-vacuum */
#endif
};
typedef Btree Bt;

/*
** Btree.inTrans may take one of the following values.
*/
#define TRANS_NONE  0
387
388
389
390
391
392
393

























































































394
395
396
397
398
399
400
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







** be defined locally, but now we use the varint routines in the util.c
** file.
*/
#define getVarint    sqlite3GetVarint
#define getVarint32  sqlite3GetVarint32
#define putVarint    sqlite3PutVarint

#ifndef SQLITE_OMIT_AUTOVACUUM

/*
** These two macros define the location of the pointer-map entry for a 
** database page. The first argument to each is the page size used 
** by the database (often 1024). The second is the page number to look
** up in the pointer map.
**
** PTRMAP_PAGENO returns the database page number of the pointer-map
** page that stores the required pointer. PTRMAP_PTROFFSET returns
** the offset of the requested map entry.
**
** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page,
** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be
** used to test if pgno is a pointer-map page.
*/
#define PTRMAP_PAGENO(pgsz, pgno) (((pgno-2)/(pgsz/5+1))*(pgsz/5+1)+2)
#define PTRMAP_PTROFFSET(pgsz, pgno) (((pgno-2)%(pgsz/5+1)-1)*5)

/*
** The first byte of each 5-byte pointer map entry identifies the type
** of page that the following 4-byte page number refers to (either a
** regular btree page or an overflow page).
**
** If the type is PTRMAP_OVERFLOW, then the page is an overflow page.
** In this case the pointer is always the first 4 bytes of the page.
**
** If the type is PTRMAP_BTREE, then the page is a btree page. In this
** case the pointer may be a 'left-pointer' (stored following a cell-header), 
** a pointer to an overflow page (stored after a cell's data payload), 
** or the 'right pointer' of a btree page.
*/
#define PTRMAP_BTREE 1
#define PTRMAP_OVERFLOW 2

/*
** Write an entry into the pointer map.
*/
static int ptrmapPut(Btree *pBt, Pgno key, u8 eType, Pgno pgno){
  u8 *pPtrmap;    /* The pointer map page */
  Pgno iPtrmap;   /* The pointer map page number */
  int offset;     /* Offset in pointer map page */
  int rc;

  iPtrmap = PTRMAP_PAGENO(pBt->pageSize, key);
  rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
  if( rc!=0 ){
    return rc;
  }
  offset = PTRMAP_PTROFFSET(pBt->pageSize, key);

  if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=pgno ){
    rc = sqlite3pager_write(pPtrmap);
    if( rc!=0 ){
      return rc;
    }
    pPtrmap[offset] = eType;
    put4byte(&pPtrmap[offset+1], pgno);
  }

  sqlite3pager_unref(pPtrmap);
  return SQLITE_OK;
}

/*
** Read an entry from the pointer map.
*/
static int ptrmapGet(Btree *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
  int iPtrmap;       /* Pointer map page index */
  u8 *pPtrmap;       /* Pointer map page data */
  int offset;        /* Offset of entry in pointer map */
  int rc;

  iPtrmap = PTRMAP_PAGENO(pBt->pageSize, key);
  rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
  if( rc!=0 ){
    return rc;
  }

  offset = PTRMAP_PTROFFSET(pBt->pageSize, key);
  *pEType = pPtrmap[offset];
  *pPgno = get4byte(&pPtrmap[offset+1]);

  sqlite3pager_unref(pPtrmap);
  return SQLITE_OK;
}

#endif /* SQLITE_OMIT_AUTOVACUUM */

/*
** Given a btree page and a cell index (0 means the first cell on
** the page, 1 means the second cell, and so forth) return a pointer
** to the cell content.
**
** This routine works only for pages that do not contain overflow cells.
*/
1083
1084
1085
1086
1087
1088
1089




1090
1091
1092
1093
1094
1095
1096
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192







+
+
+
+







    pBt->minLeafFrac = zDbHeader[23];
    pBt->pageSizeFixed = 1;
  }
  pBt->usableSize = pBt->pageSize - nReserve;
  pBt->psAligned = FORCE_ALIGNMENT(pBt->pageSize);
  sqlite3pager_set_pagesize(pBt->pPager, pBt->pageSize);
  *ppBtree = pBt;
#ifdef SQLITE_AUTOVACUUM
  /* Note: This is temporary code for use during development of auto-vacuum. */
  pBt->autoVacuum = 1;
#endif
  return SQLITE_OK;
}

/*
** Close an open database and invalidate all cursors.
*/
int sqlite3BtreeClose(Btree *pBt){
2473
2474
2475
2476
2477
2478
2479












2480
2481
2482
2483
2484
2485
2486
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594







+
+
+
+
+
+
+
+
+
+
+
+







        rc = sqlite3pager_write((*ppPage)->aData);
      }
    }
  }else{
    /* There are no pages on the freelist, so create a new page at the
    ** end of the file */
    *pPgno = sqlite3pager_pagecount(pBt->pPager) + 1;

#ifndef SQLITE_OMIT_AUTOVACUUM
    if( pBt->autoVacuum && *pPgno==PTRMAP_PAGENO(pBt->pageSize, *pPgno) ){
      /* If *pPgno refers to a pointer-map page, allocate two new pages
      ** at the end of the file instead of one. The first allocated page
      ** becomes a new pointer-map page, the second is used by the caller.
      */
      TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", *pPgno));
      (*pPgno)++;
    }
#endif

    rc = getPage(pBt, *pPgno, ppPage);
    if( rc ) return rc;
    rc = sqlite3pager_write((*ppPage)->aData);
    TRACE(("ALLOCATE: %d from end of file\n", *pPgno));
  }
  return rc;
}
2633
2634
2635
2636
2637
2638
2639



2640















2641
2642
2643
2644
2645
2646
2647
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750

2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772







+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







  *pnSize = info.nSize;
  spaceLeft = info.nLocal;
  pPayload = &pCell[nHeader];
  pPrior = &pCell[info.iOverflow];

  while( nPayload>0 ){
    if( spaceLeft==0 ){
#ifndef SQLITE_OMIT_AUTOVACUUM
      Pgno pgnoPtrmap = pgnoOvfl; /* Overflow page pointer-map entry page */
#endif
      rc =  allocatePage(pBt, &pOvfl, &pgnoOvfl, pgnoOvfl);
      rc = allocatePage(pBt, &pOvfl, &pgnoOvfl, pgnoOvfl);
#ifndef SQLITE_OMIT_AUTOVACUUM
      /* If the database supports auto-vacuum, add an entry to the 
      ** pointer-map for the overflow page just allocated. If the page just 
      ** allocated was the first in the overflow list, then the balance() 
      ** routine may adjust the pointer-map entry later.
      */
      if( pBt->autoVacuum && rc==0 ){
        if( pgnoPtrmap!=0 ){
          rc = ptrmapPut(pBt, pgnoOvfl, PTRMAP_OVERFLOW, pgnoPtrmap);
        }else{
          rc = ptrmapPut(pBt, pgnoOvfl, PTRMAP_BTREE, pPage->pgno);
        }
      }
#endif
      if( rc ){
        releasePage(pToRelease);
        clearCell(pPage, pCell);
        return rc;
      }
      put4byte(pPrior, pgnoOvfl);
      releasePage(pToRelease);
2670
2671
2672
2673
2674
2675
2676
2677

2678
2679
2680
2681

2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696







2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709

2710
2711


2712

2713
2714





2715


2716
2717
2718
2719



























2720
2721
2722
2723
2724
2725
2726
2795
2796
2797
2798
2799
2800
2801

2802
2803
2804
2805

2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840

2841
2842

2843
2844
2845
2846


2847
2848
2849
2850
2851
2852
2853
2854




2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888







-
+



-
+















+
+
+
+
+
+
+












-
+

-
+
+

+
-
-
+
+
+
+
+

+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







}

/*
** Change the MemPage.pParent pointer on the page whose number is
** given in the second argument so that MemPage.pParent holds the
** pointer in the third argument.
*/
static void reparentPage(Btree *pBt, Pgno pgno, MemPage *pNewParent, int idx){
static int reparentPage(Btree *pBt, Pgno pgno, MemPage *pNewParent, int idx){
  MemPage *pThis;
  unsigned char *aData;

  if( pgno==0 ) return;
  if( pgno==0 ) return SQLITE_OK;
  assert( pBt->pPager!=0 );
  aData = sqlite3pager_lookup(pBt->pPager, pgno);
  if( aData ){
    pThis = (MemPage*)&aData[pBt->psAligned];
    assert( pThis->aData==aData );
    if( pThis->isInit ){
      if( pThis->pParent!=pNewParent ){
        if( pThis->pParent ) sqlite3pager_unref(pThis->pParent->aData);
        pThis->pParent = pNewParent;
        if( pNewParent ) sqlite3pager_ref(pNewParent->aData);
      }
      pThis->idxParent = idx;
    }
    sqlite3pager_unref(aData);
  }

#ifndef SQLITE_OMIT_AUTOVACUUM
  if( pBt->autoVacuum ){
    return ptrmapPut(pBt, pgno, PTRMAP_BTREE, pNewParent->pgno);
  }
#endif
  return SQLITE_OK;
}

/*
** Change the pParent pointer of all children of pPage to point back
** to pPage.
**
** In other words, for every child of pPage, invoke reparentPage()
** to make sure that each child knows that pPage is its parent.
**
** This routine gets called after you memcpy() one page into
** another.
*/
static void reparentChildPages(MemPage *pPage){
static int reparentChildPages(MemPage *pPage){
  int i;
  Btree *pBt;
  Btree *pBt = pPage->pBt;
  int rc = SQLITE_OK;

#ifdef SQLITE_OMIT_AUTOVACUUM
  if( pPage->leaf ) return;
  pBt = pPage->pBt;
  if( pPage->leaf ) return SQLITE_OK;
#else
  if( !pBt->autoVacuum && pPage->leaf ) return SQLITE_OK;
#endif

  for(i=0; i<pPage->nCell; i++){
    u8 *pCell = findCell(pPage, i);
    if( !pPage->leaf ){
    reparentPage(pBt, get4byte(findCell(pPage,i)), pPage, i);
  }
  reparentPage(pBt, get4byte(&pPage->aData[pPage->hdrOffset+8]), pPage, i);
  pPage->idxShift = 0;
      rc = reparentPage(pBt, get4byte(pCell), pPage, i);
      if( rc!=SQLITE_OK ) return rc;
    }
#ifndef SQLITE_OMIT_AUTOVACUUM
    /* If the database supports auto-vacuum, then check each cell to see
    ** if it contains a pointer to an overflow page. If so, then the 
    ** pointer-map must be updated accordingly.
    **
    ** TODO: This looks like quite an expensive thing to do. Investigate.
    */
    if( pBt->autoVacuum ){
      CellInfo info;
      parseCellPtr(pPage, pCell, &info);
      if( info.iOverflow ){
        Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]);
        rc = ptrmapPut(pBt, pgnoOvfl, PTRMAP_BTREE, pPage->pgno);
        if( rc!=SQLITE_OK ) return rc;
      }
    }
#endif
  }
  if( !pPage->leaf ){
    rc = reparentPage(pBt, get4byte(&pPage->aData[pPage->hdrOffset+8]), 
       pPage, i);
    pPage->idxShift = 0;
  }
  return rc;
}

/*
** Remove the i-th cell from pPage.  This routine effects pPage only.
** The cell content is not freed or deallocated.  It is assumed that
** the cell content has been copied someplace else.  This routine just
** removes the reference to the cell from pPage.
3308
3309
3310
3311
3312
3313
3314
3315


3316
3317


3318
3319
3320
3321
3322
3323
3324
3470
3471
3472
3473
3474
3475
3476

3477
3478
3479

3480
3481
3482
3483
3484
3485
3486
3487
3488







-
+
+

-
+
+







    put4byte(findOverflowCell(pParent, nxDiv), pgnoNew[nNew-1]);
  }

  /*
  ** Reparent children of all cells.
  */
  for(i=0; i<nNew; i++){
    reparentChildPages(apNew[i]);
    rc = reparentChildPages(apNew[i]);
    if( rc!=SQLITE_OK ) goto balance_cleanup;
  }
  reparentChildPages(pParent);
  rc = reparentChildPages(pParent);
  if( rc!=SQLITE_OK ) goto balance_cleanup;

  /*
  ** Balance the parent page.  Note that the current page (pPage) might
  ** have been added to the freelist is it might no longer be initialized.
  ** But the parent page will always be initialized.
  */
  assert( pParent->isInit );
3412
3413
3414
3415
3416
3417
3418
3419


3420
3421
3422
3423
3424
3425
3426
3576
3577
3578
3579
3580
3581
3582

3583
3584
3585
3586
3587
3588
3589
3590
3591







-
+
+







      pPage->pParent = 0;
      rc = initPage(pPage, 0);
      assert( rc==SQLITE_OK );
      freePage(pChild);
      TRACE(("BALANCE: transfer child %d into root %d\n",
              pChild->pgno, pPage->pgno));
    }
    reparentChildPages(pPage);
    rc = reparentChildPages(pPage);
    if( rc!=SQLITE_OK ) goto end_shallow_balance;
    releasePage(pChild);
  }
end_shallow_balance:
  sqliteFree(apCell);
  return rc;
}

4112
4113
4114
4115
4116
4117
4118
4119
4120
4121































4122
4123
4124
4125
4126
4127
4128
4277
4278
4279
4280
4281
4282
4283

4284

4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322







-

-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







  }
  if( pCheck->anRef[iPage]==1 ){
    checkAppendMsg(pCheck, zContext, "2nd reference to page %d", iPage);
    return 1;
  }
  return  (pCheck->anRef[iPage]++)>1;
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */

#ifndef SQLITE_OMIT_INTEGRITY_CHECK
#ifndef SQLITE_OMIT_AUTOVACUUM
/*
** Check that the entry in the pointer-map for page iChild maps to 
** page iParent, pointer type ptrType. If not, append an error message
** to pCheck.
*/
static void checkPtrmap(
  IntegrityCk *pCheck,   /* Integrity check context */
  Pgno iChild,           /* Child page number */
  u8 eType,              /* Expected pointer map type */
  Pgno iParent,          /* Expected pointer map parent page number */
  char *zContext         /* Context description (used for error msg) */
){
  int rc;
  u8 ePtrmapType;
  Pgno iPtrmapParent;

  rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent);
  if( rc!=SQLITE_OK ){
    checkAppendMsg(pCheck, zContext, "Failed to read ptrmap key=%d", iChild);
    return;
  }

  if( ePtrmapType!=eType || iPtrmapParent!=iParent ){
    checkAppendMsg(pCheck, zContext, 
      "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)", 
      iChild, eType, iParent, ePtrmapType, iPtrmapParent);
  }
}
#endif

/*
** Check the integrity of the freelist or of an overflow page list.
** Verify that the number of pages on the list is N.
*/
static void checkList(
  IntegrityCk *pCheck,  /* Integrity checking context */
  int isFreeList,       /* True for a freelist.  False for overflow page list */
4155
4156
4157
4158
4159
4160
4161










4162
4163
4164
4165
4166
4167
4168
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372







+
+
+
+
+
+
+
+
+
+







      }else{
        for(i=0; i<n; i++){
          checkRef(pCheck, get4byte(&pOvfl[8+i*4]), zContext);
        }
        N -= n;
      }
    }
#ifndef SQLITE_OMIT_AUTOVACUUM
    /* If this database supports auto-vacuum and iPage is not the last
    ** page in this overflow list, check that the pointer-map entry for
    ** the following page matches iPage.
    */
    if( pCheck->pBt->autoVacuum && !isFreeList && N>0 ){
      i = get4byte(pOvfl);
      checkPtrmap(pCheck, i, PTRMAP_OVERFLOW, iPage, zContext);
    }
#endif
    iPage = get4byte(pOvfl);
    sqlite3pager_unref(pOvfl);
  }
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */

#ifndef SQLITE_OMIT_INTEGRITY_CHECK
4237
4238
4239
4240
4241
4242
4243
4244







4245
4246
4247
4248
4249
4250





4251
4252
4253
4254
4255
4256
4257
4258
4259
4260





4261
4262
4263
4264
4265
4266
4267
4441
4442
4443
4444
4445
4446
4447

4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487







-
+
+
+
+
+
+
+






+
+
+
+
+










+
+
+
+
+







    sprintf(zContext, "On tree page %d cell %d: ", iPage, i);
    pCell = findCell(pPage,i);
    parseCellPtr(pPage, pCell, &info);
    sz = info.nData;
    if( !pPage->intKey ) sz += info.nKey;
    if( sz>info.nLocal ){
      int nPage = (sz - info.nLocal + usableSize - 5)/(usableSize - 4);
      checkList(pCheck, 0, get4byte(&pCell[info.iOverflow]),nPage,zContext);
      Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]);
#ifndef SQLITE_OMIT_AUTOVACUUM
      if( pBt->autoVacuum ){
        checkPtrmap(pCheck, pgnoOvfl, PTRMAP_BTREE, iPage, zContext);
      }
#endif
      checkList(pCheck, 0, pgnoOvfl, nPage, zContext);
    }

    /* Check sanity of left child page.
    */
    if( !pPage->leaf ){
      pgno = get4byte(pCell);
#ifndef SQLITE_OMIT_AUTOVACUUM
      if( pBt->autoVacuum ){
        checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, zContext);
      }
#endif
      d2 = checkTreePage(pCheck,pgno,pPage,zContext,0,0,0,0);
      if( i>0 && d2!=depth ){
        checkAppendMsg(pCheck, zContext, "Child page depth differs");
      }
      depth = d2;
    }
  }
  if( !pPage->leaf ){
    pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]);
    sprintf(zContext, "On page %d at right child: ", iPage);
#ifndef SQLITE_OMIT_AUTOVACUUM
    if( pBt->autoVacuum ){
      checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, zContext);
    }
#endif
    checkTreePage(pCheck, pgno, pPage, zContext,0,0,0,0);
  }
 
  /* Check for complete coverage of the page
  */
  data = pPage->aData;
  hdr = pPage->hdrOffset;
4351
4352
4353
4354
4355
4356
4357

4358
4359
4360













4361
4362
4363
4364
4365
4366
4367
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601







+



+
+
+
+
+
+
+
+
+
+
+
+
+







    if( aRoot[i]==0 ) continue;
    checkTreePage(&sCheck, aRoot[i], 0, "List of tree roots: ", 0,0,0,0);
  }

  /* Make sure every page in the file is referenced
  */
  for(i=1; i<=sCheck.nPage; i++){
#ifdef SQLITE_OMIT_AUTOVACUUM
    if( sCheck.anRef[i]==0 ){
      checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
    }
#else
    /* If the database supports auto-vacuum, make sure no tables contain
    ** references to pointer-map pages.
    */
    if( sCheck.anRef[i]==0 && 
       (PTRMAP_PAGENO(pBt->pageSize, i)!=i || !pBt->autoVacuum) ){
      checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
    }
    if( sCheck.anRef[i]!=0 && 
       (PTRMAP_PAGENO(pBt->pageSize, i)==i && pBt->autoVacuum) ){
      checkAppendMsg(&sCheck, 0, "Pointer map page %d is referenced", i);
    }
#endif
  }

  /* Make sure this analysis did not leave any unref() pages
  */
  unlockBtreeIfUnused(pBt);
  if( nRef != *sqlite3pager_stats(pBt->pPager) ){
    checkAppendMsg(&sCheck, 0,