Example #1
0
        /*
        ** Parameter zSrcData points to a buffer containing the data for
        ** page iSrcPg from the source database. Copy this data into the
        ** destination database.
        */
        static int backupOnePage(sqlite3_backup p, Pgno iSrcPg, byte[] zSrcData)
        {
            Pager pDestPager = sqlite3BtreePager(p.pDest);
            int   nSrcPgsz   = sqlite3BtreeGetPageSize(p.pSrc);
            int   nDestPgsz  = sqlite3BtreeGetPageSize(p.pDest);
            int   nCopy      = MIN(nSrcPgsz, nDestPgsz);
            i64   iEnd       = (i64)iSrcPg * (i64)nSrcPgsz;

            int rc = SQLITE_OK;
            i64 iOff;

            Debug.Assert(p.bDestLocked != 0);
            Debug.Assert(!isFatalError(p.rc));
            Debug.Assert(iSrcPg != PENDING_BYTE_PAGE(p.pSrc.pBt));
            Debug.Assert(zSrcData != null);

            /* Catch the case where the destination is an in-memory database and the
            ** page sizes of the source and destination differ.
            */
            if (nSrcPgsz != nDestPgsz && sqlite3PagerIsMemdb(sqlite3BtreePager(p.pDest)))
            {
                rc = SQLITE_READONLY;
            }

            /* This loop runs once for each destination page spanned by the source
            ** page. For each iteration, variable iOff is set to the byte offset
            ** of the destination page.
            */
            for (iOff = iEnd - (i64)nSrcPgsz; rc == SQLITE_OK && iOff < iEnd; iOff += nDestPgsz)
            {
                DbPage pDestPg = null;
                u32    iDest   = (u32)(iOff / nDestPgsz) + 1;
                if (iDest == PENDING_BYTE_PAGE(p.pDest.pBt))
                {
                    continue;
                }
                if (SQLITE_OK == (rc = sqlite3PagerGet(pDestPager, iDest, ref pDestPg)) &&
                    SQLITE_OK == (rc = sqlite3PagerWrite(pDestPg))
                    )
                {
                    //string zIn = &zSrcData[iOff%nSrcPgsz];
                    byte[] zDestData = sqlite3PagerGetData(pDestPg);
                    //string zOut = &zDestData[iOff % nDestPgsz];

                    /* Copy the data from the source page into the destination page.
                    ** Then clear the Btree layer MemPage.isInit flag. Both this module
                    ** and the pager code use this trick (clearing the first byte
                    ** of the page 'extra' space to invalidate the Btree layers
                    ** cached parse of the page). MemPage.isInit is marked
                    ** "MUST BE FIRST" for this purpose.
                    */
                    Buffer.BlockCopy(zSrcData, (int)(iOff % nSrcPgsz), zDestData, (int)(iOff % nDestPgsz), nCopy); // memcpy( zOut, zIn, nCopy );
                    sqlite3PagerGetExtra(pDestPg).isInit = 0;                                                      // ( sqlite3PagerGetExtra( pDestPg ) )[0] = 0;
                }
                sqlite3PagerUnref(pDestPg);
            }

            return(rc);
        }
Example #2
0
        /// <summary>
        /// 获取页面类型信息
        /// </summary>
        /// <returns></returns>
        private PageMenu getPageMenu()
        {
            var      dbPage = new DbPage();
            PageMenu result = null;
            string   url    = this.GetPageUrl();

            result = dbPage.GetPageMenu(url);
            if (result == null)
            {
                PageMenu m = new PageMenu();
                m.ShowName = string.IsNullOrWhiteSpace(this.Title) ? "请设置名称" : this.Title;
                m.PageUrl  = url;
                dbPage.AddPageMenu(m);
                return(getPageMenu());
            }
            else
            {
                return(result);
            }
        }
    protected void GrpSiz_Changed(object sender, EventArgs e)
    {
        TextBox     txtGrpSiz = sender as TextBox;
        GridViewRow row       = txtGrpSiz.NamingContainer as GridViewRow;

        AjaxControlToolkit.ComboBox combo = row.FindControl("comboEdit3") as AjaxControlToolkit.ComboBox;

        string postbackControlId = "";

        try
        {
            if (ScriptManager.GetCurrent(txtGrpSiz.Page).IsInAsyncPostBack)
            {
                postbackControlId = DbPage.GetAsyncPostBackControlID(txtGrpSiz.Page);
            }
            else
            {
                postbackControlId = DbPage.GetPostBackControl(txtGrpSiz.Page).ID;
            }
        }
        catch (Exception) { }
        if (!postbackControlId.EndsWith(combo.ID))
        {
            int num = 0;
            try
            {
                num = int.Parse(txtGrpSiz.Text);
                if (num == -1)
                {
                    combo.SelectedValue = "Delay";
                }
                else if (num > 0)
                {
                    combo.SelectedValue = "Standard";
                }
                //txtGrpSiz.Text = 10 + "";
            }
            catch (Exception) { }
        }
    }
