aboutsummaryrefslogtreecommitdiff
path: root/src/btree.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/btree.c')
-rw-r--r--src/btree.c87
1 files changed, 72 insertions, 15 deletions
diff --git a/src/btree.c b/src/btree.c
index 51fca4b4b..154b29787 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -8528,6 +8528,57 @@ static void checkList(
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
+/*
+** An implementation of a min-heap.
+**
+** aHeap[0] is the number of elements on the heap. aHeap[1] is the
+** root element. The daughter nodes of aHeap[N] are aHeap[N*2]
+** and aHeap[N*2+1].
+**
+** The heap property is this: Every node is less than or equal to both
+** of its daughter nodes. A consequence of the heap property is that the
+** root node aHeap[1] is always the minimum value currently in the heap.
+**
+** The btreeHeapInsert() routine inserts an unsigned 32-bit number onto
+** the heap, preserving the heap property. The btreeHeapPull() routine
+** removes the root element from the heap (the minimum value in the heap)
+** and then moves other nodes around as necessary to preserve the heap
+** property.
+**
+** This heap is used for cell overlap and coverage testing. Each u32
+** entry represents the span of a cell or freeblock on a btree page.
+** The upper 16 bits are the index of the first byte of a range and the
+** lower 16 bits are the index of the last byte of that range.
+*/
+static void btreeHeapInsert(u32 *aHeap, u32 x){
+ u32 j, i = ++aHeap[0];
+ aHeap[i] = x;
+ while( (j = i/2)>0 && aHeap[j]>aHeap[i] ){
+ x = aHeap[j];
+ aHeap[j] = aHeap[i];
+ aHeap[i] = x;
+ i = j;
+ }
+}
+static int btreeHeapPull(u32 *aHeap, u32 *pOut){
+ u32 j, i, x;
+ if( (x = aHeap[0])==0 ) return 0;
+ *pOut = aHeap[1];
+ aHeap[1] = aHeap[x];
+ aHeap[x] = 0xffffffff;
+ aHeap[0]--;
+ i = 1;
+ while( (j = i*2)<=aHeap[0] ){
+ if( aHeap[j]>aHeap[j+1] ) j++;
+ if( aHeap[i]<aHeap[j] ) break;
+ x = aHeap[i];
+ aHeap[i] = aHeap[j];
+ aHeap[j] = x;
+ i = j;
+ }
+ return 1;
+}
+
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
/*
** Do various sanity checks on a single page of a tree. Return
@@ -8560,7 +8611,8 @@ static int checkTreePage(
u8 *data;
BtShared *pBt;
int usableSize;
- char *hit = 0;
+ u32 *heap = 0;
+ u32 x, prev = 0;
i64 nMinKey = 0;
i64 nMaxKey = 0;
const char *saved_zPfx = pCheck->zPfx;
@@ -8705,15 +8757,15 @@ static int checkTreePage(
*/
data = pPage->aData;
hdr = pPage->hdrOffset;
- hit = sqlite3PageMalloc( pBt->pageSize );
+ heap = (u32*)sqlite3PageMalloc( pBt->pageSize );
pCheck->zPfx = 0;
- if( hit==0 ){
+ if( heap==0 ){
pCheck->mallocFailed = 1;
}else{
int contentOffset = get2byteNotZero(&data[hdr+5]);
assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
- memset(hit+contentOffset, 0, usableSize-contentOffset);
- memset(hit, 1, contentOffset);
+ heap[0] = 0;
+ btreeHeapInsert(heap, contentOffset-1);
/* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
** number of cells on the page. */
nCell = get2byte(&data[hdr+3]);
@@ -8725,7 +8777,6 @@ static int checkTreePage(
for(i=0; i<nCell; i++){
int pc = get2byte(&data[cellStart+i*2]);
u32 size = 65536;
- int j;
if( pc<=usableSize-4 ){
size = cellSizePtr(pPage, &data[pc]);
}
@@ -8734,7 +8785,7 @@ static int checkTreePage(
checkAppendMsg(pCheck,
"Corruption detected in cell %d on page %d",i,iPage);
}else{
- for(j=pc+size-1; j>=pc; j--) hit[j]++;
+ btreeHeapInsert(heap, (pc<<16)|(pc+size-1));
}
}
/* EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header
@@ -8746,7 +8797,7 @@ static int checkTreePage(
assert( i<=usableSize-4 ); /* Enforced by btreeInitPage() */
size = get2byte(&data[i+2]);
assert( i+size<=usableSize ); /* Enforced by btreeInitPage() */
- for(j=i+size-1; j>=i; j--) hit[j]++;
+ btreeHeapInsert(heap, (i<<16)|(i+size-1));
/* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a
** big-endian integer which is the offset in the b-tree page of the next
** freeblock in the chain, or zero if the freeblock is the last on the
@@ -8758,27 +8809,33 @@ static int checkTreePage(
assert( j<=usableSize-4 ); /* Enforced by btreeInitPage() */
i = j;
}
- for(i=cnt=0; i<usableSize; i++){
- if( hit[i]==0 ){
- cnt++;
- }else if( hit[i]>1 ){
+ cnt = 0;
+ assert( heap[0]>0 );
+ assert( (heap[1]>>16)==0 );
+ btreeHeapPull(heap,&prev);
+ while( btreeHeapPull(heap,&x) ){
+ if( (prev&0xffff)+1>(x>>16) ){
checkAppendMsg(pCheck,
- "Multiple uses for byte %d of page %d", i, iPage);
+ "Multiple uses for byte %u of page %d", x>>16, iPage);
break;
+ }else{
+ cnt += (x>>16) - (prev&0xffff) - 1;
+ prev = x;
}
}
+ cnt += usableSize - (prev&0xffff) - 1;
/* EVIDENCE-OF: R-43263-13491 The total number of bytes in all fragments
** is stored in the fifth field of the b-tree page header.
** EVIDENCE-OF: R-07161-27322 The one-byte integer at offset 7 gives the
** number of fragmented free bytes within the cell content area.
*/
- if( cnt!=data[hdr+7] ){
+ if( heap[0]==0 && cnt!=data[hdr+7] ){
checkAppendMsg(pCheck,
"Fragmentation of %d bytes reported as %d on page %d",
cnt, data[hdr+7], iPage);
}
}
- sqlite3PageFree(hit);
+ sqlite3PageFree(heap);
releasePage(pPage);
end_of_check: