/ Check-in [614de91a]
Login

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

Overview
Comment:Fix a performance regression: Keep two btree masks in each prepared statement; one for btrees used and another for btrees that require locks. Only try to lock the btrees identified by the second mask.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 614de91a504d2231009a9de1305e31fce1b1c5a6
User & Date: drh 2011-04-06 22:05:53
Context
2011-04-07
01:14
Fix typos in documentation comments. No changes to code. check-in: 9c64b5a9 user: drh tags: trunk
2011-04-06
22:33
Merge in the latest changes from the trunk. check-in: 435b57dc user: drh tags: sessions
22:05
Fix a performance regression: Keep two btree masks in each prepared statement; one for btrees used and another for btrees that require locks. Only try to lock the btrees identified by the second mask. check-in: 614de91a user: drh tags: trunk
19:15
Fix a benign inaccuracy in the os_unix.c SQLITE_FCNTL_SIZE_HINT code. check-in: 61a6ccbe user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btmutex.c.

   198    198     Btree *p;
   199    199     assert( sqlite3_mutex_held(db->mutex) );
   200    200     for(i=0; i<db->nDb; i++){
   201    201       p = db->aDb[i].pBt;
   202    202       if( p ) sqlite3BtreeLeave(p);
   203    203     }
   204    204   }
          205  +
          206  +/*
          207  +** Return true if a particular Btree requires a lock.  Return FALSE if
          208  +** no lock is ever required since it is not sharable.
          209  +*/
          210  +int sqlite3BtreeSharable(Btree *p){
          211  +  return p->sharable;
          212  +}
   205    213   
   206    214   #ifndef NDEBUG
   207    215   /*
   208    216   ** Return true if the current thread holds the database connection
   209    217   ** mutex and all required BtShared mutexes.
   210    218   **
   211    219   ** This routine is used inside assert() statements only.

Changes to src/btree.h.

   208    208     void sqlite3BtreeEnterAll(sqlite3*);
   209    209   #else
   210    210   # define sqlite3BtreeEnter(X) 
   211    211   # define sqlite3BtreeEnterAll(X)
   212    212   #endif
   213    213   
   214    214   #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
          215  +  int sqlite3BtreeSharable(Btree*);
   215    216     void sqlite3BtreeLeave(Btree*);
   216    217     void sqlite3BtreeEnterCursor(BtCursor*);
   217    218     void sqlite3BtreeLeaveCursor(BtCursor*);
   218    219     void sqlite3BtreeLeaveAll(sqlite3*);
   219    220   #ifndef NDEBUG
   220    221     /* These routines are used inside assert() statements only. */
   221    222     int sqlite3BtreeHoldsMutex(Btree*);
   222    223     int sqlite3BtreeHoldsAllMutexes(sqlite3*);
   223    224     int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*);
   224    225   #endif
   225    226   #else
   226    227   
          228  +# define sqlite3BtreeSharable(X) 0
   227    229   # define sqlite3BtreeLeave(X)
   228    230   # define sqlite3BtreeEnterCursor(X)
   229    231   # define sqlite3BtreeLeaveCursor(X)
   230    232   # define sqlite3BtreeLeaveAll(X)
   231    233   
   232    234   # define sqlite3BtreeHoldsMutex(X) 1
   233    235   # define sqlite3BtreeHoldsAllMutexes(X) 1
   234    236   # define sqlite3SchemaMutexHeld(X,Y,Z) 1
   235    237   #endif
   236    238   
   237    239   
   238    240   #endif /* _BTREE_H_ */

