/ Check-in [d76f4aaa]
Login

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

Overview
Comment:Fix some zipvfs related problems in RBU vacuum.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | rbu-vacuum
Files: files | file ages | folders
SHA1: d76f4aaa4caab713460421bd27365a82ac986c20
User & Date: dan 2016-04-18 18:18:18
Context
2016-04-18
21:00
Another fix to rbu vacuum for a zipvfs case. check-in: 29407d70 user: dan tags: rbu-vacuum
18:18
Fix some zipvfs related problems in RBU vacuum. check-in: d76f4aaa user: dan tags: rbu-vacuum
09:17
Add the -vacuum switch to the "rbu" demonstration program. check-in: 9a0078a5 user: dan tags: rbu-vacuum
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/rbu/sqlite3rbu.c.

   186    186   ** locks. These are not magic numbers as they are part of the SQLite file
   187    187   ** format.
   188    188   */
   189    189   #define WAL_LOCK_WRITE  0
   190    190   #define WAL_LOCK_CKPT   1
   191    191   #define WAL_LOCK_READ0  3
   192    192   
          193  +#define SQLITE_FCNTL_RBUCNT    5149216
          194  +
   193    195   /*
   194    196   ** A structure to store values read from the rbu_state table in memory.
   195    197   */
   196    198   struct RbuState {
   197    199     int eStage;
   198    200     char *zTbl;
   199    201     char *zIdx;
................................................................................
   389    391     sqlite3_file *pReal;            /* Underlying file handle */
   390    392     rbu_vfs *pRbuVfs;               /* Pointer to the rbu_vfs object */
   391    393     sqlite3rbu *pRbu;               /* Pointer to rbu object (rbu target only) */
   392    394   
   393    395     int openFlags;                  /* Flags this file was opened with */
   394    396     u32 iCookie;                    /* Cookie value for main db files */
   395    397     u8 iWriteVer;                   /* "write-version" value for main db files */
          398  +  u8 bNolock;
   396    399   
   397    400     int nShm;                       /* Number of entries in apShm[] array */
   398    401     char **apShm;                   /* Array of mmap'd *-shm regions */
   399    402     char *zDel;                     /* Delete this when closing file */
   400    403   
   401    404     const char *zWal;               /* Wal filename for this main db file */
   402    405     rbu_file *pWalFd;               /* Wal file descriptor for this main db */
................................................................................
  2321   2324   
  2322   2325   
  2323   2326   /*
  2324   2327   ** Open the database handle and attach the RBU database as "rbu". If an
  2325   2328   ** error occurs, leave an error code and message in the RBU handle.
  2326   2329   */
  2327   2330   static void rbuOpenDatabase(sqlite3rbu *p){
         2331  +  int nRbu = 0;
  2328   2332     assert( p->rc==SQLITE_OK );
  2329   2333     assert( p->dbMain==0 && p->dbRbu==0 );
  2330   2334     assert( rbuIsVacuum(p) || p->zTarget!=0 );
  2331   2335   
  2332   2336     /* Open the RBU database */
  2333   2337     p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1);
         2338  +
         2339  +  if( rbuIsVacuum(p) ){
         2340  +    sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, &nRbu);
         2341  +  }
  2334   2342   
  2335   2343     /* If using separate RBU and state databases, attach the state database to
  2336   2344     ** the RBU db handle now.  */
  2337   2345     if( p->zState ){
  2338   2346       rbuMPrintfExec(p, p->dbRbu, "ATTACH %Q AS stat", p->zState);
  2339   2347       memcpy(p->zStateDb, "stat", 4);
  2340   2348     }else{
................................................................................
  2351   2359       }else{
  2352   2360         RbuState *pState = rbuLoadState(p);
  2353   2361         if( pState ){
  2354   2362           bOpen = (pState->eStage>RBU_STAGE_MOVE);
  2355   2363           rbuFreeState(pState);
  2356   2364         }
  2357   2365       }
  2358         -    if( bOpen ) p->dbMain = rbuOpenDbhandle(p, p->zRbu, 1);
         2366  +    if( bOpen ) p->dbMain = rbuOpenDbhandle(p, p->zRbu, nRbu<=1);
  2359   2367     }
  2360   2368   
  2361   2369     p->eStage = 0;
  2362   2370     if( p->dbMain==0 ){
  2363   2371       if( !rbuIsVacuum(p) ){
  2364   2372         p->dbMain = rbuOpenDbhandle(p, p->zTarget, 1);
  2365   2373       }else{
  2366         -      int frc = sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_ZIPVFS, 0);
  2367   2374         char *zTarget = sqlite3_mprintf("file:%s-vacuum?rbu_memory=1", p->zRbu);
  2368   2375         if( zTarget==0 ){
  2369   2376           p->rc = SQLITE_NOMEM;
  2370   2377           return;
  2371   2378         }
  2372         -      p->dbMain = rbuOpenDbhandle(p, zTarget, frc!=SQLITE_OK);
         2379  +      p->dbMain = rbuOpenDbhandle(p, zTarget, nRbu<=1);
  2373   2380         sqlite3_free(zTarget);
  2374         -      if( p->rc==SQLITE_OK ){
  2375         -        p->rc = sqlite3_exec(p->dbMain, 
  2376         -            "PRAGMA journal_mode=off; PRAGMA zipvfs_journal_mode = off;"
  2377         -            "BEGIN EXCLUSIVE; COMMIT;", 0, 0, 0
  2378         -        );
  2379         -      }
  2380   2381       }
  2381   2382     }
  2382   2383   
  2383   2384     if( p->rc==SQLITE_OK ){
  2384   2385       p->rc = sqlite3_create_function(p->dbMain, 
  2385   2386           "rbu_tmp_insert", -1, SQLITE_UTF8, (void*)p, rbuTmpInsertFunc, 0, 0
  2386   2387       );
................................................................................
  3441   3442         if( p->eStage==RBU_STAGE_OAL ){
  3442   3443           sqlite3 *db = p->dbMain;
  3443   3444   
  3444   3445           /* Open transactions both databases. The *-oal file is opened or
  3445   3446           ** created at this point. */
  3446   3447           p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
  3447   3448           if( p->rc==SQLITE_OK ){
  3448         -          p->rc = sqlite3_exec(p->dbRbu, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
         3449  +          p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, &p->zErrmsg);
  3449   3450           }
  3450   3451   
  3451   3452           /* Check if the main database is a zipvfs db. If it is, set the upper
  3452   3453           ** level pager to use "journal_mode=off". This prevents it from 
  3453   3454           ** generating a large journal using a temp file.  */
  3454   3455           if( p->rc==SQLITE_OK ){
  3455   3456             int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0);
................................................................................
  3782   3783   */
  3783   3784   static void rbuPutU32(u8 *aBuf, u32 iVal){
  3784   3785     aBuf[0] = (iVal >> 24) & 0xFF;
  3785   3786     aBuf[1] = (iVal >> 16) & 0xFF;
  3786   3787     aBuf[2] = (iVal >>  8) & 0xFF;
  3787   3788     aBuf[3] = (iVal >>  0) & 0xFF;
  3788   3789   }
         3790  +
         3791  +static void rbuPutU16(u8 *aBuf, u16 iVal){
         3792  +  aBuf[0] = (iVal >>  8) & 0xFF;
         3793  +  aBuf[1] = (iVal >>  0) & 0xFF;
         3794  +}
  3789   3795   
  3790   3796   /*
  3791   3797   ** Read data from an rbuVfs-file.
  3792   3798   */
  3793   3799   static int rbuVfsRead(
  3794   3800     sqlite3_file *pFile, 
  3795   3801     void *zBuf, 
................................................................................
  3808   3814        && (p->openFlags & SQLITE_OPEN_WAL) 
  3809   3815        && iOfst>=pRbu->iOalSz 
  3810   3816       ){
  3811   3817         rc = SQLITE_OK;
  3812   3818         memset(zBuf, 0, iAmt);
  3813   3819       }else{
  3814   3820         rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
         3821  +#if 1
         3822  +      /* If this is being called to read the first page of the target 
         3823  +      ** database as part of an rbu vacuum operation, synthesize the 
         3824  +      ** contents of the first page if it does not yet exist. Otherwise,
         3825  +      ** SQLite will not check for a *-wal file.  */
         3826  +      if( p->pRbu && rbuIsVacuum(p->pRbu) 
         3827  +          && rc==SQLITE_IOERR_SHORT_READ && iOfst==0
         3828  +          && (p->openFlags & SQLITE_OPEN_MAIN_DB)
         3829  +      ){
         3830  +        sqlite3_file *pFd = 0;
         3831  +        rc = sqlite3_file_control(
         3832  +            p->pRbu->dbRbu, "main", SQLITE_FCNTL_FILE_POINTER, (void*)&pFd
         3833  +        );
         3834  +        if( rc==SQLITE_OK ){
         3835  +          rc = pFd->pMethods->xRead(pFd, zBuf, iAmt, iOfst);
         3836  +        }
         3837  +        if( rc==SQLITE_OK ){
         3838  +          u8 *aBuf = (u8*)zBuf;
         3839  +          rbuPutU32(&aBuf[52], 0);          /* largest root page number */
         3840  +          rbuPutU32(&aBuf[36], 0);          /* number of free pages */
         3841  +          rbuPutU32(&aBuf[32], 0);          /* first page on free list trunk */
         3842  +          rbuPutU32(&aBuf[28], 1);          /* size of db file in pages */
         3843  +
         3844  +          if( iAmt>100 ){
         3845  +            assert( iAmt>=101 );
         3846  +            memset(&aBuf[101], 0, iAmt-101);
         3847  +            rbuPutU16(&aBuf[105], iAmt & 0xFFFF);
         3848  +          }
         3849  +        }
         3850  +      }
         3851  +#endif
  3815   3852       }
  3816   3853       if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
  3817   3854         /* These look like magic numbers. But they are stable, as they are part
  3818   3855          ** of the definition of the SQLite file format, which may not change. */
  3819   3856         u8 *pBuf = (u8*)zBuf;
  3820   3857         p->iCookie = rbuGetU32(&pBuf[24]);
  3821   3858         p->iWriteVer = pBuf[19];
................................................................................
  3889   3926   }
  3890   3927   
  3891   3928   /*
  3892   3929   ** Return the current file-size of an rbuVfs-file.
  3893   3930   */
  3894   3931   static int rbuVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
  3895   3932     rbu_file *p = (rbu_file *)pFile;
  3896         -  return p->pReal->pMethods->xFileSize(p->pReal, pSize);
         3933  +  int rc;
         3934  +  rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
         3935  +
         3936  +  /* If this is an RBU vacuum operation and this is the target database,
         3937  +  ** pretend that it has at least one page. Otherwise, SQLite will not
         3938  +  ** check for the existance of a *-wal file. rbuVfsRead() contains 
         3939  +  ** similar logic.  */
         3940  +  if( rc==SQLITE_OK && *pSize==0 
         3941  +   && p->pRbu && rbuIsVacuum(p->pRbu) 
         3942  +   && (p->openFlags & SQLITE_OPEN_MAIN_DB)
         3943  +  ){
         3944  +    *pSize = 1024;
         3945  +  }
         3946  +  return rc;
  3897   3947   }
  3898   3948   
  3899   3949   /*
  3900   3950   ** Lock an rbuVfs-file.
  3901   3951   */
  3902   3952   static int rbuVfsLock(sqlite3_file *pFile, int eLock){
  3903   3953     rbu_file *p = (rbu_file*)pFile;
  3904   3954     sqlite3rbu *pRbu = p->pRbu;
  3905   3955     int rc = SQLITE_OK;
  3906   3956   
  3907   3957     assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
  3908         -  if( pRbu && eLock==SQLITE_LOCK_EXCLUSIVE && pRbu->eStage!=RBU_STAGE_DONE ){
         3958  +  if( eLock==SQLITE_LOCK_EXCLUSIVE 
         3959  +   && (p->bNolock || (pRbu && pRbu->eStage!=RBU_STAGE_DONE))
         3960  +  ){
  3909   3961       /* Do not allow EXCLUSIVE locks. Preventing SQLite from taking this 
  3910   3962       ** prevents it from checkpointing the database from sqlite3_close(). */
  3911   3963       rc = SQLITE_BUSY;
  3912   3964     }else{
  3913   3965       rc = p->pReal->pMethods->xLock(p->pReal, eLock);
  3914   3966     }
  3915   3967   
................................................................................
  3963   4015           pRbu->pTargetFd = p;
  3964   4016           p->pRbu = pRbu;
  3965   4017           if( p->pWalFd ) p->pWalFd->pRbu = pRbu;
  3966   4018           rc = SQLITE_OK;
  3967   4019         }
  3968   4020       }
  3969   4021       return rc;
         4022  +  }
         4023  +  else if( op==SQLITE_FCNTL_RBUCNT ){
         4024  +    int *pnRbu = (int*)pArg;
         4025  +    (*pnRbu)++;
         4026  +    p->bNolock = 1;
  3970   4027     }
  3971   4028   
  3972   4029     rc = xControl(p->pReal, op, pArg);
  3973   4030     if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
  3974   4031       rbu_vfs *pRbuVfs = p->pRbuVfs;
  3975   4032       char *zIn = *(char**)pArg;
  3976   4033       char *zOut = sqlite3_mprintf("rbu(%s)/%z", pRbuVfs->base.zName, zIn);