diff options
author | drh <> | 2022-08-31 15:04:42 +0000 |
---|---|---|
committer | drh <> | 2022-08-31 15:04:42 +0000 |
commit | 9c3a114ca057e319bc0923d25366d1cbf29e225d (patch) | |
tree | 33de1e6f3b23bd65104332926ad114fb13b35ab9 /src | |
parent | 78d15f097a416d25086c31782599af072cad8875 (diff) | |
download | sqlite-9c3a114ca057e319bc0923d25366d1cbf29e225d.tar.gz sqlite-9c3a114ca057e319bc0923d25366d1cbf29e225d.zip |
Enhance the b-tree page sorting code to ensure that sqlite3PagerRekey() never
overloads a page number and uses only the PENDING_BYTE page for temporary
storage.
FossilOrigin-Name: 5007742886bd20de20be3973737cf46b010359911615eb3da69cd262bd9a2435
Diffstat (limited to 'src')
-rw-r--r-- | src/btree.c | 60 | ||||
-rw-r--r-- | src/pcache1.c | 5 |
2 files changed, 31 insertions, 34 deletions
diff --git a/src/btree.c b/src/btree.c index 916919928..577de2bee 100644 --- a/src/btree.c +++ b/src/btree.c @@ -7893,8 +7893,6 @@ static int balance_nonroot( Pgno pgno; /* Temp var to store a page number in */ u8 abDone[NB+2]; /* True after i'th new page is populated */ Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */ - Pgno aPgOrder[NB+2]; /* Copy of aPgno[] used for sorting pages */ - u16 aPgFlags[NB+2]; /* flags field of new pages before shuffling */ CellArray b; /* Parsed information on cells being balanced */ memset(abDone, 0, sizeof(abDone)); @@ -8318,43 +8316,39 @@ static int balance_nonroot( ** of the table is closer to a linear scan through the file. That in turn ** helps the operating system to deliver pages from the disk more rapidly. ** - ** An O(n^2) insertion sort algorithm is used, but since n is never more - ** than (NB+2) (a small constant), that should not be a problem. + ** An O(N*N) sort algorithm is used, but since N is never more than NB+2 + ** (5), that is not a performance concern. ** ** When NB==3, this one optimization makes the database about 25% faster ** for large insertions and deletions. */ for(i=0; i<nNew; i++){ - aPgOrder[i] = aPgno[i] = apNew[i]->pgno; - aPgFlags[i] = apNew[i]->pDbPage->flags; - for(j=0; j<i; j++){ - if( NEVER(aPgno[j]==aPgno[i]) ){ - /* This branch is taken if the set of sibling pages somehow contains - ** duplicate entries. This can happen if the database is corrupt. - ** It would be simpler to detect this as part of the loop below, but - ** we do the detection here in order to avoid populating the pager - ** cache with two separate objects associated with the same - ** page number. */ - assert( CORRUPT_DB ); - rc = SQLITE_CORRUPT_BKPT; - goto balance_cleanup; - } - } + aPgno[i] = apNew[i]->pgno; + assert( apNew[i]->pDbPage->flags & PGHDR_WRITEABLE ); + assert( apNew[i]->pDbPage->flags & PGHDR_DIRTY ); } - for(i=0; i<nNew; i++){ - int iBest = 0; /* aPgno[] index of page number to use */ - for(j=1; j<nNew; j++){ - if( aPgOrder[j]<aPgOrder[iBest] ) iBest = j; - } - pgno = aPgOrder[iBest]; - aPgOrder[iBest] = 0xffffffff; - if( iBest!=i ){ - if( iBest>i ){ - sqlite3PagerRekey(apNew[iBest]->pDbPage, pBt->nPage+iBest+1, - aPgFlags[iBest]); - } - sqlite3PagerRekey(apNew[i]->pDbPage, pgno, aPgFlags[iBest]); - apNew[i]->pgno = pgno; + for(i=0; i<nNew-1; i++){ + int iB = i; + for(j=i+1; j<nNew; j++){ + if( apNew[j]->pgno < apNew[iB]->pgno ) iB = j; + } + + /* If apNew[i] has a page number that is bigger than any of the + ** subsequence apNew[i] entries, then swap apNew[i] with the subsequent + ** entry that has the smallest page number (which we know to be + ** entry apNew[iB]). + */ + if( iB!=i ){ + Pgno pgnoA = apNew[i]->pgno; + Pgno pgnoB = apNew[iB]->pgno; + Pgno pgnoTemp = (PENDING_BYTE/pBt->pageSize)+1; + u16 fgA = apNew[i]->pDbPage->flags; + u16 fgB = apNew[iB]->pDbPage->flags; + sqlite3PagerRekey(apNew[i]->pDbPage, pgnoTemp, fgB); + sqlite3PagerRekey(apNew[iB]->pDbPage, pgnoA, fgA); + sqlite3PagerRekey(apNew[i]->pDbPage, pgnoB, fgB); + apNew[i]->pgno = pgnoB; + apNew[iB]->pgno = pgnoA; } } diff --git a/src/pcache1.c b/src/pcache1.c index d40d9cf4f..3e406a7a8 100644 --- a/src/pcache1.c +++ b/src/pcache1.c @@ -1122,9 +1122,11 @@ static void pcache1Rekey( unsigned int h; assert( pPage->iKey==iOld ); assert( pPage->pCache==pCache ); + assert( iOld!=iNew ); /* The page number really is changing */ pcache1EnterMutex(pCache->pGroup); - + + assert( pcache1FetchNoMutex(p, iOld, 0)==pPage ); /* pPg really is iOld */ h = iOld%pCache->nHash; pp = &pCache->apHash[h]; while( (*pp)!=pPage ){ @@ -1132,6 +1134,7 @@ static void pcache1Rekey( } *pp = pPage->pNext; + assert( pcache1FetchNoMutex(p, iNew, 0)==0 ); /* iNew not previously used */ h = iNew%pCache->nHash; pPage->iKey = iNew; pPage->pNext = pCache->apHash[h]; |