Changes to src/vdbe.c.

  4641   4641     ** sqlite3InitCallback().
  4642   4642     */
  4643   4643   #ifdef SQLITE_DEBUG
  4644   4644     for(iDb=0; iDb<db->nDb; iDb++){
  4645   4645       assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
  4646   4646     }
  4647   4647   #endif
  4648         -  assert( p->btreeMask == ~(yDbMask)0 );
  4649         -
  4650   4648   
  4651   4649     iDb = pOp->p1;
  4652   4650     assert( iDb>=0 && iDb<db->nDb );
  4653   4651     assert( DbHasProperty(db, iDb, DB_SchemaLoaded) );
  4654   4652     /* Used to be a conditional */ {
  4655   4653       zMaster = SCHEMA_TABLE(iDb);
  4656   4654       initData.db = db;

Changes to src/vdbeInt.h.

   299    299     u8 minWriteFileFormat;  /* Minimum file format for writable database files */
   300    300     u8 inVtabMethod;        /* See comments above */
   301    301     u8 usesStmtJournal;     /* True if uses a statement journal */
   302    302     u8 readOnly;            /* True for read-only statements */
   303    303     u8 isPrepareV2;         /* True if prepared with prepare_v2() */
   304    304     int nChange;            /* Number of db changes made since last reset */
   305    305     yDbMask btreeMask;      /* Bitmask of db->aDb[] entries referenced */
          306  +  yDbMask lockMask;       /* Subset of btreeMask that requires a lock */
   306    307     int iStatement;         /* Statement number (or 0 if has not opened stmt) */
   307    308     int aCounter[3];        /* Counters used by sqlite3_stmt_status() */
   308    309   #ifndef SQLITE_OMIT_TRACE
   309    310     i64 startTime;          /* Time when query started - used for profiling */
   310    311   #endif
   311    312     i64 nFkConstraint;      /* Number of imm. FK constraints this VM */
   312    313     i64 nStmtDefCons;       /* Number of def. constraints when stmt started */

Changes to src/vdbeaux.c.

   156    156     pOp->p3 = p3;
   157    157     pOp->p4.p = 0;
   158    158     pOp->p4type = P4_NOTUSED;
   159    159     p->expired = 0;
   160    160     if( op==OP_ParseSchema ){
   161    161       /* Any program that uses the OP_ParseSchema opcode needs to lock
   162    162       ** all btrees. */
   163         -    p->btreeMask = ~(yDbMask)0;
          163  +    int j;
          164  +    for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
   164    165     }
   165    166   #ifdef SQLITE_DEBUG
   166    167     pOp->zComment = 0;
   167    168     if( sqlite3VdbeAddopTrace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);
   168    169   #endif
   169    170   #ifdef VDBE_PROFILE
   170    171     pOp->cycles = 0;
................................................................................
   954    955   ** attached databases that they will be using.  A mask of these databases
   955    956   ** is maintained in p->btreeMask and is used for locking and other purposes.
   956    957   */
   957    958   void sqlite3VdbeUsesBtree(Vdbe *p, int i){
   958    959     assert( i>=0 && i<p->db->nDb && i<(int)sizeof(yDbMask)*8 );
   959    960     assert( i<(int)sizeof(p->btreeMask)*8 );
   960    961     p->btreeMask |= ((yDbMask)1)<<i;
          962  +  if( i!=1 && sqlite3BtreeSharable(p->db->aDb[i].pBt) ){
          963  +    p->lockMask |= ((yDbMask)1)<<i;
          964  +  }
   961    965   }
   962    966   
   963    967   #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
   964    968   /*
   965    969   ** If SQLite is compiled to support shared-cache mode and to be threadsafe,
   966    970   ** this routine obtains the mutex associated with each BtShared structure
   967    971   ** that may be accessed by the VM passed as an argument. In doing so it also
................................................................................
   981    985   ** corresponding to btrees that use shared cache.  Then the runtime of
   982    986   ** this routine is N*N.  But as N is rarely more than 1, this should not
   983    987   ** be a problem.
   984    988   */
   985    989   void sqlite3VdbeEnter(Vdbe *p){
   986    990     int i;
   987    991     yDbMask mask;
   988         -  sqlite3 *db = p->db;
   989         -  Db *aDb = db->aDb;
   990         -  int nDb = db->nDb;
          992  +  sqlite3 *db;
          993  +  Db *aDb;
          994  +  int nDb;
          995  +  if( p->lockMask==0 ) return;  /* The common case */
          996  +  db = p->db;
          997  +  aDb = db->aDb;
          998  +  nDb = db->nDb;
   991    999     for(i=0, mask=1; i<nDb; i++, mask += mask){
   992         -    if( i!=1 && (mask & p->btreeMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){
         1000  +    if( i!=1 && (mask & p->lockMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){
   993   1001         sqlite3BtreeEnter(aDb[i].pBt);
   994   1002       }
   995   1003     }
   996   1004   }
   997   1005   #endif
   998   1006   
   999   1007   #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
  1000   1008   /*
  1001   1009   ** Unlock all of the btrees previously locked by a call to sqlite3VdbeEnter().
  1002   1010   */
  1003   1011   void sqlite3VdbeLeave(Vdbe *p){
  1004   1012     int i;
  1005   1013     yDbMask mask;
  1006         -  sqlite3 *db = p->db;
  1007         -  Db *aDb = db->aDb;
  1008         -  int nDb = db->nDb;
  1009         -
         1014  +  sqlite3 *db;
         1015  +  Db *aDb;
         1016  +  int nDb;
         1017  +  if( p->lockMask==0 ) return;  /* The common case */
         1018  +  db = p->db;
         1019  +  aDb = db->aDb;
         1020  +  nDb = db->nDb;
  1010   1021     for(i=0, mask=1; i<nDb; i++, mask += mask){
  1011         -    if( i!=1 && (mask & p->btreeMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){
         1022  +    if( i!=1 && (mask & p->lockMask)!=0 && ALWAYS(aDb[i].pBt!=0) ){
  1012   1023         sqlite3BtreeLeave(aDb[i].pBt);
  1013   1024       }
  1014   1025     }
  1015   1026   }
  1016   1027   #endif
  1017   1028   
  1018   1029   #if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)