Index: src/memjournal.c ================================================================== --- src/memjournal.c +++ src/memjournal.c @@ -67,11 +67,10 @@ FilePoint readpoint; /* Pointer to the end of the last xRead() */ int flags; /* xOpen flags */ sqlite3_vfs *pVfs; /* The "real" underlying VFS */ const char *zJournal; /* Name of the journal file */ - sqlite3_file *pReal; /* The "real" underlying file descriptor */ }; /* ** Read data from the in-memory journal file. This is the implementation ** of the sqlite3_vfs.xRead method. @@ -81,13 +80,11 @@ void *zBuf, /* Put the results here */ int iAmt, /* Number of bytes to read */ sqlite_int64 iOfst /* Begin reading at this offset */ ){ MemJournal *p = (MemJournal *)pJfd; - if( p->pReal ){ - return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst); - }else if( (iAmt+iOfst)>p->endpoint.iOffset ){ + if( (iAmt+iOfst)>p->endpoint.iOffset ){ return SQLITE_IOERR_SHORT_READ; }else{ u8 *zOut = zBuf; int nRead = iAmt; int iChunkOffset; @@ -136,40 +133,41 @@ /* ** Flush the contents of memory to a real file on disk. */ static int memjrnlCreateFile(MemJournal *p){ - int rc = SQLITE_OK; - if( !p->pReal ){ - sqlite3_file *pReal = (sqlite3_file *)&p[1]; - rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0); - if( rc==SQLITE_OK ){ - int nChunk = p->nChunkSize; - i64 iOff = 0; - FileChunk *pIter; - p->pReal = pReal; - for(pIter=p->pFirst; pIter && rc==SQLITE_OK; pIter=pIter->pNext){ - int nWrite = nChunk; - if( pIter==p->endpoint.pChunk ){ - nWrite = p->endpoint.iOffset % p->nChunkSize; - if( nWrite==0 ) nWrite = p->nChunkSize; - } - rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nWrite, iOff); - iOff += nWrite; - } - if( rc!=SQLITE_OK ){ - /* If an error occurred while writing to the file, close it before - ** returning. This way, SQLite uses the in-memory journal data to - ** roll back changes made to the internal page-cache before this - ** function was called. */ - sqlite3OsClose(pReal); - p->pReal = 0; - }else{ - /* No error has occurred. Free the in-memory buffers. */ - memjrnlFreeChunks(p); - } - } + int rc; + sqlite3_file *pReal = (sqlite3_file*)p; + MemJournal copy = *p; + + memset(p, 0, sizeof(MemJournal)); + rc = sqlite3OsOpen(copy.pVfs, copy.zJournal, pReal, copy.flags, 0); + if( rc==SQLITE_OK ){ + int nChunk = copy.nChunkSize; + i64 iOff = 0; + FileChunk *pIter; + for(pIter=copy.pFirst; pIter && rc==SQLITE_OK; pIter=pIter->pNext){ + int nWrite = nChunk; + if( pIter==copy.endpoint.pChunk ){ + nWrite = copy.endpoint.iOffset % copy.nChunkSize; + if( nWrite==0 ) nWrite = copy.nChunkSize; + } + rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nWrite, iOff); + iOff += nWrite; + } + if( rc==SQLITE_OK ){ + /* No error has occurred. Free the in-memory buffers. */ + memjrnlFreeChunks(©); + } + } + if( rc!=SQLITE_OK ){ + /* If an error occurred while creating or writing to the file, restore + ** the original before returning. This way, SQLite uses the in-memory + ** journal data to roll back changes made to the internal page-cache + ** before this function was called. */ + sqlite3OsClose(pReal); + *p = copy; } return rc; } @@ -184,20 +182,16 @@ ){ MemJournal *p = (MemJournal *)pJfd; int nWrite = iAmt; u8 *zWrite = (u8 *)zBuf; - /* If the file has already been created on disk. */ - if( p->pReal ){ - return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst); - } - - /* If the file should be created now. */ - else if( p->nSpill>0 && (iAmt+iOfst)>p->nSpill ){ + /* If the file should be created now, create it and write the new data + ** into the file on disk. */ + if( p->nSpill>0 && (iAmt+iOfst)>p->nSpill ){ int rc = memjrnlCreateFile(p); if( rc==SQLITE_OK ){ - rc = memjrnlWrite(pJfd, zBuf, iAmt, iOfst); + rc = sqlite3OsWrite(pJfd, zBuf, iAmt, iOfst); } return rc; } /* If the contents of this write should be stored in memory */ @@ -253,13 +247,11 @@ ** is still in main memory but is being truncated to zero bytes in size, ** ignore */ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){ MemJournal *p = (MemJournal *)pJfd; - if( p->pReal ){ - return sqlite3OsTruncate(p->pReal, size); - }else if( size==0 ){ + if( size==0 ){ memjrnlFreeChunks(p); p->nSize = 0; p->endpoint.pChunk = 0; p->endpoint.iOffset = 0; p->readpoint.pChunk = 0; @@ -272,11 +264,10 @@ ** Close the file. */ static int memjrnlClose(sqlite3_file *pJfd){ MemJournal *p = (MemJournal *)pJfd; memjrnlFreeChunks(p); - if( p->pReal ) sqlite3OsClose(p->pReal); return SQLITE_OK; } /* ** Sync the file. @@ -283,25 +274,19 @@ ** ** If the real file has been created, call its xSync method. Otherwise, ** syncing an in-memory journal is a no-op. */ static int memjrnlSync(sqlite3_file *pJfd, int flags){ - MemJournal *p = (MemJournal *)pJfd; - if( p->pReal ){ - return sqlite3OsSync(p->pReal, flags); - } + UNUSED_PARAMETER2(pJfd, flags); return SQLITE_OK; } /* ** Query the size of the file in bytes. */ static int memjrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){ MemJournal *p = (MemJournal *)pJfd; - if( p->pReal ){ - return sqlite3OsFileSize(p->pReal, pSize); - } *pSize = (sqlite_int64) p->endpoint.iOffset; return SQLITE_OK; } /* @@ -352,11 +337,11 @@ /* Zero the file-handle object. If nSpill was passed zero, initialize ** it using the sqlite3OsOpen() function of the underlying VFS. In this ** case none of the code in this module is executed as a result of calls ** made on the journal file-handle. */ - memset(p, 0, sizeof(MemJournal) + (pVfs ? pVfs->szOsFile : 0)); + memset(p, 0, sizeof(MemJournal)); if( nSpill==0 ){ return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0); } if( nSpill>0 ){ @@ -401,15 +386,15 @@ ** The file-handle passed as the only argument is open on a journal file. ** Return true if this "journal file" is currently stored in heap memory, ** or false otherwise. */ int sqlite3JournalIsInMemory(sqlite3_file *p){ - return p->pMethods==&MemJournalMethods && ((MemJournal*)p)->pReal==0; + return p->pMethods==&MemJournalMethods; } /* ** Return the number of bytes required to store a JournalFile that uses vfs ** pVfs to create the underlying on-disk files. */ int sqlite3JournalSize(sqlite3_vfs *pVfs){ - return pVfs->szOsFile + sizeof(MemJournal); + return MAX(pVfs->szOsFile, sizeof(MemJournal)); }