Example #4
0
/*
** During a rollback, when the pager reloads information into the cache
** so that the cache is restored to its original state at the start of
** the transaction, for each page restored this routine is called.
**
** This routine needs to reset the extra data section at the end of the
** page to agree with the restored data.
*/
static void pageReinit( DbPage pData )
{
  MemPage pPage;
  pPage = sqlite3PagerGetExtra( pData );
  Debug.Assert( sqlite3PagerPageRefcount( pData ) > 0 );
  if ( pPage.isInit != 0 )
  {
    Debug.Assert( sqlite3_mutex_held( pPage.pBt.mutex ) );
    pPage.isInit = 0;
    if ( sqlite3PagerPageRefcount( pData ) > 1 )
    {
      /* pPage might not be a btree page;  it might be an overflow page
      ** or ptrmap page or a free page.  In those cases, the following
      ** call to btreeInitPage() will likely return SQLITE_CORRUPT.
      ** But no harm is done by this.  And it is very important that
      ** btreeInitPage() be called on every btree page so we make
      ** the call for every page that comes in for re-initing. */
      btreeInitPage( pPage );
    }
  }
}
Example #5
0
/*
** Convert a DbPage obtained from the pager into a MemPage used by
** the btree layer.
*/
static MemPage btreePageFromDbPage( DbPage pDbPage, Pgno pgno, BtShared pBt )
{
  MemPage pPage = (MemPage)sqlite3PagerGetExtra( pDbPage );
  pPage.aData = sqlite3PagerGetData( pDbPage );
  pPage.pDbPage = pDbPage;
  pPage.pBt = pBt;
  pPage.pgno = pgno;
  pPage.hdrOffset = (u8)( pPage.pgno == 1 ? 100 : 0 );
  return pPage;
}
Example #6
0
 /*
 ** Return a pointer to the Pager.nExtra bytes of "extra" space
 ** allocated along with the specified page.
 */
 static MemPage sqlite3PagerGetExtra( DbPage pPg )
 {
   return pPg.pExtra;
 }
Example #7
0
/*
** Return a pointer to the data for the specified page.
*/
    static byte[] sqlite3PagerGetData( DbPage pPg )
    {
      Debug.Assert( pPg.nRef > 0 || pPg.pPager.memDb != 0 );
      return pPg.pData;
    }
Example #8
0
    /*
** Move the page pPg to location pgno in the file.
**
** There must be no references to the page previously located at
** pgno (which we call pPgOld) though that page is allowed to be
** in cache.  If the page previously located at pgno is not already
** in the rollback journal, it is not put there by by this routine.
**
** References to the page pPg remain valid. Updating any
** meta-data associated with pPg (i.e. data stored in the nExtra bytes
** allocated along with the page) is the responsibility of the caller.
**
** A transaction must be active when this routine is called. It used to be
** required that a statement transaction was not active, but this restriction
** has been removed (CREATE INDEX needs to move a page when a statement
** transaction is active).
**
** If the fourth argument, isCommit, is non-zero, then this page is being
** moved as part of a database reorganization just before the transaction
** is being committed. In this case, it is guaranteed that the database page
** pPg refers to will not be written to again within this transaction.
**
** This function may return SQLITE_NOMEM or an IO error code if an error
** occurs. Otherwise, it returns SQLITE_OK.
*/
    static int sqlite3PagerMovepage( Pager pPager, DbPage pPg, u32 pgno, int isCommit )
    {
      PgHdr pPgOld;                /* The page being overwritten. */
      u32 needSyncPgno = 0;        /* Old value of pPg.pgno, if sync is required */
      int rc;                      /* Return code */
      Pgno origPgno;               /* The original page number */

      Debug.Assert( pPg.nRef > 0 );

      /* In order to be able to rollback, an in-memory database must journal
      ** the page we are moving from.
      */
      if (
#if SQLITE_OMIT_MEMORYDB
1==MEMDB
#else
 pPager.memDb != 0
#endif
 )
      {
        rc = sqlite3PagerWrite( pPg );
        if ( rc != 0 ) return rc;
      }

      /* If the page being moved is dirty and has not been saved by the latest
      ** savepoint, then save the current contents of the page into the
      ** sub-journal now. This is required to handle the following scenario:
      **
      **   BEGIN;
      **     <journal page X, then modify it in memory>
      **     SAVEPOINT one;
      **       <Move page X to location Y>
      **     ROLLBACK TO one;
      **
      ** If page X were not written to the sub-journal here, it would not
      ** be possible to restore its contents when the "ROLLBACK TO one"
      ** statement were is processed.
      **
      ** subjournalPage() may need to allocate space to store pPg.pgno into
      ** one or more savepoint bitvecs. This is the reason this function
      ** may return SQLITE_NOMEM.
      */
      if ( ( pPg.flags & PGHDR_DIRTY ) != 0
      && subjRequiresPage( pPg )
      && SQLITE_OK != ( rc = subjournalPage( pPg ) )
      )
      {
        return rc;
      }

      PAGERTRACE( "MOVE %d page %d (needSync=%d) moves to %d\n",
      PAGERID( pPager ), pPg.pgno, ( pPg.flags & PGHDR_NEED_SYNC ) != 0 ? 1 : 0, pgno );
      IOTRACE( "MOVE %p %d %d\n", pPager, pPg.pgno, pgno );

      /* If the journal needs to be sync()ed before page pPg.pgno can
      ** be written to, store pPg.pgno in local variable needSyncPgno.
      **
      ** If the isCommit flag is set, there is no need to remember that
      ** the journal needs to be sync()ed before database page pPg.pgno
      ** can be written to. The caller has already promised not to write to it.
      */
      if ( ( ( pPg.flags & PGHDR_NEED_SYNC ) != 0 ) && 0 == isCommit )
      {
        needSyncPgno = pPg.pgno;
        Debug.Assert( pageInJournal( pPg ) || pPg.pgno > pPager.dbOrigSize );
        Debug.Assert( ( pPg.flags & PGHDR_DIRTY ) != 0 );
        Debug.Assert( pPager.needSync );
      }

      /* If the cache contains a page with page-number pgno, remove it
      ** from its hash chain. Also, if the PgHdr.needSync was set for
      ** page pgno before the 'move' operation, it needs to be retained
      ** for the page moved there.
      */
      pPg.flags &= ~PGHDR_NEED_SYNC;
      pPgOld = pager_lookup( pPager, pgno );
      Debug.Assert( null == pPgOld || pPgOld.nRef == 1 );
      if ( pPgOld != null )
      {
        pPg.flags |= ( pPgOld.flags & PGHDR_NEED_SYNC );
        if (
#if SQLITE_OMIT_MEMORYDB
1==MEMDB
#else
 pPager.memDb != 0
#endif
 )
        {
          /* Do not discard pages from an in-memory database since we might
          ** need to rollback later.  Just move the page out of the way. */
          Debug.Assert( pPager.dbSizeValid );
          sqlite3PcacheMove( pPgOld, pPager.dbSize + 1 );
        }
        else
        {
          sqlite3PcacheDrop( pPgOld );
        }
      }
      origPgno = pPg.pgno;
      sqlite3PcacheMove( pPg, pgno );
      sqlite3PcacheMakeDirty( pPg );
      pPager.dbModified = true;

      if ( needSyncPgno != 0 )
      {
        /* If needSyncPgno is non-zero, then the journal file needs to be
        ** sync()ed before any data is written to database file page needSyncPgno.
        ** Currently, no such page exists in the page-cache and the
        ** "is journaled" bitvec flag has been set. This needs to be remedied by
        ** loading the page into the pager-cache and setting the PgHdr.needSync
        ** flag.
        **
        ** If the attempt to load the page into the page-cache fails, (due
        ** to a malloc() or IO failure), clear the bit in the pInJournal[]
        ** array. Otherwise, if the page is loaded and written again in
        ** this transaction, it may be written to the database file before
        ** it is synced into the journal file. This way, it may end up in
        ** the journal file twice, but that is not a problem.
        **
        ** The sqlite3PagerGet() call may cause the journal to sync. So make
        ** sure the Pager.needSync flag is set too.
        */
        PgHdr pPgHdr = null;
        Debug.Assert( pPager.needSync );
        rc = sqlite3PagerGet( pPager, needSyncPgno, ref pPgHdr );
        if ( rc != SQLITE_OK )
        {
          if ( needSyncPgno <= pPager.dbOrigSize )
          {
            Debug.Assert( pPager.pTmpSpace != null );
            u32[] pTemp = new u32[pPager.pTmpSpace.Length];
            sqlite3BitvecClear( pPager.pInJournal, needSyncPgno, pTemp );//pPager.pTmpSpace );
          }
          return rc;
        }
        pPager.needSync = true;
        Debug.Assert( pPager.noSync == false &&
#if SQLITE_OMIT_MEMORYDB
0==MEMDB
#else
 0 == pPager.memDb
#endif
 );
        pPgHdr.flags |= PGHDR_NEED_SYNC;
        sqlite3PcacheMakeDirty( pPgHdr );
        sqlite3PagerUnref( pPgHdr );
      }

      /*
      ** For an in-memory database, make sure the original page continues
      ** to exist, in case the transaction needs to roll back.  Use pPgOld
      ** as the original page since it has already been allocated.
      */
      if (
#if SQLITE_OMIT_MEMORYDB
MEMDB != 0
#else
 pPager.memDb != 0
#endif
 )
      {
        sqlite3PcacheMove( pPgOld, origPgno );
        sqlite3PagerUnref( pPgOld );
      }
      return SQLITE_OK;
    }
Example #9
0
 /*
 ** Return the number of references to the specified page.
 */
 static int sqlite3PagerPageRefcount( DbPage pPage )
 {
   return sqlite3PcachePageRefcount( pPage );
 }
Example #10
0
static Pgno sqlite3PagerPagenumber( DbPage pPg )    {      return pPg.pgno;    }
Example #11
0
/*
** Copy nPage pages from the source b-tree to the destination.
*/
        static public int sqlite3_backup_step(sqlite3_backup p, int nPage)
        {
            int rc;
            int destMode;     /* Destination journal mode */
            int pgszSrc  = 0; /* Source page size */
            int pgszDest = 0; /* Destination page size */

            sqlite3_mutex_enter(p.pSrcDb.mutex);
            sqlite3BtreeEnter(p.pSrc);
            if (p.pDestDb != null)
            {
                sqlite3_mutex_enter(p.pDestDb.mutex);
            }

            rc = p.rc;
            if (!isFatalError(rc))
            {
                Pager pSrcPager  = sqlite3BtreePager(p.pSrc);  /* Source pager */
                Pager pDestPager = sqlite3BtreePager(p.pDest); /* Dest pager */
                int   ii;                                      /* Iterator variable */
                Pgno  nSrcPage    = 0;                         /* Size of source db in pages */
                int   bCloseTrans = 0;                         /* True if src db requires unlocking */

                /* If the source pager is currently in a write-transaction, return
                ** SQLITE_BUSY immediately.
                */
                if (p.pDestDb != null && p.pSrc.pBt.inTransaction == TRANS_WRITE)
                {
                    rc = SQLITE_BUSY;
                }
                else
                {
                    rc = SQLITE_OK;
                }

                /* Lock the destination database, if it is not locked already. */
                if (SQLITE_OK == rc && p.bDestLocked == 0 &&
                    SQLITE_OK == (rc = sqlite3BtreeBeginTrans(p.pDest, 2))
                    )
                {
                    p.bDestLocked = 1;
                    sqlite3BtreeGetMeta(p.pDest, BTREE_SCHEMA_VERSION, ref p.iDestSchema);
                }

                /* If there is no open read-transaction on the source database, open
                ** one now. If a transaction is opened here, then it will be closed
                ** before this function exits.
                */
                if (rc == SQLITE_OK && !sqlite3BtreeIsInReadTrans(p.pSrc))
                {
                    rc          = sqlite3BtreeBeginTrans(p.pSrc, 0);
                    bCloseTrans = 1;
                }

                /* Do not allow backup if the destination database is in WAL mode
                ** and the page sizes are different between source and destination */
                pgszSrc  = sqlite3BtreeGetPageSize(p.pSrc);
                pgszDest = sqlite3BtreeGetPageSize(p.pDest);
                destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p.pDest));
                if (SQLITE_OK == rc && destMode == PAGER_JOURNALMODE_WAL && pgszSrc != pgszDest)
                {
                    rc = SQLITE_READONLY;
                }

                /* Now that there is a read-lock on the source database, query the
                ** source pager for the number of pages in the database.
                */
                nSrcPage = sqlite3BtreeLastPage(p.pSrc);
                Debug.Assert(nSrcPage >= 0);

                for (ii = 0; (nPage < 0 || ii < nPage) && p.iNext <= nSrcPage && 0 == rc; ii++)
                {
                    Pgno iSrcPg = p.iNext;   /* Source page number */
                    if (iSrcPg != PENDING_BYTE_PAGE(p.pSrc.pBt))
                    {
                        DbPage pSrcPg = null;             /* Source page object */
                        rc = sqlite3PagerGet(pSrcPager, (u32)iSrcPg, ref pSrcPg);
                        if (rc == SQLITE_OK)
                        {
                            rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg));
                            sqlite3PagerUnref(pSrcPg);
                        }
                    }
                    p.iNext++;
                }
                if (rc == SQLITE_OK)
                {
                    p.nPagecount = nSrcPage;
                    p.nRemaining = (nSrcPage + 1 - p.iNext);
                    if (p.iNext > nSrcPage)
                    {
                        rc = SQLITE_DONE;
                    }
                    else if (0 == p.isAttached)
                    {
                        attachBackupObject(p);
                    }
                }


                /* Update the schema version field in the destination database. This
                ** is to make sure that the schema-version really does change in
                ** the case where the source and destination databases have the
                ** same schema version.
                */
                if (rc == SQLITE_DONE &&
                    (rc = sqlite3BtreeUpdateMeta(p.pDest, 1, p.iDestSchema + 1)) == SQLITE_OK
                    )
                {
                    Pgno nDestTruncate;
                    if (p.pDestDb != null)
                    {
                        sqlite3ResetInternalSchema(p.pDestDb, -1);
                    }

                    /* Set nDestTruncate to the final number of pages in the destination
                    ** database. The complication here is that the destination page
                    ** size may be different to the source page size.
                    **
                    ** If the source page size is smaller than the destination page size,
                    ** round up. In this case the call to sqlite3OsTruncate() below will
                    ** fix the size of the file. However it is important to call
                    ** sqlite3PagerTruncateImage() here so that any pages in the
                    ** destination file that lie beyond the nDestTruncate page mark are
                    ** journalled by PagerCommitPhaseOne() before they are destroyed
                    ** by the file truncation.
                    */
                    Debug.Assert(pgszSrc == sqlite3BtreeGetPageSize(p.pSrc));
                    Debug.Assert(pgszDest == sqlite3BtreeGetPageSize(p.pDest));
                    if (pgszSrc < pgszDest)
                    {
                        int ratio = pgszDest / pgszSrc;
                        nDestTruncate = (Pgno)((nSrcPage + ratio - 1) / ratio);
                        if (nDestTruncate == (int)PENDING_BYTE_PAGE(p.pDest.pBt))
                        {
                            nDestTruncate--;
                        }
                    }
                    else
                    {
                        nDestTruncate = (Pgno)(nSrcPage * (pgszSrc / pgszDest));
                    }
                    sqlite3PagerTruncateImage(pDestPager, nDestTruncate);

                    if (pgszSrc < pgszDest)
                    {
                        /* If the source page-size is smaller than the destination page-size,
                        ** two extra things may need to happen:
                        **
                        **   * The destination may need to be truncated, and
                        **
                        **   * Data stored on the pages immediately following the
                        **     pending-byte page in the source database may need to be
                        **     copied into the destination database.
                        */
                        int          iSize = (int)(pgszSrc * nSrcPage);
                        sqlite3_file pFile = sqlite3PagerFile(pDestPager);
                        i64          iOff;
                        i64          iEnd;

                        Debug.Assert(pFile != null);
                        Debug.Assert((i64)nDestTruncate * (i64)pgszDest >= iSize || (
                                         nDestTruncate == (int)(PENDING_BYTE_PAGE(p.pDest.pBt) - 1) &&
                                         iSize >= PENDING_BYTE && iSize <= PENDING_BYTE + pgszDest
                                         ));

                        /* This call ensures that all data required to recreate the original
                        ** database has been stored in the journal for pDestPager and the
                        ** journal synced to disk. So at this point we may safely modify
                        ** the database file in any way, knowing that if a power failure
                        ** occurs, the original database will be reconstructed from the
                        ** journal file.  */
                        rc = sqlite3PagerCommitPhaseOne(pDestPager, null, true);

                        /* Write the extra pages and truncate the database file as required. */
                        iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
                        for (
                            iOff = PENDING_BYTE + pgszSrc;
                            rc == SQLITE_OK && iOff < iEnd;
                            iOff += pgszSrc
                            )
                        {
                            PgHdr pSrcPg = null;
                            u32   iSrcPg = (u32)((iOff / pgszSrc) + 1);
                            rc = sqlite3PagerGet(pSrcPager, iSrcPg, ref pSrcPg);
                            if (rc == SQLITE_OK)
                            {
                                byte[] zData = sqlite3PagerGetData(pSrcPg);
                                rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
                            }
                            sqlite3PagerUnref(pSrcPg);
                        }
                        if (rc == SQLITE_OK)
                        {
                            rc = backupTruncateFile(pFile, (int)iSize);
                        }

                        /* Sync the database file to disk. */
                        if (rc == SQLITE_OK)
                        {
                            rc = sqlite3PagerSync(pDestPager);
                        }
                    }
                    else
                    {
                        rc = sqlite3PagerCommitPhaseOne(pDestPager, null, false);
                    }

                    /* Finish committing the transaction to the destination database. */
                    if (SQLITE_OK == rc &&
                        SQLITE_OK == (rc = sqlite3BtreeCommitPhaseTwo(p.pDest, 0))
                        )
                    {
                        rc = SQLITE_DONE;
                    }
                }

                /* If bCloseTrans is true, then this function opened a read transaction
                ** on the source database. Close the read transaction here. There is
                ** no need to check the return values of the btree methods here, as
                ** "committing" a read-only transaction cannot fail.
                */
                if (bCloseTrans != 0)
                {
#if !NDEBUG || SQLITE_COVERAGE_TEST
                    //TESTONLY( int rc2 );
                    //TESTONLY( rc2  = ) sqlite3BtreeCommitPhaseOne(p.pSrc, 0);
                    //TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p.pSrc);
                    int rc2;
                    rc2  = sqlite3BtreeCommitPhaseOne(p.pSrc, string.Empty);
                    rc2 |= sqlite3BtreeCommitPhaseTwo(p.pSrc, 0);
                    Debug.Assert(rc2 == SQLITE_OK);
#else
                    sqlite3BtreeCommitPhaseOne(p.pSrc, null);
                    sqlite3BtreeCommitPhaseTwo(p.pSrc, 0);
#endif
                }

                if (rc == SQLITE_IOERR_NOMEM)
                {
                    rc = SQLITE_NOMEM;
                }
                p.rc = rc;
            }
            if (p.pDestDb != null)
            {
                sqlite3_mutex_leave(p.pDestDb.mutex);
            }
            sqlite3BtreeLeave(p.pSrc);
            sqlite3_mutex_leave(p.pSrcDb.mutex);
            return(rc);
        }
