From bf4bca541ead82084e9ff86b531166b6c41ed07b Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 6 Sep 2007 22:19:14 +0000 Subject: [PATCH] Allocate page cache headers and page cache data buffers separately. The data buffer will be a power of two in size and this gives some malloc implementation additional optimization opportunitites. (CVS 4409) FossilOrigin-Name: 2b755defe51a565a2b6ace58381d6e91f6f17db8 --- manifest | 16 ++++++------- manifest.uuid | 2 +- src/btree.c | 25 ++++++++++---------- src/pager.c | 63 +++++++++++++++++++++++++++++-------------------- test/btree.test | 3 ++- 5 files changed, 61 insertions(+), 48 deletions(-) diff --git a/manifest b/manifest index b4d56e1913..bc950fd013 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Updated\scomments\son\sjournal.c.\s\sNo\schanges\sto\scode.\s(CVS\s4408) -D 2007-09-06T13:49:37 +C Allocate\spage\scache\sheaders\sand\spage\scache\sdata\sbuffers\sseparately.\nThe\sdata\sbuffer\swill\sbe\sa\spower\sof\stwo\sin\ssize\sand\sthis\sgives\ssome\nmalloc\simplementation\sadditional\soptimization\sopportunitites.\s(CVS\s4409) +D 2007-09-06T22:19:15 F Makefile.in cbfb898945536a8f9ea8b897e1586dd1fdbcc5db F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -81,7 +81,7 @@ F src/analyze.c 49b4bd45eb286d833793ed6bf72355a5c1974865 F src/attach.c 02fd8779270b1df1c63e7ba6e6655b960fa0f3d5 F src/auth.c d41c34f3150b3b8248d364770ef922bbcefbff82 F src/btmutex.c 442be6f068d77ca9ffd69899cf0a3943c244548c -F src/btree.c b1e8025ac1ba81d78c2d2bab47af8efd1d143995 +F src/btree.c f37796c6f0306ed61e69e4c54621350572df30d1 F src/btree.h d0736ebca4b6eafbdd823c46a8de574cea078211 F src/btreeInt.h 4330c19b8314545fdb209cc77e2a57f6a5290e9c F src/build.c 94d0d6dfd1e706c480903fbdda2e77466f21b898 @@ -120,7 +120,7 @@ F src/os_unix.c 522486e24d1a743efc366cb93a727fa9314797b4 F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e F src/os_win.c b663c171abbbfa8ca20e5b9b93f7a0f09df616e9 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b -F src/pager.c 0ce52a22ebfae0c085b68e00e30e9bf9ea462d0d +F src/pager.c 10a95d9373105af62255a05aac1ffe0400b93a3d F src/pager.h d783e7f184afdc33adff37ba58d4e029bd8793b3 F src/parse.y 2d2ce439dc6184621fb0b86f4fc5aca7f391a590 F src/pragma.c 363e548dafb52327face8d99757ab56a7b1c1b26 @@ -202,7 +202,7 @@ F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747 F test/bind.test 261fd1603613e7f877a516d29f281c9d8c2ecf52 F test/bindxfer.test b9a57f66dbd317feeefa28bd65b6576f1592ee98 F test/blob.test 28c3b25150684ee3d108bb78cfb67a472deef2f0 -F test/btree.test d394f22b03712f05fca9c59f6f4848a3cad01379 +F test/btree.test eef24f3dd52b5b268321ae5aacfe30d3baca4e84 F test/btree2.test 4b56a2a4a4f84d68c77aef271223a713bf5ebafc F test/btree4.test 3797b4305694c7af6828675b0f4b1424b8ca30e4 F test/btree5.test 8e5ff32c02e685d36516c6499add9375fe1377f2 @@ -570,7 +570,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P 79cf4e886cd5f1cd22574ce13135d4e32c1047b6 -R e940832e4042881361230f79ce400588 +P 3298441086330d1d24c30b7c061dfec98e9ea3ac +R fab7f476269f83c2a9fb525589500817 U drh -Z 99beef2eb5ea70985d445f46a130fc96 +Z 091fe80161eedb1e09f57479031bbfb6 diff --git a/manifest.uuid b/manifest.uuid index 4cd35fe7d3..f5421050f9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3298441086330d1d24c30b7c061dfec98e9ea3ac \ No newline at end of file +2b755defe51a565a2b6ace58381d6e91f6f17db8 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index c56518b780..5f672082cf 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.422 2007/09/03 22:00:39 drh Exp $ +** $Id: btree.c,v 1.423 2007/09/06 22:19:15 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. @@ -902,7 +902,8 @@ int sqlite3BtreeInitPage( assert( pParent==0 || pParent->pBt==pBt ); assert( sqlite3_mutex_held(pBt->mutex) ); assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); - assert( pPage->aData == &((unsigned char*)pPage)[-pBt->pageSize] ); + assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); + assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){ /* The parent page should never change unless the file is corrupt */ return SQLITE_CORRUPT_BKPT; @@ -969,7 +970,8 @@ static void zeroPage(MemPage *pPage, int flags){ int first; assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno ); - assert( &data[pBt->pageSize] == (unsigned char*)pPage ); + assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); + assert( sqlite3PagerGetData(pPage->pDbPage) == data ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( sqlite3_mutex_held(pBt->mutex) ); memset(&data[hdr], 0, pBt->usableSize - hdr); @@ -1053,7 +1055,8 @@ static void releasePage(MemPage *pPage){ if( pPage ){ assert( pPage->aData ); assert( pPage->pBt ); - assert( &pPage->aData[pPage->pBt->pageSize]==(unsigned char*)pPage ); + assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); + assert( sqlite3PagerGetData(pPage->pDbPage)==pPage->aData ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); sqlite3PagerUnref(pPage->pDbPage); } @@ -1731,7 +1734,7 @@ static void unlockBtreeIfUnused(BtShared *pBt){ if( sqlite3PagerRefcount(pBt->pPager)>=1 ){ if( pBt->pPage1->aData==0 ){ MemPage *pPage = pBt->pPage1; - pPage->aData = &((u8*)pPage)[-pBt->pageSize]; + pPage->aData = sqlite3PagerGetData(pPage->pDbPage); pPage->pBt = pBt; pPage->pgno = 1; } @@ -4348,7 +4351,7 @@ static int reparentPage(BtShared *pBt, Pgno pgno, MemPage *pNewParent, int idx){ if( pDbPage ){ pThis = (MemPage *)sqlite3PagerGetExtra(pDbPage); if( pThis->isInit ){ - assert( pThis->aData==(sqlite3PagerGetData(pDbPage)) ); + assert( pThis->aData==sqlite3PagerGetData(pDbPage) ); if( pThis->pParent!=pNewParent ){ if( pThis->pParent ) sqlite3PagerUnref(pThis->pParent->pDbPage); pThis->pParent = pNewParent; @@ -4899,12 +4902,10 @@ static int balance_nonroot(MemPage *pPage){ ** process of being overwritten. */ for(i=0; ipageSize]; - p->aData = &((u8*)p)[-pBt->pageSize]; - memcpy(p->aData, apOld[i]->aData, pBt->pageSize + sizeof(MemPage)); - /* The memcpy() above changes the value of p->aData so we have to - ** set it again. */ - p->aData = &((u8*)p)[-pBt->pageSize]; + MemPage *p = apCopy[i] = (MemPage*)aCopy[i]; + memcpy(p, apOld[i], sizeof(MemPage)); + p->aData = (void*)&p[1]; + memcpy(p->aData, apOld[i]->aData, pBt->pageSize); } /* diff --git a/src/pager.c b/src/pager.c index e3b10016f5..c276736a3e 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.385 2007/09/03 15:19:35 drh Exp $ +** @(#) $Id: pager.c,v 1.386 2007/09/06 22:19:15 drh Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" @@ -271,12 +271,11 @@ struct PgHdr { #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT PagerLruLink gfree; /* Global list of nRef==0 pages */ #endif - u32 notUsed; /* Buffer space */ #ifdef SQLITE_CHECK_PAGES u32 pageHash; #endif - /* pPager->pageSize bytes of page data follow this header */ - /* Pager.nExtra bytes of local data follow the page data */ + void *pData; /* Page data */ + /* Pager.nExtra bytes of local data appended to this header */ }; /* @@ -313,11 +312,10 @@ struct PgHistory { ** Convert a pointer to a PgHdr into a pointer to its data ** and back again. */ -#define PGHDR_TO_DATA(P) ((void*)(&(P)[1])) -#define DATA_TO_PGHDR(D) (&((PgHdr*)(D))[-1]) -#define PGHDR_TO_EXTRA(G,P) ((void*)&((char*)(&(G)[1]))[(P)->pageSize]) +#define PGHDR_TO_DATA(P) ((P)->pData) +#define PGHDR_TO_EXTRA(G,P) ((void*)&((G)[1])) #define PGHDR_TO_HIST(P,PGR) \ - ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->pageSize+(PGR)->nExtra]) + ((PgHistory*)&((char*)(&(P)[1]))[(PGR)->nExtra]) /* ** A open page cache is an instance of the following structure. @@ -1245,6 +1243,7 @@ static void pager_reset(Pager *pPager){ PAGER_INCR(sqlite3_pager_pgfree_count); pNext = pPg->pNextAll; lruListRemove(pPg); + sqlite3_free(pPg->pData); sqlite3_free(pPg); } assert(pPager->lru.pFirst==0); @@ -2495,6 +2494,7 @@ static void pager_truncate_cache(Pager *pPager){ PAGER_INCR(sqlite3_pager_pgfree_count); unlinkPage(pPg); makeClean(pPg); + sqlite3_free(pPg->pData); sqlite3_free(pPg); pPager->nPage--; } @@ -3158,6 +3158,7 @@ int sqlite3PagerReleaseMemory(int nReq){ ); IOTRACE(("PGFREE %p %d *\n", pPager, pPg->pgno)); PAGER_INCR(sqlite3_pager_pgfree_count); + sqlite3_free(pPg->pData); sqlite3_free(pPg); pPager->nPage--; }else{ @@ -3394,6 +3395,7 @@ static int pagerSharedLock(Pager *pPager){ static int pagerAllocatePage(Pager *pPager, PgHdr **ppPg){ int rc = SQLITE_OK; PgHdr *pPg; + void *pData; /* Create a new PgHdr if any of the four conditions defined ** above are met: */ @@ -3411,9 +3413,15 @@ static int pagerAllocatePage(Pager *pPager, PgHdr **ppPg){ } } pagerLeave(pPager); - pPg = sqlite3_malloc( sizeof(*pPg) + pPager->pageSize - + sizeof(u32) + pPager->nExtra + pPg = sqlite3_malloc( sizeof(*pPg) + sizeof(u32) + pPager->nExtra + MEMDB*sizeof(PgHistory) ); + if( pPg ){ + pData = sqlite3_malloc( pPager->pageSize ); + if( pData==0 ){ + sqlite3_free(pPg); + pPg = 0; + } + } pagerEnter(pPager); if( pPg==0 ){ rc = SQLITE_NOMEM; @@ -3423,6 +3431,7 @@ static int pagerAllocatePage(Pager *pPager, PgHdr **ppPg){ if( MEMDB ){ memset(PGHDR_TO_HIST(pPg, pPager), 0, sizeof(PgHistory)); } + pPg->pData = pData; pPg->pPager = pPager; pPg->pNextAll = pPager->pAll; pPager->pAll = pPg; @@ -3987,7 +3996,6 @@ static int pager_write(PgHdr *pPg){ */ if( !pPg->inJournal && (pPager->useJournal || MEMDB) ){ if( (int)pPg->pgno <= pPager->origDbSize ){ - int szPg; if( MEMDB ){ PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager); PAGERTRACE3("JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); @@ -3997,8 +4005,8 @@ static int pager_write(PgHdr *pPg){ memcpy(pHist->pOrig, PGHDR_TO_DATA(pPg), pPager->pageSize); } }else{ - u32 cksum, saved; - char *pData2, *pEnd; + u32 cksum; + char *pData2; /* We should never write to the journal file the page that ** contains the database locks. The following assert verifies @@ -4006,20 +4014,21 @@ static int pager_write(PgHdr *pPg){ assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) ); pData2 = CODEC2(pPager, pData, pPg->pgno, 7); cksum = pager_cksum(pPager, (u8*)pData2); - pEnd = pData2 + pPager->pageSize; - pData2 -= 4; - saved = *(u32*)pEnd; - put32bits(pEnd, cksum); - szPg = pPager->pageSize+8; - put32bits(pData2, pPg->pgno); - rc = sqlite3OsWrite(pPager->jfd, pData2, szPg, pPager->journalOff); - IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno, + rc = write32bits(pPager->jfd, pPager->journalOff, pPg->pgno); + if( rc==SQLITE_OK ){ + rc = sqlite3OsWrite(pPager->jfd, pData2, pPager->pageSize, + pPager->journalOff + 4); + pPager->journalOff += pPager->pageSize+4; + } + if( rc==SQLITE_OK ){ + rc = write32bits(pPager->jfd, pPager->journalOff, cksum); + pPager->journalOff += 4; + } + IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno, pPager->journalOff, szPg)); PAGER_INCR(sqlite3_pager_writej_count); - pPager->journalOff += szPg; PAGERTRACE5("JOURNAL %d page %d needSync=%d hash(%08x)\n", PAGERID(pPager), pPg->pgno, pPg->needSync, pager_pagehash(pPg)); - *(u32*)pEnd = saved; /* An error has occured writing to the journal file. The ** transaction will be rolled back by the layer above. @@ -4068,9 +4077,11 @@ static int pager_write(PgHdr *pPg){ page_add_to_stmt_list(pPg); }else{ i64 offset = pPager->stmtNRec*(4+pPager->pageSize); - char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7)-4; - put32bits(pData2, pPg->pgno); - rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize+4, offset); + char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7); + rc = write32bits(pPager->stfd, offset, pPg->pgno); + if( rc==SQLITE_OK ){ + rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize, offset+4); + } PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); if( rc!=SQLITE_OK ){ return rc; diff --git a/test/btree.test b/test/btree.test index dcd545bb0b..d8575d06bd 100644 --- a/test/btree.test +++ b/test/btree.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script is btree database backend # -# $Id: btree.test,v 1.40 2007/06/25 08:16:58 danielk1977 Exp $ +# $Id: btree.test,v 1.41 2007/09/06 22:19:15 drh Exp $ set testdir [file dirname $argv0] @@ -782,6 +782,7 @@ do_test btree-10.2 { lindex [btree_pager_stats $::b1] 1 } {2} do_test btree-10.3 { +btree_breakpoint for {set i 1} {$i<=30} {incr i} { set key [format %03d $i] set data "*** $key *** $key *** $key *** $key ***"