Esempio n. 1
0
        // was:sqlite3PagerOpen
        public static RC Open(VirtualFileSystem pVfs, out Pager ppPager, string zFilename, int nExtra, PAGEROPEN flags, VFSOPEN vfsFlags, Action<PgHdr> xReinit, Func<object> memPageBuilder)
        {
            Pager pPager = null;     // Pager object to allocate and return
            byte memDb = 0;            // True if this is an in-memory file
            bool readOnly = false;   // True if this is a read-only file
            string zPathname = null; // Full path to database file
            //int nPathname = 0;       // Number of bytes in zPathname
            bool useJournal = (flags & PAGEROPEN.OMIT_JOURNAL) == 0; // False to omit journal
            bool noReadlock = (flags & PAGEROPEN.NO_READLOCK) != 0;  // True to omit read-lock
            int pcacheSize = PCache.sqlite3PcacheSize();       // Bytes to allocate for PCache
            uint szPageDflt = SQLITE_DEFAULT_PAGE_SIZE;  // Default page size
            string zUri = null;     // URI args to copy
            int nUri = 0;           // Number of bytes of URI args at *zUri
            // Figure out how much space is required for each journal file-handle (there are two of them, the main journal and the sub-journal). This
            // is the maximum space required for an in-memory journal file handle and a regular journal file-handle. Note that a "regular journal-handle"
            // may be a wrapper capable of caching the first portion of the journal file in memory to implement the atomic-write optimization (see
            // source file journal.c).
            int journalFileSize = SysEx.ROUND8(sqlite3JournalSize(pVfs) > MemJournalFile.sqlite3MemJournalSize() ? sqlite3JournalSize(pVfs) : MemJournalFile.sqlite3MemJournalSize()); // Bytes to allocate for each journal fd
            // Set the output variable to NULL in case an error occurs.
            ppPager = null;
            #if !SQLITE_OMIT_MEMORYDB
            if ((flags & PAGEROPEN.MEMORY) != 0)
            {
                memDb = 1;
                zFilename = null;
            }
            #endif
            // Compute and store the full pathname in an allocated buffer pointed to by zPathname, length nPathname. Or, if this is a temporary file,
            // leave both nPathname and zPathname set to 0.
            var rc = RC.OK;
            if (!string.IsNullOrEmpty(zFilename))
            {
                rc = pVfs.xFullPathname(zFilename, out zPathname);
                var z = zUri = zFilename;
                nUri = zUri.Length;
                if (rc == RC.OK && zPathname.Length + 8 > pVfs.mxPathname)
                    // This branch is taken when the journal path required by the database being opened will be more than pVfs.mxPathname
                    // bytes in length. This means the database cannot be opened, as it will not be possible to open the journal file or even
                    // check for a hot-journal before reading.
                    rc = SysEx.SQLITE_CANTOPEN_BKPT();
                if (rc != RC.OK)
                    return rc;
            }
            // Allocate memory for the Pager structure, PCache object, the three file descriptors, the database file name and the journal
            // file name. The layout in memory is as follows:
            //     Pager object                    (sizeof(Pager) bytes)
            //     PCache object                   (sqlite3PcacheSize() bytes)
            //     Database file handle            (pVfs.szOsFile bytes)
            //     Sub-journal file handle         (journalFileSize bytes)
            //     Main journal file handle        (journalFileSize bytes)
            //     Database file name              (nPathname+1 bytes)
            //     Journal file name               (nPathname+8+1 bytes)
            pPager = new Pager(memPageBuilder);
            pPager.pPCache = new PCache();
            pPager.fd = new VirtualFile();
            pPager.sjfd = new VirtualFile();
            pPager.jfd = new VirtualFile();
            // Fill in the Pager.zFilename and Pager.zJournal buffers, if required.
            if (zPathname != null)
            {
                Debug.Assert(zPathname.Length > 0);
                pPager.zFilename = zPathname.ToString();
                zUri = pPager.zFilename;
                pPager.zJournal = pPager.zFilename + "-journal";
            #if !SQLITE_OMIT_WAL
                pPager.zWal = &pPager.zJournal[nPathname + 8 + 1];
                memcpy(pPager.zWal, zPathname, nPathname);
                memcpy(&pPager.zWal[nPathname], "-wal", 4);
            #endif
            }
            else
                pPager.zFilename = string.Empty;
            pPager.pVfs = pVfs;
            pPager.vfsFlags = vfsFlags;
            // Open the pager file.
            var tempFile = LOCKINGMODE.NORMAL;         // True for temp files (incl. in-memory files)
            if (!string.IsNullOrEmpty(zFilename))
            {
                VFSOPEN fout = 0; // VFS flags returned by xOpen()
                rc = FileEx.sqlite3OsOpen(pVfs, zFilename, pPager.fd, vfsFlags, ref fout);
                Debug.Assert(0 == memDb);
                readOnly = (fout & VFSOPEN.READONLY) != 0;
                // If the file was successfully opened for read/write access, choose a default page size in case we have to create the
                // database file. The default page size is the maximum of:
                //    + SQLITE_DEFAULT_PAGE_SIZE,
                //    + The value returned by sqlite3OsSectorSize()
                //    + The largest page size that can be written atomically.
                if (rc == RC.OK && !readOnly)
                {
                    pPager.setSectorSize();
                    Debug.Assert(SQLITE_DEFAULT_PAGE_SIZE <= SQLITE_MAX_DEFAULT_PAGE_SIZE);
                    if (szPageDflt < pPager.sectorSize)
                        szPageDflt = (pPager.sectorSize > SQLITE_MAX_DEFAULT_PAGE_SIZE ? SQLITE_MAX_DEFAULT_PAGE_SIZE : (uint)pPager.sectorSize);
            #if SQLITE_ENABLE_ATOMIC_WRITE
                    int iDc = sqlite3OsDeviceCharacteristics(pPager.fd);
                    Debug.Assert(SQLITE_IOCAP_ATOMIC512 == (512 >> 8));
                    Debug.Assert(SQLITE_IOCAP_ATOMIC64K == (65536 >> 8));
                    Debug.Assert(SQLITE_MAX_DEFAULT_PAGE_SIZE <= 65536);
                    for (var ii = szPageDflt; ii <= SQLITE_MAX_DEFAULT_PAGE_SIZE; ii = ii * 2)
                        if (iDc & (SQLITE_IOCAP_ATOMIC | (ii >> 8)))
                            szPageDflt = ii;
            #endif
                }
            }
            else
            {
                // If a temporary file is requested, it is not opened immediately. In this case we accept the default page size and delay actually
                // opening the file until the first call to OsWrite().
                // This branch is also run for an in-memory database. An in-memory database is the same as a temp-file that is never written out to
                // disk and uses an in-memory rollback journal.
                tempFile = LOCKINGMODE.EXCLUSIVE;
                pPager.eState = PAGER.READER;
                pPager.eLock = VFSLOCK.EXCLUSIVE;
                readOnly = (vfsFlags & VFSOPEN.READONLY) != 0;
            }

            // The following call to PagerSetPagesize() serves to set the value of Pager.pageSize and to allocate the Pager.pTmpSpace buffer.
            if (rc == RC.OK)
            {
                Debug.Assert(pPager.memDb == 0);
                rc = pPager.SetPageSize(ref szPageDflt, -1);
            }
            // If an error occurred in either of the blocks above, free the Pager structure and close the file.
            if (rc != RC.OK)
            {
                Debug.Assert(null == pPager.pTmpSpace);
                FileEx.sqlite3OsClose(pPager.fd);
                return rc;
            }
            // Initialize the PCache object.
            Debug.Assert(nExtra < 1000);
            nExtra = SysEx.ROUND8(nExtra);
            PCache.Open((int)szPageDflt, nExtra, (memDb == 0), (memDb == 0 ? (Func<object, PgHdr, RC>)pagerStress : null), pPager, pPager.pPCache);
            PAGERTRACE("OPEN {0} {1}", FILEHANDLEID(pPager.fd), pPager.zFilename);
            SysEx.IOTRACE("OPEN {0:x} {1}", pPager.GetHashCode(), pPager.zFilename);
            pPager.useJournal = (byte)(useJournal ? 1 : 0);
            pPager.noReadlock = (byte)(noReadlock && readOnly ? 1 : 0);
            pPager.mxPgno = SQLITE_MAX_PAGE_COUNT;
            #if false
            Debug.Assert(pPager.state == (tempFile != 0 ? PAGER.EXCLUSIVE : PAGER.UNLOCK));
            #endif
            pPager.tempFile = tempFile != 0;
            Debug.Assert(tempFile == LOCKINGMODE.NORMAL || tempFile == LOCKINGMODE.EXCLUSIVE);
            pPager.exclusiveMode = tempFile != 0;
            pPager.changeCountDone = pPager.tempFile;
            pPager.memDb = memDb;
            pPager.readOnly = readOnly;
            Debug.Assert(useJournal || pPager.tempFile);
            pPager.noSync = pPager.tempFile;
            pPager.fullSync = pPager.noSync;
            pPager.syncFlags = (pPager.noSync ? 0 : VirtualFile.SYNC.NORMAL);
            pPager.ckptSyncFlags = pPager.syncFlags;
            pPager.nExtra = (ushort)nExtra;
            pPager.journalSizeLimit = SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT;
            Debug.Assert(pPager.fd.IsOpen || tempFile != 0);
            pPager.setSectorSize();
            if (!useJournal)
                pPager.journalMode = JOURNALMODE.OFF;
            else if (memDb != 0)
                pPager.journalMode = JOURNALMODE.MEMORY;
            pPager.xReiniter = xReinit;
            ppPager = pPager;
            return RC.OK;
        }