blob: bdc36bcaecbaf94063a829b9090e9bff5b348a2f [file] [log] [blame]
danielk1977c7b60172007-08-22 11:22:03 +00001/*
2** 2007 August 22
3**
4** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
6**
7** May you do good and not evil.
8** May you find forgiveness for yourself and forgive others.
9** May you share freely, never taking more than you give.
10**
11*************************************************************************
12**
drhb7d63622008-05-01 18:01:46 +000013** @(#) $Id: journal.c,v 1.8 2008/05/01 18:01:47 drh Exp $
danielk1977c7b60172007-08-22 11:22:03 +000014*/
15
16#ifdef SQLITE_ENABLE_ATOMIC_WRITE
17
18/*
19** This file implements a special kind of sqlite3_file object used
20** by SQLite to create journal files if the atomic-write optimization
21** is enabled.
22**
23** The distinctive characteristic of this sqlite3_file is that the
24** actual on disk file is created lazily. When the file is created,
25** the caller specifies a buffer size for an in-memory buffer to
26** be used to service read() and write() requests. The actual file
27** on disk is not created or populated until either:
28**
29** 1) The in-memory representation grows too large for the allocated
30** buffer, or
31** 2) The xSync() method is called.
32*/
33
34#include "sqliteInt.h"
35
drh24e824c2007-09-06 13:49:37 +000036
37/*
38** A JournalFile object is a subclass of sqlite3_file used by
39** as an open file handle for journal files.
40*/
danielk1977c7b60172007-08-22 11:22:03 +000041struct JournalFile {
drh24e824c2007-09-06 13:49:37 +000042 sqlite3_io_methods *pMethod; /* I/O methods on journal files */
43 int nBuf; /* Size of zBuf[] in bytes */
44 char *zBuf; /* Space to buffer journal writes */
45 int iSize; /* Amount of zBuf[] currently used */
46 int flags; /* xOpen flags */
47 sqlite3_vfs *pVfs; /* The "real" underlying VFS */
48 sqlite3_file *pReal; /* The "real" underlying file descriptor */
49 const char *zJournal; /* Name of the journal file */
danielk1977c7b60172007-08-22 11:22:03 +000050};
51typedef struct JournalFile JournalFile;
52
53/*
54** If it does not already exists, create and populate the on-disk file
55** for JournalFile p.
56*/
57static int createFile(JournalFile *p){
58 int rc = SQLITE_OK;
59 if( !p->pReal ){
danielk19772ca0f862007-08-23 08:06:44 +000060 sqlite3_file *pReal = (sqlite3_file *)&p[1];
61 rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0);
62 if( rc==SQLITE_OK ){
63 p->pReal = pReal;
64 if( p->iSize>0 ){
65 assert(p->iSize<=p->nBuf);
66 rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0);
67 }
danielk1977c7b60172007-08-22 11:22:03 +000068 }
69 }
70 return rc;
71}
72
73/*
74** Close the file.
75*/
76static int jrnlClose(sqlite3_file *pJfd){
77 JournalFile *p = (JournalFile *)pJfd;
78 if( p->pReal ){
79 sqlite3OsClose(p->pReal);
80 }
81 sqlite3_free(p->zBuf);
82 return SQLITE_OK;
83}
84
85/*
86** Read data from the file.
87*/
88static int jrnlRead(
drh24e824c2007-09-06 13:49:37 +000089 sqlite3_file *pJfd, /* The journal file from which to read */
90 void *zBuf, /* Put the results here */
91 int iAmt, /* Number of bytes to read */
92 sqlite_int64 iOfst /* Begin reading at this offset */
danielk1977c7b60172007-08-22 11:22:03 +000093){
94 int rc = SQLITE_OK;
95 JournalFile *p = (JournalFile *)pJfd;
96 if( p->pReal ){
97 rc = sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
98 }else{
drh33f4e022007-09-03 15:19:34 +000099 assert( iAmt+iOfst<=p->iSize );
danielk1977880c15b2007-09-01 18:24:55 +0000100 memcpy(zBuf, &p->zBuf[iOfst], iAmt);
danielk1977c7b60172007-08-22 11:22:03 +0000101 }
102 return rc;
103}
104
105/*
106** Write data to the file.
107*/
108static int jrnlWrite(
drh24e824c2007-09-06 13:49:37 +0000109 sqlite3_file *pJfd, /* The journal file into which to write */
110 const void *zBuf, /* Take data to be written from here */
111 int iAmt, /* Number of bytes to write */
112 sqlite_int64 iOfst /* Begin writing at this offset into the file */
danielk1977c7b60172007-08-22 11:22:03 +0000113){
114 int rc = SQLITE_OK;
115 JournalFile *p = (JournalFile *)pJfd;
116 if( !p->pReal && (iOfst+iAmt)>p->nBuf ){
117 rc = createFile(p);
118 }
119 if( rc==SQLITE_OK ){
120 if( p->pReal ){
121 rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
122 }else{
123 memcpy(&p->zBuf[iOfst], zBuf, iAmt);
124 if( p->iSize<(iOfst+iAmt) ){
125 p->iSize = (iOfst+iAmt);
126 }
127 }
128 }
129 return rc;
130}
131
132/*
133** Truncate the file.
134*/
135static int jrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
136 int rc = SQLITE_OK;
137 JournalFile *p = (JournalFile *)pJfd;
138 if( p->pReal ){
139 rc = sqlite3OsTruncate(p->pReal, size);
danielk1977880c15b2007-09-01 18:24:55 +0000140 }else if( size<p->iSize ){
danielk1977c7b60172007-08-22 11:22:03 +0000141 p->iSize = size;
142 }
143 return rc;
144}
145
146/*
147** Sync the file.
148*/
149static int jrnlSync(sqlite3_file *pJfd, int flags){
150 int rc;
151 JournalFile *p = (JournalFile *)pJfd;
drhb7d63622008-05-01 18:01:46 +0000152 if( p->pReal ){
danielk1977c7b60172007-08-22 11:22:03 +0000153 rc = sqlite3OsSync(p->pReal, flags);
drhb7d63622008-05-01 18:01:46 +0000154 }else{
155 rc = SQLITE_OK;
danielk1977c7b60172007-08-22 11:22:03 +0000156 }
157 return rc;
158}
159
160/*
161** Query the size of the file in bytes.
162*/
163static int jrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
164 int rc = SQLITE_OK;
165 JournalFile *p = (JournalFile *)pJfd;
166 if( p->pReal ){
167 rc = sqlite3OsFileSize(p->pReal, pSize);
168 }else{
169 *pSize = (sqlite_int64) p->iSize;
170 }
171 return rc;
172}
173
174/*
175** Table of methods for JournalFile sqlite3_file object.
176*/
177static struct sqlite3_io_methods JournalFileMethods = {
178 1, /* iVersion */
179 jrnlClose, /* xClose */
180 jrnlRead, /* xRead */
181 jrnlWrite, /* xWrite */
182 jrnlTruncate, /* xTruncate */
183 jrnlSync, /* xSync */
184 jrnlFileSize, /* xFileSize */
185 0, /* xLock */
186 0, /* xUnlock */
187 0, /* xCheckReservedLock */
drh9e33c2c2007-08-31 18:34:59 +0000188 0, /* xFileControl */
danielk1977c7b60172007-08-22 11:22:03 +0000189 0, /* xSectorSize */
190 0 /* xDeviceCharacteristics */
191};
192
193/*
194** Open a journal file.
195*/
196int sqlite3JournalOpen(
drh24e824c2007-09-06 13:49:37 +0000197 sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */
198 const char *zName, /* Name of the journal file */
199 sqlite3_file *pJfd, /* Preallocated, blank file handle */
200 int flags, /* Opening flags */
201 int nBuf /* Bytes buffered before opening the file */
danielk1977c7b60172007-08-22 11:22:03 +0000202){
203 JournalFile *p = (JournalFile *)pJfd;
204 memset(p, 0, sqlite3JournalSize(pVfs));
205 if( nBuf>0 ){
206 p->zBuf = sqlite3MallocZero(nBuf);
207 if( !p->zBuf ){
208 return SQLITE_NOMEM;
209 }
210 }else{
211 return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
212 }
213 p->pMethod = &JournalFileMethods;
214 p->nBuf = nBuf;
215 p->flags = flags;
216 p->zJournal = zName;
217 p->pVfs = pVfs;
218 return SQLITE_OK;
219}
220
danielk1977f55b8992007-08-24 08:15:53 +0000221/*
222** If the argument p points to a JournalFile structure, and the underlying
223** file has not yet been created, create it now.
224*/
225int sqlite3JournalCreate(sqlite3_file *p){
226 if( p->pMethods!=&JournalFileMethods ){
227 return SQLITE_OK;
228 }
229 return createFile((JournalFile *)p);
230}
231
danielk1977c7b60172007-08-22 11:22:03 +0000232/*
233** Return the number of bytes required to store a JournalFile that uses vfs
234** pVfs to create the underlying on-disk files.
235*/
236int sqlite3JournalSize(sqlite3_vfs *pVfs){
237 return (pVfs->szOsFile+sizeof(JournalFile));
238}
239#endif