/ Check-in [def55027]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Backport of all batch-atomic-write changes through check-in [67bad7fb9b]
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | batch-atomic-write-3.19
Files: files | file ages | folders
SHA3-256: def55027b1f1db9c083830019dbcc3daed94f6cc70a76b285ac1af9d82f81695
User & Date: drh 2017-07-28 02:02:45
Context
2017-07-31
12:04
Merge further enhancements to the batch-atomic-write subsystem. Leaf check-in: 4be4265d user: drh tags: batch-atomic-write-3.19
2017-07-28
02:02
Backport of all batch-atomic-write changes through check-in [67bad7fb9b] check-in: def55027 user: drh tags: batch-atomic-write-3.19
01:53
Add the SQLITE_ENABLE_BATCH_ATOMIC_WRITE macro to ctime.c check-in: 67bad7fb user: drh tags: batch-atomic-write
2017-07-27
00:27
Do now allow the geometry object in the right operand of a MATCH operator in the RTREE extension to be inpersonated by a BLOB literal. check-in: 24c9cd46 user: drh tags: branch-3.19
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/ctime.c.

    85     85     "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES),
    86     86   #endif
    87     87   #if SQLITE_ENABLE_API_ARMOR
    88     88     "ENABLE_API_ARMOR",
    89     89   #endif
    90     90   #if SQLITE_ENABLE_ATOMIC_WRITE
    91     91     "ENABLE_ATOMIC_WRITE",
           92  +#endif
           93  +#if SQLITE_ENABLE_BATCH_ATOMIC_WRITE
           94  +  "ENABLE_BATCH_ATOMIC_WRITE",
    92     95   #endif
    93     96   #if SQLITE_ENABLE_CEROD
    94     97     "ENABLE_CEROD",
    95     98   #endif
    96     99   #if SQLITE_ENABLE_COLUMN_METADATA
    97    100     "ENABLE_COLUMN_METADATA",
    98    101   #endif

Changes to src/memjournal.c.

    92     92   ){
    93     93     MemJournal *p = (MemJournal *)pJfd;
    94     94     u8 *zOut = zBuf;
    95     95     int nRead = iAmt;
    96     96     int iChunkOffset;
    97     97     FileChunk *pChunk;
    98     98   
    99         -#ifdef SQLITE_ENABLE_ATOMIC_WRITE
           99  +#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
          100  + || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
   100    101     if( (iAmt+iOfst)>p->endpoint.iOffset ){
   101    102       return SQLITE_IOERR_SHORT_READ;
   102    103     }
   103    104   #endif
   104    105   
   105    106     assert( (iAmt+iOfst)<=p->endpoint.iOffset );
   106    107     assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 );
