xref: /sqlite-3.40.0/src/memjournal.c (revision 2756f806)
139281b4bSdanielk1977 /*
227c3bd7bSdrh ** 2008 October 7
339281b4bSdanielk1977 **
439281b4bSdanielk1977 ** The author disclaims copyright to this source code.  In place of
539281b4bSdanielk1977 ** a legal notice, here is a blessing:
639281b4bSdanielk1977 **
739281b4bSdanielk1977 **    May you do good and not evil.
839281b4bSdanielk1977 **    May you find forgiveness for yourself and forgive others.
939281b4bSdanielk1977 **    May you share freely, never taking more than you give.
1039281b4bSdanielk1977 **
1139281b4bSdanielk1977 *************************************************************************
1239281b4bSdanielk1977 **
1327c3bd7bSdrh ** This file contains code use to implement an in-memory rollback journal.
1427c3bd7bSdrh ** The in-memory rollback journal is used to journal transactions for
1527c3bd7bSdrh ** ":memory:" databases and when the journal_mode=MEMORY pragma is used.
1670b8d6bbSdrh **
1770b8d6bbSdrh ** Update:  The in-memory journal is also used to temporarily cache
1870b8d6bbSdrh ** smaller journals that are not critical for power-loss recovery.
1970b8d6bbSdrh ** For example, statement journals that are not too big will be held
2070b8d6bbSdrh ** entirely in memory, thus reducing the number of file I/O calls, and
2170b8d6bbSdrh ** more importantly, reducing temporary file creation events.  If these
2270b8d6bbSdrh ** journals become too large for memory, they are spilled to disk.  But
2370b8d6bbSdrh ** in the common case, they are usually small and no file I/O needs to
2470b8d6bbSdrh ** occur.
2539281b4bSdanielk1977 */
2639281b4bSdanielk1977 #include "sqliteInt.h"
2739281b4bSdanielk1977 
2827c3bd7bSdrh /* Forward references to internal structures */
2939281b4bSdanielk1977 typedef struct MemJournal MemJournal;
3039281b4bSdanielk1977 typedef struct FilePoint FilePoint;
3139281b4bSdanielk1977 typedef struct FileChunk FileChunk;
3239281b4bSdanielk1977 
3327c3bd7bSdrh /*
3427c3bd7bSdrh ** The rollback journal is composed of a linked list of these structures.
352491de28Sdan **
362491de28Sdan ** The zChunk array is always at least 8 bytes in size - usually much more.
372491de28Sdan ** Its actual size is stored in the MemJournal.nChunkSize variable.
3827c3bd7bSdrh */
3939281b4bSdanielk1977 struct FileChunk {
4027c3bd7bSdrh   FileChunk *pNext;               /* Next chunk in the journal */
412491de28Sdan   u8 zChunk[8];                   /* Content of this chunk */
4239281b4bSdanielk1977 };
4339281b4bSdanielk1977 
4427c3bd7bSdrh /*
452491de28Sdan ** By default, allocate this many bytes of memory for each FileChunk object.
462491de28Sdan */
472491de28Sdan #define MEMJOURNAL_DFLT_FILECHUNKSIZE 1024
482491de28Sdan 
492491de28Sdan /*
502491de28Sdan ** For chunk size nChunkSize, return the number of bytes that should
512491de28Sdan ** be allocated for each FileChunk structure.
522491de28Sdan */
532491de28Sdan #define fileChunkSize(nChunkSize) (sizeof(FileChunk) + ((nChunkSize)-8))
542491de28Sdan 
552491de28Sdan /*
5627c3bd7bSdrh ** An instance of this object serves as a cursor into the rollback journal.
5727c3bd7bSdrh ** The cursor can be either for reading or writing.
5827c3bd7bSdrh */
5939281b4bSdanielk1977 struct FilePoint {
6027c3bd7bSdrh   sqlite3_int64 iOffset;          /* Offset from the beginning of the file */
6127c3bd7bSdrh   FileChunk *pChunk;              /* Specific chunk into which cursor points */
6239281b4bSdanielk1977 };
6339281b4bSdanielk1977 
6427c3bd7bSdrh /*
652491de28Sdan ** This structure is a subclass of sqlite3_file. Each open memory-journal
6627c3bd7bSdrh ** is an instance of this class.
6727c3bd7bSdrh */
6839281b4bSdanielk1977 struct MemJournal {
692491de28Sdan   const sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */
702491de28Sdan   int nChunkSize;                 /* In-memory chunk-size */
712491de28Sdan 
72c2f18addSdrh   int nSpill;                     /* Bytes of data before flushing */
7339281b4bSdanielk1977   FileChunk *pFirst;              /* Head of in-memory chunk-list */
7439281b4bSdanielk1977   FilePoint endpoint;             /* Pointer to the end of the file */
7539281b4bSdanielk1977   FilePoint readpoint;            /* Pointer to the end of the last xRead() */
762491de28Sdan 
772491de28Sdan   int flags;                      /* xOpen flags */
782491de28Sdan   sqlite3_vfs *pVfs;              /* The "real" underlying VFS */
792491de28Sdan   const char *zJournal;           /* Name of the journal file */
8039281b4bSdanielk1977 };
8139281b4bSdanielk1977 
8239281b4bSdanielk1977 /*
832206a2b6Sdrh ** Read data from the in-memory journal file.  This is the implementation
842206a2b6Sdrh ** of the sqlite3_vfs.xRead method.
8539281b4bSdanielk1977 */
memjrnlRead(sqlite3_file * pJfd,void * zBuf,int iAmt,sqlite_int64 iOfst)8639281b4bSdanielk1977 static int memjrnlRead(
8739281b4bSdanielk1977   sqlite3_file *pJfd,    /* The journal file from which to read */
8839281b4bSdanielk1977   void *zBuf,            /* Put the results here */
8939281b4bSdanielk1977   int iAmt,              /* Number of bytes to read */
9039281b4bSdanielk1977   sqlite_int64 iOfst     /* Begin reading at this offset */
9139281b4bSdanielk1977 ){
9239281b4bSdanielk1977   MemJournal *p = (MemJournal *)pJfd;
9339281b4bSdanielk1977   u8 *zOut = zBuf;
9439281b4bSdanielk1977   int nRead = iAmt;
9539281b4bSdanielk1977   int iChunkOffset;
9639281b4bSdanielk1977   FileChunk *pChunk;
9739281b4bSdanielk1977 
98d93b2b84Sdrh   if( (iAmt+iOfst)>p->endpoint.iOffset ){
99d93b2b84Sdrh     return SQLITE_IOERR_SHORT_READ;
100d93b2b84Sdrh   }
10138b3dde0Sdrh   assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 );
10239281b4bSdanielk1977   if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
10339281b4bSdanielk1977     sqlite3_int64 iOff = 0;
10439281b4bSdanielk1977     for(pChunk=p->pFirst;
1052491de28Sdan         ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst;
10639281b4bSdanielk1977         pChunk=pChunk->pNext
10739281b4bSdanielk1977     ){
1082491de28Sdan       iOff += p->nChunkSize;
10939281b4bSdanielk1977     }
11039281b4bSdanielk1977   }else{
11139281b4bSdanielk1977     pChunk = p->readpoint.pChunk;
11238b3dde0Sdrh     assert( pChunk!=0 );
11339281b4bSdanielk1977   }
11439281b4bSdanielk1977 
1152491de28Sdan   iChunkOffset = (int)(iOfst%p->nChunkSize);
11639281b4bSdanielk1977   do {
1172491de28Sdan     int iSpace = p->nChunkSize - iChunkOffset;
1182491de28Sdan     int nCopy = MIN(nRead, (p->nChunkSize - iChunkOffset));
11965a7e769Sdrh     memcpy(zOut, (u8*)pChunk->zChunk + iChunkOffset, nCopy);
12039281b4bSdanielk1977     zOut += nCopy;
12139281b4bSdanielk1977     nRead -= iSpace;
12239281b4bSdanielk1977     iChunkOffset = 0;
123ea678832Sdrh   } while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 );
12438b3dde0Sdrh   p->readpoint.iOffset = pChunk ? iOfst+iAmt : 0;
12539281b4bSdanielk1977   p->readpoint.pChunk = pChunk;
12639281b4bSdanielk1977 
12739281b4bSdanielk1977   return SQLITE_OK;
12839281b4bSdanielk1977 }
12939281b4bSdanielk1977 
13039281b4bSdanielk1977 /*
1312491de28Sdan ** Free the list of FileChunk structures headed at MemJournal.pFirst.
1322491de28Sdan */
memjrnlFreeChunks(FileChunk * pFirst)133f43fef29Sdan static void memjrnlFreeChunks(FileChunk *pFirst){
1342491de28Sdan   FileChunk *pIter;
1352491de28Sdan   FileChunk *pNext;
136f43fef29Sdan   for(pIter=pFirst; pIter; pIter=pNext){
1372491de28Sdan     pNext = pIter->pNext;
1382491de28Sdan     sqlite3_free(pIter);
1392491de28Sdan   }
1402491de28Sdan }
1412491de28Sdan 
1422491de28Sdan /*
1432491de28Sdan ** Flush the contents of memory to a real file on disk.
1442491de28Sdan */
memjrnlCreateFile(MemJournal * p)145c2f18addSdrh static int memjrnlCreateFile(MemJournal *p){
1467ed40208Sdan   int rc;
1477ed40208Sdan   sqlite3_file *pReal = (sqlite3_file*)p;
1487ed40208Sdan   MemJournal copy = *p;
1497ed40208Sdan 
1507ed40208Sdan   memset(p, 0, sizeof(MemJournal));
1517ed40208Sdan   rc = sqlite3OsOpen(copy.pVfs, copy.zJournal, pReal, copy.flags, 0);
1522491de28Sdan   if( rc==SQLITE_OK ){
1537ed40208Sdan     int nChunk = copy.nChunkSize;
1542491de28Sdan     i64 iOff = 0;
1552491de28Sdan     FileChunk *pIter;
156769b4c95Sdrh     for(pIter=copy.pFirst; pIter; pIter=pIter->pNext){
157d93b2b84Sdrh       if( iOff + nChunk > copy.endpoint.iOffset ){
158d93b2b84Sdrh         nChunk = copy.endpoint.iOffset - iOff;
1592491de28Sdan       }
160d93b2b84Sdrh       rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nChunk, iOff);
161769b4c95Sdrh       if( rc ) break;
162d93b2b84Sdrh       iOff += nChunk;
1632491de28Sdan     }
1647ed40208Sdan     if( rc==SQLITE_OK ){
1652491de28Sdan       /* No error has occurred. Free the in-memory buffers. */
166f43fef29Sdan       memjrnlFreeChunks(copy.pFirst);
1672491de28Sdan     }
1682491de28Sdan   }
1697ed40208Sdan   if( rc!=SQLITE_OK ){
1707ed40208Sdan     /* If an error occurred while creating or writing to the file, restore
1717ed40208Sdan     ** the original before returning. This way, SQLite uses the in-memory
1727ed40208Sdan     ** journal data to roll back changes made to the internal page-cache
1737ed40208Sdan     ** before this function was called.  */
1747ed40208Sdan     sqlite3OsClose(pReal);
1757ed40208Sdan     *p = copy;
1762491de28Sdan   }
1772491de28Sdan   return rc;
1782491de28Sdan }
1792491de28Sdan 
1802491de28Sdan 
181e63b7bdaSdrh /* Forward reference */
182e63b7bdaSdrh static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size);
183e63b7bdaSdrh 
1842491de28Sdan /*
18539281b4bSdanielk1977 ** Write data to the file.
18639281b4bSdanielk1977 */
memjrnlWrite(sqlite3_file * pJfd,const void * zBuf,int iAmt,sqlite_int64 iOfst)18739281b4bSdanielk1977 static int memjrnlWrite(
18839281b4bSdanielk1977   sqlite3_file *pJfd,    /* The journal file into which to write */
18939281b4bSdanielk1977   const void *zBuf,      /* Take data to be written from here */
19039281b4bSdanielk1977   int iAmt,              /* Number of bytes to write */
19139281b4bSdanielk1977   sqlite_int64 iOfst     /* Begin writing at this offset into the file */
19239281b4bSdanielk1977 ){
19339281b4bSdanielk1977   MemJournal *p = (MemJournal *)pJfd;
19439281b4bSdanielk1977   int nWrite = iAmt;
19539281b4bSdanielk1977   u8 *zWrite = (u8 *)zBuf;
19639281b4bSdanielk1977 
1977ed40208Sdan   /* If the file should be created now, create it and write the new data
1987ed40208Sdan   ** into the file on disk. */
1997ed40208Sdan   if( p->nSpill>0 && (iAmt+iOfst)>p->nSpill ){
200c2f18addSdrh     int rc = memjrnlCreateFile(p);
2012491de28Sdan     if( rc==SQLITE_OK ){
2027ed40208Sdan       rc = sqlite3OsWrite(pJfd, zBuf, iAmt, iOfst);
2032491de28Sdan     }
2042491de28Sdan     return rc;
2052491de28Sdan   }
2062491de28Sdan 
2072491de28Sdan   /* If the contents of this write should be stored in memory */
2082491de28Sdan   else{
2092491de28Sdan     /* An in-memory journal file should only ever be appended to. Random
2102491de28Sdan     ** access writes are not required. The only exception to this is when
2112491de28Sdan     ** the in-memory journal is being used by a connection using the
2122491de28Sdan     ** atomic-write optimization. In this case the first 28 bytes of the
2132491de28Sdan     ** journal file may be written as part of committing the transaction. */
214e63b7bdaSdrh     assert( iOfst<=p->endpoint.iOffset );
215e63b7bdaSdrh     if( iOfst>0 && iOfst!=p->endpoint.iOffset ){
216e63b7bdaSdrh       memjrnlTruncate(pJfd, iOfst);
217e63b7bdaSdrh     }
2182491de28Sdan     if( iOfst==0 && p->pFirst ){
2192491de28Sdan       assert( p->nChunkSize>iAmt );
22065a7e769Sdrh       memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
221e63b7bdaSdrh     }else{
22239281b4bSdanielk1977       while( nWrite>0 ){
22339281b4bSdanielk1977         FileChunk *pChunk = p->endpoint.pChunk;
2242491de28Sdan         int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize);
2252491de28Sdan         int iSpace = MIN(nWrite, p->nChunkSize - iChunkOffset);
22639281b4bSdanielk1977 
2270ca09883Sdrh         assert( pChunk!=0 || iChunkOffset==0 );
22839281b4bSdanielk1977         if( iChunkOffset==0 ){
22939281b4bSdanielk1977           /* New chunk is required to extend the file. */
2302491de28Sdan           FileChunk *pNew = sqlite3_malloc(fileChunkSize(p->nChunkSize));
23139281b4bSdanielk1977           if( !pNew ){
232fad3039cSmistachkin             return SQLITE_IOERR_NOMEM_BKPT;
23339281b4bSdanielk1977           }
23439281b4bSdanielk1977           pNew->pNext = 0;
23539281b4bSdanielk1977           if( pChunk ){
23639281b4bSdanielk1977             assert( p->pFirst );
23739281b4bSdanielk1977             pChunk->pNext = pNew;
23839281b4bSdanielk1977           }else{
23939281b4bSdanielk1977             assert( !p->pFirst );
24039281b4bSdanielk1977             p->pFirst = pNew;
24139281b4bSdanielk1977           }
2420ca09883Sdrh           pChunk = p->endpoint.pChunk = pNew;
24339281b4bSdanielk1977         }
24439281b4bSdanielk1977 
2450ca09883Sdrh         assert( pChunk!=0 );
2460ca09883Sdrh         memcpy((u8*)pChunk->zChunk + iChunkOffset, zWrite, iSpace);
24739281b4bSdanielk1977         zWrite += iSpace;
24839281b4bSdanielk1977         nWrite -= iSpace;
24939281b4bSdanielk1977         p->endpoint.iOffset += iSpace;
25039281b4bSdanielk1977       }
2512491de28Sdan     }
2522491de28Sdan   }
25339281b4bSdanielk1977 
25439281b4bSdanielk1977   return SQLITE_OK;
25539281b4bSdanielk1977 }
25639281b4bSdanielk1977 
25739281b4bSdanielk1977 /*
258f43fef29Sdan ** Truncate the in-memory file.
25939281b4bSdanielk1977 */
memjrnlTruncate(sqlite3_file * pJfd,sqlite_int64 size)26039281b4bSdanielk1977 static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
26139281b4bSdanielk1977   MemJournal *p = (MemJournal *)pJfd;
262c00727abSdan   assert( p->endpoint.pChunk==0 || p->endpoint.pChunk->pNext==0 );
263c00727abSdan   if( size<p->endpoint.iOffset ){
264f43fef29Sdan     FileChunk *pIter = 0;
265f43fef29Sdan     if( size==0 ){
266f43fef29Sdan       memjrnlFreeChunks(p->pFirst);
267f43fef29Sdan       p->pFirst = 0;
268f43fef29Sdan     }else{
269f43fef29Sdan       i64 iOff = p->nChunkSize;
2700f42f71dSdan       for(pIter=p->pFirst; ALWAYS(pIter) && iOff<size; pIter=pIter->pNext){
271f43fef29Sdan         iOff += p->nChunkSize;
272f43fef29Sdan       }
2731b1a1ddaSdrh       if( ALWAYS(pIter) ){
274f43fef29Sdan         memjrnlFreeChunks(pIter->pNext);
275f43fef29Sdan         pIter->pNext = 0;
276f43fef29Sdan       }
277f43fef29Sdan     }
278f43fef29Sdan 
279f43fef29Sdan     p->endpoint.pChunk = pIter;
280f43fef29Sdan     p->endpoint.iOffset = size;
2812491de28Sdan     p->readpoint.pChunk = 0;
2822491de28Sdan     p->readpoint.iOffset = 0;
283c00727abSdan   }
28439281b4bSdanielk1977   return SQLITE_OK;
28539281b4bSdanielk1977 }
28639281b4bSdanielk1977 
28739281b4bSdanielk1977 /*
28839281b4bSdanielk1977 ** Close the file.
28939281b4bSdanielk1977 */
memjrnlClose(sqlite3_file * pJfd)29039281b4bSdanielk1977 static int memjrnlClose(sqlite3_file *pJfd){
2912491de28Sdan   MemJournal *p = (MemJournal *)pJfd;
292f43fef29Sdan   memjrnlFreeChunks(p->pFirst);
29339281b4bSdanielk1977   return SQLITE_OK;
29439281b4bSdanielk1977 }
29539281b4bSdanielk1977 
29639281b4bSdanielk1977 /*
29739281b4bSdanielk1977 ** Sync the file.
2982206a2b6Sdrh **
2992491de28Sdan ** If the real file has been created, call its xSync method. Otherwise,
3002491de28Sdan ** syncing an in-memory journal is a no-op.
30139281b4bSdanielk1977 */
memjrnlSync(sqlite3_file * pJfd,int flags)3022491de28Sdan static int memjrnlSync(sqlite3_file *pJfd, int flags){
3037ed40208Sdan   UNUSED_PARAMETER2(pJfd, flags);
30409c0f6d0Sdrh   return SQLITE_OK;
30509c0f6d0Sdrh }
30639281b4bSdanielk1977 
30739281b4bSdanielk1977 /*
30839281b4bSdanielk1977 ** Query the size of the file in bytes.
30939281b4bSdanielk1977 */
memjrnlFileSize(sqlite3_file * pJfd,sqlite_int64 * pSize)31039281b4bSdanielk1977 static int memjrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
31139281b4bSdanielk1977   MemJournal *p = (MemJournal *)pJfd;
31239281b4bSdanielk1977   *pSize = (sqlite_int64) p->endpoint.iOffset;
31339281b4bSdanielk1977   return SQLITE_OK;
31439281b4bSdanielk1977 }
31539281b4bSdanielk1977 
31639281b4bSdanielk1977 /*
31739281b4bSdanielk1977 ** Table of methods for MemJournal sqlite3_file object.
31839281b4bSdanielk1977 */
319f83dc1efSdrh static const struct sqlite3_io_methods MemJournalMethods = {
32039281b4bSdanielk1977   1,                /* iVersion */
32139281b4bSdanielk1977   memjrnlClose,     /* xClose */
32239281b4bSdanielk1977   memjrnlRead,      /* xRead */
32339281b4bSdanielk1977   memjrnlWrite,     /* xWrite */
32439281b4bSdanielk1977   memjrnlTruncate,  /* xTruncate */
32539281b4bSdanielk1977   memjrnlSync,      /* xSync */
32639281b4bSdanielk1977   memjrnlFileSize,  /* xFileSize */
32739281b4bSdanielk1977   0,                /* xLock */
32839281b4bSdanielk1977   0,                /* xUnlock */
32939281b4bSdanielk1977   0,                /* xCheckReservedLock */
33039281b4bSdanielk1977   0,                /* xFileControl */
33139281b4bSdanielk1977   0,                /* xSectorSize */
332ff82894fSdrh   0,                /* xDeviceCharacteristics */
333ff82894fSdrh   0,                /* xShmMap */
3346e1f4828Sdrh   0,                /* xShmLock */
335ff82894fSdrh   0,                /* xShmBarrier */
336da8caa0bSdrh   0,                /* xShmUnmap */
337da8caa0bSdrh   0,                /* xFetch */
338da8caa0bSdrh   0                 /* xUnfetch */
33939281b4bSdanielk1977 };
34039281b4bSdanielk1977 
34139281b4bSdanielk1977 /*
34239281b4bSdanielk1977 ** Open a journal file.
3432491de28Sdan **
3442491de28Sdan ** The behaviour of the journal file depends on the value of parameter
345c2f18addSdrh ** nSpill. If nSpill is 0, then the journal file is always create and
346c2f18addSdrh ** accessed using the underlying VFS. If nSpill is less than zero, then
347c2f18addSdrh ** all content is always stored in main-memory. Finally, if nSpill is a
3482491de28Sdan ** positive value, then the journal file is initially created in-memory
3492491de28Sdan ** but may be flushed to disk later on. In this case the journal file is
350c2f18addSdrh ** flushed to disk either when it grows larger than nSpill bytes in size,
3512491de28Sdan ** or when sqlite3JournalCreate() is called.
3522491de28Sdan */
sqlite3JournalOpen(sqlite3_vfs * pVfs,const char * zName,sqlite3_file * pJfd,int flags,int nSpill)3532491de28Sdan int sqlite3JournalOpen(
3542491de28Sdan   sqlite3_vfs *pVfs,         /* The VFS to use for actual file I/O */
3552491de28Sdan   const char *zName,         /* Name of the journal file */
3562491de28Sdan   sqlite3_file *pJfd,        /* Preallocated, blank file handle */
3572491de28Sdan   int flags,                 /* Opening flags */
358c2f18addSdrh   int nSpill                 /* Bytes buffered before opening the file */
3592491de28Sdan ){
3602491de28Sdan   MemJournal *p = (MemJournal*)pJfd;
3612491de28Sdan 
362*2756f806Sdan   assert( zName || nSpill<0 || (flags & SQLITE_OPEN_EXCLUSIVE) );
363*2756f806Sdan 
364c2f18addSdrh   /* Zero the file-handle object. If nSpill was passed zero, initialize
3652491de28Sdan   ** it using the sqlite3OsOpen() function of the underlying VFS. In this
3662491de28Sdan   ** case none of the code in this module is executed as a result of calls
3672491de28Sdan   ** made on the journal file-handle.  */
3687ed40208Sdan   memset(p, 0, sizeof(MemJournal));
369c2f18addSdrh   if( nSpill==0 ){
3702491de28Sdan     return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
3712491de28Sdan   }
3722491de28Sdan 
373c2f18addSdrh   if( nSpill>0 ){
374c2f18addSdrh     p->nChunkSize = nSpill;
3752491de28Sdan   }else{
3762491de28Sdan     p->nChunkSize = 8 + MEMJOURNAL_DFLT_FILECHUNKSIZE - sizeof(FileChunk);
3772491de28Sdan     assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) );
3782491de28Sdan   }
3792491de28Sdan 
380d9059bdbSdrh   pJfd->pMethods = (const sqlite3_io_methods*)&MemJournalMethods;
381c2f18addSdrh   p->nSpill = nSpill;
3822491de28Sdan   p->flags = flags;
3832491de28Sdan   p->zJournal = zName;
3842491de28Sdan   p->pVfs = pVfs;
3852491de28Sdan   return SQLITE_OK;
3862491de28Sdan }
3872491de28Sdan 
3882491de28Sdan /*
3892491de28Sdan ** Open an in-memory journal file.
39039281b4bSdanielk1977 */
sqlite3MemJournalOpen(sqlite3_file * pJfd)39139281b4bSdanielk1977 void sqlite3MemJournalOpen(sqlite3_file *pJfd){
3922491de28Sdan   sqlite3JournalOpen(0, 0, pJfd, 0, -1);
39339281b4bSdanielk1977 }
39439281b4bSdanielk1977 
395d67a9770Sdan #if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
396d67a9770Sdan  || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
39739281b4bSdanielk1977 /*
3982491de28Sdan ** If the argument p points to a MemJournal structure that is not an
3995f37ed51Sdan ** in-memory-only journal file (i.e. is one that was opened with a +ve
400efe16971Sdan ** nSpill parameter or as SQLITE_OPEN_MAIN_JOURNAL), and the underlying
401efe16971Sdan ** file has not yet been created, create it now.
40239281b4bSdanielk1977 */
sqlite3JournalCreate(sqlite3_file * pJfd)403efe16971Sdan int sqlite3JournalCreate(sqlite3_file *pJfd){
4042491de28Sdan   int rc = SQLITE_OK;
405efe16971Sdan   MemJournal *p = (MemJournal*)pJfd;
406d9059bdbSdrh   if( pJfd->pMethods==&MemJournalMethods && (
4079e61104cSdrh #ifdef SQLITE_ENABLE_ATOMIC_WRITE
4089e61104cSdrh      p->nSpill>0
4099e61104cSdrh #else
4109e61104cSdrh      /* While this appears to not be possible without ATOMIC_WRITE, the
4119e61104cSdrh      ** paths are complex, so it seems prudent to leave the test in as
4129e61104cSdrh      ** a NEVER(), in case our analysis is subtly flawed. */
4139e61104cSdrh      NEVER(p->nSpill>0)
4149e61104cSdrh #endif
415d67a9770Sdan #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
416d67a9770Sdan      || (p->flags & SQLITE_OPEN_MAIN_JOURNAL)
417d67a9770Sdan #endif
418d67a9770Sdan   )){
419efe16971Sdan     rc = memjrnlCreateFile(p);
42039281b4bSdanielk1977   }
4212491de28Sdan   return rc;
4222491de28Sdan }
423ff6b8266Sdrh #endif
4242491de28Sdan 
4252491de28Sdan /*
4265f37ed51Sdan ** The file-handle passed as the only argument is open on a journal file.
4275f37ed51Sdan ** Return true if this "journal file" is currently stored in heap memory,
4282491de28Sdan ** or false otherwise.
4292491de28Sdan */
sqlite3JournalIsInMemory(sqlite3_file * p)4302491de28Sdan int sqlite3JournalIsInMemory(sqlite3_file *p){
4317ed40208Sdan   return p->pMethods==&MemJournalMethods;
4322491de28Sdan }
4332491de28Sdan 
4342491de28Sdan /*
4352491de28Sdan ** Return the number of bytes required to store a JournalFile that uses vfs
4362491de28Sdan ** pVfs to create the underlying on-disk files.
4372491de28Sdan */
sqlite3JournalSize(sqlite3_vfs * pVfs)4382491de28Sdan int sqlite3JournalSize(sqlite3_vfs *pVfs){
43913969f5aSdrh   return MAX(pVfs->szOsFile, (int)sizeof(MemJournal));
4402491de28Sdan }
441