📄 fileio.html
字号:
an error while attempting to detect or roll back a <i>hot journal file</i>, then the <i>shared-lock</i> on the database file is released, no transaction is opened and an error returned to the user.</p> <p> Section <cite>hot_journal_detection</cite> contains a description of and requirements governing the detection of a hot-journal file refered to in the above requirements.<p class=req id=H21004> Assuming no errors have occured, then after attempting to detect and roll back a <i>hot journal file</i>, if the <i>page cache</i> contains any entries associated with the current <i>database connection</i>, then SQLite shall validate the contents of the <i>page cache</i> by testing the <i>file change counter</i>. This procedure is known as <i>cache validiation</i>.</p> <p> The <i>cache validiation</i> process is described in detail in section <cite>cache_validation</cite><p class=req id=H21005> If the cache validiate procedure prescribed by H21004 is required and does not prove that the <i>page cache</i> entries associated with the current <i>database connection</i> are valid, then SQLite shall discard all entries associated with the current <i>database connection</i> from the <i>page cache</i>.</p> <p> The numbered list above notes that the data for the first page of the database file, if it exists and is not already loaded into the <i>page cache</i>, must be read from the database file before the <i>read-only transaction</i> may be considered opened. This is handled by requirement H21024. <h3 id=hot_journal_detection>Hot Journal Detection</h3> <p> This section describes the procedure that SQLite uses to detect a <i>hot journal file</i>. If a <i>hot journal file</i> is detected, this indicates that at some point the process of writing a transaction to the database was interrupted and a recovery operation (<i>hot journal rollback</i>) needs to take place. This section does not describe the process of <i>hot journal rollback</i> (see section <cite>hot_journal_rollback</cite>) or the processes by which a <i>hot journal file</i> may be created (see section <cite>writing_data</cite>). <p> The procedure used to detect a <i>hot-journal file</i> is quite complex. The following steps take place: <ol class=spacedlist> <li>Using the VFS xAccess() method, SQLite queries the file-system to see if the journal file associated with the database exists. If it does not, then there is no hot-journal file. <li>By invoking the xCheckReservedLock() method of the file-handle opened on the database file, SQLite checks if some other connection holds a <i>reserved lock</i> or greater. If some other connection does hold a <i>reserved lock</i>, this indicates that the other connection is midway through a <i>read/write transaction</i> (see section <cite>writing_data</cite>). In this case the <i>journal file</i> is not a <i>hot-journal</i> and must not be rolled back. <li>Using the xFileSize() method of the file-handle opened on the database file, SQLite checks if the database file is 0 bytes in size. If it is, the journal file is not considered to be a <i>hot journal</i> file. Instead of rolling back the journal file, in this case it is deleted from the file-system by calling the VFS xDelete() method. <span class=todo>Technically, there is a race condition here. This step should be moved to after the exclusive lock is held.</span> <li>An attempt is made to upgrade to an <i>exclusive lock</i> on the database file. If the attempt fails, then all locks, including the recently obtained <i>shared lock</i> are dropped. The attempt to open a <i>read-only transaction</i> has failed. This occurs when some other connection is also attempting to open a <i>read-only transaction</i> and the attempt to gain the <i>exclusive lock</i> fails because the other connection is also holding a <i>shared lock</i>. It is left to the other connection to roll back the <i>hot journal</i>. <div style="margin-top:0.5em"></div> It is important that the file-handle lock is upgraded directly from <i>shared</i> to <i>exclusive</i> in this case, instead of first upgrading to <i>reserved</i> or </i>pending</i> locks as is required when obtaining an <i>exclusive lock</i> to write to the database file (section <cite>writing_data</cite>). If SQLite were to first upgrade to a <i>reserved</i> or <i>pending</i> lock in this scenario, then a second process also trying to open a <i>read-transaction</i> on the database file might detect the <i>reserved</i> lock in step 2 of this process, conclude that there was no <i>hot journal</i>, and commence reading data from the <i>database file</i>. <li>The xAccess() method is invoked again to detect if the journal file is still in the file system. If it is, then it is a hot-journal file and SQLite tries to roll it back (see section <cite>rollback</cite>). </ol> <p class=todo> Master journal file pointers? <p> The following requirements describe step 1 of the above procedure in more detail.<p class=req id=H21014> When required to attempt to detect a <i>hot-journal file</i>, SQLite shall first use the xAccess() method of the VFS layer to check if a journal file exists in the file-system.</p><p class=req id=H21051> If the call to xAccess() required by H21014 fails (due to an IO error or similar), then SQLite shall abandon the attempt to open a <i>read-only transaction</i>, relinquish the <i>shared lock</i> held on the database file and return an error to the user.</p><p class=req id=H21015> When required to attempt to detect a <i>hot-journal file</i>, if the call to xAccess() required by H21014 indicates that a journal file does not exist, then SQLite shall conclude that there is no <i>hot-journal file</i> in the file system and therefore that no <i>hot journal rollback</i> is required.</p> <p> The following requirements describe step 2 of the above procedure in more detail.<p class=req id=H21016> When required to attempt to detect a <i>hot-journal file</i>, if the call to xAccess() required by H21014 indicates that a journal file is present, then the xCheckReservedLock() method of the database file file-handle is invoked to determine whether or not some other process is holding a <i>reserved</i> or greater lock on the database file.</p><p class=req id=H21052> If the call to xCheckReservedLock() required by H21016 fails (due to an IO or other internal VFS error), then SQLite shall abandon the attempt to open a <i>read-only transaction</i>, relinquish the <i>shared lock</i> held on the database file and return an error to the user.</p><p class=req id=H21017> If the call to xCheckReservedLock() required by H21016 indicates that some other <i>database connection</i> is holding a <i>reserved</i> or greater lock on the database file, then SQLite shall conclude that there is no <i>hot journal file</i>. In this case the attempt to detect a <i>hot journal file</i> is concluded.</p> <p> The following requirements describe step 3 of the above procedure in more detail.<p class=req id=H21044> If while attempting to detect a <i>hot-journal file</i> the call to xCheckReservedLock() indicates that no process holds a <i>reserved</i> or greater lock on the <i>database file</i>, then SQLite shall open a file handle on the potentially hot journal file using the VFS xOpen() method.</p><p class=req id=H21053> If the call to xOpen() required by H21044 fails (due to an IO or other internal VFS error), then SQLite shall abandon the attempt to open a <i>read-only transaction</i>, relinquish the <i>shared lock</i> held on the database file and return an error to the user.</p><p class=req id=H21045> After successfully opening a file-handle on a potentially hot journal file, SQLite shall query the file for its size in bytes using the xFileSize() method of the open file handle. </p><p class=req id=H21054> If the call to xFileSize() required by H21045 fails (due to an IO or other internal VFS error), then SQLite shall abandon the attempt to open a <i>read-only transaction</i>, relinquish the <i>shared lock</i> held on the database file, close the file handle opened on the journal file and return an error to the user.</p><p class=req id=H21046> If the size of a potentially hot journal file is revealed to be zero bytes by a query required by H21045, then SQLite shall close the file handle opened on the journal file and delete the journal file using a call to the VFS xDelete() method. In this case SQLite shall conclude that there is no <i>hot journal file</i>.</p><p class=req id=H21055> If the call to xDelete() required by H21045 fails (due to an IO or other internal VFS error), then SQLite shall abandon the attempt to open a <i>read-only transaction</i>, relinquish the <i>shared lock</i> held on the database file and return an error to the user.</p> <p> The following requirements describe step 4 of the above procedure in more detail.<p class=req id=H21047> If the size of a potentially hot journal file is revealed to be greater than zero bytes by a query required by H21045, then SQLite shall attempt to upgrade the <i>shared lock</i> held by the <i>database connection</i> on the <i>database file</i> directly to an <i>exclusive lock</i>.</p><p class=req id=H21048> If an attempt to upgrade to an <i>exclusive lock</i> prescribed by H21047 fails for any reason, then SQLite shall release all locks held by the <i>database connection</i> and close the file handle opened on the <i>journal file</i>. The attempt to open a <i>read-only transaction</i> shall be deemed to have failed and an error returned to the user.</p> <p> Finally, the following requirements describe step 5 of the above procedure in more detail.<p class=req id=H21049> If, as part of the <i>hot journal file</i> detection process, the attempt to upgrade to an <i>exclusive lock</i> mandated by H21047 is successful, then SQLite shall query the file-system using the xAccess() method of the VFS implementation to test whether or not the journal file is still present in the file-system.</p><p class=req id=H21056> If the call to xAccess() required by H21049 fails (due to an IO or other internal VFS error), then SQLite shall abandon the attempt to open a <i>read-only transaction</i>, relinquish the lock held on the database file, close the file handle opened on the journal file and return an error to the user.</p><p class=req id=H21057> If the call to xAccess() required by H21049 reveals that the journal file is no longer present in the file system, then SQLite shall abandon the attempt to open a <i>read-only transaction</i>, relinquish the lock held on the database file, close the file handle opened on the journal file and return an SQLITE_BUSY error to the user.</p><p class=req id=H21050> If the xAccess() query required by H21049 reveals that the journal file is still present in the file system, then SQLite shall conclude that the journal file is a <i>hot journal file</i> that needs to be rolled back. SQLite shall immediately begin <i>hot journal rollback</i>.</p> <h3 id=cache_validation>Cache Validation</h3> <p> When a <i>database connection</i> opens a <i>read transaction</i>, the <i>page cache</i> may already contain data associated with the <i>database connection</i>. However, if another process has modified the database file since the cached pages were loaded it is possible that the cached data is invalid. <p> SQLite determines whether or not the <i>page cache</i> entries belonging to the <i>database connection</i> are valid or not using the <i>file change counter</i>, a field in the <i>database file header</i>. The <i>file change counter</i> is a 4-byte big-endian integer field stored starting at byte offset 24 of the <i>database file header</i>. Before the conclusion of a <i>read/write transaction</i> that modifies the contents of the database file in any way (see section <cite>writing_data</cite>), the value stored in the <i>file change counter</i> is incremented. When a <i>database connection</i> unlocks the database file, it stores the current value of the <i>file change counter</i>. Later, while opening a new <i>read-only transaction</i>, SQLite checks the value of the <i>file change counter</i> stored in the database file. If the value has not changed since the database file was unlocked, then the <i>page cache</i> entries can be trusted. If the value has changed, then the <i>page cache</i> entries cannot be trusted and all entries associated with the current <i>database connection</i> are discarded.<p class=req id=H21018> When a file-handle open on a database file is unlocked, if the <i>page cache</i> contains one or more entries belonging to the associated <i>database connection</i>, SQLite shall store the value of the <i>file change counter</i> internally.</p><p class=req id=H21019> When required to perform <i>cache validation</i> as part of opening a <i>read transaction</i>, SQLite shall read a 16 byte block starting at byte offset 24 of the <i>database file</i> using the xRead() method of the <i>database connections</i> file handle.</p> <p class=todo> Why a 16 byte block? Why not 4? (something to do with encrypted databases).<p class=req id=H21020> While performing <i>cache validation</i>, after loading the 16 byte
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -