⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 backup.c

📁 sqlite最新源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*** 2009 January 28**** The author disclaims copyright to this source code.  In place of** a legal notice, here is a blessing:****    May you do good and not evil.**    May you find forgiveness for yourself and forgive others.**    May you share freely, never taking more than you give.***************************************************************************** This file contains the implementation of the sqlite3_backup_XXX() ** API functions and the related features.**** $Id: backup.c,v 1.12 2009/02/16 17:55:47 shane Exp $*/#include "sqliteInt.h"#include "btreeInt.h"/* Macro to find the minimum of two numeric values.*/#ifndef MIN# define MIN(x,y) ((x)<(y)?(x):(y))#endif/*** Structure allocated for each backup operation.*/struct sqlite3_backup {  sqlite3* pDestDb;        /* Destination database handle */  Btree *pDest;            /* Destination b-tree file */  u32 iDestSchema;         /* Original schema cookie in destination */  int bDestLocked;         /* True once a write-transaction is open on pDest */  Pgno iNext;              /* Page number of the next source page to copy */  sqlite3* pSrcDb;         /* Source database handle */  Btree *pSrc;             /* Source b-tree file */  int rc;                  /* Backup process error code */  /* These two variables are set by every call to backup_step(). They are  ** read by calls to backup_remaining() and backup_pagecount().  */  Pgno nRemaining;         /* Number of pages left to copy */  Pgno nPagecount;         /* Total number of pages to copy */  sqlite3_backup *pNext;   /* Next backup associated with source pager */};/*** THREAD SAFETY NOTES:****   Once it has been created using backup_init(), a single sqlite3_backup**   structure may be accessed via two groups of thread-safe entry points:****     * Via the sqlite3_backup_XXX() API function backup_step() and **       backup_finish(). Both these functions obtain the source database**       handle mutex and the mutex associated with the source BtShared **       structure, in that order.****     * Via the BackupUpdate() and BackupRestart() functions, which are**       invoked by the pager layer to report various state changes in**       the page cache associated with the source database. The mutex**       associated with the source database BtShared structure will always **       be held when either of these functions are invoked.****   The other sqlite3_backup_XXX() API functions, backup_remaining() and**   backup_pagecount() are not thread-safe functions. If they are called**   while some other thread is calling backup_step() or backup_finish(),**   the values returned may be invalid. There is no way for a call to**   BackupUpdate() or BackupRestart() to interfere with backup_remaining()**   or backup_pagecount().****   Depending on the SQLite configuration, the database handles and/or**   the Btree objects may have their own mutexes that require locking.**   Non-sharable Btrees (in-memory databases for example), do not have**   associated mutexes.*//*** Return a pointer corresponding to database zDb (i.e. "main", "temp")** in connection handle pDb. If such a database cannot be found, return** a NULL pointer and write an error message to pErrorDb.**** If the "temp" database is requested, it may need to be opened by this ** function. If an error occurs while doing so, return 0 and write an ** error message to pErrorDb.*/static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){  int i = sqlite3FindDbName(pDb, zDb);  if( i==1 ){    Parse sParse;    memset(&sParse, 0, sizeof(sParse));    sParse.db = pDb;    if( sqlite3OpenTempDatabase(&sParse) ){      sqlite3ErrorClear(&sParse);      sqlite3Error(pErrorDb, sParse.rc, "%s", sParse.zErrMsg);      return 0;    }    assert( sParse.zErrMsg==0 );  }  if( i<0 ){    sqlite3Error(pErrorDb, SQLITE_ERROR, "unknown database %s", zDb);    return 0;  }  return pDb->aDb[i].pBt;}/*** Create an sqlite3_backup process to copy the contents of zSrcDb from** connection handle pSrcDb to zDestDb in pDestDb. If successful, return** a pointer to the new sqlite3_backup object.**** If an error occurs, NULL is returned and an error code and error message** stored in database handle pDestDb.*/sqlite3_backup *sqlite3_backup_init(  sqlite3* pDestDb,                     /* Database to write to */  const char *zDestDb,                  /* Name of database within pDestDb */  sqlite3* pSrcDb,                      /* Database connection to read from */  const char *zSrcDb                    /* Name of database within pSrcDb */){  sqlite3_backup *p;                    /* Value to return */  /* Lock the source database handle. The destination database  ** handle is not locked in this routine, but it is locked in  ** sqlite3_backup_step(). The user is required to ensure that no  ** other thread accesses the destination handle for the duration  ** of the backup operation.  Any attempt to use the destination  ** database connection while a backup is in progress may cause  ** a malfunction or a deadlock.  */  sqlite3_mutex_enter(pSrcDb->mutex);  sqlite3_mutex_enter(pDestDb->mutex);  if( pSrcDb==pDestDb ){    sqlite3Error(        pDestDb, SQLITE_ERROR, "source and destination must be distinct"    );    p = 0;  }else {    /* Allocate space for a new sqlite3_backup object */    p = (sqlite3_backup *)sqlite3_malloc(sizeof(sqlite3_backup));    if( !p ){      sqlite3Error(pDestDb, SQLITE_NOMEM, 0);    }  }  /* If the allocation succeeded, populate the new object. */  if( p ){    memset(p, 0, sizeof(sqlite3_backup));    p->pSrc = findBtree(pDestDb, pSrcDb, zSrcDb);    p->pDest = findBtree(pDestDb, pDestDb, zDestDb);    p->pDestDb = pDestDb;    p->pSrcDb = pSrcDb;    p->iNext = 1;    if( 0==p->pSrc || 0==p->pDest ){      /* One (or both) of the named databases did not exist. An error has      ** already been written into the pDestDb handle. All that is left      ** to do here is free the sqlite3_backup structure.      */      sqlite3_free(p);      p = 0;    }  }  /* If everything has gone as planned, attach the backup object to the  ** source pager. The source pager calls BackupUpdate() and BackupRestart()  ** to notify this module if the source file is modified mid-backup.  */  if( p ){    sqlite3_backup **pp;             /* Pointer to head of pagers backup list */    sqlite3BtreeEnter(p->pSrc);    pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc));    p->pNext = *pp;    *pp = p;    sqlite3BtreeLeave(p->pSrc);    p->pSrc->nBackup++;  }  sqlite3_mutex_leave(pDestDb->mutex);  sqlite3_mutex_leave(pSrcDb->mutex);  return p;}/*** Argument rc is an SQLite error code. Return true if this error is ** considered fatal if encountered during a backup operation. All errors** are considered fatal except for SQLITE_BUSY and SQLITE_LOCKED.*/static int isFatalError(int rc){  return (rc!=SQLITE_OK && rc!=SQLITE_BUSY && rc!=SQLITE_LOCKED);}/*** 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, const u8 *zSrcData){  Pager * const pDestPager = sqlite3BtreePager(p->pDest);  const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc);  int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest);  const int nCopy = MIN(nSrcPgsz, nDestPgsz);  const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz;  int rc = SQLITE_OK;  i64 iOff;  assert( p->bDestLocked );  assert( !isFatalError(p->rc) );  assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) );  assert( zSrcData );  /* 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 = 0;    Pgno iDest = (Pgno)(iOff/nDestPgsz)+1;    if( iDest==PENDING_BYTE_PAGE(p->pDest->pBt) ) continue;    if( SQLITE_OK==(rc = sqlite3PagerGet(pDestPager, iDest, &pDestPg))     && SQLITE_OK==(rc = sqlite3PagerWrite(pDestPg))    ){      const u8 *zIn = &zSrcData[iOff%nSrcPgsz];      u8 *zDestData = sqlite3PagerGetData(pDestPg);      u8 *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.      */      memcpy(zOut, zIn, nCopy);      ((u8 *)sqlite3PagerGetExtra(pDestPg))[0] = 0;    }    sqlite3PagerUnref(pDestPg);  }  return rc;}/*** If pFile is currently larger than iSize bytes, then truncate it to** exactly iSize bytes. If pFile is not larger than iSize bytes, then** this function is a no-op.**** Return SQLITE_OK if everything is successful, or an SQLite error ** code if an error occurs.*/static int backupTruncateFile(sqlite3_file *pFile, i64 iSize){  i64 iCurrent;  int rc = sqlite3OsFileSize(pFile, &iCurrent);  if( rc==SQLITE_OK && iCurrent>iSize ){    rc = sqlite3OsTruncate(pFile, iSize);  }  return rc;}/*** Copy nPage pages from the source b-tree to the destination.*/int sqlite3_backup_step(sqlite3_backup *p, int nPage){  int rc;  sqlite3_mutex_enter(p->pSrcDb->mutex);  sqlite3BtreeEnter(p->pSrc);  if( p->pDestDb ){    sqlite3_mutex_enter(p->pDestDb->mutex);  }  rc = p->rc;  if( !isFatalError(rc) ){    Pager * const pSrcPager = sqlite3BtreePager(p->pSrc);     /* Source pager */    Pager * const pDestPager = sqlite3BtreePager(p->pDest);   /* Dest pager */    int ii;                            /* Iterator variable */    int nSrcPage = -1;                 /* 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_LOCKED immediately.    */    if( p->pDestDb && p->pSrc->pBt->inTransaction==TRANS_WRITE ){      rc = SQLITE_LOCKED;    }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))     ){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -