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>