pager.c

来自「sqlite最新源码」· C语言 代码 · 共 1,620 行 · 第 1/5 页

C
1,620
字号
/*** 2001 September 15**** 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 is the implementation of the page cache subsystem or "pager".** ** 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.570 2009/02/17 17:56:30 danielk1977 Exp $*/#ifndef SQLITE_OMIT_DISKIO#include "sqliteInt.h"/*** Macros for troubleshooting.  Normally turned off*/#if 0int sqlite3PagerTrace=1;  /* True to enable tracing */#define sqlite3DebugPrintf printf#define PAGERTRACE(X)     if( sqlite3PagerTrace ){ sqlite3DebugPrintf X; }#else#define PAGERTRACE(X)#endif/*** The following two macros are used within the PAGERTRACE() macros above** to print out file-descriptors. **** PAGERID() takes a pointer to a Pager struct as its argument. The** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file** struct as its argument.*/#define PAGERID(p) ((int)(p->fd))#define FILEHANDLEID(fd) ((int)fd)/*** The page cache as a whole is always in one of the following** states:****   PAGER_UNLOCK        The page cache is not currently reading or **                       writing the database file.  There is no**                       data held in memory.  This is the initial**                       state.****   PAGER_SHARED        The page cache is reading the database.**                       Writing is not permitted.  There can be**                       multiple readers accessing the same database**                       file at the same time.****   PAGER_RESERVED      This process has reserved the database for writing**                       but has not yet made any changes.  Only one process**                       at a time can reserve the database.  The original**                       database file has not been modified so other**                       processes may still be reading the on-disk**                       database file.****   PAGER_EXCLUSIVE     The page cache is writing the database.**                       Access is exclusive.  No other processes or**                       threads can be reading or writing while one**                       process is writing.****   PAGER_SYNCED        The pager moves to this state from PAGER_EXCLUSIVE**                       after all dirty pages have been written to the**                       database file and the file has been synced to**                       disk. All that remains to do is to remove or**                       truncate the journal file and the transaction **                       will be committed.**** The page cache comes up in PAGER_UNLOCK.  The first time a** sqlite3PagerGet() occurs, the state transitions to PAGER_SHARED.** After all pages have been released using sqlite_page_unref(),** the state transitions back to PAGER_UNLOCK.  The first time** that sqlite3PagerWrite() is called, the state transitions to** PAGER_RESERVED.  (Note that sqlite3PagerWrite() can only be** called on an outstanding page which means that the pager must** be in PAGER_SHARED before it transitions to PAGER_RESERVED.)** PAGER_RESERVED means that there is an open rollback journal.** The transition to PAGER_EXCLUSIVE occurs before any changes** are made to the database file, though writes to the rollback** journal occurs with just PAGER_RESERVED.  After an sqlite3PagerRollback()** or sqlite3PagerCommitPhaseTwo(), the state can go back to PAGER_SHARED,** or it can stay at PAGER_EXCLUSIVE if we are in exclusive access mode.*/#define PAGER_UNLOCK      0#define PAGER_SHARED      1   /* same as SHARED_LOCK */#define PAGER_RESERVED    2   /* same as RESERVED_LOCK */#define PAGER_EXCLUSIVE   4   /* same as EXCLUSIVE_LOCK */#define PAGER_SYNCED      5/*** This macro rounds values up so that if the value is an address it** is guaranteed to be an address that is aligned to an 8-byte boundary.*/#define FORCE_ALIGNMENT(X)   (((X)+7)&~7)/*** A macro used for invoking the codec if there is one*/#ifdef SQLITE_HAS_CODEC# define CODEC1(P,D,N,X) if( P->xCodec!=0 ){ P->xCodec(P->pCodecArg,D,N,X); }# define CODEC2(P,D,N,X) ((char*)(P->xCodec!=0?P->xCodec(P->pCodecArg,D,N,X):D))#else# define CODEC1(P,D,N,X) /* NO-OP */# define CODEC2(P,D,N,X) ((char*)D)#endif/*** The maximum allowed sector size. 16MB. If the xSectorsize() method ** returns a value larger than this, then MAX_SECTOR_SIZE is used instead.** This could conceivably cause corruption following a power failure on** such a system. This is currently an undocumented limit.*/#define MAX_SECTOR_SIZE 0x0100000/*** An instance of the following structure is allocated for each active** savepoint and statement transaction in the system. All such structures** are stored in the Pager.aSavepoint[] array, which is allocated and** resized using sqlite3Realloc().**** When a savepoint is created, the PagerSavepoint.iHdrOffset field is** set to 0. If a journal-header is written into the main journal while** the savepoint is active, then iHdrOffset is set to the byte offset ** immediately following the last journal record written into the main** journal before the journal-header. This is required during savepoint** rollback (see pagerPlaybackSavepoint()).*/typedef struct PagerSavepoint PagerSavepoint;struct PagerSavepoint {  i64 iOffset;                 /* Starting offset in main journal */  i64 iHdrOffset;              /* See above */  Bitvec *pInSavepoint;        /* Set of pages in this savepoint */  Pgno nOrig;                  /* Original number of pages in file */  Pgno iSubRec;                /* Index of first record in sub-journal */};/*** A open page cache is an instance of the following structure.**** errCode****   Pager.errCode may be set to SQLITE_IOERR, SQLITE_CORRUPT, or**   or SQLITE_FULL. Once one of the first three errors occurs, it persists**   and is returned as the result of every major pager API call.  The**   SQLITE_FULL return code is slightly different. It persists only until the**   next successful rollback is performed on the pager cache. Also,**   SQLITE_FULL does not affect the sqlite3PagerGet() and sqlite3PagerLookup()**   APIs, they may still be used successfully.**** dbSizeValid, dbSize, dbOrigSize, dbFileSize****   Managing the size of the database file in pages is a little complicated.**   The variable Pager.dbSize contains the number of pages that the database**   image currently contains. As the database image grows or shrinks this**   variable is updated. The variable Pager.dbFileSize contains the number**   of pages in the database file. This may be different from Pager.dbSize**   if some pages have been appended to the database image but not yet written**   out from the cache to the actual file on disk. Or if the image has been**   truncated by an incremental-vacuum operation. The Pager.dbOrigSize variable**   contains the number of pages in the database image when the current**   transaction was opened. The contents of all three of these variables is**   only guaranteed to be correct if the boolean Pager.dbSizeValid is true.****   TODO: Under what conditions is dbSizeValid set? Cleared?**** changeCountDone****   This boolean variable is used to make sure that the change-counter **   (the 4-byte header field at byte offset 24 of the database file) is **   not updated more often than necessary. ****   It is set to true when the change-counter field is updated, which **   can only happen if an exclusive lock is held on the database file.**   It is cleared (set to false) whenever an exclusive lock is **   relinquished on the database file. Each time a transaction is committed,**   The changeCountDone flag is inspected. If it is true, the work of**   updating the change-counter is omitted for the current transaction.****   This mechanism means that when running in exclusive mode, a connection **   need only update the change-counter once, for the first transaction**   committed.**** dbModified****   The dbModified flag is set whenever a database page is dirtied.**   It is cleared at the end of each transaction.****   It is used when committing or otherwise ending a transaction. If**   the dbModified flag is clear then less work has to be done.**** journalStarted****   This flag is set whenever the the main journal is synced. ****   The point of this flag is that it must be set after the **   first journal header in a journal file has been synced to disk.**   After this has happened, new pages appended to the database **   do not need the PGHDR_NEED_SYNC flag set, as they do not need**   to wait for a journal sync before they can be written out to**   the database file (see function pager_write()).**   ** setMaster****   This variable is used to ensure that the master journal file name**   (if any) is only written into the journal file once.****   When committing a transaction, the master journal file name (if any)**   may be written into the journal file while the pager is still in**   PAGER_RESERVED state (see CommitPhaseOne() for the action). It**   then attempts to upgrade to an exclusive lock. If this attempt**   fails, then SQLITE_BUSY may be returned to the user and the user**   may attempt to commit the transaction again later (calling**   CommitPhaseOne() again). This flag is used to ensure that the **   master journal name is only written to the journal file the first**   time CommitPhaseOne() is called.**** doNotSync****   This variable is set and cleared by sqlite3PagerWrite().**** needSync****   TODO: It might be easier to set this variable in writeJournalHdr()**   and writeMasterJournal() only. Change its meaning to "unsynced data**   has been written to the journal".*/struct Pager {  sqlite3_vfs *pVfs;          /* OS functions to use for IO */  u8 exclusiveMode;           /* Boolean. True if locking_mode==EXCLUSIVE */  u8 journalMode;             /* On of the PAGER_JOURNALMODE_* values */  u8 useJournal;              /* Use a rollback journal on this file */  u8 noReadlock;              /* Do not bother to obtain readlocks */  u8 noSync;                  /* Do not sync the journal if true */  u8 fullSync;                /* Do extra syncs of the journal for robustness */  u8 sync_flags;              /* One of SYNC_NORMAL or SYNC_FULL */  u8 tempFile;                /* zFilename is a temporary file */  u8 readOnly;                /* True for a read-only database */  u8 memDb;                   /* True to inhibit all file I/O */  /* The following block contains those class members that are dynamically  ** modified during normal operations. The other variables in this structure  ** are either constant throughout the lifetime of the pager, or else  ** used to store configuration parameters that affect the way the pager   ** operates.  **  ** The 'state' variable is described in more detail along with the  ** descriptions of the values it may take - PAGER_UNLOCK etc. Many of the  ** other variables in this block are described in the comment directly   ** above this class definition.  */  u8 state;                   /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */  u8 dbModified;              /* True if there are any changes to the Db */  u8 needSync;                /* True if an fsync() is needed on the journal */  u8 journalStarted;          /* True if header of journal is synced */  u8 changeCountDone;         /* Set after incrementing the change-counter */  u8 setMaster;               /* True if a m-j name has been written to jrnl */  u8 doNotSync;               /* Boolean. While true, do not spill the cache */  u8 dbSizeValid;             /* Set when dbSize is correct */  Pgno dbSize;                /* Number of pages in the database */  Pgno dbOrigSize;            /* dbSize before the current transaction */  Pgno dbFileSize;            /* Number of pages in the database file */  int errCode;                /* One of several kinds of errors */  int nRec;                   /* Pages journalled since last j-header written */  u32 cksumInit;              /* Quasi-random value added to every checksum */  u32 nSubRec;                /* Number of records written to sub-journal */  Bitvec *pInJournal;         /* One bit for each page in the database file */  sqlite3_file *fd;           /* File descriptor for database */  sqlite3_file *jfd;          /* File descriptor for main journal */  sqlite3_file *sjfd;         /* File descriptor for sub-journal */  i64 journalOff;             /* Current write offset in the journal file */  i64 journalHdr;             /* Byte offset to previous journal header */  PagerSavepoint *aSavepoint; /* Array of active savepoints */  int nSavepoint;             /* Number of elements in aSavepoint[] */  char dbFileVers[16];        /* Changes whenever database file changes */  u32 sectorSize;             /* Assumed sector size during rollback */  int nExtra;                 /* Add this many bytes to each in-memory page */  u32 vfsFlags;               /* Flags for sqlite3_vfs.xOpen() */  int pageSize;               /* Number of bytes in a page */  Pgno mxPgno;                /* Maximum allowed size of the database */  char *zFilename;            /* Name of the database file */  char *zJournal;             /* Name of the journal file */  int (*xBusyHandler)(void*); /* Function to call when busy */  void *pBusyHandlerArg;      /* Context argument for xBusyHandler */#ifdef SQLITE_TEST  int nHit, nMiss;            /* Cache hits and missing */  int nRead, nWrite;          /* Database pages read/written */#endif  void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */#ifdef SQLITE_HAS_CODEC  void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */  void *pCodecArg;            /* First argument to xCodec() */#endif  char *pTmpSpace;            /* Pager.pageSize bytes of space for tmp use */  i64 journalSizeLimit;       /* Size limit for persistent journal files */  PCache *pPCache;            /* Pointer to page cache object */  sqlite3_backup *pBackup;    /* Pointer to list of ongoing backup processes */};/*** The following global variables hold counters used for** testing purposes only.  These variables do not exist in** a non-testing build.  These variables are not thread-safe.*/#ifdef SQLITE_TESTint sqlite3_pager_readdb_count = 0;    /* Number of full pages read from DB */int sqlite3_pager_writedb_count = 0;   /* Number of full pages written to DB */int sqlite3_pager_writej_count = 0;    /* Number of pages written to journal */# define PAGER_INCR(v)  v++#else# define PAGER_INCR(v)#endif

⌨️ 快捷键说明

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