00001 /* 00002 ** 2008 October 7 00003 ** 00004 ** The author disclaims copyright to this source code. In place of 00005 ** a legal notice, here is a blessing: 00006 ** 00007 ** May you do good and not evil. 00008 ** May you find forgiveness for yourself and forgive others. 00009 ** May you share freely, never taking more than you give. 00010 ** 00011 ************************************************************************* 00012 ** 00013 ** This file contains code use to implement an in-memory rollback journal. 00014 ** The in-memory rollback journal is used to journal transactions for 00015 ** ":memory:" databases and when the journal_mode=MEMORY pragma is used. 00016 ** 00017 ** @(#) $Id: memjournal.c,v 1.3 2008/11/12 15:24:28 drh Exp $ 00018 */ 00019 #include "sqliteInt.h" 00020 00021 /* Forward references to internal structures */ 00022 typedef struct MemJournal MemJournal; 00023 typedef struct FilePoint FilePoint; 00024 typedef struct FileChunk FileChunk; 00025 00026 /* Space to hold the rollback journal is allocated in increments of 00027 ** this many bytes. 00028 */ 00029 #define JOURNAL_CHUNKSIZE 1024 00030 00031 /* Macro to find the minimum of two numeric values. 00032 */ 00033 #ifndef MIN 00034 # define MIN(x,y) ((x)<(y)?(x):(y)) 00035 #endif 00036 00037 /* 00038 ** The rollback journal is composed of a linked list of these structures. 00039 */ 00040 struct FileChunk { 00041 FileChunk *pNext; /* Next chunk in the journal */ 00042 u8 zChunk[JOURNAL_CHUNKSIZE]; /* Content of this chunk */ 00043 }; 00044 00045 /* 00046 ** An instance of this object serves as a cursor into the rollback journal. 00047 ** The cursor can be either for reading or writing. 00048 */ 00049 struct FilePoint { 00050 sqlite3_int64 iOffset; /* Offset from the beginning of the file */ 00051 FileChunk *pChunk; /* Specific chunk into which cursor points */ 00052 }; 00053 00054 /* 00055 ** This subclass is a subclass of sqlite3_file. Each open memory-journal 00056 ** is an instance of this class. 00057 */ 00058 struct MemJournal { 00059 sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */ 00060 FileChunk *pFirst; /* Head of in-memory chunk-list */ 00061 FilePoint endpoint; /* Pointer to the end of the file */ 00062 FilePoint readpoint; /* Pointer to the end of the last xRead() */ 00063 }; 00064 00065 /* 00066 ** Read data from the file. 00067 */ 00068 static int memjrnlRead( 00069 sqlite3_file *pJfd, /* The journal file from which to read */ 00070 void *zBuf, /* Put the results here */ 00071 int iAmt, /* Number of bytes to read */ 00072 sqlite_int64 iOfst /* Begin reading at this offset */ 00073 ){ 00074 MemJournal *p = (MemJournal *)pJfd; 00075 u8 *zOut = zBuf; 00076 int nRead = iAmt; 00077 int iChunkOffset; 00078 FileChunk *pChunk; 00079 00080 assert( iOfst+iAmt<=p->endpoint.iOffset ); 00081 00082 if( p->readpoint.iOffset!=iOfst || iOfst==0 ){ 00083 sqlite3_int64 iOff = 0; 00084 for(pChunk=p->pFirst; 00085 pChunk && (iOff+JOURNAL_CHUNKSIZE)<=iOfst; 00086 pChunk=pChunk->pNext 00087 ){ 00088 iOff += JOURNAL_CHUNKSIZE; 00089 } 00090 }else{ 00091 pChunk = p->readpoint.pChunk; 00092 } 00093 00094 iChunkOffset = (iOfst%JOURNAL_CHUNKSIZE); 00095 do { 00096 int iSpace = JOURNAL_CHUNKSIZE - iChunkOffset; 00097 int nCopy = MIN(nRead, (JOURNAL_CHUNKSIZE - iChunkOffset)); 00098 memcpy(zOut, &pChunk->zChunk[iChunkOffset], nCopy); 00099 zOut += nCopy; 00100 nRead -= iSpace; 00101 iChunkOffset = 0; 00102 } while( nRead>=0 && (pChunk=pChunk->pNext) && nRead>0 ); 00103 p->readpoint.iOffset = iOfst+iAmt; 00104 p->readpoint.pChunk = pChunk; 00105 00106 return SQLITE_OK; 00107 } 00108 00109 /* 00110 ** Write data to the file. 00111 */ 00112 static int memjrnlWrite( 00113 sqlite3_file *pJfd, /* The journal file into which to write */ 00114 const void *zBuf, /* Take data to be written from here */ 00115 int iAmt, /* Number of bytes to write */ 00116 sqlite_int64 iOfst /* Begin writing at this offset into the file */ 00117 ){ 00118 MemJournal *p = (MemJournal *)pJfd; 00119 int nWrite = iAmt; 00120 u8 *zWrite = (u8 *)zBuf; 00121 00122 /* An in-memory journal file should only ever be appended to. Random 00123 ** access writes are not required by sqlite. 00124 */ 00125 assert(iOfst==p->endpoint.iOffset); 00126 00127 while( nWrite>0 ){ 00128 FileChunk *pChunk = p->endpoint.pChunk; 00129 int iChunkOffset = p->endpoint.iOffset%JOURNAL_CHUNKSIZE; 00130 int iSpace = MIN(nWrite, JOURNAL_CHUNKSIZE - iChunkOffset); 00131 00132 if( iChunkOffset==0 ){ 00133 /* New chunk is required to extend the file. */ 00134 FileChunk *pNew = sqlite3_malloc(sizeof(FileChunk)); 00135 if( !pNew ){ 00136 return SQLITE_IOERR_NOMEM; 00137 } 00138 pNew->pNext = 0; 00139 if( pChunk ){ 00140 assert( p->pFirst ); 00141 pChunk->pNext = pNew; 00142 }else{ 00143 assert( !p->pFirst ); 00144 p->pFirst = pNew; 00145 } 00146 p->endpoint.pChunk = pNew; 00147 } 00148 00149 memcpy(&p->endpoint.pChunk->zChunk[iChunkOffset], zWrite, iSpace); 00150 zWrite += iSpace; 00151 nWrite -= iSpace; 00152 p->endpoint.iOffset += iSpace; 00153 } 00154 00155 return SQLITE_OK; 00156 } 00157 00158 /* 00159 ** Truncate the file. 00160 */ 00161 static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){ 00162 MemJournal *p = (MemJournal *)pJfd; 00163 FileChunk *pChunk; 00164 assert(size==0); 00165 pChunk = p->pFirst; 00166 while( pChunk ){ 00167 FileChunk *pTmp = pChunk; 00168 pChunk = pChunk->pNext; 00169 sqlite3_free(pTmp); 00170 } 00171 sqlite3MemJournalOpen(pJfd); 00172 return SQLITE_OK; 00173 } 00174 00175 /* 00176 ** Close the file. 00177 */ 00178 static int memjrnlClose(sqlite3_file *pJfd){ 00179 memjrnlTruncate(pJfd, 0); 00180 return SQLITE_OK; 00181 } 00182 00183 00184 /* 00185 ** Sync the file. 00186 */ 00187 static int memjrnlSync(sqlite3_file *pJfd, int flags){ 00188 return SQLITE_OK; 00189 } 00190 00191 /* 00192 ** Query the size of the file in bytes. 00193 */ 00194 static int memjrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){ 00195 MemJournal *p = (MemJournal *)pJfd; 00196 *pSize = (sqlite_int64) p->endpoint.iOffset; 00197 return SQLITE_OK; 00198 } 00199 00200 /* 00201 ** Table of methods for MemJournal sqlite3_file object. 00202 */ 00203 static struct sqlite3_io_methods MemJournalMethods = { 00204 1, /* iVersion */ 00205 memjrnlClose, /* xClose */ 00206 memjrnlRead, /* xRead */ 00207 memjrnlWrite, /* xWrite */ 00208 memjrnlTruncate, /* xTruncate */ 00209 memjrnlSync, /* xSync */ 00210 memjrnlFileSize, /* xFileSize */ 00211 0, /* xLock */ 00212 0, /* xUnlock */ 00213 0, /* xCheckReservedLock */ 00214 0, /* xFileControl */ 00215 0, /* xSectorSize */ 00216 0 /* xDeviceCharacteristics */ 00217 }; 00218 00219 /* 00220 ** Open a journal file. 00221 */ 00222 void sqlite3MemJournalOpen(sqlite3_file *pJfd){ 00223 MemJournal *p = (MemJournal *)pJfd; 00224 memset(p, 0, sqlite3MemJournalSize()); 00225 p->pMethod = &MemJournalMethods; 00226 } 00227 00228 /* 00229 ** Return true if the file-handle passed as an argument is 00230 ** an in-memory journal 00231 */ 00232 int sqlite3IsMemJournal(sqlite3_file *pJfd){ 00233 return pJfd->pMethods==&MemJournalMethods; 00234 } 00235 00236 /* 00237 ** Return the number of bytes required to store a MemJournal that uses vfs 00238 ** pVfs to create the underlying on-disk files. 00239 */ 00240 int sqlite3MemJournalSize(){ 00241 return sizeof(MemJournal); 00242 }
ContextLogger2—ContextLogger2 Logger Daemon Internals—Generated on Mon May 2 13:49:55 2011 by Doxygen 1.6.1