Example #12
0
    /*
    ** Mark a data page as writeable. This routine must be called before
    ** making changes to a page. The caller must check the return value
    ** of this function and be careful not to change any page data unless
    ** this routine returns SQLITE_OK.
    **
    ** The difference between this function and pager_write() is that this
    ** function also deals with the special case where 2 or more pages
    ** fit on a single disk sector. In this case all co-resident pages
    ** must have been written to the journal file before returning.
    **
    ** If an error occurs, SQLITE_NOMEM or an IO error code is returned
    ** as appropriate. Otherwise, SQLITE_OK.
    */
    static int sqlite3PagerWrite( DbPage pDbPage )
    {
      int rc = SQLITE_OK;

      PgHdr pPg = pDbPage;
      Pager pPager = pPg.pPager;
      u32 nPagePerSector = (u32)( pPager.sectorSize / pPager.pageSize );

      if ( nPagePerSector > 1 )
      {
        Pgno nPageCount = 0;     /* Total number of pages in database file */
        Pgno pg1;                /* First page of the sector pPg is located on. */
        Pgno nPage;              /* Number of pages starting at pg1 to journal */
        int ii;                  /* Loop counter */
        bool needSync = false;   /* True if any page has PGHDR_NEED_SYNC */

        /* Set the doNotSync flag to 1. This is because we cannot allow a journal
        ** header to be written between the pages journaled by this function.
        */
        Debug.Assert(
#if SQLITE_OMIT_MEMORYDB
0==MEMDB
#else
 0 == pPager.memDb
#endif
 );
        Debug.Assert( !pPager.doNotSync );
        pPager.doNotSync = true;

        /* This trick assumes that both the page-size and sector-size are
        ** an integer power of 2. It sets variable pg1 to the identifier
        ** of the first page of the sector pPg is located on.
        */
        pg1 = (u32)( ( pPg.pgno - 1 ) & ~( nPagePerSector - 1 ) ) + 1;

        sqlite3PagerPagecount( pPager, ref nPageCount );
        if ( pPg.pgno > nPageCount )
        {
          nPage = (u32)( pPg.pgno - pg1 ) + 1;
        }
        else if ( ( pg1 + nPagePerSector - 1 ) > nPageCount )
        {
          nPage = (u32)( nPageCount + 1 - pg1 );
        }
        else
        {
          nPage = nPagePerSector;
        }
        Debug.Assert( nPage > 0 );
        Debug.Assert( pg1 <= pPg.pgno );
        Debug.Assert( ( pg1 + nPage ) > pPg.pgno );

        for ( ii = 0; ii < nPage && rc == SQLITE_OK; ii++ )
        {
          u32 pg = (u32)( pg1 + ii );
          PgHdr pPage = new PgHdr();
          if ( pg == pPg.pgno || sqlite3BitvecTest( pPager.pInJournal, pg ) == 0 )
          {
            if ( pg != ( ( PENDING_BYTE / ( pPager.pageSize ) ) + 1 ) ) //PAGER_MJ_PGNO(pPager))
            {
              rc = sqlite3PagerGet( pPager, pg, ref pPage );
              if ( rc == SQLITE_OK )
              {
                rc = pager_write( pPage );
                if ( ( pPage.flags & PGHDR_NEED_SYNC ) != 0 )
                {
                  needSync = true;
                  Debug.Assert( pPager.needSync );

                }
                sqlite3PagerUnref( pPage );
              }
            }
          }
          else if ( ( pPage = pager_lookup( pPager, pg ) ) != null )
          {
            if ( ( pPage.flags & PGHDR_NEED_SYNC ) != 0 )
            {
              needSync = true;
            }
            sqlite3PagerUnref( pPage );
          }
        }

        /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages
        ** starting at pg1, then it needs to be set for all of them. Because
        ** writing to any of these nPage pages may damage the others, the
        ** journal file must contain sync()ed copies of all of them
        ** before any of them can be written out to the database file.
        */
        if ( rc == SQLITE_OK && needSync )
        {
          Debug.Assert(
#if SQLITE_OMIT_MEMORYDB
0==MEMDB
#else
 0 == pPager.memDb
#endif
 && pPager.noSync == false );
          for ( ii = 0; ii < nPage; ii++ )
          {
            PgHdr pPage = pager_lookup( pPager, (u32)( pg1 + ii ) );
            if ( pPage != null )
            {
              pPage.flags |= PGHDR_NEED_SYNC;
              sqlite3PagerUnref( pPage );
            }
          }
          Debug.Assert( pPager.needSync );
        }

        Debug.Assert( pPager.doNotSync );
        pPager.doNotSync = false;
      }
      else
      {
        rc = pager_write( pDbPage );
      }
      return rc;
    }
