/ Check-in [5b9d498f]
Login

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

Overview
Comment:Add experimental new API sqlite3_wal_info().
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | begin-concurrent
Files: files | file ages | folders
SHA3-256: 5b9d498f6e9de6ee2ab86370c02c28a2a8b83d717b96d23b1fc52107677e45a2
User & Date: dan 2017-05-23 19:23:45
Wiki:begin-concurrent
Context
2017-05-25
21:02
Fix a problem with the deferred page allocation on this branch that could occur when the database file is just slightly smaller than the PENDING_BYTE page offset. check-in: 47a7dd92 user: dan tags: begin-concurrent
2017-05-23
19:23
Add experimental new API sqlite3_wal_info(). check-in: 5b9d498f user: dan tags: begin-concurrent
2017-05-19
19:57
Invoke sqlite3_log() in response to irregularities surrounding the Pager.pAllRead bit-vector. check-in: 9527089b user: dan tags: begin-concurrent
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/main.c.

  4091   4091   /*
  4092   4092   ** Free a snapshot handle obtained from sqlite3_snapshot_get().
  4093   4093   */
  4094   4094   void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){
  4095   4095     sqlite3_free(pSnapshot);
  4096   4096   }
  4097   4097   #endif /* SQLITE_ENABLE_SNAPSHOT */
         4098  +
         4099  +SQLITE_EXPERIMENTAL int sqlite3_wal_info(
         4100  +  sqlite3 *db, const char *zDb, 
         4101  +  unsigned int *pnPrior, unsigned int *pnFrame
         4102  +){
         4103  +  int rc = SQLITE_OK;
         4104  +
         4105  +#ifndef SQLITE_OMIT_WAL
         4106  +  Btree *pBt;
         4107  +  int iDb;
         4108  +
         4109  +#ifdef SQLITE_ENABLE_API_ARMOR
         4110  +  if( !sqlite3SafetyCheckOk(db) ){
         4111  +    return SQLITE_MISUSE_BKPT;
         4112  +  }
         4113  +#endif
         4114  +
         4115  +  sqlite3_mutex_enter(db->mutex);
         4116  +  iDb = sqlite3FindDbName(db, zDb);
         4117  +  if( iDb<0 ){
         4118  +    return SQLITE_ERROR;
         4119  +  }
         4120  +  pBt = db->aDb[iDb].pBt;
         4121  +  rc = sqlite3PagerWalInfo(sqlite3BtreePager(pBt), pnPrior, pnFrame);
         4122  +  sqlite3_mutex_leave(db->mutex);
         4123  +#endif   /* SQLITE_OMIT_WAL */
         4124  +
         4125  +  return rc;
         4126  +}
         4127  +
         4128  +

Changes to src/pager.c.

  7703   7703       rc = sqlite3WalSnapshotRecover(pPager->pWal);
  7704   7704     }else{
  7705   7705       rc = SQLITE_ERROR;
  7706   7706     }
  7707   7707     return rc;
  7708   7708   }
  7709   7709   #endif /* SQLITE_ENABLE_SNAPSHOT */
         7710  +
         7711  +int sqlite3PagerWalInfo(Pager *pPager, u32 *pnPrior, u32 *pnFrame){
         7712  +  return sqlite3WalInfo(pPager->pWal, pnPrior, pnFrame);
         7713  +}
         7714  +
  7710   7715   #endif /* !SQLITE_OMIT_WAL */
  7711   7716   
  7712   7717   #ifdef SQLITE_ENABLE_ZIPVFS
  7713   7718   /*
  7714   7719   ** A read-lock must be held on the pager when this function is called. If
  7715   7720   ** the pager is in WAL mode and the WAL file currently contains one or more
  7716   7721   ** frames, return the size in bytes of the page images stored within the

Changes to src/pager.h.

   226    226   void sqlite3PagerSetDbsize(Pager *pPager, Pgno);
   227    227   int sqlite3PagerIsWal(Pager*);
   228    228   #else
   229    229   # define sqlite3PagerEndConcurrent(x)
   230    230   #endif
   231    231   
   232    232   int sqlite3PagerIswriteable(DbPage*);
          233  +
          234  +int sqlite3PagerWalInfo(Pager*, u32 *pnPrior, u32 *pnFrame);
   233    235   
   234    236   #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
   235    237   void *sqlite3PagerCodec(DbPage *);
   236    238   #endif
   237    239   
   238    240   /* Functions to support testing and debugging. */
   239    241   #if !defined(NDEBUG) || defined(SQLITE_TEST)

