File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sqlite3 / src / memjournal.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:04:17 2012 UTC (12 years, 8 months ago) by misho
Branches: sqlite3, MAIN
CVS tags: v3_7_10, HEAD
sqlite3

    1: /*
    2: ** 2008 October 7
    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: ** This file contains code use to implement an in-memory rollback journal.
   14: ** The in-memory rollback journal is used to journal transactions for
   15: ** ":memory:" databases and when the journal_mode=MEMORY pragma is used.
   16: */
   17: #include "sqliteInt.h"
   18: 
   19: /* Forward references to internal structures */
   20: typedef struct MemJournal MemJournal;
   21: typedef struct FilePoint FilePoint;
   22: typedef struct FileChunk FileChunk;
   23: 
   24: /* Space to hold the rollback journal is allocated in increments of
   25: ** this many bytes.
   26: **
   27: ** The size chosen is a little less than a power of two.  That way,
   28: ** the FileChunk object will have a size that almost exactly fills
   29: ** a power-of-two allocation.  This mimimizes wasted space in power-of-two
   30: ** memory allocators.
   31: */
   32: #define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*)))
   33: 
   34: /* Macro to find the minimum of two numeric values.
   35: */
   36: #ifndef MIN
   37: # define MIN(x,y) ((x)<(y)?(x):(y))
   38: #endif
   39: 
   40: /*
   41: ** The rollback journal is composed of a linked list of these structures.
   42: */
   43: struct FileChunk {
   44:   FileChunk *pNext;               /* Next chunk in the journal */
   45:   u8 zChunk[JOURNAL_CHUNKSIZE];   /* Content of this chunk */
   46: };
   47: 
   48: /*
   49: ** An instance of this object serves as a cursor into the rollback journal.
   50: ** The cursor can be either for reading or writing.
   51: */
   52: struct FilePoint {
   53:   sqlite3_int64 iOffset;          /* Offset from the beginning of the file */
   54:   FileChunk *pChunk;              /* Specific chunk into which cursor points */
   55: };
   56: 
   57: /*
   58: ** This subclass is a subclass of sqlite3_file.  Each open memory-journal
   59: ** is an instance of this class.
   60: */
   61: struct MemJournal {
   62:   sqlite3_io_methods *pMethod;    /* Parent class. MUST BE FIRST */
   63:   FileChunk *pFirst;              /* Head of in-memory chunk-list */
   64:   FilePoint endpoint;             /* Pointer to the end of the file */
   65:   FilePoint readpoint;            /* Pointer to the end of the last xRead() */
   66: };
   67: 
   68: /*
   69: ** Read data from the in-memory journal file.  This is the implementation
   70: ** of the sqlite3_vfs.xRead method.
   71: */
   72: static int memjrnlRead(
   73:   sqlite3_file *pJfd,    /* The journal file from which to read */
   74:   void *zBuf,            /* Put the results here */
   75:   int iAmt,              /* Number of bytes to read */
   76:   sqlite_int64 iOfst     /* Begin reading at this offset */
   77: ){
   78:   MemJournal *p = (MemJournal *)pJfd;
   79:   u8 *zOut = zBuf;
   80:   int nRead = iAmt;
   81:   int iChunkOffset;
   82:   FileChunk *pChunk;
   83: 
   84:   /* SQLite never tries to read past the end of a rollback journal file */
   85:   assert( iOfst+iAmt<=p->endpoint.iOffset );
   86: 
   87:   if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
   88:     sqlite3_int64 iOff = 0;
   89:     for(pChunk=p->pFirst; 
   90:         ALWAYS(pChunk) && (iOff+JOURNAL_CHUNKSIZE)<=iOfst;
   91:         pChunk=pChunk->pNext
   92:     ){
   93:       iOff += JOURNAL_CHUNKSIZE;
   94:     }
   95:   }else{
   96:     pChunk = p->readpoint.pChunk;
   97:   }
   98: 
   99:   iChunkOffset = (int)(iOfst%JOURNAL_CHUNKSIZE);
  100:   do {
  101:     int iSpace = JOURNAL_CHUNKSIZE - iChunkOffset;
  102:     int nCopy = MIN(nRead, (JOURNAL_CHUNKSIZE - iChunkOffset));
  103:     memcpy(zOut, &pChunk->zChunk[iChunkOffset], nCopy);
  104:     zOut += nCopy;
  105:     nRead -= iSpace;
  106:     iChunkOffset = 0;
  107:   } while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 );
  108:   p->readpoint.iOffset = iOfst+iAmt;
  109:   p->readpoint.pChunk = pChunk;
  110: 
  111:   return SQLITE_OK;
  112: }
  113: 
  114: /*
  115: ** Write data to the file.
  116: */
  117: static int memjrnlWrite(
  118:   sqlite3_file *pJfd,    /* The journal file into which to write */
  119:   const void *zBuf,      /* Take data to be written from here */
  120:   int iAmt,              /* Number of bytes to write */
  121:   sqlite_int64 iOfst     /* Begin writing at this offset into the file */
  122: ){
  123:   MemJournal *p = (MemJournal *)pJfd;
  124:   int nWrite = iAmt;
  125:   u8 *zWrite = (u8 *)zBuf;
  126: 
  127:   /* An in-memory journal file should only ever be appended to. Random
  128:   ** access writes are not required by sqlite.
  129:   */
  130:   assert( iOfst==p->endpoint.iOffset );
  131:   UNUSED_PARAMETER(iOfst);
  132: 
  133:   while( nWrite>0 ){
  134:     FileChunk *pChunk = p->endpoint.pChunk;
  135:     int iChunkOffset = (int)(p->endpoint.iOffset%JOURNAL_CHUNKSIZE);
  136:     int iSpace = MIN(nWrite, JOURNAL_CHUNKSIZE - iChunkOffset);
  137: 
  138:     if( iChunkOffset==0 ){
  139:       /* New chunk is required to extend the file. */
  140:       FileChunk *pNew = sqlite3_malloc(sizeof(FileChunk));
  141:       if( !pNew ){
  142:         return SQLITE_IOERR_NOMEM;
  143:       }
  144:       pNew->pNext = 0;
  145:       if( pChunk ){
  146:         assert( p->pFirst );
  147:         pChunk->pNext = pNew;
  148:       }else{
  149:         assert( !p->pFirst );
  150:         p->pFirst = pNew;
  151:       }
  152:       p->endpoint.pChunk = pNew;
  153:     }
  154: 
  155:     memcpy(&p->endpoint.pChunk->zChunk[iChunkOffset], zWrite, iSpace);
  156:     zWrite += iSpace;
  157:     nWrite -= iSpace;
  158:     p->endpoint.iOffset += iSpace;
  159:   }
  160: 
  161:   return SQLITE_OK;
  162: }
  163: 
  164: /*
  165: ** Truncate the file.
  166: */
  167: static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
  168:   MemJournal *p = (MemJournal *)pJfd;
  169:   FileChunk *pChunk;
  170:   assert(size==0);
  171:   UNUSED_PARAMETER(size);
  172:   pChunk = p->pFirst;
  173:   while( pChunk ){
  174:     FileChunk *pTmp = pChunk;
  175:     pChunk = pChunk->pNext;
  176:     sqlite3_free(pTmp);
  177:   }
  178:   sqlite3MemJournalOpen(pJfd);
  179:   return SQLITE_OK;
  180: }
  181: 
  182: /*
  183: ** Close the file.
  184: */
  185: static int memjrnlClose(sqlite3_file *pJfd){
  186:   memjrnlTruncate(pJfd, 0);
  187:   return SQLITE_OK;
  188: }
  189: 
  190: 
  191: /*
  192: ** Sync the file.
  193: **
  194: ** Syncing an in-memory journal is a no-op.  And, in fact, this routine
  195: ** is never called in a working implementation.  This implementation
  196: ** exists purely as a contingency, in case some malfunction in some other
  197: ** part of SQLite causes Sync to be called by mistake.
  198: */
  199: static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){
  200:   UNUSED_PARAMETER2(NotUsed, NotUsed2);
  201:   return SQLITE_OK;
  202: }
  203: 
  204: /*
  205: ** Query the size of the file in bytes.
  206: */
  207: static int memjrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
  208:   MemJournal *p = (MemJournal *)pJfd;
  209:   *pSize = (sqlite_int64) p->endpoint.iOffset;
  210:   return SQLITE_OK;
  211: }
  212: 
  213: /*
  214: ** Table of methods for MemJournal sqlite3_file object.
  215: */
  216: static const struct sqlite3_io_methods MemJournalMethods = {
  217:   1,                /* iVersion */
  218:   memjrnlClose,     /* xClose */
  219:   memjrnlRead,      /* xRead */
  220:   memjrnlWrite,     /* xWrite */
  221:   memjrnlTruncate,  /* xTruncate */
  222:   memjrnlSync,      /* xSync */
  223:   memjrnlFileSize,  /* xFileSize */
  224:   0,                /* xLock */
  225:   0,                /* xUnlock */
  226:   0,                /* xCheckReservedLock */
  227:   0,                /* xFileControl */
  228:   0,                /* xSectorSize */
  229:   0,                /* xDeviceCharacteristics */
  230:   0,                /* xShmMap */
  231:   0,                /* xShmLock */
  232:   0,                /* xShmBarrier */
  233:   0                 /* xShmUnlock */
  234: };
  235: 
  236: /* 
  237: ** Open a journal file.
  238: */
  239: void sqlite3MemJournalOpen(sqlite3_file *pJfd){
  240:   MemJournal *p = (MemJournal *)pJfd;
  241:   assert( EIGHT_BYTE_ALIGNMENT(p) );
  242:   memset(p, 0, sqlite3MemJournalSize());
  243:   p->pMethod = (sqlite3_io_methods*)&MemJournalMethods;
  244: }
  245: 
  246: /*
  247: ** Return true if the file-handle passed as an argument is 
  248: ** an in-memory journal 
  249: */
  250: int sqlite3IsMemJournal(sqlite3_file *pJfd){
  251:   return pJfd->pMethods==&MemJournalMethods;
  252: }
  253: 
  254: /* 
  255: ** Return the number of bytes required to store a MemJournal file descriptor.
  256: */
  257: int sqlite3MemJournalSize(void){
  258:   return sizeof(MemJournal);
  259: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>