Пример #1
0
/*
** Call sqlite3WalOpen() to open the WAL handle. If the pager is in
** exclusive-locking mode when this function is called, take an EXCLUSIVE
** lock on the database file and use heap-memory to store the wal-index
** in. Otherwise, use the normal shared-memory.
*/
        static int pagerOpenWal(Pager *pPager)
        {
            int rc = SQLITE.OK;

            assert(pPager.pWal == 0 && pPager.tempFile == 0);
            assert(pPager.eLock == SHARED_LOCK || pPager.eLock == EXCLUSIVE_LOCK || pPager.noReadlock);

/* If the pager is already in exclusive-mode, the WAL module will use
** heap-memory for the wal-index instead of the VFS shared-memory
** implementation. Take the exclusive lock now, before opening the WAL
** file, to make sure this is safe.
*/
            if (pPager.exclusiveMode)
            {
                rc = pagerExclusiveLock(pPager);
            }

/* Open the connection to the log file. If this operation fails,
** (e.g. due to malloc() failure), return an error code.
*/
            if (rc == SQLITE.OK)
            {
                rc = sqlite3WalOpen(pPager.pVfs,
                                    pPager.fd, pPager.zWal, pPager.exclusiveMode, &pPager.pWal
                                    pPager.journalSizeLimit, &pPager.pWal
                                    );
            }

            return(rc);
        }
Пример #2
0
/*
** This function is called when the user invokes "PRAGMA wal_checkpoint",
** "PRAGMA wal_blocking_checkpoint" or calls the sqlite3_wal_checkpoint()
** or wal_blocking_checkpoint() API functions.
**
** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
*/
        int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt)
        {
            int rc = SQLITE.OK;

            if (pPager.pWal)
            {
                rc = sqlite3WalCheckpoint(pPager.pWal, eMode,
                                          pPager.xBusyHandler, pPager.pBusyHandlerArg,
                                          pPager.ckptSyncFlags, pPager.pageSize, (u8 *)pPager.pTmpSpace,
                                          pnLog, pnCkpt
                                          );
            }
            return(rc);
        }
Пример #3
0
/*
** Attempt to take an exclusive lock on the database file. If a PENDING lock
** is obtained instead, immediately release it.
*/
        static int pagerExclusiveLock(Pager *pPager)
        {
            int rc;             /* Return code */

            assert(pPager.eLock == SHARED_LOCK || pPager.eLock == EXCLUSIVE_LOCK);
            rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
            if (rc != SQLITE.OK)
            {
/* If the attempt to grab the exclusive lock failed, release the
** pending lock that may have been obtained instead.  */
                pagerUnlockDb(pPager, SHARED_LOCK);
            }

            return(rc);
        }
Пример #4
0
        /*
        ** Check if the *-wal file that corresponds to the database opened by pPager
        ** exists if the database is not empy, or verify that the *-wal file does
        ** not exist (by deleting it) if the database file is empty.
        **
        ** If the database is not empty and the *-wal file exists, open the pager
        ** in WAL mode.  If the database is empty or if no *-wal file exists and
        ** if no error occurs, make sure Pager.journalMode is not set to
        ** PAGER_JOURNALMODE_WAL.
        **
        ** Return SQLITE.OK or an error code.
        **
        ** The caller must hold a SHARED lock on the database file to call this
        ** function. Because an EXCLUSIVE lock on the db file is required to delete
        ** a WAL on a none-empty database, this ensures there is no race condition
        ** between the xAccess() below and an xDelete() being executed by some
        ** other connection.
        */
        static int pagerOpenWalIfPresent(Pager *pPager)
        {
            int rc = SQLITE.OK;

            Debug.Assert(pPager.eState == PAGER_OPEN);
            Debug.Assert(pPager.eLock >= SHARED_LOCK || pPager.noReadlock);

            if (!pPager.tempFile)
            {
                int  isWal;                   /* True if WAL file exists */
                Pgno nPage;                   /* Size of the database file */

                rc = pagerPagecount(pPager, &nPage);
                if (rc)
                {
                    return(rc);
                }
                if (nPage == 0)
                {
                    rc    = sqlite3OsDelete(pPager.pVfs, pPager.zWal, 0);
                    isWal = 0;
                }
                else
                {
                    rc = sqlite3OsAccess(
                        pPager.pVfs, pPager.zWal, SQLITE_ACCESS_EXISTS, &isWal
                        );
                }
                if (rc == SQLITE.OK)
                {
                    if (isWal)
                    {
                        testcase(sqlite3PcachePagecount(pPager.pPCache) == 0);
                        rc = sqlite3PagerOpenWal(pPager, 0);
                    }
                    else if (pPager.journalMode == PAGER_JOURNALMODE_WAL)
                    {
                        pPager.journalMode = PAGER_JOURNALMODE_DELETE;
                    }
                }
            }
            return(rc);
        }
