From 9eed505701059022a2bb1923ca5f2c656d847242 Mon Sep 17 00:00:00 2001 From: danielk1977 Date: Fri, 4 Jun 2004 10:38:30 +0000 Subject: [PATCH] Defer the exclusive db lock until the pager cache is flushed to disk. 41 tests now fail. (CVS 1528) FossilOrigin-Name: d2f69e5ef2f261a00bb8427a4e2a1638ecfd17a9 --- manifest | 16 ++++---- manifest.uuid | 2 +- src/os.h | 1 + src/os_unix.c | 24 ----------- src/pager.c | 109 ++++++++++++++++++++++++++++++++++---------------- 5 files changed, 84 insertions(+), 68 deletions(-) diff --git a/manifest b/manifest index bb4ad21f51..c286507243 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Move\sthe\s'busy-callback'\slogic\sto\sthe\spager\slayer.\s(CVS\s1527) -D 2004-06-04T06:22:01 +C Defer\sthe\sexclusive\sdb\slock\suntil\sthe\spager\scache\sis\sflushed\sto\sdisk.\s41\ntests\snow\sfail.\s(CVS\s1528) +D 2004-06-04T10:38:30 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -39,15 +39,15 @@ F src/insert.c 4268d9e3959cc845ea243fb4ec7507269404dad9 F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f F src/main.c 4e8e5c96e5a9460e71b97c83cb30cb3ad44db259 F src/md5.c 4302e84ae516c616bb079c4e6d038c0addb33481 -F src/os.h cc2fd62b2e8e11103701913871908ff77532af58 +F src/os.h 4e480eb92737ebcdd1e1136bdbf5cd22223bd1b4 F src/os_common.h 744286a27de55c52f1b18921e8d17abbf7fafc0f F src/os_mac.c b823874690615ace0dd520d3ad1fe8bfd864b7e0 F src/os_mac.h 51d2445f47e182ed32d3bd6937f81070c6fd9bd4 -F src/os_unix.c 3175540f8d1c820dab7a470c50875c221c3a98cd +F src/os_unix.c a4feb70b23fa5272f53cd2c74588484b54294800 F src/os_unix.h 7999f2246c6347707e98f7078871ea8ca605df3f F src/os_win.c 92b51a38437b98d8aa3ac05b57c71e1d1092e5be F src/os_win.h 5d41af24caaef6c13a2d8e2399caa1c57d45c84d -F src/pager.c 00fabe423729e8d8a4c5e8f9602341b69a5a21b5 +F src/pager.c 944f6b071279887574081281f27bb2af88b42905 F src/pager.h 0c7b5ac45c69e690c45d160d03bdc8fbd2d4657b F src/parse.y 27c1ce09f9d309be91f9e537df2fb00892990af4 F src/pragma.c 1b58d852b84b36a8b84e2245dd29b63c377414ec @@ -214,7 +214,7 @@ F www/support.tcl 1801397edd271cc39a2aadd54e701184b5181248 F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P d57e5252c8baaf615c2cd218a33356ea5d95a5e2 -R 2d675c6973e7ef6b1853da4802084a3d +P ff70b6d2b60c143e3ada0606ceff97571998c7e3 +R 0c89db702f37cfc005476b7d72917d3b U danielk1977 -Z bb8854c6d118151a9229d93a5653a12b +Z 2dc315e5203a158a5157a45199e1dfe1 diff --git a/manifest.uuid b/manifest.uuid index 2108920713..ab70ce9809 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ff70b6d2b60c143e3ada0606ceff97571998c7e3 \ No newline at end of file +d2f69e5ef2f261a00bb8427a4e2a1638ecfd17a9 \ No newline at end of file diff --git a/src/os.h b/src/os.h index e496564d3e..a33662190d 100644 --- a/src/os.h +++ b/src/os.h @@ -84,6 +84,7 @@ ** The following values may be passed as the second argument to ** sqlite3OsLock(). */ +#define NO_LOCK 0 #define SHARED_LOCK 1 #define RESERVED_LOCK 2 #define PENDING_LOCK 3 diff --git a/src/os_unix.c b/src/os_unix.c index 9ea4569707..8ee48de882 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -641,30 +641,6 @@ int sqlite3OsFileSize(OsFile *id, off_t *pSize){ return SQLITE_OK; } - -/* -** Change the status of the lock on the file "id" to be a readlock. -** If the file was write locked, then this reduces the lock to a read. -** If the file was read locked, then this acquires a new read lock. -** -** Return SQLITE_OK on success and SQLITE_BUSY on failure. If this -** library was compiled with large file support (LFS) but LFS is not -** available on the host, then an SQLITE_NOLFS is returned. -*/ -int sqlite3OsReadLock(OsFile *id){ - return sqlite3OsLock(id, SHARED_LOCK); -} - -/* -** Change the lock status to be an exclusive or write lock. Return -** SQLITE_OK on success and SQLITE_BUSY on a failure. If this -** library was compiled with large file support (LFS) but LFS is not -** available on the host, then an SQLITE_NOLFS is returned. -*/ -int sqlite3OsWriteLock(OsFile *id){ - return sqlite3OsLock(id, EXCLUSIVE_LOCK); -} - /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, return diff --git a/src/pager.c b/src/pager.c index 1f95e72e6a..3a655b745c 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.111 2004/06/04 06:22:01 danielk1977 Exp $ +** @(#) $Id: pager.c,v 1.112 2004/06/04 10:38:31 danielk1977 Exp $ */ #include "os.h" /* Must be first to enable large file support */ #include "sqliteInt.h" @@ -522,7 +522,7 @@ static int pager_unwritelock(Pager *pPager){ }else{ assert( pPager->dirtyFile==0 || pPager->useJournal==0 ); } - rc = sqlite3OsReadLock(&pPager->fd); + rc = sqlite3OsLock(&pPager->fd, SHARED_LOCK); if( rc==SQLITE_OK ){ pPager->state = SQLITE_READLOCK; }else{ @@ -658,15 +658,28 @@ static int pager_delmaster(const char *zMaster){ */ OsFile journal; int nMaster; + off_t jsz; rc = sqlite3OsOpenReadOnly(zJournal, &journal); + sqliteFree(zJournal); if( rc!=SQLITE_OK ){ sqlite3OsClose(&journal); - sqliteFree(zJournal); goto delmaster_out; } - sqlite3OsClose(&journal); + /* Check if the file is big enough to be a format 3 journal file + ** with the required master journal name. If not, ignore it. + */ + rc = sqlite3OsFileSize(&journal, &jsz); + if( rc!=SQLITE_OK ){ + sqlite3OsClose(&journal); + goto delmaster_out; + } + if( jsz<(sizeof(aJournalMagic3)+4*sizeof(u32)+strlen(zMaster)+1) ){ + sqlite3OsClose(&journal); + continue; + } + /* Seek to the point in the journal where the master journal name ** is stored. Read the master journal name into memory obtained ** from malloc. @@ -1532,9 +1545,40 @@ static int syncJournal(Pager *pPager, const char *zMaster){ static int pager_write_pagelist(PgHdr *pList){ Pager *pPager; int rc; + int busy = 1; if( pList==0 ) return SQLITE_OK; pPager = pList->pPager; + + /* At this point there may be either a RESERVED or EXCLUSIVE lock on the + ** database file. If there is already an EXCLUSIVE lock, the following + ** calls to sqlite3OsLock() are no-ops. + ** + ** The upgrade from a RESERVED to PENDING lock cannot return SQLITE_BUSY, + ** unless someone is not following the locking protocol. + ** + ** The upgrade from PENDING to EXCLUSIVE can return SQLITE_BUSY. It's + ** not totally clear that the busy-callback should be invoked here + ** though. (?) + */ + rc = sqlite3OsLock(&pPager->fd, PENDING_LOCK); + if( rc==SQLITE_BUSY ){ + return SQLITE_PROTOCOL; + } + if( rc!=SQLITE_OK ){ + return rc; + } + do { + rc = sqlite3OsLock(&pPager->fd, EXCLUSIVE_LOCK); + }while( rc==SQLITE_BUSY && + pPager->pBusyHandler && + pPager->pBusyHandler->xFunc && + pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, "", busy++) + ); + if( rc!=SQLITE_OK ){ + return rc; + } + while( pList ){ assert( pList->dirty ); sqlite3OsSeek(&pPager->fd, (pList->pgno-1)*(off_t)SQLITE_PAGE_SIZE); @@ -1607,20 +1651,15 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){ */ if( pPager->nRef==0 && !pPager->memDb ){ int busy = 1; - while( busy ){ - rc = sqlite3OsReadLock(&pPager->fd); - if( rc==SQLITE_BUSY && - pPager->pBusyHandler && - pPager->pBusyHandler->xFunc && - pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, "", busy++) - ){ - rc = SQLITE_OK; - }else{ - busy = 0; - } - if( rc!=SQLITE_OK ){ - return rc; - } + do { + rc = sqlite3OsLock(&pPager->fd, SHARED_LOCK); + }while( rc==SQLITE_BUSY && + pPager->pBusyHandler && + pPager->pBusyHandler->xFunc && + pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, "", busy++) + ); + if( rc!=SQLITE_OK ){ + return rc; } pPager->state = SQLITE_READLOCK; @@ -1906,7 +1945,7 @@ static int pager_open_journal(Pager *pPager){ sqlite3pager_pagecount(pPager); pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 ); if( pPager->aInJournal==0 ){ - sqlite3OsReadLock(&pPager->fd); + sqlite3OsLock(&pPager->fd, SHARED_LOCK); pPager->state = SQLITE_READLOCK; return SQLITE_NOMEM; } @@ -1914,7 +1953,7 @@ static int pager_open_journal(Pager *pPager){ if( rc!=SQLITE_OK ){ sqliteFree(pPager->aInJournal); pPager->aInJournal = 0; - sqlite3OsReadLock(&pPager->fd); + sqlite3OsLock(&pPager->fd, SHARED_LOCK); pPager->state = SQLITE_READLOCK; return SQLITE_CANTOPEN; } @@ -2020,20 +2059,20 @@ int sqlite3pager_begin(void *pData, int nMaster){ pPager->origDbSize = pPager->dbSize; }else{ int busy = 1; - while( busy ){ - rc = sqlite3OsWriteLock(&pPager->fd); - if( rc==SQLITE_BUSY && - pPager->pBusyHandler && - pPager->pBusyHandler->xFunc && - pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, "", busy++) - ){ - rc = SQLITE_OK; - }else{ - busy = 0; - } - if( rc!=SQLITE_OK ){ - return rc; - } + do { + /* If the library grabs an EXCLUSIVE lock here, as in the commented + ** out line, then it exhibits the old locking behaviour - a writer + ** excludes all readers, not just other writers. + */ + /* rc = sqlite3OsLock(&pPager->fd, EXCLUSIVE_LOCK); */ + rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK); + }while( rc==SQLITE_BUSY && + pPager->pBusyHandler && + pPager->pBusyHandler->xFunc && + pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, "", busy++) + ); + if( rc!=SQLITE_OK ){ + return rc; } pPager->nMaster = nMaster; pPager->state = SQLITE_WRITELOCK; @@ -2515,7 +2554,7 @@ int sqlite3pager_stmt_begin(Pager *pPager){ assert( pPager->journalOpen ); pPager->aInStmt = sqliteMalloc( pPager->dbSize/8 + 1 ); if( pPager->aInStmt==0 ){ - sqlite3OsReadLock(&pPager->fd); + sqlite3OsLock(&pPager->fd, SHARED_LOCK); return SQLITE_NOMEM; } #ifndef NDEBUG