Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Defer the exclusive db lock until the pager cache is flushed to disk. 41 tests now fail. (CVS 1528) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
d2f69e5ef2f261a00bb8427a4e2a1638 |
User & Date: | danielk1977 2004-06-04 10:38:30.000 |
Context
2004-06-05
| ||
00:01 | Critical bugs fixed in btree.c. Incompatible file format change. Unrelated comment fix in select.c (CVS 1530) (check-in: cb1ffabf86 user: drh tags: trunk) | |
2004-06-04
| ||
10:38 | Defer the exclusive db lock until the pager cache is flushed to disk. 41 tests now fail. (CVS 1528) (check-in: d2f69e5ef2 user: danielk1977 tags: trunk) | |
06:22 | Move the 'busy-callback' logic to the pager layer. (CVS 1527) (check-in: ff70b6d2b6 user: danielk1977 tags: trunk) | |
Changes
Changes to src/os.h.
︙ | ︙ | |||
80 81 82 83 84 85 86 87 88 89 90 91 92 93 | # define TEMP_FILE_PREFIX "sqlite_" #endif /* ** The following values may be passed as the second argument to ** sqlite3OsLock(). */ #define SHARED_LOCK 1 #define RESERVED_LOCK 2 #define PENDING_LOCK 3 #define EXCLUSIVE_LOCK 4 int sqlite3OsDelete(const char*); int sqlite3OsFileExists(const char*); | > | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | # define TEMP_FILE_PREFIX "sqlite_" #endif /* ** 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 #define EXCLUSIVE_LOCK 4 int sqlite3OsDelete(const char*); int sqlite3OsFileExists(const char*); |
︙ | ︙ |
Changes to src/os_unix.c.
︙ | ︙ | |||
637 638 639 640 641 642 643 | if( fstat(id->fd, &buf)!=0 ){ return SQLITE_IOERR; } *pSize = buf.st_size; return SQLITE_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < | 637 638 639 640 641 642 643 644 645 646 647 648 649 650 | if( fstat(id->fd, &buf)!=0 ){ return SQLITE_IOERR; } *pSize = buf.st_size; return SQLITE_OK; } /* ** 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 ** non-zero, otherwise zero. */ int sqlite3OsCheckWriteLock(OsFile *id){ int r = 0; |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** ** @(#) $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" #include "pager.h" #include <assert.h> #include <string.h> |
︙ | ︙ | |||
518 519 520 521 522 523 524 | pPg->inJournal = 0; pPg->dirty = 0; pPg->needSync = 0; } }else{ assert( pPager->dirtyFile==0 || pPager->useJournal==0 ); } | | | 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 | pPg->inJournal = 0; pPg->dirty = 0; pPg->needSync = 0; } }else{ assert( pPager->dirtyFile==0 || pPager->useJournal==0 ); } rc = sqlite3OsLock(&pPager->fd, SHARED_LOCK); if( rc==SQLITE_OK ){ pPager->state = SQLITE_READLOCK; }else{ /* This can only happen if a process does a BEGIN, then forks and the ** child process does the COMMIT. Because of the semantics of unix ** file locking, the unlock will fail. */ |
︙ | ︙ | |||
654 655 656 657 658 659 660 661 662 663 664 | if( sqlite3OsFileExists(zJournal) ){ /* One of the journals pointed to by the master journal exists. ** Open it and check if it points at the master journal. If ** so, return without deleting the master journal file. */ OsFile journal; int nMaster; rc = sqlite3OsOpenReadOnly(zJournal, &journal); if( rc!=SQLITE_OK ){ sqlite3OsClose(&journal); | > > > > | > > > > > > > | > | > | 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 | if( sqlite3OsFileExists(zJournal) ){ /* One of the journals pointed to by the master journal exists. ** Open it and check if it points at the master journal. If ** so, return without deleting the master journal file. */ OsFile journal; int nMaster; off_t jsz; rc = sqlite3OsOpenReadOnly(zJournal, &journal); sqliteFree(zJournal); if( rc!=SQLITE_OK ){ sqlite3OsClose(&journal); goto delmaster_out; } /* 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. */ rc = sqlite3OsSeek(&journal, sizeof(aJournalMagic3)+2*sizeof(u32)); if( rc!=SQLITE_OK ) goto delmaster_out; rc = read32bits(3, &journal, (u32 *)&nMaster); |
︙ | ︙ | |||
1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 | ** Given a list of pages (connected by the PgHdr.pDirty pointer) write ** every one of those pages out to the database file and mark them all ** as clean. */ static int pager_write_pagelist(PgHdr *pList){ Pager *pPager; int rc; if( pList==0 ) return SQLITE_OK; pPager = pList->pPager; while( pList ){ assert( pList->dirty ); sqlite3OsSeek(&pPager->fd, (pList->pgno-1)*(off_t)SQLITE_PAGE_SIZE); CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6); TRACE2("STORE %d\n", pList->pgno); rc = sqlite3OsWrite(&pPager->fd, PGHDR_TO_DATA(pList), SQLITE_PAGE_SIZE); CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 | ** Given a list of pages (connected by the PgHdr.pDirty pointer) write ** every one of those pages out to the database file and mark them all ** as clean. */ 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); CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6); TRACE2("STORE %d\n", pList->pgno); rc = sqlite3OsWrite(&pPager->fd, PGHDR_TO_DATA(pList), SQLITE_PAGE_SIZE); CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0); |
︙ | ︙ | |||
1603 1604 1605 1606 1607 1608 1609 | } /* If this is the first page accessed, then get a SHARED lock ** on the database file. */ if( pPager->nRef==0 && !pPager->memDb ){ int busy = 1; | | | | | | | | < < < < | | < | 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 | } /* If this is the first page accessed, then get a SHARED lock ** on the database file. */ if( pPager->nRef==0 && !pPager->memDb ){ int busy = 1; 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; /* If a journal file exists, and there is no RESERVED lock on the ** database file, then it either needs to be played back or deleted. */ if( pPager->useJournal && |
︙ | ︙ | |||
1902 1903 1904 1905 1906 1907 1908 | int rc; assert( pPager->state==SQLITE_WRITELOCK ); assert( pPager->journalOpen==0 ); assert( pPager->useJournal ); sqlite3pager_pagecount(pPager); pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 ); if( pPager->aInJournal==0 ){ | | | | 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 | int rc; assert( pPager->state==SQLITE_WRITELOCK ); assert( pPager->journalOpen==0 ); assert( pPager->useJournal ); sqlite3pager_pagecount(pPager); pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 ); if( pPager->aInJournal==0 ){ sqlite3OsLock(&pPager->fd, SHARED_LOCK); pPager->state = SQLITE_READLOCK; return SQLITE_NOMEM; } rc = sqlite3OsOpenExclusive(pPager->zJournal, &pPager->jfd,pPager->tempFile); if( rc!=SQLITE_OK ){ sqliteFree(pPager->aInJournal); pPager->aInJournal = 0; sqlite3OsLock(&pPager->fd, SHARED_LOCK); pPager->state = SQLITE_READLOCK; return SQLITE_CANTOPEN; } sqlite3OsOpenDirectory(pPager->zDirectory, &pPager->jfd); pPager->journalOpen = 1; pPager->journalStarted = 0; pPager->needSync = 0; |
︙ | ︙ | |||
2016 2017 2018 2019 2020 2021 2022 | if( pPager->state==SQLITE_READLOCK ){ assert( pPager->aInJournal==0 ); if( pPager->memDb ){ pPager->state = SQLITE_WRITELOCK; pPager->origDbSize = pPager->dbSize; }else{ int busy = 1; | | > > > > > | | | | | | < < < < | | < | 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 | if( pPager->state==SQLITE_READLOCK ){ assert( pPager->aInJournal==0 ); if( pPager->memDb ){ pPager->state = SQLITE_WRITELOCK; pPager->origDbSize = pPager->dbSize; }else{ int busy = 1; 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; pPager->dirtyFile = 0; TRACE1("TRANSACTION\n"); if( pPager->useJournal && !pPager->tempFile ){ rc = pager_open_journal(pPager); |
︙ | ︙ | |||
2511 2512 2513 2514 2515 2516 2517 | if( !pPager->journalOpen ){ pPager->stmtAutoopen = 1; return SQLITE_OK; } assert( pPager->journalOpen ); pPager->aInStmt = sqliteMalloc( pPager->dbSize/8 + 1 ); if( pPager->aInStmt==0 ){ | | | 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 | if( !pPager->journalOpen ){ pPager->stmtAutoopen = 1; return SQLITE_OK; } assert( pPager->journalOpen ); pPager->aInStmt = sqliteMalloc( pPager->dbSize/8 + 1 ); if( pPager->aInStmt==0 ){ sqlite3OsLock(&pPager->fd, SHARED_LOCK); return SQLITE_NOMEM; } #ifndef NDEBUG rc = sqlite3OsFileSize(&pPager->jfd, &pPager->stmtJSize); if( rc ) goto stmt_begin_failed; assert( pPager->stmtJSize == pPager->nRec*JOURNAL_PG_SZ(journal_format) + |
︙ | ︙ |