Example #13
0
 /*
 ** Release a page reference.
 **
 ** If the number of references to the page drop to zero, then the
 ** page is added to the LRU list.  When all references to all pages
 ** are released, a rollback occurs and the lock on the database is
 ** removed.
 */
 static void sqlite3PagerUnref( DbPage pPg )
 {
   if ( pPg != null )
   {
     Pager pPager = pPg.pPager;
     sqlite3PcacheRelease( pPg );
     pagerUnlockIfUnused( pPager );
   }
 }
Example #14
0
    static int sqlite3PagerAcquire(
    Pager pPager,      /* The pager open on the database file */
    u32 pgno,          /* Page number to fetch */
    ref DbPage ppPage, /* Write a pointer to the page here */
    u8 noContent     /* Do not bother reading content from disk if true */
    )
    {
      int rc;
      PgHdr pPg = null;

      Debug.Assert( assert_pager_state( pPager ) );
      Debug.Assert( pPager.state > PAGER_UNLOCK );
      if ( pgno == 0 )
      {
        return SQLITE_CORRUPT_BKPT();
      }

      /* If the pager is in the error state, return an error immediately. 
      ** Otherwise, request the page from the PCache layer. */
      if ( pPager.errCode != SQLITE_OK && pPager.errCode != SQLITE_FULL )
      {
        rc = pPager.errCode;
      }
      else
      {
        rc = sqlite3PcacheFetch( pPager.pPCache, pgno, 1, ref  ppPage );
      }

      if ( rc != SQLITE_OK )
      {
        /* Either the call to sqlite3PcacheFetch() returned an error or the
        ** pager was already in the error-state when this function was called.
        ** Set pPg to 0 and jump to the exception handler.  */
        pPg = null;
        goto pager_acquire_err;
      }
      Debug.Assert( ( ppPage ).pgno == pgno );
      Debug.Assert( ( ppPage ).pPager == pPager || ( ppPage ).pPager == null );

      if ( ( ppPage ).pPager != null )
      {
        /* In this case the pcache already contains an initialized copy of
        ** the page. Return without further ado.  */
        Debug.Assert( pgno <= PAGER_MAX_PGNO && pgno != PAGER_MJ_PGNO( pPager ) );
        PAGER_INCR( ref pPager.nHit );
        return SQLITE_OK;

      }
      else
      {
        /* The pager cache has created a new page. Its content needs to 
        ** be initialized.  */
        Pgno nMax = 0;
#if SQLITE_TEST
        PAGER_INCR( ref pPager.nMiss );
#endif
        pPg = ppPage;
        pPg.pPager = pPager;
        pPg.pExtra = new MemPage();//memset(pPg.pExtra, 0, pPager.nExtra);

        /* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
        ** number greater than this, or the unused locking-page, is requested. */
        if ( pgno > PAGER_MAX_PGNO || pgno == PAGER_MJ_PGNO( pPager ) )
        {
          rc = SQLITE_CORRUPT_BKPT();
          goto pager_acquire_err;
        }
        rc = sqlite3PagerPagecount( pPager, ref nMax );
        if ( rc != SQLITE_OK )
        {
          goto pager_acquire_err;
        }

        if (
#if SQLITE_OMIT_MEMORYDB
1==MEMDB
#else
 pPager.memDb != 0
#endif
 || nMax < (int)pgno || noContent != 0  || !isOpen(pPager.fd) )
        {
          if ( pgno > pPager.mxPgno )
          {
            rc = SQLITE_FULL;
            goto pager_acquire_err;
          }
          if ( noContent != 0 )
          {
            /* Failure to set the bits in the InJournal bit-vectors is benign.
            ** It merely means that we might do some extra work to journal a
            ** page that does not need to be journaled.  Nevertheless, be sure
            ** to test the case where a malloc error occurs while trying to set
            ** a bit in a bit vector.
            */
            sqlite3BeginBenignMalloc();
            if ( pgno <= pPager.dbOrigSize )
            {
#if !NDEBUG || SQLITE_COVERAGE_TEST
              rc = sqlite3BitvecSet( pPager.pInJournal, pgno );          //TESTONLY( rc = ) sqlite3BitvecSet(pPager.pInJournal, pgno);
#else
sqlite3BitvecSet(pPager.pInJournal, pgno);
#endif
              testcase( rc == SQLITE_NOMEM );
            }
#if !NDEBUG || SQLITE_COVERAGE_TEST
            rc = addToSavepointBitvecs( pPager, pgno ); //TESTONLY( rc = ) addToSavepointBitvecs(pPager, pgno);
#else
addToSavepointBitvecs(pPager, pgno);
#endif

            testcase( rc == SQLITE_NOMEM );
            sqlite3EndBenignMalloc();
          }
          //memset(pPg->pData, 0, pPager.pageSize);
          Array.Clear( pPg.pData, 0, pPager.pageSize );
          IOTRACE( "ZERO %p %d\n", pPager, pgno );
        }
        else
        {
          Debug.Assert( pPg.pPager == pPager );
          rc = readDbPage( pPg );
          if ( rc != SQLITE_OK )
          {
            goto pager_acquire_err;
          }
        }

#if SQLITE_CHECK_PAGES
pPg.pageHash = pager_pagehash(pPg);
#endif
      }
      return SQLITE_OK;

    pager_acquire_err:
      Debug.Assert( rc != SQLITE_OK );
      if ( pPg != null )
      {
        sqlite3PcacheDrop( pPg );
      }
      pagerUnlockIfUnused( pPager );

      ppPage = null;
      return rc;
    }
Example #15
0
    /*
    ** Acquire a reference to page number pgno in pager pPager (a page
    ** reference has type DbPage*). If the requested reference is
    ** successfully obtained, it is copied to *ppPage and SQLITE_OK returned.
    **
    ** If the requested page is already in the cache, it is returned.
    ** Otherwise, a new page object is allocated and populated with data
    ** read from the database file. In some cases, the pcache module may
    ** choose not to allocate a new page object and may reuse an existing
    ** object with no outstanding references.
    **
    ** The extra data appended to a page is always initialized to zeros the
    ** first time a page is loaded into memory. If the page requested is
    ** already in the cache when this function is called, then the extra
    ** data is left as it was when the page object was last used.
    **
    ** If the database image is smaller than the requested page or if a
    ** non-zero value is passed as the noContent parameter and the
    ** requested page is not already stored in the cache, then no
    ** actual disk read occurs. In this case the memory image of the
    ** page is initialized to all zeros.
    **
    ** If noContent is true, it means that we do not care about the contents
    ** of the page. This occurs in two seperate scenarios:
    **
    **   a) When reading a free-list leaf page from the database, and
    **
    **   b) When a savepoint is being rolled back and we need to load
    **      a new page into the cache to populate with the data read
    **      from the savepoint journal.
    **
    ** If noContent is true, then the data returned is zeroed instead of
    ** being read from the database. Additionally, the bits corresponding
    ** to pgno in Pager.pInJournal (bitvec of pages already written to the
    ** journal file) and the PagerSavepoint.pInSavepoint bitvecs of any open
    ** savepoints are set. This means if the page is made writable at any
    ** point in the future, using a call to sqlite3PagerWrite(), its contents
    ** will not be journaled. This saves IO.
    **
    ** The acquisition might fail for several reasons.  In all cases,
    ** an appropriate error code is returned and *ppPage is set to NULL.
    **
    ** See also sqlite3PagerLookup().  Both this routine and Lookup() attempt
    ** to find a page in the in-memory cache first.  If the page is not already
    ** in memory, this routine goes to disk to read it in whereas Lookup()
    ** just returns 0.  This routine acquires a read-lock the first time it
    ** has to go to disk, and could also playback an old journal if necessary.
    ** Since Lookup() never goes to disk, it never has to deal with locks
    ** or journal files.
    */

    // Under C# from the header file
    //#define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0)

    static int sqlite3PagerGet(
    Pager pPager,       /* The pager open on the database file */
    u32 pgno,          /* Page number to fetch */
    ref DbPage ppPage   /* Write a pointer to the page here */
    )
    {
      return sqlite3PagerAcquire( pPager, pgno, ref ppPage, 0 );
    }
