|
1 /* |
|
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 ** |
|
13 ** @(#) $Id: journal.cpp 1282 2008-11-13 09:31:33Z LarsPson $ |
|
14 */ |
|
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 |
|
36 |
|
37 /* |
|
38 ** A JournalFile object is a subclass of sqlite3_file used by |
|
39 ** as an open file handle for journal files. |
|
40 */ |
|
41 struct JournalFile { |
|
42 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 */ |
|
50 }; |
|
51 typedef struct JournalFile JournalFile; |
|
52 |
|
53 /* |
|
54 ** If it does not already exists, create and populate the on-disk file |
|
55 ** for JournalFile p. |
|
56 */ |
|
57 static int createFile(JournalFile *p){ |
|
58 int rc = SQLITE_OK; |
|
59 if( !p->pReal ){ |
|
60 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 } |
|
68 } |
|
69 } |
|
70 return rc; |
|
71 } |
|
72 |
|
73 /* |
|
74 ** Close the file. |
|
75 */ |
|
76 static 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 */ |
|
88 static int jrnlRead( |
|
89 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 */ |
|
93 ){ |
|
94 int rc = SQLITE_OK; |
|
95 JournalFile *p = (JournalFile *)pJfd; |
|
96 if( p->pReal ){ |
|
97 rc = sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst); |
|
98 }else{ |
|
99 assert( iAmt+iOfst<=p->iSize ); |
|
100 memcpy(zBuf, &p->zBuf[iOfst], iAmt); |
|
101 } |
|
102 return rc; |
|
103 } |
|
104 |
|
105 /* |
|
106 ** Write data to the file. |
|
107 */ |
|
108 static int jrnlWrite( |
|
109 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 */ |
|
113 ){ |
|
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 */ |
|
135 static 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); |
|
140 }else if( size<p->iSize ){ |
|
141 p->iSize = size; |
|
142 } |
|
143 return rc; |
|
144 } |
|
145 |
|
146 /* |
|
147 ** Sync the file. |
|
148 */ |
|
149 static int jrnlSync(sqlite3_file *pJfd, int flags){ |
|
150 int rc; |
|
151 JournalFile *p = (JournalFile *)pJfd; |
|
152 rc = createFile(p); |
|
153 if( rc==SQLITE_OK ){ |
|
154 rc = sqlite3OsSync(p->pReal, flags); |
|
155 } |
|
156 return rc; |
|
157 } |
|
158 |
|
159 /* |
|
160 ** Query the size of the file in bytes. |
|
161 */ |
|
162 static int jrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){ |
|
163 int rc = SQLITE_OK; |
|
164 JournalFile *p = (JournalFile *)pJfd; |
|
165 if( p->pReal ){ |
|
166 rc = sqlite3OsFileSize(p->pReal, pSize); |
|
167 }else{ |
|
168 *pSize = (sqlite_int64) p->iSize; |
|
169 } |
|
170 return rc; |
|
171 } |
|
172 |
|
173 /* |
|
174 ** Table of methods for JournalFile sqlite3_file object. |
|
175 */ |
|
176 static struct sqlite3_io_methods JournalFileMethods = { |
|
177 1, /* iVersion */ |
|
178 jrnlClose, /* xClose */ |
|
179 jrnlRead, /* xRead */ |
|
180 jrnlWrite, /* xWrite */ |
|
181 jrnlTruncate, /* xTruncate */ |
|
182 jrnlSync, /* xSync */ |
|
183 jrnlFileSize, /* xFileSize */ |
|
184 0, /* xLock */ |
|
185 0, /* xUnlock */ |
|
186 0, /* xCheckReservedLock */ |
|
187 0, /* xFileControl */ |
|
188 0, /* xSectorSize */ |
|
189 0 /* xDeviceCharacteristics */ |
|
190 }; |
|
191 |
|
192 /* |
|
193 ** Open a journal file. |
|
194 */ |
|
195 int sqlite3JournalOpen( |
|
196 sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */ |
|
197 const char *zName, /* Name of the journal file */ |
|
198 sqlite3_file *pJfd, /* Preallocated, blank file handle */ |
|
199 int flags, /* Opening flags */ |
|
200 int nBuf /* Bytes buffered before opening the file */ |
|
201 ){ |
|
202 JournalFile *p = (JournalFile *)pJfd; |
|
203 memset(p, 0, sqlite3JournalSize(pVfs)); |
|
204 if( nBuf>0 ){ |
|
205 p->zBuf = sqlite3MallocZero(nBuf); |
|
206 if( !p->zBuf ){ |
|
207 return SQLITE_NOMEM; |
|
208 } |
|
209 }else{ |
|
210 return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0); |
|
211 } |
|
212 p->pMethod = &JournalFileMethods; |
|
213 p->nBuf = nBuf; |
|
214 p->flags = flags; |
|
215 p->zJournal = zName; |
|
216 p->pVfs = pVfs; |
|
217 return SQLITE_OK; |
|
218 } |
|
219 |
|
220 /* |
|
221 ** If the argument p points to a JournalFile structure, and the underlying |
|
222 ** file has not yet been created, create it now. |
|
223 */ |
|
224 int sqlite3JournalCreate(sqlite3_file *p){ |
|
225 if( p->pMethods!=&JournalFileMethods ){ |
|
226 return SQLITE_OK; |
|
227 } |
|
228 return createFile((JournalFile *)p); |
|
229 } |
|
230 |
|
231 /* |
|
232 ** Return the number of bytes required to store a JournalFile that uses vfs |
|
233 ** pVfs to create the underlying on-disk files. |
|
234 */ |
|
235 int sqlite3JournalSize(sqlite3_vfs *pVfs){ |
|
236 return (pVfs->szOsFile+sizeof(JournalFile)); |
|
237 } |
|
238 #endif |