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 + -
显示快捷键?