Example #16
0
    /*
** Increment the reference count for page pPg.
*/
    static void sqlite3PagerRef( DbPage pPg )
    {
      sqlite3PcacheRef( pPg );
    }
Example #17
0
 /*
 ** Dummy page reinitializer
 */
 static void pager_test_reiniter( DbPage pNotUsed )
 {
   return;
 }
Example #18
0
    /*
    ** Return TRUE if the page given in the argument was previously passed
    ** to sqlite3PagerWrite().  In other words, return TRUE if it is ok
    ** to change the content of the page.
    */
#if !NDEBUG
    static bool sqlite3PagerIswriteable( DbPage pPg )
    {
      return ( pPg.flags & PGHDR_DIRTY ) != 0;
    }
Example #19
0
 /*
 ** Dummy page reinitializer
 */
 static void pager_test_reiniter(DbPage pNotUsed)
 {
     return;
 }
Example #20
0
static bool sqlite3PagerIswriteable( DbPage pPg ) { return true; }
Example #21
0
        /*
        ** Copy nPage pages from the source b-tree to the destination.
        */
        public static int sqlite3_backup_step(sqlite3_backup p, int nPage)
        {
            int rc;

            sqlite3_mutex_enter(p.pSrcDb.mutex);
            sqlite3BtreeEnter(p.pSrc);
            if (p.pDestDb != null)
            {
                sqlite3_mutex_enter(p.pDestDb.mutex);
            }

            rc = p.rc;
            if (!isFatalError(rc))
            {
                var  pSrcPager  = sqlite3BtreePager(p.pSrc);  /* Source pager */
                var  pDestPager = sqlite3BtreePager(p.pDest); /* Dest pager */
                int  ii;                                      /* Iterator variable */
                uint nSrcPage    = 0;                         /* Size of source db in pages */
                var  bCloseTrans = 0;                         /* True if src db requires unlocking */

                /* If the source pager is currently in a write-transaction, return
                ** SQLITE_BUSY immediately.
                */
                if (p.pDestDb != null && p.pSrc.pBt.inTransaction == TRANS_WRITE)
                {
                    rc = SQLITE_BUSY;
                }
                else
                {
                    rc = SQLITE_OK;
                }

                /* Lock the destination database, if it is not locked already. */
                if (SQLITE_OK == rc && p.bDestLocked == 0 &&
                    SQLITE_OK == (rc = sqlite3BtreeBeginTrans(p.pDest, 2))
                    )
                {
                    p.bDestLocked = 1;
                    sqlite3BtreeGetMeta(p.pDest, BTREE_SCHEMA_VERSION, ref p.iDestSchema);
                }

                /* If there is no open read-transaction on the source database, open
                ** one now. If a transaction is opened here, then it will be closed
                ** before this function exits.
                */
                if (rc == SQLITE_OK && !sqlite3BtreeIsInReadTrans(p.pSrc))
                {
                    rc          = sqlite3BtreeBeginTrans(p.pSrc, 0);
                    bCloseTrans = 1;
                }

                /* Now that there is a read-lock on the source database, query the
                ** source pager for the number of pages in the database.
                */
                if (rc == SQLITE_OK)
                {
                    rc = sqlite3PagerPagecount(pSrcPager, ref nSrcPage);
                }
                for (ii = 0; (nPage < 0 || ii < nPage) && p.iNext <= nSrcPage && 0 == rc; ii++)
                {
                    var iSrcPg = p.iNext; /* Source page number */
                    if (iSrcPg != PENDING_BYTE_PAGE(p.pSrc.pBt))
                    {
                        DbPage pSrcPg = null; /* Source page object */
                        rc = sqlite3PagerGet(pSrcPager, iSrcPg, ref pSrcPg);
                        if (rc == SQLITE_OK)
                        {
                            rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg));
                            sqlite3PagerUnref(pSrcPg);
                        }
                    }

                    p.iNext++;
                }

                if (rc == SQLITE_OK)
                {
                    p.nPagecount = nSrcPage;
                    p.nRemaining = nSrcPage + 1 - p.iNext;
                    if (p.iNext > nSrcPage)
                    {
                        rc = SQLITE_DONE;
                    }
                    else if (0 == p.isAttached)
                    {
                        attachBackupObject(p);
                    }
                }


                /* Update the schema version field in the destination database. This
                ** is to make sure that the schema-version really does change in
                ** the case where the source and destination databases have the
                ** same schema version.
                */
                if (rc == SQLITE_DONE &&
                    (rc = sqlite3BtreeUpdateMeta(p.pDest, 1, p.iDestSchema + 1)) == SQLITE_OK
                    )
                {
                    var  nSrcPagesize  = sqlite3BtreeGetPageSize(p.pSrc);
                    var  nDestPagesize = sqlite3BtreeGetPageSize(p.pDest);
                    uint nDestTruncate;
                    if (p.pDestDb != null)
                    {
                        sqlite3ResetInternalSchema(p.pDestDb, 0);
                    }

                    /* Set nDestTruncate to the final number of pages in the destination
                    ** database. The complication here is that the destination page
                    ** size may be different to the source page size.
                    **
                    ** If the source page size is smaller than the destination page size,
                    ** round up. In this case the call to sqlite3OsTruncate() below will
                    ** fix the size of the file. However it is important to call
                    ** sqlite3PagerTruncateImage() here so that any pages in the
                    ** destination file that lie beyond the nDestTruncate page mark are
                    ** journalled by PagerCommitPhaseOne() before they are destroyed
                    ** by the file truncation.
                    */
                    if (nSrcPagesize < nDestPagesize)
                    {
                        var ratio = nDestPagesize / nSrcPagesize;
                        nDestTruncate = (uint)((nSrcPage + ratio - 1) / ratio);
                        if (nDestTruncate == (int)PENDING_BYTE_PAGE(p.pDest.pBt))
                        {
                            nDestTruncate--;
                        }
                    }
                    else
                    {
                        nDestTruncate = (uint)(nSrcPage * (nSrcPagesize / nDestPagesize));
                    }

                    sqlite3PagerTruncateImage(pDestPager, nDestTruncate);

                    if (nSrcPagesize < nDestPagesize)
                    {
                        /* If the source page-size is smaller than the destination page-size,
                        ** two extra things may need to happen:
                        **
                        **   * The destination may need to be truncated, and
                        **
                        **   * Data stored on the pages immediately following the
                        **     pending-byte page in the source database may need to be
                        **     copied into the destination database.
                        */
                        var iSize = (uint)nSrcPagesize * nSrcPage;
                        var pFile = sqlite3PagerFile(pDestPager);

                        Debug.Assert(pFile != null);
                        Debug.Assert(nDestTruncate * nDestPagesize >= iSize ||
                                     nDestTruncate == (int)(PENDING_BYTE_PAGE(p.pDest.pBt) - 1) &&
                                     iSize >= PENDING_BYTE && iSize <= PENDING_BYTE + nDestPagesize);
                        if (SQLITE_OK == (rc = sqlite3PagerCommitPhaseOne(pDestPager, null, true)) &&
                            SQLITE_OK == (rc = backupTruncateFile(pFile, (int)iSize)) &&
                            SQLITE_OK == (rc = sqlite3PagerSync(pDestPager))
                            )
                        {
                            long iOff;
                            long iEnd = MIN(PENDING_BYTE + nDestPagesize, iSize);
                            for (
                                iOff = PENDING_BYTE + nSrcPagesize;
                                rc == SQLITE_OK && iOff < iEnd;
                                iOff += nSrcPagesize
                                )
                            {
                                PgHdr pSrcPg = null;
                                var   iSrcPg = (uint)(iOff / nSrcPagesize + 1);
                                rc = sqlite3PagerGet(pSrcPager, iSrcPg, ref pSrcPg);
                                if (rc == SQLITE_OK)
                                {
                                    var zData = sqlite3PagerGetData(pSrcPg);
                                    rc = sqlite3OsWrite(pFile, zData, nSrcPagesize, iOff);
                                }

                                sqlite3PagerUnref(pSrcPg);
                            }
                        }
                    }
                    else
                    {
                        rc = sqlite3PagerCommitPhaseOne(pDestPager, null, false);
                    }

                    /* Finish committing the transaction to the destination database. */
                    if (SQLITE_OK == rc &&
                        SQLITE_OK == (rc = sqlite3BtreeCommitPhaseTwo(p.pDest))
                        )
                    {
                        rc = SQLITE_DONE;
                    }
                }

                /* If bCloseTrans is true, then this function opened a read transaction
                ** on the source database. Close the read transaction here. There is
                ** no need to check the return values of the btree methods here, as
                ** "committing" a read-only transaction cannot fail.
                */
                if (bCloseTrans != 0)
                {
#if !NDEBUG || SQLITE_COVERAGE_TEST
                    //TESTONLY( int rc2 );
                    //TESTONLY( rc2  = ) sqlite3BtreeCommitPhaseOne(p.pSrc, 0);
                    //TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p.pSrc);
                    int rc2;
                    rc2  = sqlite3BtreeCommitPhaseOne(p.pSrc, "");
                    rc2 |= sqlite3BtreeCommitPhaseTwo(p.pSrc);
                    Debug.Assert(rc2 == SQLITE_OK);
#else
                    sqlite3BtreeCommitPhaseOne(p.pSrc, null);
                    sqlite3BtreeCommitPhaseTwo(p.pSrc);
#endif
                }

                p.rc = rc;
            }

            if (p.pDestDb != null)
            {
                sqlite3_mutex_leave(p.pDestDb.mutex);
            }
            sqlite3BtreeLeave(p.pSrc);
            sqlite3_mutex_leave(p.pSrcDb.mutex);
            return(rc);
        }