memjournal.c

Go to the documentation of this file.
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