Changes to src/sqlite.h.in.

  8490   8490   ** sqlite3_snapshot_open(). It is an error if there is already a read
  8491   8491   ** transaction open on the database, or if the database is not a wal mode
  8492   8492   ** database.
  8493   8493   **
  8494   8494   ** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
  8495   8495   */
  8496   8496   SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
         8497  +
         8498  +/*
         8499  +** CAPI3REF: Wal related information regarding the most recent COMMIT
         8500  +** EXPERIMENTAL
         8501  +**
         8502  +** This function reports on the state of the wal file (if any) for database 
         8503  +** zDb, which should be "main", "temp", or the name of the attached database.
         8504  +** Its results - the values written to the output parameters - are only
         8505  +** defined if the most recent SQL command on the connection was a successful 
         8506  +** COMMIT that wrote data to wal-mode database zDb.
         8507  +**
         8508  +** Assuming the above conditions are met, output parameter (*pnFrame) is set
         8509  +** to the total number of frames in the wal file. Parameter (*pnPrior) is
         8510  +** set to the number of frames that were present in the wal file before the
         8511  +** most recent transaction was committed. So that the number of frames written
         8512  +** by the most recent transaction is (*pnFrame)-(*pnPrior).
         8513  +**
         8514  +** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code. It
         8515  +** is not an error if this function is called at a time when the results
         8516  +** are undefined.
         8517  +*/
         8518  +SQLITE_EXPERIMENTAL int sqlite3_wal_info(
         8519  +  sqlite3 *db, const char *zDb, 
         8520  +  unsigned int *pnPrior, unsigned int *pnFrame
         8521  +);
  8497   8522   
  8498   8523   /*
  8499   8524   ** Undo the hack that converts floating point types to integer for
  8500   8525   ** builds on processors without floating point support.
  8501   8526   */
  8502   8527   #ifdef SQLITE_OMIT_FLOATING_POINT
  8503   8528   # undef double
  8504   8529   #endif
  8505   8530   
  8506   8531   #ifdef __cplusplus
  8507   8532   }  /* End of the 'extern "C"' block */
  8508   8533   #endif
  8509   8534   #endif /* SQLITE3_H */

