Home | History | Annotate | Download | only in src
      1 /*
      2 ** 2007 August 22
      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 implements a special kind of sqlite3_file object used
     14 ** by SQLite to create journal files if the atomic-write optimization
     15 ** is enabled.
     16 **
     17 ** The distinctive characteristic of this sqlite3_file is that the
     18 ** actual on disk file is created lazily. When the file is created,
     19 ** the caller specifies a buffer size for an in-memory buffer to
     20 ** be used to service read() and write() requests. The actual file
     21 ** on disk is not created or populated until either:
     22 **
     23 **   1) The in-memory representation grows too large for the allocated
     24 **      buffer, or
     25 **   2) The sqlite3JournalCreate() function is called.
     26 */
     27 #ifdef SQLITE_ENABLE_ATOMIC_WRITE
     28 #include "sqliteInt.h"
     29 
     30 
     31 /*
     32 ** A JournalFile object is a subclass of sqlite3_file used by
     33 ** as an open file handle for journal files.
     34 */
     35 struct JournalFile {
     36   sqlite3_io_methods *pMethod;    /* I/O methods on journal files */
     37   int nBuf;                       /* Size of zBuf[] in bytes */
     38   char *zBuf;                     /* Space to buffer journal writes */
     39   int iSize;                      /* Amount of zBuf[] currently used */
     40   int flags;                      /* xOpen flags */
     41   sqlite3_vfs *pVfs;              /* The "real" underlying VFS */
     42   sqlite3_file *pReal;            /* The "real" underlying file descriptor */
     43   const char *zJournal;           /* Name of the journal file */
     44 };
     45 typedef struct JournalFile JournalFile;
     46 
     47 /*
     48 ** If it does not already exists, create and populate the on-disk file
     49 ** for JournalFile p.
     50 */
     51 static int createFile(JournalFile *p){
     52   int rc = SQLITE_OK;
     53   if( !p->pReal ){
     54     sqlite3_file *pReal = (sqlite3_file *)&p[1];
     55     rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0);
     56     if( rc==SQLITE_OK ){
     57       p->pReal = pReal;
     58       if( p->iSize>0 ){
     59         assert(p->iSize<=p->nBuf);
     60         rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0);
     61       }
     62     }
     63   }
     64   return rc;
     65 }
     66 
     67 /*
     68 ** Close the file.
     69 */
     70 static int jrnlClose(sqlite3_file *pJfd){
     71   JournalFile *p = (JournalFile *)pJfd;
     72   if( p->pReal ){
     73     sqlite3OsClose(p->pReal);
     74   }
     75   sqlite3_free(p->zBuf);
     76   return SQLITE_OK;
     77 }
     78 
     79 /*
     80 ** Read data from the file.
     81 */
     82 static int jrnlRead(
     83   sqlite3_file *pJfd,    /* The journal file from which to read */
     84   void *zBuf,            /* Put the results here */
     85   int iAmt,              /* Number of bytes to read */
     86   sqlite_int64 iOfst     /* Begin reading at this offset */
     87 ){
     88   int rc = SQLITE_OK;
     89   JournalFile *p = (JournalFile *)pJfd;
     90   if( p->pReal ){
     91     rc = sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
     92   }else if( (iAmt+iOfst)>p->iSize ){
     93     rc = SQLITE_IOERR_SHORT_READ;
     94   }else{
     95     memcpy(zBuf, &p->zBuf[iOfst], iAmt);
     96   }
     97   return rc;
     98 }
     99 
    100 /*
    101 ** Write data to the file.
    102 */
    103 static int jrnlWrite(
    104   sqlite3_file *pJfd,    /* The journal file into which to write */
    105   const void *zBuf,      /* Take data to be written from here */
    106   int iAmt,              /* Number of bytes to write */
    107   sqlite_int64 iOfst     /* Begin writing at this offset into the file */
    108 ){
    109   int rc = SQLITE_OK;
    110   JournalFile *p = (JournalFile *)pJfd;
    111   if( !p->pReal && (iOfst+iAmt)>p->nBuf ){
    112     rc = createFile(p);
    113   }
    114   if( rc==SQLITE_OK ){
    115     if( p->pReal ){
    116       rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
    117     }else{
    118       memcpy(&p->zBuf[iOfst], zBuf, iAmt);
    119       if( p->iSize<(iOfst+iAmt) ){
    120         p->iSize = (iOfst+iAmt);
    121       }
    122     }
    123   }
    124   return rc;
    125 }
    126 
    127 /*
    128 ** Truncate the file.
    129 */
    130 static int jrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
    131   int rc = SQLITE_OK;
    132   JournalFile *p = (JournalFile *)pJfd;
    133   if( p->pReal ){
    134     rc = sqlite3OsTruncate(p->pReal, size);
    135   }else if( size<p->iSize ){
    136     p->iSize = size;
    137   }
    138   return rc;
    139 }
    140 
    141 /*
    142 ** Sync the file.
    143 */
    144 static int jrnlSync(sqlite3_file *pJfd, int flags){
    145   int rc;
    146   JournalFile *p = (JournalFile *)pJfd;
    147   if( p->pReal ){
    148     rc = sqlite3OsSync(p->pReal, flags);
    149   }else{
    150     rc = SQLITE_OK;
    151   }
    152   return rc;
    153 }
    154 
    155 /*
    156 ** Query the size of the file in bytes.
    157 */
    158 static int jrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
    159   int rc = SQLITE_OK;
    160   JournalFile *p = (JournalFile *)pJfd;
    161   if( p->pReal ){
    162     rc = sqlite3OsFileSize(p->pReal, pSize);
    163   }else{
    164     *pSize = (sqlite_int64) p->iSize;
    165   }
    166   return rc;
    167 }
    168 
    169 /*
    170 ** Table of methods for JournalFile sqlite3_file object.
    171 */
    172 static struct sqlite3_io_methods JournalFileMethods = {
    173   1,             /* iVersion */
    174   jrnlClose,     /* xClose */
    175   jrnlRead,      /* xRead */
    176   jrnlWrite,     /* xWrite */
    177   jrnlTruncate,  /* xTruncate */
    178   jrnlSync,      /* xSync */
    179   jrnlFileSize,  /* xFileSize */
    180   0,             /* xLock */
    181   0,             /* xUnlock */
    182   0,             /* xCheckReservedLock */
    183   0,             /* xFileControl */
    184   0,             /* xSectorSize */
    185   0,             /* xDeviceCharacteristics */
    186   0,             /* xShmMap */
    187   0,             /* xShmLock */
    188   0,             /* xShmBarrier */
    189   0              /* xShmUnmap */
    190 };
    191 
    192 /*
    193 ** Open a journal file.
    194 */
    195 int sqlite3JournalOpen(
    196   sqlite3_vfs *pVfs,         /* The VFS to use for actual file I/O */
    197   const char *zName,         /* Name of the journal file */
    198   sqlite3_file *pJfd,        /* Preallocated, blank file handle */
    199   int flags,                 /* Opening flags */
    200   int nBuf                   /* Bytes buffered before opening the file */
    201 ){
    202   JournalFile *p = (JournalFile *)pJfd;
    203   memset(p, 0, sqlite3JournalSize(pVfs));
    204   if( nBuf>0 ){
    205     p->zBuf = sqlite3MallocZero(nBuf);
    206     if( !p->zBuf ){
    207       return SQLITE_NOMEM;
    208     }
    209   }else{
    210     return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
    211   }
    212   p->pMethod = &JournalFileMethods;
    213   p->nBuf = nBuf;
    214   p->flags = flags;
    215   p->zJournal = zName;
    216   p->pVfs = pVfs;
    217   return SQLITE_OK;
    218 }
    219 
    220 /*
    221 ** If the argument p points to a JournalFile structure, and the underlying
    222 ** file has not yet been created, create it now.
    223 */
    224 int sqlite3JournalCreate(sqlite3_file *p){
    225   if( p->pMethods!=&JournalFileMethods ){
    226     return SQLITE_OK;
    227   }
    228   return createFile((JournalFile *)p);
    229 }
    230 
    231 /*
    232 ** Return the number of bytes required to store a JournalFile that uses vfs
    233 ** pVfs to create the underlying on-disk files.
    234 */
    235 int sqlite3JournalSize(sqlite3_vfs *pVfs){
    236   return (pVfs->szOsFile+sizeof(JournalFile));
    237 }
    238 #endif
    239