Annotation of embedaddon/sqlite3/src/memjournal.c, revision 1.1.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>