................................................................................
   211    212     else{
   212    213       /* An in-memory journal file should only ever be appended to. Random
   213    214       ** access writes are not required. The only exception to this is when
   214    215       ** the in-memory journal is being used by a connection using the
   215    216       ** atomic-write optimization. In this case the first 28 bytes of the
   216    217       ** journal file may be written as part of committing the transaction. */ 
   217    218       assert( iOfst==p->endpoint.iOffset || iOfst==0 );
   218         -#ifdef SQLITE_ENABLE_ATOMIC_WRITE
          219  +#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
          220  + || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
   219    221       if( iOfst==0 && p->pFirst ){
   220    222         assert( p->nChunkSize>iAmt );
   221    223         memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
   222    224       }else
   223    225   #else
   224    226       assert( iOfst>0 || p->pFirst==0 );
   225    227   #endif
................................................................................
   380    382   /*
   381    383   ** Open an in-memory journal file.
   382    384   */
   383    385   void sqlite3MemJournalOpen(sqlite3_file *pJfd){
   384    386     sqlite3JournalOpen(0, 0, pJfd, 0, -1);
   385    387   }
   386    388   
   387         -#ifdef SQLITE_ENABLE_ATOMIC_WRITE
          389  +#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
          390  + || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
   388    391   /*
   389    392   ** If the argument p points to a MemJournal structure that is not an 
   390    393   ** in-memory-only journal file (i.e. is one that was opened with a +ve
   391         -** nSpill parameter), and the underlying file has not yet been created, 
   392         -** create it now.
          394  +** nSpill parameter or as SQLITE_OPEN_MAIN_JOURNAL), and the underlying 
          395  +** file has not yet been created, create it now.
   393    396   */
   394         -int sqlite3JournalCreate(sqlite3_file *p){
          397  +int sqlite3JournalCreate(sqlite3_file *pJfd){
   395    398     int rc = SQLITE_OK;
   396         -  if( p->pMethods==&MemJournalMethods && ((MemJournal*)p)->nSpill>0 ){
   397         -    rc = memjrnlCreateFile((MemJournal*)p);
          399  +  MemJournal *p = (MemJournal*)pJfd;
          400  +  if( p->pMethod==&MemJournalMethods && (p->nSpill>0 
          401  +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
          402  +     || (p->flags & SQLITE_OPEN_MAIN_JOURNAL)
          403  +#endif
          404  +  )){
          405  +    rc = memjrnlCreateFile(p);
   398    406     }
   399    407     return rc;
   400    408   }
   401    409   #endif
   402    410   
   403    411   /*
   404    412   ** The file-handle passed as the only argument is open on a journal file.

Changes to src/os_unix.c.

    86     86   
    87     87   /*
    88     88   ** standard include files.
    89     89   */
    90     90   #include <sys/types.h>
    91     91   #include <sys/stat.h>
    92     92   #include <fcntl.h>
           93  +#include <sys/ioctl.h>
    93     94   #include <unistd.h>
    94     95   #include <time.h>
    95     96   #include <sys/time.h>
    96     97   #include <errno.h>
    97     98   #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
    98     99   # include <sys/mman.h>
    99    100   #endif
................................................................................
   216    217   #if SQLITE_MAX_MMAP_SIZE>0
   217    218     int nFetchOut;                      /* Number of outstanding xFetch refs */
   218    219     sqlite3_int64 mmapSize;             /* Usable size of mapping at pMapRegion */
   219    220     sqlite3_int64 mmapSizeActual;       /* Actual size of mapping at pMapRegion */
   220    221     sqlite3_int64 mmapSizeMax;          /* Configured FCNTL_MMAP_SIZE value */
   221    222     void *pMapRegion;                   /* Memory mapped region */
   222    223   #endif
   223         -#ifdef __QNXNTO__
   224    224     int sectorSize;                     /* Device sector size */
   225    225     int deviceCharacteristics;          /* Precomputed device characteristics */
   226         -#endif
   227    226   #if SQLITE_ENABLE_LOCKING_STYLE
   228    227     int openFlags;                      /* The flags specified at open() */
   229    228   #endif
   230    229   #if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
   231    230     unsigned fsFlags;                   /* cached details from statfs() */
   232    231   #endif
   233    232   #if OS_VXWORKS
................................................................................
   323    322   /*
   324    323   ** Explicitly call the 64-bit version of lseek() on Android. Otherwise, lseek()
   325    324   ** is the 32-bit version, even if _FILE_OFFSET_BITS=64 is defined.
   326    325   */
   327    326   #ifdef __ANDROID__
   328    327   # define lseek lseek64
   329    328   #endif
          329  +
          330  +#ifdef __linux__
          331  +/*
          332  +** Linux-specific IOCTL magic numbers used for controlling F2FS
          333  +*/
          334  +#define F2FS_IOCTL_MAGIC        0xf5
          335  +#define F2FS_IOC_START_ATOMIC_WRITE     _IO(F2FS_IOCTL_MAGIC, 1)
          336  +#define F2FS_IOC_COMMIT_ATOMIC_WRITE    _IO(F2FS_IOCTL_MAGIC, 2)
          337  +#define F2FS_IOC_START_VOLATILE_WRITE   _IO(F2FS_IOCTL_MAGIC, 3)
          338  +#define F2FS_IOC_ABORT_VOLATILE_WRITE   _IO(F2FS_IOCTL_MAGIC, 5)
          339  +#define F2FS_IOC_GET_FEATURES           _IOR(F2FS_IOCTL_MAGIC, 12, u32)
          340  +#define F2FS_FEATURE_ATOMIC_WRITE 0x0004
          341  +#endif /* __linux__ */
          342  +
   330    343   
   331    344   /*
   332    345   ** Different Unix systems declare open() in different ways.  Same use
   333    346   ** open(const char*,int,mode_t).  Others use open(const char*,int,...).
   334    347   ** The difference is important when using a pointer to the function.
   335    348   **
   336    349   ** The safest way to deal with the problem is to always use this wrapper
................................................................................
   495    508   
   496    509   #if defined(HAVE_LSTAT)
   497    510     { "lstat",         (sqlite3_syscall_ptr)lstat,          0 },
   498    511   #else
   499    512     { "lstat",         (sqlite3_syscall_ptr)0,              0 },
   500    513   #endif
   501    514   #define osLstat      ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent)
          515  +
          516  +  { "ioctl",         (sqlite3_syscall_ptr)ioctl,          0 },
          517  +#define osIoctl ((int(*)(int,int,...))aSyscall[28].pCurrent)
   502    518   
   503    519   }; /* End of the overrideable system calls */
   504    520   
   505    521   
   506    522   /*
   507    523   ** On some systems, calls to fchown() will trigger a message in a security
   508    524   ** log if they come from non-root processes.  So avoid calling fchown() if
................................................................................
  3773   3789   
  3774   3790   /*
  3775   3791   ** Information and control of an open file handle.
  3776   3792   */
  3777   3793   static int unixFileControl(sqlite3_file *id, int op, void *pArg){
  3778   3794     unixFile *pFile = (unixFile*)id;
  3779   3795     switch( op ){
         3796  +#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
         3797  +    case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: {
         3798  +      int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE);
         3799  +      return rc ? SQLITE_ERROR : SQLITE_OK;
         3800  +    }
         3801  +    case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: {
         3802  +      int rc = osIoctl(pFile->h, F2FS_IOC_COMMIT_ATOMIC_WRITE);
         3803  +      return rc ? SQLITE_ERROR : SQLITE_OK;
         3804  +    }
         3805  +    case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: {
         3806  +      int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE);
         3807  +      return rc ? SQLITE_ERROR : SQLITE_OK;
         3808  +    }
         3809  +#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
         3810  +
  3780   3811       case SQLITE_FCNTL_LOCKSTATE: {
  3781   3812         *(int*)pArg = pFile->eFileLock;
  3782   3813         return SQLITE_OK;
  3783   3814       }
  3784   3815       case SQLITE_FCNTL_LAST_ERRNO: {
  3785   3816         *(int*)pArg = pFile->lastErrno;
  3786   3817         return SQLITE_OK;
................................................................................
  3856   3887       }
  3857   3888   #endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
  3858   3889     }
  3859   3890     return SQLITE_NOTFOUND;
  3860   3891   }
  3861   3892   
  3862   3893   /*
  3863         -** Return the sector size in bytes of the underlying block device for
  3864         -** the specified file. This is almost always 512 bytes, but may be
  3865         -** larger for some devices.
  3866         -**
  3867         -** SQLite code assumes this function cannot fail. It also assumes that
  3868         -** if two files are created in the same file-system directory (i.e.
  3869         -** a database and its journal file) that the sector size will be the
  3870         -** same for both.
  3871         -*/
  3872         -#ifndef __QNXNTO__ 
  3873         -static int unixSectorSize(sqlite3_file *NotUsed){
  3874         -  UNUSED_PARAMETER(NotUsed);
  3875         -  return SQLITE_DEFAULT_SECTOR_SIZE;
  3876         -}
  3877         -#endif
  3878         -
  3879         -/*
  3880         -** The following version of unixSectorSize() is optimized for QNX.
  3881         -*/
  3882         -#ifdef __QNXNTO__
         3894  +** If pFd->sectorSize is non-zero when this function is called, it is a
         3895  +** no-op. Otherwise, the values of pFd->sectorSize and 
         3896  +** pFd->deviceCharacteristics are set according to the file-system 
         3897  +** characteristics. 
         3898  +**
         3899  +** There are two versions of this function. One for QNX and one for all
         3900  +** other systems.
         3901  +*/
         3902  +#ifndef __QNXNTO__
         3903  +static void setDeviceCharacteristics(unixFile *pFd){
         3904  +  assert( pFd->deviceCharacteristics==0 || pFd->sectorSize!=0 );
         3905  +  if( pFd->sectorSize==0 ){
         3906  +#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
         3907  +    int res;
         3908  +    u32 f = 0;
         3909  +
         3910  +    /* Check for support for F2FS atomic batch writes. */
         3911  +    res = osIoctl(pFd->h, F2FS_IOC_GET_FEATURES, &f);
         3912  +    if( res==0 && (f & F2FS_FEATURE_ATOMIC_WRITE) ){
         3913  +      pFd->deviceCharacteristics = SQLITE_IOCAP_BATCH_ATOMIC;
         3914  +    }
         3915  +#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
         3916  +
         3917  +    /* Set the POWERSAFE_OVERWRITE flag if requested. */
         3918  +    if( pFd->ctrlFlags & UNIXFILE_PSOW ){
         3919  +      pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
         3920  +    }
         3921  +
         3922  +    pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
         3923  +  }
         3924  +}
         3925  +#else
  3883   3926   #include <sys/dcmd_blk.h>
  3884   3927   #include <sys/statvfs.h>
  3885         -static int unixSectorSize(sqlite3_file *id){
  3886         -  unixFile *pFile = (unixFile*)id;
         3928  +static void setDeviceCharacteristics(unixFile *pFile){
  3887   3929     if( pFile->sectorSize == 0 ){
  3888   3930       struct statvfs fsInfo;
  3889   3931          
  3890   3932       /* Set defaults for non-supported filesystems */
  3891   3933       pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
  3892   3934       pFile->deviceCharacteristics = 0;
  3893   3935       if( fstatvfs(pFile->h, &fsInfo) == -1 ) {
................................................................................
  3948   3990     }
  3949   3991     /* Last chance verification.  If the sector size isn't a multiple of 512
  3950   3992     ** then it isn't valid.*/
  3951   3993     if( pFile->sectorSize % 512 != 0 ){
  3952   3994       pFile->deviceCharacteristics = 0;
  3953   3995       pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
  3954   3996     }
  3955         -  return pFile->sectorSize;
  3956   3997   }
  3957         -#endif /* __QNXNTO__ */
         3998  +#endif
         3999  +
         4000  +/*
         4001  +** Return the sector size in bytes of the underlying block device for
         4002  +** the specified file. This is almost always 512 bytes, but may be
         4003  +** larger for some devices.
         4004  +**
         4005  +** SQLite code assumes this function cannot fail. It also assumes that
         4006  +** if two files are created in the same file-system directory (i.e.
         4007  +** a database and its journal file) that the sector size will be the
         4008  +** same for both.
         4009  +*/
         4010  +static int unixSectorSize(sqlite3_file *id){
         4011  +  unixFile *pFd = (unixFile*)id;
         4012  +  setDeviceCharacteristics(pFd);
         4013  +  return pFd->sectorSize;
         4014  +}
  3958   4015   
  3959   4016   /*
  3960   4017   ** Return the device characteristics for the file.
  3961   4018   **
  3962   4019   ** This VFS is set up to return SQLITE_IOCAP_POWERSAFE_OVERWRITE by default.
  3963   4020   ** However, that choice is controversial since technically the underlying
  3964   4021   ** file system does not always provide powersafe overwrites.  (In other
................................................................................
  3966   4023   ** written might end up being altered.)  However, non-PSOW behavior is very,
  3967   4024   ** very rare.  And asserting PSOW makes a large reduction in the amount
  3968   4025   ** of required I/O for journaling, since a lot of padding is eliminated.
  3969   4026   **  Hence, while POWERSAFE_OVERWRITE is on by default, there is a file-control
  3970   4027   ** available to turn it off and URI query parameter available to turn it off.
  3971   4028   */
  3972   4029   static int unixDeviceCharacteristics(sqlite3_file *id){
  3973         -  unixFile *p = (unixFile*)id;
  3974         -  int rc = 0;
  3975         -#ifdef __QNXNTO__
  3976         -  if( p->sectorSize==0 ) unixSectorSize(id);
  3977         -  rc = p->deviceCharacteristics;
  3978         -#endif
  3979         -  if( p->ctrlFlags & UNIXFILE_PSOW ){
  3980         -    rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
  3981         -  }
  3982         -  return rc;
         4030  +  unixFile *pFd = (unixFile*)id;
         4031  +  setDeviceCharacteristics(pFd);
         4032  +  return pFd->deviceCharacteristics;
  3983   4033   }
  3984   4034   
  3985   4035   #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
  3986   4036   
  3987   4037   /*
  3988   4038   ** Return the system page size.
  3989   4039   **
................................................................................
  7594   7644       UNIXVFS("unix-proxy",    proxyIoFinder ),
  7595   7645   #endif
  7596   7646     };
  7597   7647     unsigned int i;          /* Loop counter */
  7598   7648   
  7599   7649     /* Double-check that the aSyscall[] array has been constructed
  7600   7650     ** correctly.  See ticket [bb3a86e890c8e96ab] */
  7601         -  assert( ArraySize(aSyscall)==28 );
         7651  +  assert( ArraySize(aSyscall)==29 );
  7602   7652   
  7603   7653     /* Register all VFSes defined in the aVfs[] array */
  7604   7654     for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
  7605   7655       sqlite3_vfs_register(&aVfs[i], i==0);
  7606   7656     }
  7607   7657     return SQLITE_OK; 
  7608   7658   }

Changes to src/pager.c.

   943    943         assert( p->eLock==EXCLUSIVE_LOCK );
   944    944         assert( pPager->errCode==SQLITE_OK );
   945    945         assert( !pagerUseWal(pPager) );
   946    946         assert( p->eLock>=EXCLUSIVE_LOCK );
   947    947         assert( isOpen(p->jfd) 
   948    948              || p->journalMode==PAGER_JOURNALMODE_OFF 
   949    949              || p->journalMode==PAGER_JOURNALMODE_WAL 
          950  +           || (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
   950    951         );
   951    952         assert( pPager->dbOrigSize<=pPager->dbHintSize );
   952    953         break;
   953    954   
   954    955       case PAGER_WRITER_FINISHED:
   955    956         assert( p->eLock==EXCLUSIVE_LOCK );
   956    957         assert( pPager->errCode==SQLITE_OK );
   957    958         assert( !pagerUseWal(pPager) );
   958    959         assert( isOpen(p->jfd) 
   959    960              || p->journalMode==PAGER_JOURNALMODE_OFF 
   960    961              || p->journalMode==PAGER_JOURNALMODE_WAL 
          962  +           || (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
   961    963         );
   962    964         break;
   963    965   
   964    966       case PAGER_ERROR:
   965    967         /* There must be at least one outstanding reference to the pager if
   966    968         ** in ERROR state. Otherwise the pager should have already dropped
   967    969         ** back to OPEN state.
................................................................................
  1164   1166         IOTRACE(("LOCK %p %d\n", pPager, eLock))
  1165   1167       }
  1166   1168     }
  1167   1169     return rc;
  1168   1170   }
  1169   1171   
  1170   1172   /*
  1171         -** This function determines whether or not the atomic-write optimization
  1172         -** can be used with this pager. The optimization can be used if:
         1173  +** This function determines whether or not the atomic-write or
         1174  +** atomic-batch-write optimizations can be used with this pager. The
         1175  +** atomic-write optimization can be used if:
  1173   1176   **
  1174   1177   **  (a) the value returned by OsDeviceCharacteristics() indicates that
  1175   1178   **      a database page may be written atomically, and
  1176   1179   **  (b) the value returned by OsSectorSize() is less than or equal
  1177   1180   **      to the page size.
  1178   1181   **
  1179         -** The optimization is also always enabled for temporary files. It is
  1180         -** an error to call this function if pPager is opened on an in-memory
  1181         -** database.
         1182  +** If it can be used, then the value returned is the size of the journal 
         1183  +** file when it contains rollback data for exactly one page.
  1182   1184   **
  1183         -** If the optimization cannot be used, 0 is returned. If it can be used,
  1184         -** then the value returned is the size of the journal file when it
  1185         -** contains rollback data for exactly one page.
         1185  +** The atomic-batch-write optimization can be used if OsDeviceCharacteristics()
         1186  +** returns a value with the SQLITE_IOCAP_BATCH_ATOMIC bit set. -1 is
         1187  +** returned in this case.
         1188  +**
         1189  +** If neither optimization can be used, 0 is returned.
  1186   1190   */
  1187         -#ifdef SQLITE_ENABLE_ATOMIC_WRITE
  1188   1191   static int jrnlBufferSize(Pager *pPager){
  1189   1192     assert( !MEMDB );
  1190         -  if( !pPager->tempFile ){
  1191         -    int dc;                           /* Device characteristics */
  1192         -    int nSector;                      /* Sector size */
  1193         -    int szPage;                       /* Page size */
  1194   1193   
  1195         -    assert( isOpen(pPager->fd) );
  1196         -    dc = sqlite3OsDeviceCharacteristics(pPager->fd);
  1197         -    nSector = pPager->sectorSize;
  1198         -    szPage = pPager->pageSize;
         1194  +#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
         1195  + || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
         1196  +  int dc;                           /* Device characteristics */
         1197  +
         1198  +  assert( isOpen(pPager->fd) );
         1199  +  dc = sqlite3OsDeviceCharacteristics(pPager->fd);
         1200  +#endif
         1201  +
         1202  +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
         1203  +  if( dc&SQLITE_IOCAP_BATCH_ATOMIC ){
         1204  +    return -1;
         1205  +  }
         1206  +#endif
         1207  +
         1208  +#ifdef SQLITE_ENABLE_ATOMIC_WRITE
         1209  +  {
         1210  +    int nSector = pPager->sectorSize;
         1211  +    int szPage = pPager->pageSize;
  1199   1212   
  1200   1213       assert(SQLITE_IOCAP_ATOMIC512==(512>>8));
  1201   1214       assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8));
  1202   1215       if( 0==(dc&(SQLITE_IOCAP_ATOMIC|(szPage>>8)) || nSector>szPage) ){
  1203   1216         return 0;
  1204   1217       }
  1205   1218     }
  1206   1219   
  1207   1220     return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager);
         1221  +#endif
         1222  +
         1223  +  return 0;
  1208   1224   }
  1209         -#else
  1210         -# define jrnlBufferSize(x) 0
  1211         -#endif
  1212   1225   
  1213   1226   /*
  1214   1227   ** If SQLITE_CHECK_PAGES is defined then we do some sanity checking
  1215   1228   ** on the cache using a hash function.  This is used for testing
  1216   1229   ** and debugging only.
  1217   1230   */
  1218   1231   #ifdef SQLITE_CHECK_PAGES
................................................................................
  2008   2021     assert( assert_pager_state(pPager) );
  2009   2022     assert( pPager->eState!=PAGER_ERROR );
  2010   2023     if( pPager->eState<PAGER_WRITER_LOCKED && pPager->eLock<RESERVED_LOCK ){
  2011   2024       return SQLITE_OK;
  2012   2025     }
  2013   2026   
  2014   2027     releaseAllSavepoints(pPager);
  2015         -  assert( isOpen(pPager->jfd) || pPager->pInJournal==0 );
         2028  +  assert( isOpen(pPager->jfd) || pPager->pInJournal==0 
         2029  +      || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
         2030  +  );
  2016   2031     if( isOpen(pPager->jfd) ){
  2017   2032       assert( !pagerUseWal(pPager) );
  2018   2033   
  2019   2034       /* Finalize the journal file. */
  2020   2035       if( sqlite3JournalIsInMemory(pPager->jfd) ){
  2021   2036         /* assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ); */
  2022   2037         sqlite3OsClose(pPager->jfd);
................................................................................
  4565   4580     if( pagerUseWal(pPager) ){
  4566   4581       /* Write a single frame for this page to the log. */
  4567   4582       rc = subjournalPageIfRequired(pPg); 
  4568   4583       if( rc==SQLITE_OK ){
  4569   4584         rc = pagerWalFrames(pPager, pPg, 0, 0);
  4570   4585       }
  4571   4586     }else{
         4587  +    
         4588  +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
         4589  +    if( pPager->tempFile==0 ){
         4590  +      rc = sqlite3JournalCreate(pPager->jfd);
         4591  +      if( rc!=SQLITE_OK ) return pager_error(pPager, rc);
         4592  +    }
         4593  +#endif
  4572   4594     
  4573   4595       /* Sync the journal file if required. */
  4574   4596       if( pPg->flags&PGHDR_NEED_SYNC 
  4575   4597        || pPager->eState==PAGER_WRITER_CACHEMOD
  4576   4598       ){
  4577   4599         rc = syncJournal(pPager, 1);
  4578   4600       }
................................................................................
  6350   6372           rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1);
  6351   6373         }
  6352   6374         sqlite3PagerUnref(pPageOne);
  6353   6375         if( rc==SQLITE_OK ){
  6354   6376           sqlite3PcacheCleanAll(pPager->pPCache);
  6355   6377         }
  6356   6378       }else{
         6379  +      /* The bBatch boolean is true if the batch-atomic-write commit method
         6380  +      ** should be used.  No rollback journal is created if batch-atomic-write
         6381  +      ** is enabled.
         6382  +      */
         6383  +      sqlite3_file *fd = pPager->fd;
         6384  +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
         6385  +      const int bBatch = zMaster==0    /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
         6386  +        && (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC)
         6387  +        && !pPager->noSync
         6388  +        && sqlite3JournalIsInMemory(pPager->jfd);
         6389  +#else
         6390  +# define bBatch 0
         6391  +#endif
         6392  +
         6393  +#ifdef SQLITE_ENABLE_ATOMIC_WRITE
  6357   6394         /* The following block updates the change-counter. Exactly how it
  6358   6395         ** does this depends on whether or not the atomic-update optimization
  6359   6396         ** was enabled at compile time, and if this transaction meets the 
  6360   6397         ** runtime criteria to use the operation: 
  6361   6398         **
  6362   6399         **    * The file-system supports the atomic-write property for
  6363   6400         **      blocks of size page-size, and 
................................................................................
  6373   6410         ** mode. 
  6374   6411         **
  6375   6412         ** Otherwise, if the optimization is both enabled and applicable,
  6376   6413         ** then call pager_incr_changecounter() to update the change-counter
  6377   6414         ** in 'direct' mode. In this case the journal file will never be
  6378   6415         ** created for this transaction.
  6379   6416         */
  6380         -  #ifdef SQLITE_ENABLE_ATOMIC_WRITE
  6381         -      PgHdr *pPg;
  6382         -      assert( isOpen(pPager->jfd) 
  6383         -           || pPager->journalMode==PAGER_JOURNALMODE_OFF 
  6384         -           || pPager->journalMode==PAGER_JOURNALMODE_WAL 
  6385         -      );
  6386         -      if( !zMaster && isOpen(pPager->jfd) 
  6387         -       && pPager->journalOff==jrnlBufferSize(pPager) 
  6388         -       && pPager->dbSize>=pPager->dbOrigSize
  6389         -       && (0==(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
  6390         -      ){
  6391         -        /* Update the db file change counter via the direct-write method. The 
  6392         -        ** following call will modify the in-memory representation of page 1 
  6393         -        ** to include the updated change counter and then write page 1 
  6394         -        ** directly to the database file. Because of the atomic-write 
  6395         -        ** property of the host file-system, this is safe.
  6396         -        */
  6397         -        rc = pager_incr_changecounter(pPager, 1);
  6398         -      }else{
  6399         -        rc = sqlite3JournalCreate(pPager->jfd);
  6400         -        if( rc==SQLITE_OK ){
  6401         -          rc = pager_incr_changecounter(pPager, 0);
         6417  +      if( bBatch==0 ){
         6418  +        PgHdr *pPg;
         6419  +        assert( isOpen(pPager->jfd) 
         6420  +            || pPager->journalMode==PAGER_JOURNALMODE_OFF 
         6421  +            || pPager->journalMode==PAGER_JOURNALMODE_WAL 
         6422  +            );
         6423  +        if( !zMaster && isOpen(pPager->jfd) 
         6424  +         && pPager->journalOff==jrnlBufferSize(pPager) 
         6425  +         && pPager->dbSize>=pPager->dbOrigSize
         6426  +         && (!(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
         6427  +        ){
         6428  +          /* Update the db file change counter via the direct-write method. The 
         6429  +          ** following call will modify the in-memory representation of page 1 
         6430  +          ** to include the updated change counter and then write page 1 
         6431  +          ** directly to the database file. Because of the atomic-write 
         6432  +          ** property of the host file-system, this is safe.
         6433  +          */
         6434  +          rc = pager_incr_changecounter(pPager, 1);
         6435  +        }else{
         6436  +          rc = sqlite3JournalCreate(pPager->jfd);
         6437  +          if( rc==SQLITE_OK ){
         6438  +            rc = pager_incr_changecounter(pPager, 0);
         6439  +          }
  6402   6440           }
  6403   6441         }
  6404         -  #else
         6442  +#else 
         6443  +#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
         6444  +      if( zMaster ){
         6445  +        rc = sqlite3JournalCreate(pPager->jfd);
         6446  +        if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
         6447  +      }
         6448  +#endif
  6405   6449         rc = pager_incr_changecounter(pPager, 0);
  6406         -  #endif
         6450  +#endif
  6407   6451         if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
  6408   6452     
  6409   6453         /* Write the master journal name into the journal file. If a master 
  6410   6454         ** journal file name has already been written to the journal file, 
  6411   6455         ** or if zMaster is NULL (no master journal), then this call is a no-op.
  6412   6456         */
  6413   6457         rc = writeMasterJournal(pPager, zMaster);
................................................................................
  6422   6466         ** journal requires a sync here. However, in locking_mode=exclusive
  6423   6467         ** on a system under memory pressure it is just possible that this is 
  6424   6468         ** not the case. In this case it is likely enough that the redundant
  6425   6469         ** xSync() call will be changed to a no-op by the OS anyhow. 
  6426   6470         */
  6427   6471         rc = syncJournal(pPager, 0);
  6428   6472         if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
  6429         -  
         6473  +
         6474  +      if( bBatch ){
         6475  +        /* The pager is now in DBMOD state. But regardless of what happens
         6476  +        ** next, attempting to play the journal back into the database would
         6477  +        ** be unsafe. Close it now to make sure that does not happen.  */
         6478  +        sqlite3OsClose(pPager->jfd);
         6479  +        rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
         6480  +        if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
         6481  +      }
  6430   6482         rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
         6483  +      if( bBatch ){
         6484  +        if( rc==SQLITE_OK ){
         6485  +          rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
         6486  +        }else{
         6487  +          sqlite3OsFileControl(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
         6488  +        }
         6489  +      }
         6490  +
  6431   6491         if( rc!=SQLITE_OK ){
  6432   6492           assert( rc!=SQLITE_IOERR_BLOCKED );
  6433   6493           goto commit_phase_one_exit;
  6434   6494         }
  6435   6495         sqlite3PcacheCleanAll(pPager->pPCache);
  6436   6496   
  6437   6497         /* If the file on disk is smaller than the database image, use 

Changes to src/sqlite.h.in.

   576    576   ** file that were written at the application level might have changed
   577    577   ** and that adjacent bytes, even bytes within the same sector are
   578    578   ** guaranteed to be unchanged.  The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
   579    579   ** flag indicates that a file cannot be deleted when open.  The
   580    580   ** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on
   581    581   ** read-only media and cannot be changed even by processes with
   582    582   ** elevated privileges.
          583  +**
          584  +** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying
          585  +** filesystem supports doing multiple write operations atomically when those
          586  +** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
          587  +** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
   583    588   */
   584    589   #define SQLITE_IOCAP_ATOMIC                 0x00000001
   585    590   #define SQLITE_IOCAP_ATOMIC512              0x00000002
   586    591   #define SQLITE_IOCAP_ATOMIC1K               0x00000004
   587    592   #define SQLITE_IOCAP_ATOMIC2K               0x00000008
   588    593   #define SQLITE_IOCAP_ATOMIC4K               0x00000010
   589    594   #define SQLITE_IOCAP_ATOMIC8K               0x00000020
................................................................................
   591    596   #define SQLITE_IOCAP_ATOMIC32K              0x00000080
   592    597   #define SQLITE_IOCAP_ATOMIC64K              0x00000100
   593    598   #define SQLITE_IOCAP_SAFE_APPEND            0x00000200
   594    599   #define SQLITE_IOCAP_SEQUENTIAL             0x00000400
   595    600   #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN  0x00000800
   596    601   #define SQLITE_IOCAP_POWERSAFE_OVERWRITE    0x00001000
   597    602   #define SQLITE_IOCAP_IMMUTABLE              0x00002000
          603  +#define SQLITE_IOCAP_BATCH_ATOMIC           0x00004000
   598    604   
   599    605   /*
   600    606   ** CAPI3REF: File Locking Levels
   601    607   **
   602    608   ** SQLite uses one of these integer values as the second
   603    609   ** argument to calls it makes to the xLock() and xUnlock() methods
   604    610   ** of an [sqlite3_io_methods] object.
................................................................................
   725    731   ** <li> [SQLITE_IOCAP_ATOMIC32K]
   726    732   ** <li> [SQLITE_IOCAP_ATOMIC64K]
   727    733   ** <li> [SQLITE_IOCAP_SAFE_APPEND]
   728    734   ** <li> [SQLITE_IOCAP_SEQUENTIAL]
   729    735   ** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
   730    736   ** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
   731    737   ** <li> [SQLITE_IOCAP_IMMUTABLE]
          738  +** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
   732    739   ** </ul>
   733    740   **
   734    741   ** The SQLITE_IOCAP_ATOMIC property means that all writes of
   735    742   ** any size are atomic.  The SQLITE_IOCAP_ATOMICnnn values
   736    743   ** mean that writes of blocks that are nnn bytes in size and
   737    744   ** are aligned to an address which is an integer multiple of
   738    745   ** nnn are atomic.  The SQLITE_IOCAP_SAFE_APPEND value means
................................................................................
  1008   1015   ** The [SQLITE_FCNTL_ZIPVFS] opcode is implemented by zipvfs only. All other
  1009   1016   ** VFS should return SQLITE_NOTFOUND for this opcode.
  1010   1017   **
  1011   1018   ** <li>[[SQLITE_FCNTL_RBU]]
  1012   1019   ** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by
  1013   1020   ** the RBU extension only.  All other VFS should return SQLITE_NOTFOUND for
  1014   1021   ** this opcode.  
         1022  +**
         1023  +** <li>[[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]]
         1024  +** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then
         1025  +** the file descriptor is placed in "batch write mode", which
         1026  +** means all subsequent write operations will be deferred and done
         1027  +** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].  Systems
         1028  +** that do not support batch atomic writes will return SQLITE_NOTFOUND.
         1029  +** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to
         1030  +** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or
         1031  +** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make
         1032  +** no VFS interface calls on the same [sqlite3_file] file descriptor
         1033  +** except for calls to the xWrite method and the xFileControl method
         1034  +** with [SQLITE_FCNTL_SIZE_HINT].
         1035  +**
         1036  +** <li>[[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]]
         1037  +** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write
         1038  +** operations since the previous successful call to 
         1039  +** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically.
         1040  +** This file control returns [SQLITE_OK] if and only if the writes were
         1041  +** all performed successfully and have been committed to persistent storage.
         1042  +** ^Regardless of whether or not it is successful, this file control takes
         1043  +** the file descriptor out of batch write mode so that all subsequent
         1044  +** write operations are independent.
         1045  +** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without
         1046  +** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
         1047  +**
         1048  +** <li>[[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]]
         1049  +** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write
         1050  +** operations since the previous successful call to 
         1051  +** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back.
         1052  +** ^This file control takes the file descriptor out of batch write mode
         1053  +** so that all subsequent write operations are independent.
         1054  +** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without
         1055  +** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
  1015   1056   ** </ul>
  1016   1057   */
  1017   1058   #define SQLITE_FCNTL_LOCKSTATE               1
  1018   1059   #define SQLITE_FCNTL_GET_LOCKPROXYFILE       2
  1019   1060   #define SQLITE_FCNTL_SET_LOCKPROXYFILE       3
  1020   1061   #define SQLITE_FCNTL_LAST_ERRNO              4
  1021   1062   #define SQLITE_FCNTL_SIZE_HINT               5
................................................................................
  1039   1080   #define SQLITE_FCNTL_WAL_BLOCK              24
  1040   1081   #define SQLITE_FCNTL_ZIPVFS                 25
  1041   1082   #define SQLITE_FCNTL_RBU                    26
  1042   1083   #define SQLITE_FCNTL_VFS_POINTER            27
  1043   1084   #define SQLITE_FCNTL_JOURNAL_POINTER        28
  1044   1085   #define SQLITE_FCNTL_WIN32_GET_HANDLE       29
  1045   1086   #define SQLITE_FCNTL_PDB                    30
         1087  +#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE     31
         1088  +#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE    32
         1089  +#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE  33
  1046   1090   
  1047   1091   /* deprecated names */
  1048   1092   #define SQLITE_GET_LOCKPROXYFILE      SQLITE_FCNTL_GET_LOCKPROXYFILE
  1049   1093   #define SQLITE_SET_LOCKPROXYFILE      SQLITE_FCNTL_SET_LOCKPROXYFILE
  1050   1094   #define SQLITE_LAST_ERRNO             SQLITE_FCNTL_LAST_ERRNO
  1051   1095   
  1052   1096   

Changes to src/sqliteInt.h.

   621    621   ** The default value of "20" was choosen to minimize the run-time of the
   622    622   ** speedtest1 test program with options: --shrink-memory --reprepare
   623    623   */
   624    624   #ifndef SQLITE_DEFAULT_PCACHE_INITSZ
   625    625   # define SQLITE_DEFAULT_PCACHE_INITSZ 20
   626    626   #endif
   627    627   
          628  +/*
          629  +** The compile-time options SQLITE_MMAP_READWRITE and 
          630  +** SQLITE_ENABLE_BATCH_ATOMIC_WRITE are not compatible with one another.
          631  +** You must choose one or the other (or neither) but not both.
          632  +*/
          633  +#if defined(SQLITE_MMAP_READWRITE) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
          634  +#error Cannot use both SQLITE_MMAP_READWRITE and SQLITE_ENABLE_BATCH_ATOMIC_WRITE
          635  +#endif
          636  +
   628    637   /*
   629    638   ** GCC does not define the offsetof() macro so we'll have to do it
   630    639   ** ourselves.
   631    640   */
   632    641   #ifndef offsetof
   633    642   #define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD))
   634    643   #endif
................................................................................
  4252   4261   #define IN_INDEX_NOOP_OK     0x0001  /* OK to return IN_INDEX_NOOP */
  4253   4262   #define IN_INDEX_MEMBERSHIP  0x0002  /* IN operator used for membership test */
  4254   4263   #define IN_INDEX_LOOP        0x0004  /* IN operator used as a loop */
  4255   4264   int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*);
  4256   4265   
  4257   4266   int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
  4258   4267   int sqlite3JournalSize(sqlite3_vfs *);
  4259         -#ifdef SQLITE_ENABLE_ATOMIC_WRITE
         4268  +#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
         4269  + || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
  4260   4270     int sqlite3JournalCreate(sqlite3_file *);
  4261   4271   #endif
  4262   4272   
  4263   4273   int sqlite3JournalIsInMemory(sqlite3_file *p);
  4264   4274   void sqlite3MemJournalOpen(sqlite3_file *);
  4265   4275   
  4266   4276   void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p);

Changes to src/test1.c.

  2545   2545     }
  2546   2546     zFile = (const char*)Tcl_GetString(objv[1]);
  2547   2547     rc = sqlite3_delete_database(zFile);
  2548   2548   
  2549   2549     Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
  2550   2550     return TCL_OK;
  2551   2551   }
         2552  +
         2553  +/*
         2554  +** Usage: atomic_batch_write PATH
         2555  +*/
         2556  +static int SQLITE_TCLAPI test_atomic_batch_write(
         2557  +  void * clientData,
         2558  +  Tcl_Interp *interp,
         2559  +  int objc,
         2560  +  Tcl_Obj *CONST objv[]
         2561  +){
         2562  +  char *zFile = 0;                /* Path to file to test */
         2563  +  sqlite3 *db = 0;                /* Database handle */
         2564  +  sqlite3_file *pFd = 0;          /* SQLite fd open on zFile */
         2565  +  int bRes = 0;                   /* Integer result of this command */
         2566  +  int dc = 0;                     /* Device-characteristics mask */
         2567  +  int rc;                         /* sqlite3_open() return code */
         2568  +
         2569  +  if( objc!=2 ){
         2570  +    Tcl_WrongNumArgs(interp, 1, objv, "PATH");
         2571  +    return TCL_ERROR;
         2572  +  }
         2573  +  zFile = Tcl_GetString(objv[1]);
         2574  +
         2575  +  rc = sqlite3_open(zFile, &db);
         2576  +  if( rc!=SQLITE_OK ){
         2577  +    Tcl_AppendResult(interp, sqlite3_errmsg(db), 0);
         2578  +    sqlite3_close(db);
         2579  +    return TCL_ERROR;
         2580  +  }
         2581  +
         2582  +  rc = sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void*)&pFd);
         2583  +  dc = pFd->pMethods->xDeviceCharacteristics(pFd);
         2584  +  if( dc & SQLITE_IOCAP_BATCH_ATOMIC ){
         2585  +    bRes = 1;
         2586  +  }
         2587  +
         2588  +  Tcl_SetObjResult(interp, Tcl_NewIntObj(bRes));
         2589  +  sqlite3_close(db);
         2590  +  return TCL_OK;
         2591  +}
  2552   2592   
  2553   2593   /*
  2554   2594   ** Usage:  sqlite3_next_stmt  DB  STMT
  2555   2595   **
  2556   2596   ** Return the next statment in sequence after STMT.
  2557   2597   */
  2558   2598   static int SQLITE_TCLAPI test_next_stmt(
................................................................................
  7635   7675        { "sqlite3_snapshot_cmp", test_snapshot_cmp, 0 },
  7636   7676        { "sqlite3_snapshot_recover", test_snapshot_recover, 0 },
  7637   7677        { "sqlite3_snapshot_get_blob", test_snapshot_get_blob, 0 },
  7638   7678        { "sqlite3_snapshot_open_blob", test_snapshot_open_blob, 0 },
  7639   7679        { "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 },
  7640   7680   #endif
  7641   7681        { "sqlite3_delete_database", test_delete_database, 0 },
         7682  +     { "atomic_batch_write",      test_atomic_batch_write,     0   },
  7642   7683     };
  7643   7684     static int bitmask_size = sizeof(Bitmask)*8;
  7644   7685     static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
  7645   7686     int i;
  7646   7687     extern int sqlite3_sync_count, sqlite3_fullsync_count;
  7647   7688     extern int sqlite3_opentemp_count;
  7648   7689     extern int sqlite3_like_count;

Changes to src/test6.c.

   732    732       { "atomic8k",            SQLITE_IOCAP_ATOMIC8K              },
   733    733       { "atomic16k",           SQLITE_IOCAP_ATOMIC16K             },
   734    734       { "atomic32k",           SQLITE_IOCAP_ATOMIC32K             },
   735    735       { "atomic64k",           SQLITE_IOCAP_ATOMIC64K             },
   736    736       { "sequential",          SQLITE_IOCAP_SEQUENTIAL            },
   737    737       { "safe_append",         SQLITE_IOCAP_SAFE_APPEND           },
   738    738       { "powersafe_overwrite", SQLITE_IOCAP_POWERSAFE_OVERWRITE   },
          739  +    { "batch-atomic",        SQLITE_IOCAP_BATCH_ATOMIC          },
   739    740       { 0, 0 }
   740    741     };
   741    742   
   742    743     int i;
   743    744     int iDc = 0;
   744    745     int iSectorSize = 0;
   745    746     int setSectorsize = 0;
................................................................................
   972    973   
   973    974     if( processDevSymArgs(interp, objc-1, &objv[1], &iDc, &iSectorSize) ){
   974    975       return TCL_ERROR;
   975    976     }
   976    977     devsym_register(iDc, iSectorSize);
   977    978   
   978    979     return TCL_OK;
          980  +}
   979    981   
          982  +/*
          983  +** tclcmd: sqlite3_crash_on_write N
          984  +*/
          985  +static int SQLITE_TCLAPI writeCrashObjCmd(
          986  +  void * clientData,
          987  +  Tcl_Interp *interp,
          988  +  int objc,
          989  +  Tcl_Obj *CONST objv[]
          990  +){
          991  +  void devsym_crash_on_write(int);
          992  +  int nWrite = 0;
          993  +
          994  +  if( objc!=2 ){
          995  +    Tcl_WrongNumArgs(interp, 1, objv, "NWRITE");
          996  +    return TCL_ERROR;
          997  +  }
          998  +  if( Tcl_GetIntFromObj(interp, objv[1], &nWrite) ){
          999  +    return TCL_ERROR;
         1000  +  }
         1001  +
         1002  +  devsym_crash_on_write(nWrite);
         1003  +  return TCL_OK;
   980   1004   }
   981   1005   
   982   1006   /*
   983   1007   ** tclcmd: unregister_devsim
   984   1008   */
   985   1009   static int SQLITE_TCLAPI dsUnregisterObjCmd(
   986   1010     void * clientData,
................................................................................
  1064   1088   */
  1065   1089   int Sqlitetest6_Init(Tcl_Interp *interp){
  1066   1090   #ifndef SQLITE_OMIT_DISKIO
  1067   1091     Tcl_CreateObjCommand(interp, "sqlite3_crash_enable", crashEnableCmd, 0, 0);
  1068   1092     Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0);
  1069   1093     Tcl_CreateObjCommand(interp, "sqlite3_crash_now", crashNowCmd, 0, 0);
  1070   1094     Tcl_CreateObjCommand(interp, "sqlite3_simulate_device", devSymObjCmd, 0, 0);
         1095  +  Tcl_CreateObjCommand(interp, "sqlite3_crash_on_write", writeCrashObjCmd,0,0);
  1071   1096     Tcl_CreateObjCommand(interp, "unregister_devsim", dsUnregisterObjCmd, 0, 0);
  1072   1097     Tcl_CreateObjCommand(interp, "register_jt_vfs", jtObjCmd, 0, 0);
  1073   1098     Tcl_CreateObjCommand(interp, "unregister_jt_vfs", jtUnregisterObjCmd, 0, 0);
  1074   1099   #endif
  1075   1100     return TCL_OK;
  1076   1101   }
  1077   1102   
  1078   1103   #endif /* SQLITE_TEST */

Changes to src/test_devsym.c.

    24     24   */
    25     25   #define DEVSYM_MAX_PATHNAME 512
    26     26   
    27     27   /*
    28     28   ** Name used to identify this VFS.
    29     29   */
    30     30   #define DEVSYM_VFS_NAME "devsym"
           31  +#define WRITECRASH_NAME "writecrash"
    31     32   
    32     33   typedef struct devsym_file devsym_file;
    33     34   struct devsym_file {
    34     35     sqlite3_file base;
    35     36     sqlite3_file *pReal;
    36     37   };
    37     38   
................................................................................
    68     69   static void (*devsymDlSym(sqlite3_vfs*,void*, const char *zSymbol))(void);
    69     70   static void devsymDlClose(sqlite3_vfs*, void*);
    70     71   #endif /* SQLITE_OMIT_LOAD_EXTENSION */
    71     72   static int devsymRandomness(sqlite3_vfs*, int nByte, char *zOut);
    72     73   static int devsymSleep(sqlite3_vfs*, int microseconds);
    73     74   static int devsymCurrentTime(sqlite3_vfs*, double*);
    74     75   
    75         -static sqlite3_vfs devsym_vfs = {
    76         -  2,                     /* iVersion */
    77         -  sizeof(devsym_file),      /* szOsFile */
    78         -  DEVSYM_MAX_PATHNAME,      /* mxPathname */
    79         -  0,                     /* pNext */
    80         -  DEVSYM_VFS_NAME,          /* zName */
    81         -  0,                     /* pAppData */
    82         -  devsymOpen,               /* xOpen */
    83         -  devsymDelete,             /* xDelete */
    84         -  devsymAccess,             /* xAccess */
    85         -  devsymFullPathname,       /* xFullPathname */
    86         -#ifndef SQLITE_OMIT_LOAD_EXTENSION
    87         -  devsymDlOpen,             /* xDlOpen */
    88         -  devsymDlError,            /* xDlError */
    89         -  devsymDlSym,              /* xDlSym */
    90         -  devsymDlClose,            /* xDlClose */
    91         -#else
    92         -  0,                        /* xDlOpen */
    93         -  0,                        /* xDlError */
    94         -  0,                        /* xDlSym */
    95         -  0,                        /* xDlClose */
    96         -#endif /* SQLITE_OMIT_LOAD_EXTENSION */
    97         -  devsymRandomness,         /* xRandomness */
    98         -  devsymSleep,              /* xSleep */
    99         -  devsymCurrentTime,        /* xCurrentTime */
   100         -  0,                        /* xGetLastError */
   101         -  0                         /* xCurrentTimeInt64 */
   102         -};
   103         -
   104         -static sqlite3_io_methods devsym_io_methods = {
   105         -  2,                                /* iVersion */
   106         -  devsymClose,                      /* xClose */
   107         -  devsymRead,                       /* xRead */
   108         -  devsymWrite,                      /* xWrite */
   109         -  devsymTruncate,                   /* xTruncate */
   110         -  devsymSync,                       /* xSync */
   111         -  devsymFileSize,                   /* xFileSize */
   112         -  devsymLock,                       /* xLock */
   113         -  devsymUnlock,                     /* xUnlock */
   114         -  devsymCheckReservedLock,          /* xCheckReservedLock */
   115         -  devsymFileControl,                /* xFileControl */
   116         -  devsymSectorSize,                 /* xSectorSize */
   117         -  devsymDeviceCharacteristics,      /* xDeviceCharacteristics */
   118         -  devsymShmMap,                     /* xShmMap */
   119         -  devsymShmLock,                    /* xShmLock */
   120         -  devsymShmBarrier,                 /* xShmBarrier */
   121         -  devsymShmUnmap                    /* xShmUnmap */
   122         -};
   123         -
   124     76   struct DevsymGlobal {
   125     77     sqlite3_vfs *pVfs;
   126     78     int iDeviceChar;
   127     79     int iSectorSize;
           80  +  int nWriteCrash;
   128     81   };
   129         -struct DevsymGlobal g = {0, 0, 512};
           82  +struct DevsymGlobal g = {0, 0, 512, 0};
   130     83   
   131     84   /*
   132     85   ** Close an devsym-file.
   133     86   */
   134     87   static int devsymClose(sqlite3_file *pFile){
   135     88     devsym_file *p = (devsym_file *)pFile;
   136     89     sqlite3OsClose(p->pReal);
................................................................................
   267    220   static int devsymOpen(
   268    221     sqlite3_vfs *pVfs,
   269    222     const char *zName,
   270    223     sqlite3_file *pFile,
   271    224     int flags,
   272    225     int *pOutFlags
   273    226   ){
          227  +static sqlite3_io_methods devsym_io_methods = {
          228  +  2,                                /* iVersion */
          229  +  devsymClose,                      /* xClose */
          230  +  devsymRead,                       /* xRead */
          231  +  devsymWrite,                      /* xWrite */
          232  +  devsymTruncate,                   /* xTruncate */
          233  +  devsymSync,                       /* xSync */
          234  +  devsymFileSize,                   /* xFileSize */
          235  +  devsymLock,                       /* xLock */
          236  +  devsymUnlock,                     /* xUnlock */
          237  +  devsymCheckReservedLock,          /* xCheckReservedLock */
          238  +  devsymFileControl,                /* xFileControl */
          239  +  devsymSectorSize,                 /* xSectorSize */
          240  +  devsymDeviceCharacteristics,      /* xDeviceCharacteristics */
          241  +  devsymShmMap,                     /* xShmMap */
          242  +  devsymShmLock,                    /* xShmLock */
          243  +  devsymShmBarrier,                 /* xShmBarrier */
          244  +  devsymShmUnmap                    /* xShmUnmap */
          245  +};
          246  +
   274    247     int rc;
   275    248     devsym_file *p = (devsym_file *)pFile;
   276    249     p->pReal = (sqlite3_file *)&p[1];
   277    250     rc = sqlite3OsOpen(g.pVfs, zName, p->pReal, flags, pOutFlags);
   278    251     if( p->pReal->pMethods ){
   279    252       pFile->pMethods = &devsym_io_methods;
   280    253     }
................................................................................
   368    341   /*
   369    342   ** Return the current time as a Julian Day number in *pTimeOut.
   370    343   */
   371    344   static int devsymCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
   372    345     return g.pVfs->xCurrentTime(g.pVfs, pTimeOut);
   373    346   }
   374    347   
          348  +/*
          349  +** Return the sector-size in bytes for an writecrash-file.
          350  +*/
          351  +static int writecrashSectorSize(sqlite3_file *pFile){
          352  +  devsym_file *p = (devsym_file *)pFile;
          353  +  return sqlite3OsSectorSize(p->pReal);
          354  +}
          355  +
          356  +/*
          357  +** Return the device characteristic flags supported by an writecrash-file.
          358  +*/
          359  +static int writecrashDeviceCharacteristics(sqlite3_file *pFile){
          360  +  devsym_file *p = (devsym_file *)pFile;
          361  +  return sqlite3OsDeviceCharacteristics(p->pReal);
          362  +}
          363  +
          364  +/*
          365  +** Write data to an writecrash-file.
          366  +*/
          367  +static int writecrashWrite(
          368  +  sqlite3_file *pFile, 
          369  +  const void *zBuf, 
          370  +  int iAmt, 
          371  +  sqlite_int64 iOfst
          372  +){
          373  +  devsym_file *p = (devsym_file *)pFile;
          374  +  if( g.nWriteCrash>0 ){
          375  +    g.nWriteCrash--;
          376  +    if( g.nWriteCrash==0 ) abort();
          377  +  }
          378  +  return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
          379  +}
          380  +
          381  +/*
          382  +** Open an writecrash file handle.
          383  +*/
          384  +static int writecrashOpen(
          385  +  sqlite3_vfs *pVfs,
          386  +  const char *zName,
          387  +  sqlite3_file *pFile,
          388  +  int flags,
          389  +  int *pOutFlags
          390  +){
          391  +static sqlite3_io_methods writecrash_io_methods = {
          392  +  2,                                /* iVersion */
          393  +  devsymClose,                      /* xClose */
          394  +  devsymRead,                       /* xRead */
          395  +  writecrashWrite,                  /* xWrite */
          396  +  devsymTruncate,                   /* xTruncate */
          397  +  devsymSync,                       /* xSync */
          398  +  devsymFileSize,                   /* xFileSize */
          399  +  devsymLock,                       /* xLock */
          400  +  devsymUnlock,                     /* xUnlock */
          401  +  devsymCheckReservedLock,          /* xCheckReservedLock */
          402  +  devsymFileControl,                /* xFileControl */
          403  +  writecrashSectorSize,             /* xSectorSize */
          404  +  writecrashDeviceCharacteristics,  /* xDeviceCharacteristics */
          405  +  devsymShmMap,                     /* xShmMap */
          406  +  devsymShmLock,                    /* xShmLock */
          407  +  devsymShmBarrier,                 /* xShmBarrier */
          408  +  devsymShmUnmap                    /* xShmUnmap */
          409  +};
          410  +
          411  +  int rc;
          412  +  devsym_file *p = (devsym_file *)pFile;
          413  +  p->pReal = (sqlite3_file *)&p[1];
          414  +  rc = sqlite3OsOpen(g.pVfs, zName, p->pReal, flags, pOutFlags);
          415  +  if( p->pReal->pMethods ){
          416  +    pFile->pMethods = &writecrash_io_methods;
          417  +  }
          418  +  return rc;
          419  +}
          420  +
          421  +static sqlite3_vfs devsym_vfs = {
          422  +  2,                     /* iVersion */
          423  +  sizeof(devsym_file),      /* szOsFile */
          424  +  DEVSYM_MAX_PATHNAME,      /* mxPathname */
          425  +  0,                     /* pNext */
          426  +  DEVSYM_VFS_NAME,          /* zName */
          427  +  0,                     /* pAppData */
          428  +  devsymOpen,               /* xOpen */
          429  +  devsymDelete,             /* xDelete */
          430  +  devsymAccess,             /* xAccess */
          431  +  devsymFullPathname,       /* xFullPathname */
          432  +#ifndef SQLITE_OMIT_LOAD_EXTENSION
          433  +  devsymDlOpen,             /* xDlOpen */
          434  +  devsymDlError,            /* xDlError */
          435  +  devsymDlSym,              /* xDlSym */
          436  +  devsymDlClose,            /* xDlClose */
          437  +#else
          438  +  0,                        /* xDlOpen */
          439  +  0,                        /* xDlError */
          440  +  0,                        /* xDlSym */
          441  +  0,                        /* xDlClose */
          442  +#endif /* SQLITE_OMIT_LOAD_EXTENSION */
          443  +  devsymRandomness,         /* xRandomness */
          444  +  devsymSleep,              /* xSleep */
          445  +  devsymCurrentTime,        /* xCurrentTime */
          446  +  0,                        /* xGetLastError */
          447  +  0                         /* xCurrentTimeInt64 */
          448  +};
          449  +
          450  +static sqlite3_vfs writecrash_vfs = {
          451  +  2,                     /* iVersion */
          452  +  sizeof(devsym_file),      /* szOsFile */
          453  +  DEVSYM_MAX_PATHNAME,      /* mxPathname */
          454  +  0,                     /* pNext */
          455  +  WRITECRASH_NAME,          /* zName */
          456  +  0,                     /* pAppData */
          457  +  writecrashOpen,           /* xOpen */
          458  +  devsymDelete,             /* xDelete */
          459  +  devsymAccess,             /* xAccess */
          460  +  devsymFullPathname,       /* xFullPathname */
          461  +#ifndef SQLITE_OMIT_LOAD_EXTENSION
          462  +  devsymDlOpen,             /* xDlOpen */
          463  +  devsymDlError,            /* xDlError */
          464  +  devsymDlSym,              /* xDlSym */
          465  +  devsymDlClose,            /* xDlClose */
          466  +#else
          467  +  0,                        /* xDlOpen */
          468  +  0,                        /* xDlError */
          469  +  0,                        /* xDlSym */
          470  +  0,                        /* xDlClose */
          471  +#endif /* SQLITE_OMIT_LOAD_EXTENSION */
          472  +  devsymRandomness,         /* xRandomness */
          473  +  devsymSleep,              /* xSleep */
          474  +  devsymCurrentTime,        /* xCurrentTime */
          475  +  0,                        /* xGetLastError */
          476  +  0                         /* xCurrentTimeInt64 */
          477  +};
          478  +
   375    479   
   376    480   /*
   377    481   ** This procedure registers the devsym vfs with SQLite. If the argument is
   378    482   ** true, the devsym vfs becomes the new default vfs. It is the only publicly
   379    483   ** available function in this file.
   380    484   */
   381    485   void devsym_register(int iDeviceChar, int iSectorSize){
          486  +
   382    487     if( g.pVfs==0 ){
   383    488       g.pVfs = sqlite3_vfs_find(0);
   384    489       devsym_vfs.szOsFile += g.pVfs->szOsFile;
          490  +    writecrash_vfs.szOsFile += g.pVfs->szOsFile;
   385    491       sqlite3_vfs_register(&devsym_vfs, 0);
          492  +    sqlite3_vfs_register(&writecrash_vfs, 0);
   386    493     }
   387    494     if( iDeviceChar>=0 ){
   388    495       g.iDeviceChar = iDeviceChar;
   389    496     }else{
   390    497       g.iDeviceChar = 0;
   391    498     }
   392    499     if( iSectorSize>=0 ){
................................................................................
   398    505   
   399    506   void devsym_unregister(){
   400    507     sqlite3_vfs_unregister(&devsym_vfs);
   401    508     g.pVfs = 0;
   402    509     g.iDeviceChar = 0;
   403    510     g.iSectorSize = 0;
   404    511   }
          512  +
          513  +void devsym_crash_on_write(int nWrite){
          514  +  if( g.pVfs==0 ){
          515  +    g.pVfs = sqlite3_vfs_find(0);
          516  +    devsym_vfs.szOsFile += g.pVfs->szOsFile;
          517  +    writecrash_vfs.szOsFile += g.pVfs->szOsFile;
          518  +    sqlite3_vfs_register(&devsym_vfs, 0);
          519  +    sqlite3_vfs_register(&writecrash_vfs, 0);
          520  +  }
          521  +  g.nWriteCrash = nWrite;
          522  +}
   405    523   
   406    524   #endif

Changes to test/fallocate.test.

    55     55   #
    56     56   # We need to check this to verify that if in the unlikely event a rollback
    57     57   # causes a database file to grow, the database grows to its previous size
    58     58   # on disk, not to the minimum size required to hold the database image.
    59     59   #
    60     60   do_test fallocate-1.7 {
    61     61     execsql { BEGIN; INSERT INTO t1 VALUES(1, 2); }
    62         -  if {[permutation] != "inmemory_journal"} {
           62  +  if {[permutation] != "inmemory_journal"
           63  +   && [permutation] != "atomic-batch-write"
           64  +  } {
    63     65       hexio_get_int [hexio_read test.db-journal 16 4]
    64     66     } else {
    65     67       set {} 1024
    66     68     }
    67     69   } {1024}
    68     70   do_test fallocate-1.8 { execsql { COMMIT } } {}
    69     71   

Changes to test/misc1.test.

   475    475   # The following tests can only work if the current SQLite VFS has the concept
   476    476   # of a current directory.
   477    477   #
   478    478   ifcapable curdir {
   479    479   # Make sure a database connection still works after changing the
   480    480   # working directory.
   481    481   #
   482         -do_test misc1-14.1 {
   483         -  file mkdir tempdir
   484         -  cd tempdir
   485         -  execsql {BEGIN}
   486         -  file exists ./test.db-journal
   487         -} {0}
   488         -do_test misc1-14.2a {
   489         -  execsql {UPDATE t1 SET a=a||'x' WHERE 0}
   490         -  file exists ../test.db-journal
   491         -} {0}
   492         -do_test misc1-14.2b {
   493         -  execsql {UPDATE t1 SET a=a||'y' WHERE 1}
   494         -  file exists ../test.db-journal
   495         -} {1}
   496         -do_test misc1-14.3 {
   497         -  cd ..
   498         -  forcedelete tempdir
   499         -  execsql {COMMIT}
   500         -  file exists ./test.db-journal
   501         -} {0}
          482  +if {[atomic_batch_write test.db]==0} {
          483  +  do_test misc1-14.1 {
          484  +    file mkdir tempdir
          485  +    cd tempdir
          486  +    execsql {BEGIN}
          487  +    file exists ./test.db-journal
          488  +  } {0}
          489  +  do_test misc1-14.2a {
          490  +    execsql {UPDATE t1 SET a=a||'x' WHERE 0}
          491  +    file exists ../test.db-journal
          492  +  } {0}
          493  +  do_test misc1-14.2b {
          494  +    execsql {UPDATE t1 SET a=a||'y' WHERE 1}
          495  +    file exists ../test.db-journal
          496  +  } {1}
          497  +  do_test misc1-14.3 {
          498  +    cd ..
          499  +    forcedelete tempdir
          500  +    execsql {COMMIT}
          501  +    file exists ./test.db-journal
          502  +  } {0}
          503  +}
   502    504   }
   503    505   
   504    506   # A failed create table should not leave the table in the internal
   505    507   # data structures.  Ticket #238.
   506    508   #
   507    509   do_test misc1-15.1.1 {
   508    510     catchsql {

Changes to test/permutations.test.

   379    379     which do not work with a VFS that uses the pVfs argument passed to
   380    380     sqlite3_vfs methods.
   381    381   } -files [
   382    382     test_set $allquicktests -exclude *malloc* *ioerr* *fault* oserror.test \
   383    383     pager1.test syscall.test sysfault.test tkt3457.test quota* superlock* \
   384    384     wal* mmap*
   385    385   ]
          386  +
          387  +test_suite "atomic-batch-write" -prefix "" -description {
          388  +  Like veryquick.test, but must be run on a file-system that supports
          389  +  atomic-batch-writes. Tests that depend on the journal file being present
          390  +  are omitted.
          391  +} -files [
          392  +  test_set $allquicktests -exclude *malloc* *ioerr* *fault* *bigfile* *_err* \
          393  +      *fts5corrupt* *fts5big* *fts5aj*  \
          394  +      crash8.test delete_db.test        \
          395  +      exclusive.test journal3.test      \
          396  +      journal1.test                     \
          397  +      jrnlmode.test jrnlmode2.test      \
          398  +      lock4.test pager1.test            \
          399  +      pager3.test sharedA.test          \
          400  +      symlink.test stmt.test            \
          401  +      sync.test sync2.test              \
          402  +      tempdb.test tkt3457.test          \
          403  +      vacuum5.test wal2.test            \
          404  +      walmode.test zerodamage.test
          405  +] -initialize {
          406  +  if {[atomic_batch_write test.db]==0} {
          407  +    error "File system does NOT support atomic-batch-write"
          408  +  }
          409  +}
   386    410   
   387    411   lappend ::testsuitelist xxx
   388    412   #-------------------------------------------------------------------------
   389    413   # Define the coverage related test suites:
   390    414   #
   391    415   #   coverage-wal
   392    416   #

Changes to test/rollback.test.

    78     78   do_test rollback-1.9 {
    79     79     sqlite3_finalize $STMT
    80     80   } {SQLITE_OK}
    81     81   
    82     82   if {$tcl_platform(platform) == "unix" 
    83     83    && [permutation] ne "onefile"
    84     84    && [permutation] ne "inmemory_journal"
           85  + && [permutation] ne "atomic-batch-write"
    85     86   } {
    86     87     do_test rollback-2.1 {
    87     88       execsql {
    88     89         BEGIN;
    89     90         INSERT INTO t3 VALUES('hello world');
    90     91       }
    91     92       forcecopy test.db testA.db

Changes to test/syscall.test.

    57     57   # Tests for the xNextSystemCall method.
    58     58   #
    59     59   foreach s {
    60     60       open close access getcwd stat fstat ftruncate
    61     61       fcntl read pread write pwrite fchmod fallocate
    62     62       pread64 pwrite64 unlink openDirectory mkdir rmdir 
    63     63       statvfs fchown geteuid umask mmap munmap mremap
    64         -    getpagesize readlink lstat
           64  +    getpagesize readlink lstat ioctl
    65     65   } {
    66     66     if {[test_syscall exists $s]} {lappend syscall_list $s}
    67     67   }
    68     68   do_test 3.1 { lsort [test_syscall list] } [lsort $syscall_list]
    69     69   
    70     70   #-------------------------------------------------------------------------
    71     71   # This test verifies that if a call to open() fails and errno is set to

Changes to test/tester.tcl.

  1586   1586       puts $f $tclbody
  1587   1587     }
  1588   1588     if {[string length $sql]>0} {
  1589   1589       puts $f "db eval {"
  1590   1590       puts $f   "$sql"
  1591   1591       puts $f "}"
  1592   1592     }
         1593  +  close $f
         1594  +  set r [catch {
         1595  +    exec [info nameofexec] crash.tcl >@stdout
         1596  +  } msg]
         1597  +
         1598  +  # Windows/ActiveState TCL returns a slightly different
         1599  +  # error message.  We map that to the expected message
         1600  +  # so that we don't have to change all of the test
         1601  +  # cases.
         1602  +  if {$::tcl_platform(platform)=="windows"} {
         1603  +    if {$msg=="child killed: unknown signal"} {
         1604  +      set msg "child process exited abnormally"
         1605  +    }
         1606  +  }
         1607  +
         1608  +  lappend r $msg
         1609  +}
         1610  +
         1611  +#   crash_on_write ?-devchar DEVCHAR? CRASHDELAY SQL
         1612  +#
         1613  +proc crash_on_write {args} {
         1614  +
         1615  +  set nArg [llength $args]
         1616  +  if {$nArg<2 || $nArg%2} {
         1617  +    error "bad args: $args"
         1618  +  }
         1619  +  set zSql [lindex $args end]
         1620  +  set nDelay [lindex $args end-1]
         1621  +
         1622  +  set devchar {}
         1623  +  for {set ii 0} {$ii < $nArg-2} {incr ii 2} {
         1624  +    set opt [lindex $args $ii]
         1625  +    switch -- [lindex $args $ii] {
         1626  +      -devchar {
         1627  +        set devchar [lindex $args [expr $ii+1]]
         1628  +      }
         1629  +
         1630  +      default { error "unrecognized option: $opt" }
         1631  +    }
         1632  +  }
         1633  +
         1634  +  set f [open crash.tcl w]
         1635  +  puts $f "sqlite3_crash_on_write $nDelay"
         1636  +  puts $f "sqlite3_test_control_pending_byte $::sqlite_pending_byte"
         1637  +  puts $f "sqlite3 db test.db -vfs writecrash"
         1638  +  puts $f "db eval {$zSql}"
         1639  +  puts $f "set {} {}"
         1640  +
  1593   1641     close $f
  1594   1642     set r [catch {
  1595   1643       exec [info nameofexec] crash.tcl >@stdout
  1596   1644     } msg]
  1597   1645   
  1598   1646     # Windows/ActiveState TCL returns a slightly different
  1599   1647     # error message.  We map that to the expected message

Added test/writecrash.test.

            1  +# 2009 January 8
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +#
           12  +# Test the outcome of a writer crashing within a call to the VFS
           13  +# xWrite function.
           14  +#
           15  +
           16  +
           17  +set testdir [file dirname $argv0]
           18  +source $testdir/tester.tcl
           19  +set testprefix writecrash
           20  +
           21  +do_not_use_codec
           22  +
           23  +do_execsql_test 1.0 {
           24  +  CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB UNIQUE);
           25  +  WITH s(i) AS (
           26  +    VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100
           27  +  )
           28  +  INSERT INTO t1 SELECT NULL, randomblob(900) FROM s;
           29  +} {}
           30  +
           31  +set bGo 1
           32  +for {set tn 1} {$bGo} {incr tn} {
           33  +
           34  +db close
           35  +sqlite3 db test.db
           36  +
           37  +  do_test 1.$tn.1 {
           38  +    set res [crash_on_write $tn {
           39  +      UPDATE t1 SET b = randomblob(899) WHERE (a%3)==0
           40  +    }]
           41  +    set bGo 0
           42  +    if {[string match {1 {child killed:*}} $res]} {
           43  +      set res {0 {}}
           44  +      set bGo 1
           45  +    }
           46  +    set res
           47  +  } {0 {}}
           48  +
           49  +#db close
           50  +#sqlite3 db test.db
           51  +
           52  +  do_execsql_test 1.$tn.2 { PRAGMA integrity_check } {ok}
           53  +
           54  +db close
           55  +sqlite3 db test.db
           56  +
           57  +  do_execsql_test 1.$tn.3 { PRAGMA integrity_check } {ok}
           58  +}
           59  +
           60  +
           61  +
           62  +finish_test