From 341eae8d3515b5bb2f095e2720748494be572da3 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 21 Jan 2003 02:39:36 +0000 Subject: [PATCH] In the pager, cache a pointer to the first page on the freelist that does not need to be synced. This makes a fetch of a page that is not in cache go a lot faster when the cache is full. This check-in also adds some performance instrumentation to the OS layer. (CVS 842) FossilOrigin-Name: 00f08fc0b5b6b9c5efbf15a62f9a1cc1cfa71283 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/os.c | 35 +++++++++++++++++++++++++++++------ src/pager.c | 48 ++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 75 insertions(+), 24 deletions(-) diff --git a/manifest b/manifest index 902e36a4b7..15712eb9b7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\scomments.\s\sNo\schanges\sto\scode.\s(CVS\s841) -D 2003-01-19T03:59:46 +C In\sthe\spager,\scache\sa\spointer\sto\sthe\sfirst\spage\son\sthe\sfreelist\sthat\sdoes\snot\nneed\sto\sbe\ssynced.\s\sThis\smakes\sa\sfetch\sof\sa\spage\sthat\sis\snot\sin\scache\sgo\sa\nlot\sfaster\swhen\sthe\scache\sis\sfull.\s\sThis\scheck-in\salso\sadds\ssome\sperformance\ninstrumentation\sto\sthe\sOS\slayer.\s(CVS\s842) +D 2003-01-21T02:39:37 F Makefile.in 6606854b1512f185b8e8c779b8d7fc2750463d64 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -31,9 +31,9 @@ F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8 F src/insert.c db954e955970795819145a3649fd2ad116a58890 F src/main.c ad3193c56da5acd31bc6cd48aa50dae1962d7c78 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565 -F src/os.c 3a652608c296cf639ce63bd31d255db862e45685 +F src/os.c ed27e178e0c4b71f2807da81b8851f0fadc50778 F src/os.h afa3e096213bad86845f8bdca81a9e917505e401 -F src/pager.c 081155624cff7bec54590133b69906a23f9b3659 +F src/pager.c f35799e6c5d9dbb9701f3a8945a557a34b8e4850 F src/pager.h 540833e8cb826b80ce2e39aa917deee5e12db626 F src/parse.y a4fbfbe3c4254c96dae8c33264fb54af755a3770 F src/printf.c e8e9a0605602cb1a3a2dc754e0978fa9064ecee7 @@ -154,7 +154,7 @@ F www/speed.tcl 52759968401d81760fc01f9d3ab6242f6d2a7066 F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P 424cb2edb0c51b911791422ce7a9f5284a57f9ce -R c412fddde0211bcedc2c913718bf3cae +P f6a8706872c43cee3003b48bb427c7b74b1f89e7 +R 55e4cf10cd865df3b849840e7c63f464 U drh -Z 08ec0c344754362c114e2ab7933a5823 +Z 512b1f62fa409b79d94b59ec53fdbfdf diff --git a/manifest.uuid b/manifest.uuid index e992802038..521e6dcc41 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f6a8706872c43cee3003b48bb427c7b74b1f89e7 \ No newline at end of file +00f08fc0b5b6b9c5efbf15a62f9a1cc1cfa71283 \ No newline at end of file diff --git a/src/os.c b/src/os.c index 61af629a68..a071679db1 100644 --- a/src/os.c +++ b/src/os.c @@ -52,15 +52,32 @@ */ #if 0 static int last_page = 0; -#define SEEK(X) last_page=(X) -#define TRACE1(X) fprintf(stderr,X) -#define TRACE2(X,Y) fprintf(stderr,X,Y) -#define TRACE3(X,Y,Z) fprintf(stderr,X,Y,Z) +__inline__ unsigned long long int hwtime(void){ + unsigned long long int x; + __asm__("rdtsc\n\t" + "mov %%edx, %%ecx\n\t" + :"=A" (x)); + return x; +} +static unsigned long long int g_start; +static unsigned int elapse; +#define TIMER_START g_start=hwtime() +#define TIMER_END elapse=hwtime()-g_start +#define SEEK(X) last_page=(X) +#define TRACE1(X) fprintf(stderr,X) +#define TRACE2(X,Y) fprintf(stderr,X,Y) +#define TRACE3(X,Y,Z) fprintf(stderr,X,Y,Z) +#define TRACE4(X,Y,Z,A) fprintf(stderr,X,Y,Z,A) +#define TRACE5(X,Y,Z,A,B) fprintf(stderr,X,Y,Z,A,B) #else +#define TIMER_START +#define TIMER_END #define SEEK(X) #define TRACE1(X) #define TRACE2(X,Y) #define TRACE3(X,Y,Z) +#define TRACE4(X,Y,Z,A) +#define TRACE5(X,Y,Z,A,B) #endif @@ -664,8 +681,11 @@ int sqliteOsRead(OsFile *id, void *pBuf, int amt){ #if OS_UNIX int got; SimulateIOError(SQLITE_IOERR); - TRACE3("READ %-3d %d\n", id->fd, last_page); + TIMER_START; got = read(id->fd, pBuf, amt); + TIMER_END; + TRACE4("READ %-3d %7d %d\n", id->fd, last_page, elapse); + SEEK(0); /* if( got<0 ) got = 0; */ if( got==amt ){ return SQLITE_OK; @@ -712,11 +732,14 @@ int sqliteOsWrite(OsFile *id, const void *pBuf, int amt){ #if OS_UNIX int wrote = 0; SimulateIOError(SQLITE_IOERR); - TRACE3("WRITE %-3d %d\n", id->fd, last_page); + TIMER_START; while( amt>0 && (wrote = write(id->fd, pBuf, amt))>0 ){ amt -= wrote; pBuf = &((char*)pBuf)[wrote]; } + TIMER_END; + TRACE4("WRITE %-3d %7d %d\n", id->fd, last_page, elapse); + SEEK(0); if( amt>0 ){ return SQLITE_FULL; } diff --git a/src/pager.c b/src/pager.c index 4311445c63..0d18bd2eed 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.68 2003/01/16 13:42:43 drh Exp $ +** @(#) $Id: pager.c,v 1.69 2003/01/21 02:39:37 drh Exp $ */ #include "os.h" /* Must be first to enable large file support */ #include "sqliteInt.h" @@ -162,6 +162,7 @@ struct Pager { u8 *aInJournal; /* One bit for each page in the database file */ u8 *aInCkpt; /* One bit for each page in the database */ PgHdr *pFirst, *pLast; /* List of free pages */ + PgHdr *pFirstSynced; /* First free page with PgHdr.needSync==0 */ PgHdr *pAll; /* List of all pages */ PgHdr *pCkpt; /* List of pages in the checkpoint journal */ PgHdr *aHash[N_PG_HASH]; /* Hash table to map page number of PgHdr */ @@ -346,6 +347,7 @@ static void pager_reset(Pager *pPager){ sqliteFree(pPg); } pPager->pFirst = 0; + pPager->pFirstSynced = 0; pPager->pLast = 0; pPager->pAll = 0; memset(pPager->aHash, 0, sizeof(pPager->aHash)); @@ -737,6 +739,7 @@ int sqlitepager_open( pPager->needSync = 0; pPager->noSync = pPager->tempFile || !useJournal; pPager->pFirst = 0; + pPager->pFirstSynced = 0; pPager->pLast = 0; pPager->nExtra = nExtra; memset(pPager->aHash, 0, sizeof(pPager->aHash)); @@ -837,6 +840,11 @@ Pgno sqlitepager_pagenumber(void *pData){ static void _page_ref(PgHdr *pPg){ if( pPg->nRef==0 ){ /* The page is currently on the freelist. Remove it. */ + if( pPg==pPg->pPager->pFirstSynced ){ + PgHdr *p = pPg->pNextFree; + while( p && p->needSync ){ p = p->pNextFree; } + pPg->pPager->pFirstSynced = p; + } if( pPg->pPrevFree ){ pPg->pPrevFree->pNextFree = pPg->pNextFree; }else{ @@ -901,13 +909,29 @@ static int syncAllPages(Pager *pPager){ pPager->journalStarted = 1; } pPager->needSync = 0; + + /* Erase the needSync flag from every page. + */ + for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ + pPg->needSync = 0; + } + pPager->pFirstSynced = pPager->pFirst; } - /* Erase the needSync flag from every page. +#ifndef NDEBUG + /* If the Pager.needSync flag is clear then the PgHdr.needSync + ** flag must also be clear for all pages. Verify that this + ** invariant is true. */ - for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ - pPg->needSync = 0; + else{ + for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ + assert( pPg->needSync==0 ); + } + assert( pPager->pFirstSynced==pPager->pFirst ); } +#endif + + return rc; } @@ -1032,10 +1056,7 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){ /* Find a page to recycle. Try to locate a page that does not ** require us to do an fsync() on the journal. */ - pPg = pPager->pFirst; - while( pPg && pPg->needSync ){ - pPg = pPg->pNextFree; - } + pPg = pPager->pFirstSynced; /* If we could not find a page that does not require an fsync() ** on the journal file then fsync the journal file. This is a @@ -1083,6 +1104,11 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){ /* Unlink the old page from the free list and the hash table */ + if( pPg==pPager->pFirstSynced ){ + PgHdr *p = pPg->pNextFree; + while( p && p->needSync ){ p = p->pNextFree; } + pPager->pFirstSynced = p; + } if( pPg->pPrevFree ){ pPg->pPrevFree->pNextFree = pPg->pNextFree; }else{ @@ -1226,6 +1252,9 @@ int sqlitepager_unref(void *pData){ }else{ pPager->pFirst = pPg; } + if( pPg->needSync==0 && pPager->pFirstSynced==0 ){ + pPager->pFirstSynced = pPg; + } if( pPager->xDestructor ){ pPager->xDestructor(pData); } @@ -1577,13 +1606,12 @@ int sqlitepager_commit(Pager *pPager){ if( pPager->dirtyFile==0 ){ /* Exit early (without doing the time-consuming sqliteOsSync() calls) ** if there have been no changes to the database file. */ + assert( pPager->needSync==0 ); rc = pager_unwritelock(pPager); pPager->dbSize = -1; return rc; } assert( pPager->journalOpen ); - if( !pPager->journalStarted && !pPager->noSync ) pPager->needSync = 1; - assert( pPager->dirtyFile || !pPager->needSync ); if( pPager->needSync && sqliteOsSync(&pPager->jfd)!=SQLITE_OK ){ goto commit_abort; }