Changes to src/test1.c.

  7364   7364     }else{
  7365   7365       if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  7366   7366       rc = sqlite3_db_config(db, SQLITE_DBCONFIG_MAINDBNAME, "icecube");
  7367   7367       Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
  7368   7368       return TCL_OK;
  7369   7369     }
  7370   7370   }
         7371  +
         7372  +/*
         7373  +** Usage: sqlite3_wal_info DB DBNAME
         7374  +*/
         7375  +static int SQLITE_TCLAPI test_wal_info(
         7376  +  void * clientData,
         7377  +  Tcl_Interp *interp,
         7378  +  int objc,
         7379  +  Tcl_Obj *CONST objv[]
         7380  +){
         7381  +  int rc;
         7382  +  sqlite3 *db;
         7383  +  char *zName;
         7384  +  unsigned int nPrior;
         7385  +  unsigned int nFrame;
         7386  +
         7387  +  if( objc!=3 ){
         7388  +    Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
         7389  +    return TCL_ERROR;
         7390  +  }
         7391  +  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
         7392  +  zName = Tcl_GetString(objv[2]);
         7393  +
         7394  +  rc = sqlite3_wal_info(db, zName, &nPrior, &nFrame);
         7395  +  if( rc!=SQLITE_OK ){
         7396  +    Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
         7397  +    return TCL_ERROR;
         7398  +  }else{
         7399  +    Tcl_Obj *pNew = Tcl_NewObj();
         7400  +    Tcl_ListObjAppendElement(interp, pNew, Tcl_NewWideIntObj((i64)nPrior));
         7401  +    Tcl_ListObjAppendElement(interp, pNew, Tcl_NewWideIntObj((i64)nFrame));
         7402  +    Tcl_SetObjResult(interp, pNew);
         7403  +  }
         7404  +  return TCL_OK;
         7405  +}
  7371   7406   
  7372   7407   /*
  7373   7408   ** Register commands with the TCL interpreter.
  7374   7409   */
  7375   7410   int Sqlitetest1_Init(Tcl_Interp *interp){
  7376   7411     extern int sqlite3_search_count;
  7377   7412     extern int sqlite3_found_count;
................................................................................
  7635   7670        { "sqlite3_snapshot_cmp", test_snapshot_cmp, 0 },
  7636   7671        { "sqlite3_snapshot_recover", test_snapshot_recover, 0 },
  7637   7672        { "sqlite3_snapshot_get_blob", test_snapshot_get_blob, 0 },
  7638   7673        { "sqlite3_snapshot_open_blob", test_snapshot_open_blob, 0 },
  7639   7674        { "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 },
  7640   7675   #endif
  7641   7676        { "sqlite3_delete_database", test_delete_database, 0 },
         7677  +     { "sqlite3_wal_info", test_wal_info, 0 },
  7642   7678     };
  7643   7679     static int bitmask_size = sizeof(Bitmask)*8;
  7644   7680     static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
  7645   7681     int i;
  7646   7682     extern int sqlite3_sync_count, sqlite3_fullsync_count;
  7647   7683     extern int sqlite3_opentemp_count;
  7648   7684     extern int sqlite3_like_count;

Changes to src/wal.c.

   442    442     u8 readOnly;               /* WAL_RDWR, WAL_RDONLY, or WAL_SHM_RDONLY */
   443    443     u8 truncateOnCommit;       /* True to truncate WAL file on commit */
   444    444     u8 syncHeader;             /* Fsync the WAL header if true */
   445    445     u8 padToSectorBoundary;    /* Pad transactions out to the next sector */
   446    446     WalIndexHdr hdr;           /* Wal-index header for current transaction */
   447    447     u32 minFrame;              /* Ignore wal frames before this one */
   448    448     u32 iReCksum;              /* On commit, recalculate checksums from here */
          449  +  u32 nPriorFrame;           /* For sqlite3WalInfo() */
   449    450     const char *zWalName;      /* Name of WAL file */
   450    451     u32 nCkpt;                 /* Checkpoint sequence counter in the wal-header */
   451    452   #ifdef SQLITE_DEBUG
   452    453     u8 lockError;              /* True if a locking error has occurred */
   453    454   #endif
   454    455   #ifdef SQLITE_ENABLE_SNAPSHOT
   455    456     WalIndexHdr *pSnapshot;    /* Start transaction here if not NULL */
................................................................................
  2503   2504       rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
  2504   2505     }while( rc==WAL_RETRY );
  2505   2506     testcase( (rc&0xff)==SQLITE_BUSY );
  2506   2507     testcase( (rc&0xff)==SQLITE_IOERR );
  2507   2508     testcase( rc==SQLITE_PROTOCOL );
  2508   2509     testcase( rc==SQLITE_OK );
  2509   2510   
         2511  +  pWal->nPriorFrame = pWal->hdr.mxFrame;
  2510   2512   #ifdef SQLITE_ENABLE_SNAPSHOT
  2511   2513     if( rc==SQLITE_OK ){
  2512   2514       if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
  2513   2515         /* At this point the client has a lock on an aReadMark[] slot holding
  2514   2516         ** a value equal to or smaller than pSnapshot->mxFrame, but pWal->hdr
  2515   2517         ** is populated with the wal-index header corresponding to the head
  2516   2518         ** of the wal file. Verify that pSnapshot is still valid before
................................................................................
  2944   2946             }
  2945   2947           }
  2946   2948           if( rc!=SQLITE_OK ) break;
  2947   2949         }
  2948   2950       }
  2949   2951     }
  2950   2952   
         2953  +  pWal->nPriorFrame = pWal->hdr.mxFrame;
  2951   2954     return rc;
  2952   2955   }
  2953   2956   
  2954   2957   /* !defined(SQLITE_OMIT_CONCURRENT)
  2955   2958   **
  2956   2959   ** This function is called as part of committing an CONCURRENT transaction.
  2957   2960   ** It is assumed that sqlite3WalLockForCommit() has already been successfully
................................................................................
  3114   3117           **
  3115   3118           ** In theory it would be Ok to update the cache of the header only
  3116   3119           ** at this point. But updating the actual wal-index header is also
  3117   3120           ** safe and means there is no special case for sqlite3WalUndo()
  3118   3121           ** to handle if this transaction is rolled back.  */
  3119   3122           walRestartHdr(pWal, salt1);
  3120   3123           walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
         3124  +        pWal->nPriorFrame = 0;
  3121   3125         }else if( rc!=SQLITE_BUSY ){
  3122   3126           return rc;
  3123   3127         }
  3124   3128       }
  3125   3129   
  3126   3130       /* Regardless of whether or not the wal file was restarted, change the
  3127   3131       ** read-lock held by this client to a slot other than aReadmark[0]. 
................................................................................
  3754   3758   #endif
  3755   3759   
  3756   3760   /* Return the sqlite3_file object for the WAL file
  3757   3761   */
  3758   3762   sqlite3_file *sqlite3WalFile(Wal *pWal){
  3759   3763     return pWal->pWalFd;
  3760   3764   }
         3765  +
         3766  +/* 
         3767  +** Return the values required by sqlite3_wal_info().
         3768  +*/
         3769  +int sqlite3WalInfo(Wal *pWal, u32 *pnPrior, u32 *pnFrame){
         3770  +  int rc = SQLITE_OK;
         3771  +  if( pWal ){
         3772  +    *pnFrame = pWal->hdr.mxFrame;
         3773  +    *pnPrior = pWal->nPriorFrame;
         3774  +  }
         3775  +  return rc;
         3776  +}
  3761   3777   
  3762   3778   #endif /* #ifndef SQLITE_OMIT_WAL */

