62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
-
-
-
-
-
-
-
-
-
-
-
+
-
+
+
+
+
+
-
-
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
+
-
|
** When sqlite3PcacheTrace is 2, a dump of the pcache showing all cache entries
** is displayed for many operations, resulting in a lot of output.
*/
#if defined(SQLITE_DEBUG) && 0
int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */
int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */
# define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;}
static void pcachePageTrace(int i, sqlite3_pcache_page *pLower){
PgHdr *pPg;
unsigned char *a;
int j;
pPg = (PgHdr*)pLower->pExtra;
printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
a = (unsigned char *)pLower->pBuf;
for(j=0; j<12; j++) printf("%02x", a[j]);
printf(" ptr %p\n", pPg);
}
static void pcacheDump(PCache *pCache){
void pcacheDump(PCache *pCache){
int N;
int i;
int i, j;
sqlite3_pcache_page *pLower;
PgHdr *pPg;
unsigned char *a;
if( sqlite3PcacheTrace<2 ) return;
if( pCache->pCache==0 ) return;
N = sqlite3PcachePagecount(pCache);
if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump;
for(i=1; i<=N; i++){
pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0);
if( pLower==0 ) continue;
pPg = (PgHdr*)pLower->pExtra;
printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
pcachePageTrace(i, pLower);
if( ((PgHdr*)pLower)->pPage==0 ){
a = (unsigned char *)pLower->pBuf;
for(j=0; j<12; j++) printf("%02x", a[j]);
printf("\n");
if( pPg->pPage==0 ){
sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0);
}
}
}
#else
#else
# define pcacheTrace(X)
# define pcachePageTrace(PGNO, X)
# define pcacheDump(X)
#endif
/*
** Return 1 if pPg is on the dirty list for pCache. Return 0 if not.
** This routine runs inside of assert() statements only.
*/
#ifdef SQLITE_DEBUG
static int pageOnDirtyList(PCache *pCache, PgHdr *pPg){
PgHdr *p;
for(p=pCache->pDirty; p; p=p->pDirtyNext){
if( p==pPg ) return 1;
}
return 0;
}
#endif
/*
** Check invariants on a PgHdr entry. Return true if everything is OK.
** Return false if any invariant is violated.
**
** This routine is for use inside of assert() statements only. For
** example:
**
** assert( sqlite3PcachePageSanity(pPg) );
*/
#ifdef SQLITE_DEBUG
int sqlite3PcachePageSanity(PgHdr *pPg){
PCache *pCache;
assert( pPg!=0 );
assert( pPg->pgno>0 || pPg->pPager==0 ); /* Page number is 1 or more */
pCache = pPg->pCache;
assert( pCache!=0 ); /* Every page has an associated PCache */
if( pPg->flags & PGHDR_CLEAN ){
assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */
assert( !pageOnDirtyList(pCache, pPg) );/* CLEAN pages not on dirty list */
assert( pCache->pDirty!=pPg ); /* CLEAN pages not on dirty list */
}else{
assert( (pPg->flags & PGHDR_DIRTY)!=0 );/* If not CLEAN must be DIRTY */
assert( pPg->pDirtyNext==0 || pPg->pDirtyNext->pDirtyPrev==pPg );
assert( pPg->pDirtyPrev==0 || pPg->pDirtyPrev->pDirtyNext==pPg );
assert( pPg->pDirtyPrev!=0 || pCache->pDirty==pPg );
assert( pCache->pDirtyTail!=pPg );
assert( pageOnDirtyList(pCache, pPg) );
}
/* WRITEABLE pages must also be DIRTY */
if( pPg->flags & PGHDR_WRITEABLE ){
assert( pPg->flags & PGHDR_DIRTY ); /* WRITEABLE implies DIRTY */
}
/* NEED_SYNC can be set independently of WRITEABLE. This can happen,
** for example, when using the sqlite3PagerDontWrite() optimization:
|
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
|
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
|
-
+
-
|
** (createFlag==1 AND !(bPurgeable AND pDirty)
*/
eCreate = createFlag & pCache->eCreate;
assert( eCreate==0 || eCreate==1 || eCreate==2 );
assert( createFlag==0 || pCache->eCreate==eCreate );
assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
pcacheTrace(("%p.FETCH %d%s (result: %p) ",pCache,pgno,
pcacheTrace(("%p.FETCH %d%s (result: %p)\n",pCache,pgno,
createFlag?" create":"",pRes));
pcachePageTrace(pgno, pRes);
return pRes;
}
/*
** If the sqlite3PcacheFetch() routine is unable to allocate a new
** page because no clean pages are available for reuse and the cache
** size limit has been reached, then this routine can be invoked to
|
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
|
513
514
515
516
517
518
519
520
521
522
523
524
525
526
|
-
|
assert( p->nRef>0 );
p->pCache->nRefSum--;
if( (--p->nRef)==0 ){
if( p->flags&PGHDR_CLEAN ){
pcacheUnpin(p);
}else{
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
assert( sqlite3PcachePageSanity(p) );
}
}
}
/*
** Increase the reference count of a supplied page by 1.
*/
|
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
|
556
557
558
559
560
561
562
563
564
565
566
567
568
569
|
-
|
if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){ /*OPTIMIZATION-IF-FALSE*/
p->flags &= ~PGHDR_DONT_WRITE;
if( p->flags & PGHDR_CLEAN ){
p->flags ^= (PGHDR_DIRTY|PGHDR_CLEAN);
pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno));
assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY );
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
assert( sqlite3PcachePageSanity(p) );
}
assert( sqlite3PcachePageSanity(p) );
}
}
/*
** Make sure the page is marked as clean. If it isn't clean already,
|
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
|
626
627
628
629
630
631
632
633
634
635
636
637
638
639
|
-
|
assert( newPgno>0 );
assert( sqlite3PcachePageSanity(p) );
pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno));
sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
p->pgno = newPgno;
if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
assert( sqlite3PcachePageSanity(p) );
}
}
/*
** Drop every cache entry whose page number is greater than "pgno". The
** caller must ensure that there are no outstanding references to any pages
** other than page 1 with a page number greater than pgno.
|
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
|
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
|
-
+
|
PgHdr *p;
PgHdr *pNext;
pcacheTrace(("%p.TRUNCATE %d\n",pCache,pgno));
for(p=pCache->pDirty; p; p=pNext){
pNext = p->pDirtyNext;
/* This routine never gets call with a positive pgno except right
** after sqlite3PcacheCleanAll(). So if there are dirty pages,
** it must be that pgno==0.
** it must be that pgno>0.
*/
assert( p->pgno>0 );
if( p->pgno>pgno ){
assert( p->flags&PGHDR_DIRTY );
sqlite3PcacheMakeClean(p);
}
}
|