Пример #5
0
/*
** This function is called to close the connection to the log file prior
** to switching from WAL to rollback mode.
**
** Before closing the log file, this function attempts to take an
** EXCLUSIVE lock on the database file. If this cannot be obtained, an
** error (SQLITE_BUSY) is returned and the log connection is not closed.
** If successful, the EXCLUSIVE lock is not released before returning.
*/
        int sqlite3PagerCloseWal(Pager *pPager)
        {
            int rc = SQLITE.OK;

            assert(pPager.journalMode == PAGER_JOURNALMODE_WAL);

/* If the log file is not already open, but does exist in the file-system,
** it may need to be checkpointed before the connection can switch to
** rollback mode. Open it now so this can happen.
*/
            if (!pPager.pWal)
            {
                int logexists = 0;
                rc = pagerLockDb(pPager, SHARED_LOCK);
                if (rc == SQLITE.OK)
                {
                    rc = sqlite3OsAccess(
                        pPager.pVfs, pPager.zWal, SQLITE_ACCESS_EXISTS, &logexists
                        );
                }
                if (rc == SQLITE.OK && logexists)
                {
                    rc = pagerOpenWal(pPager);
                }
            }

/* Checkpoint and close the log. Because an EXCLUSIVE lock is held on
** the database file, the log and log-summary files will be deleted.
*/
            if (rc == SQLITE.OK && pPager.pWal)
            {
                rc = pagerExclusiveLock(pPager);
                if (rc == SQLITE.OK)
                {
                    rc = sqlite3WalClose(pPager.pWal, pPager.ckptSyncFlags,
                                         pPager.pageSize, (u8 *)pPager.pTmpSpace);
                    pPager.pWal = 0;
                }
            }
            return(rc);
        }
Пример #6
0
        /*
        ** Begin a read transaction on the WAL.
        **
        ** This routine used to be called "pagerOpenSnapshot()" because it essentially
        ** makes a snapshot of the database at the current point in time and preserves
        ** that snapshot for use by the reader in spite of concurrently changes by
        ** other writers or checkpointers.
        */
        static int pagerBeginReadTransaction(Pager *pPager)
        {
            int rc;                         /* Return code */
            int changed = 0;                /* True if cache must be reset */

            assert(pagerUseWal(pPager));
            assert(pPager.eState == PAGER_OPEN || pPager.eState == PAGER_READER);

            /* sqlite3WalEndReadTransaction() was not called for the previous
            ** transaction in locking_mode=EXCLUSIVE.  So call it now.  If we
            ** are in locking_mode=NORMAL and EndRead() was previously called,
            ** the duplicate call is harmless.
            */
            sqlite3WalEndReadTransaction(pPager.pWal);

            rc = sqlite3WalBeginReadTransaction(pPager.pWal, &changed);
            if (rc != SQLITE.OK || changed)
            {
                pager_reset(pPager);
            }

            return(rc);
        }
Пример #7
0
/*
** The caller must be holding a SHARED lock on the database file to call
** this function.
**
** If the pager passed as the first argument is open on a real database
** file (not a temp file or an in-memory database), and the WAL file
** is not already open, make an attempt to open it now. If successful,
** return SQLITE.OK. If an error occurs or the VFS used by the pager does
** not support the xShmXXX() methods, return an error code. *pbOpen is
** not modified in either case.
**
** If the pager is open on a temp-file (or in-memory database), or if
** the WAL file is already open, set *pbOpen to 1 and return SQLITE.OK
** without doing anything.
*/
        int sqlite3PagerOpenWal(
            Pager *pPager,      /* Pager object */
            int *pbOpen         /* OUT: Set to true if call is a no-op */
            )
        {
            int rc = SQLITE.OK; /* Return code */

            assert(assert_pager_state(pPager));
            assert(pPager.eState == PAGER_OPEN || pbOpen);
            assert(pPager.eState == PAGER_READER || !pbOpen);
            assert(pbOpen == 0 || *pbOpen == 0);
            assert(pbOpen != 0 || (!pPager.tempFile && !pPager.pWal));

            if (!pPager.tempFile && !pPager.pWal)
            {
                if (!sqlite3PagerWalSupported(pPager))
                {
                    return(SQLITE_CANTOPEN);
                }

/* Close any rollback journal previously open */
                sqlite3OsClose(pPager.jfd);

                rc = pagerOpenWal(pPager);
                if (rc == SQLITE.OK)
                {
                    pPager.journalMode = PAGER_JOURNALMODE_WAL;
                    pPager.eState      = PAGER_OPEN;
                }
            }
            else
            {
                *pbOpen = 1;
            }

            return(rc);
        }
Пример #8
0
/*
** Return true if the underlying VFS for the given pager supports the
** primitives necessary for write-ahead logging.
*/
        int sqlite3PagerWalSupported(Pager *pPager)
        {
            const sqlite3_io_methods *pMethods = pPager.fd->pMethods;

            return(pPager.exclusiveMode || (pMethods->iVersion >= 2 && pMethods->xShmMap));
        }
Пример #9
0
 int sqlite3PagerWalCallback(Pager *pPager)
 {
     return(sqlite3WalCallback(pPager.pWal));
 }