Annotation of embedaddon/sqlite3/src/memjournal.c, revision 1.1

1.1     ! misho       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>