Changes to src/wal.h.

   149    149   */
   150    150   int sqlite3WalFramesize(Wal *pWal);
   151    151   #endif
   152    152   
   153    153   /* Return the sqlite3_file object for the WAL file */
   154    154   sqlite3_file *sqlite3WalFile(Wal *pWal);
   155    155   
          156  +/* sqlite3_wal_info() data */
          157  +int sqlite3WalInfo(Wal *pWal, u32 *pnPrior, u32 *pnFrame);
          158  +
   156    159   #endif /* ifndef SQLITE_OMIT_WAL */
   157    160   #endif /* SQLITE_WAL_H */

Changes to test/concurrent2.test.

   543    543       code1 { sqlite3_finalize $::stmt }
   544    544       sql1 {
   545    545         INSERT INTO t2 VALUES(8);
   546    546         COMMIT;
   547    547       }
   548    548     } {}
   549    549   }
          550  +
          551  +do_multiclient_test tn {
          552  +  do_test 11.$tn.1 {
          553  +    sql1 {
          554  +      PRAGMA journal_mode = wal;
          555  +      CREATE TABLE t1(a);
          556  +    }
          557  +  } {wal}
          558  +
          559  +  do_test 11.$tn.2 {
          560  +    code1 { sqlite3_wal_info db main }
          561  +  } {0 2}
          562  +
          563  +  do_test 11.$tn.3 {
          564  +    sql1 { INSERT INTO t1 VALUES(1) }
          565  +    code1 { sqlite3_wal_info db main }
          566  +  } {2 3}
          567  +
          568  +  do_test 11.$tn.4 {
          569  +    sql2 { INSERT INTO t1 VALUES(2) }
          570  +    code2 { sqlite3_wal_info db2 main }
          571  +  } {3 4}
          572  +
          573  +  do_test 11.$tn.5 {
          574  +    sql1 { PRAGMA wal_checkpoint }
          575  +    sql2 { INSERT INTO t1 VALUES(3) }
          576  +    code2 { sqlite3_wal_info db2 main }
          577  +  } {0 1}
          578  +}
   550    579   
   551    580   
   552    581   finish_test