/ Check-in [a8c74feb]
Login

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

Overview
Comment:Improve performance by about 10% by avoiding excess calls to get the thread-specific data. (CVS 2921)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:a8c74febec11eb689ca9f6b454f8c8bbadfc49d7
User & Date: drh 2006-01-12 01:25:18
Context
2006-01-12
01:56
Add the legacy_file_format pragma. (CVS 2922) check-in: b2dbd1a5 user: drh tags: trunk
01:25
Improve performance by about 10% by avoiding excess calls to get the thread-specific data. (CVS 2921) check-in: a8c74feb user: drh tags: trunk
2006-01-11
23:40
Testing of the automatic TSD deallocation logic. The sqlite3_thread_cleanup() API is documented. This should close ticket #1601. (CVS 2920) check-in: fb518b0c user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/os_unix.c.

  1644   1644   # endif
  1645   1645   #else
  1646   1646   # define TSD_COUNTER(N)  /* no-op */
  1647   1647   #endif
  1648   1648   
  1649   1649   
  1650   1650   /*
  1651         -** If called with allocateFlag==1, then return a pointer to thread
         1651  +** If called with allocateFlag>1, then return a pointer to thread
  1652   1652   ** specific data for the current thread.  Allocate and zero the
  1653   1653   ** thread-specific data if it does not already exist necessary.
  1654   1654   **
  1655   1655   ** If called with allocateFlag==0, then check the current thread
  1656         -** specific data.  If it exists and is all zeros, then deallocate it.
         1656  +** specific data.  Return it if it exists.  If it does not exist,
         1657  +** then return NULL.
         1658  +**
         1659  +** If called with allocateFlag<0, check to see if the thread specific
         1660  +** data is allocated and is all zero.  If it is then deallocate it.
  1657   1661   ** Return a pointer to the thread specific data or NULL if it is
  1658         -** unallocated.
         1662  +** unallocated or gets deallocated.
  1659   1663   */
  1660   1664   ThreadData *sqlite3UnixThreadSpecificData(int allocateFlag){
  1661   1665     static const ThreadData zeroData;
  1662   1666   #ifdef SQLITE_UNIX_THREADS
  1663   1667     static pthread_key_t key;
  1664   1668     static int keyInit = 0;
  1665   1669     ThreadData *pTsd;
................................................................................
  1675   1679         }
  1676   1680         keyInit = 1;
  1677   1681       }
  1678   1682       sqlite3OsLeaveMutex();
  1679   1683     }
  1680   1684   
  1681   1685     pTsd = pthread_getspecific(key);
  1682         -  if( allocateFlag ){
         1686  +  if( allocateFlag>0 ){
  1683   1687       if( pTsd==0 ){
  1684   1688         pTsd = sqlite3OsMalloc(sizeof(zeroData));
  1685   1689         if( pTsd ){
  1686   1690           *pTsd = zeroData;
  1687   1691           pthread_setspecific(key, pTsd);
  1688   1692           TSD_COUNTER(+1);
  1689   1693         }
  1690   1694       }
  1691         -  }else if( pTsd!=0 && memcmp(pTsd, &zeroData, sizeof(zeroData))==0 ){
         1695  +  }else if( pTsd!=0 && allocateFlag<0 
         1696  +            && memcmp(pTsd, &zeroData, sizeof(zeroData))==0 ){
  1692   1697       sqlite3OsFree(pTsd);
  1693   1698       pthread_setspecific(key, 0);
  1694   1699       TSD_COUNTER(-1);
  1695   1700       pTsd = 0;
  1696   1701     }
  1697   1702     return pTsd;
  1698   1703   #else
  1699   1704     static ThreadData *pTsd = 0;
  1700         -  if( allocateFlag ){
         1705  +  if( allocateFlag>0 ){
  1701   1706       if( pTsd==0 ){
  1702   1707         pTsd = sqlite3OsMalloc( sizeof(zeroData) );
  1703   1708         if( pTsd ){
  1704   1709           *pTsd = zeroData;
  1705   1710           TSD_COUNTER(+1);
  1706   1711         }
  1707   1712       }
  1708         -  }else if( pTsd!=0 && memcmp(pTsd, &zeroData, sizeof(zeroData))==0 ){
         1713  +  }else if( pTsd!=0 && allocateFlag<0
         1714  +            && memcmp(pTsd, &zeroData, sizeof(zeroData))==0 ){
  1709   1715       sqlite3OsFree(pTsd);
  1710   1716       TSD_COUNTER(-1);
  1711   1717       pTsd = 0;
  1712   1718     }
  1713   1719     return pTsd;
  1714   1720   #endif
  1715   1721   }

Changes to src/os_win.c.

  1161   1161   # define TSD_COUNTER_INCR  /* no-op */
  1162   1162   # define TSD_COUNTER_DECR  /* no-op */
  1163   1163   #endif
  1164   1164   
  1165   1165   
  1166   1166   
  1167   1167   /*
  1168         -** If called with allocateFlag==1, then return a pointer to thread
         1168  +** If called with allocateFlag>1, then return a pointer to thread
  1169   1169   ** specific data for the current thread.  Allocate and zero the
  1170   1170   ** thread-specific data if it does not already exist necessary.
  1171   1171   **
  1172   1172   ** If called with allocateFlag==0, then check the current thread
  1173         -** specific data.  If it exists and is all zeros, then deallocate it.
         1173  +** specific data.  Return it if it exists.  If it does not exist,
         1174  +** then return NULL.
         1175  +**
         1176  +** If called with allocateFlag<0, check to see if the thread specific
         1177  +** data is allocated and is all zero.  If it is then deallocate it.
  1174   1178   ** Return a pointer to the thread specific data or NULL if it is
  1175         -** unallocated.
         1179  +** unallocated or gets deallocated.
  1176   1180   */
  1177   1181   ThreadData *sqlite3WinThreadSpecificData(int allocateFlag){
  1178   1182     static int key;
  1179   1183     static int keyInit = 0;
  1180   1184     static const ThreadData zeroData;
  1181   1185     ThreadData *pTsd;
  1182   1186   
................................................................................
  1189   1193           return 0;
  1190   1194         }
  1191   1195         keyInit = 1;
  1192   1196       }
  1193   1197       sqlite3OsLeaveMutex();
  1194   1198     }
  1195   1199     pTsd = TlsGetValue(key);
  1196         -  if( allocateFlag ){
         1200  +  if( allocateFlag>0 ){
  1197   1201       if( !pTsd ){
  1198   1202         pTsd = sqlite3OsMalloc( sizeof(zeroData) );
  1199   1203         if( pTsd ){
  1200   1204           *pTsd = zeroData;
  1201   1205           TlsSetValue(key, pTsd);
  1202   1206           TSD_COUNTER_INCR;
  1203   1207         }
  1204   1208       }
  1205         -  }else if( pTsd!=0 && memcmp(pTsd, &zeroData, sizeof(zeroData))==0 ){
         1209  +  }else if( pTsd!=0 && allocateFlag<0 
         1210  +              && memcmp(pTsd, &zeroData, sizeof(zeroData))==0 ){
  1206   1211       sqlite3OsFree(pTsd);
  1207   1212       TlsSetValue(key, 0);
  1208   1213       TSD_COUNTER_DECR;
  1209   1214       pTsd = 0;
  1210   1215     }
  1211   1216     return pTsd;
  1212   1217   }
  1213   1218   #endif /* OS_WIN */

Changes to src/sqliteInt.h.

     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** Internal interface definitions for SQLite.
    13     13   **
    14         -** @(#) $Id: sqliteInt.h,v 1.462 2006/01/11 21:41:22 drh Exp $
           14  +** @(#) $Id: sqliteInt.h,v 1.463 2006/01/12 01:25:18 drh Exp $
    15     15   */
    16     16   #ifndef _SQLITEINT_H_
    17     17   #define _SQLITEINT_H_
    18     18   
    19     19   /*
    20     20   ** Extra interface definitions for those who need them
    21     21   */
................................................................................
   290    290   ** specific to a single thread.
   291    291   **
   292    292   ** To avoid a memory leak on windows, the content of this structure is
   293    293   ** checked at the conclusion of each API call.  If it is all zero, it
   294    294   ** is deallocated.
   295    295   */
   296    296   struct ThreadData {
   297         -  u8 mallocFailed;         /* True after a malloc() has failed */
          297  +  int mallocFailed;        /* True after a malloc() has failed */
          298  +  int nRef;                /* Number of users */
   298    299   
   299    300   #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
   300    301     int nSoftHeapLimit;      /* Suggested max mem allocation.  No limit if <0 */
   301    302     int nAlloc;              /* Number of bytes currently allocated */
   302    303     Pager *pPager;           /* Linked list of all pagers in this thread */
   303    304   #endif
   304    305   

Changes to src/util.c.

    10     10   **
    11     11   *************************************************************************
    12     12   ** Utility functions used throughout sqlite.
    13     13   **
    14     14   ** This file contains functions for allocating memory, comparing
    15     15   ** strings, and stuff like that.
    16     16   **
    17         -** $Id: util.c,v 1.168 2006/01/11 21:41:22 drh Exp $
           17  +** $Id: util.c,v 1.169 2006/01/12 01:25:18 drh Exp $
    18     18   */
    19     19   #include "sqliteInt.h"
    20     20   #include "os.h"
    21     21   #include <stdarg.h>
    22     22   #include <ctype.h>
    23     23   
    24     24   /*
................................................................................
   505    505   */
   506    506   #define OSMALLOC(x)        sqlite3OsMalloc(x)
   507    507   #define OSREALLOC(x,y)     sqlite3OsRealloc(x,y)
   508    508   #define OSFREE(x)          sqlite3OsFree(x)
   509    509   #define OSSIZEOF(x)        sqlite3OsAllocationSize(x)
   510    510   #define OSMALLOC_FAILED()
   511    511   
   512         -#endif
          512  +#endif  /* SQLITE_MEMDEBUG */
   513    513   /*
   514    514   ** End code for memory allocation system test layer.
   515    515   **--------------------------------------------------------------------------*/
   516    516   
   517    517   /*
   518    518   ** The handleSoftLimit() function is called before each call to 
   519    519   ** sqlite3OsMalloc() or xRealloc(). The parameter 'n' is the number of
................................................................................
  1328   1328   }
  1329   1329   
  1330   1330   /*
  1331   1331   ** Check to see if the ThreadData for this thread is all zero.  If it
  1332   1332   ** is, then deallocate it. 
  1333   1333   */
  1334   1334   void sqlite3ReleaseThreadData(){
  1335         -  sqlite3OsThreadSpecificData(0);
         1335  +  sqlite3OsThreadSpecificData(-1);
  1336   1336   }
  1337   1337   
  1338   1338   /*
  1339   1339   ** Clear the "mallocFailed" flag. This should be invoked before exiting any
  1340   1340   ** entry points that may have called sqliteMalloc().
  1341   1341   */
  1342   1342   void sqlite3MallocClearFailed(){

Changes to src/vdbe.c.

    39     39   **
    40     40   ** Various scripts scan this source file in order to generate HTML
    41     41   ** documentation, headers files, or other derived files.  The formatting
    42     42   ** of the code in this file is, therefore, important.  See other comments
    43     43   ** in this file for details.  If in doubt, do not deviate from existing
    44     44   ** commenting and indentation practices when changing or adding code.
    45     45   **
    46         -** $Id: vdbe.c,v 1.523 2006/01/11 21:41:22 drh Exp $
           46  +** $Id: vdbe.c,v 1.524 2006/01/12 01:25:18 drh Exp $
    47     47   */
    48     48   #include "sqliteInt.h"
    49     49   #include "os.h"
    50     50   #include <ctype.h>
    51     51   #include "vdbeInt.h"
    52     52   
    53     53   /*
................................................................................
   386    386   #endif
   387    387   #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
   388    388     int nProgressOps = 0;      /* Opcodes executed since progress callback. */
   389    389   #endif
   390    390   #ifndef NDEBUG
   391    391     Mem *pStackLimit;
   392    392   #endif
          393  +  ThreadData *pTsd = sqlite3ThreadData();
   393    394   
   394    395     if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE;
          396  +  pTsd->nRef++;
   395    397     assert( db->magic==SQLITE_MAGIC_BUSY );
   396    398     pTos = p->pTos;
   397    399     if( p->rc==SQLITE_NOMEM ){
   398    400       /* This happens if a malloc() inside a call to sqlite3_column_text() or
   399    401       ** sqlite3_column_text16() failed.  */
   400    402       goto no_mem;
   401    403     }
................................................................................
   408    410     }
   409    411     p->resOnStack = 0;
   410    412     db->busyHandler.nBusy = 0;
   411    413     CHECK_FOR_INTERRUPT;
   412    414     for(pc=p->pc; rc==SQLITE_OK; pc++){
   413    415       assert( pc>=0 && pc<p->nOp );
   414    416       assert( pTos<=&p->aStack[pc] );
   415         -    if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto no_mem;
          417  +    if( pTsd->mallocFailed ) goto no_mem;
   416    418   #ifdef VDBE_PROFILE
   417    419       origPc = pc;
   418    420       start = hwtime();
   419    421   #endif
   420    422       pOp = &p->aOp[pc];
   421    423   
   422    424       /* Only allow tracing if SQLITE_DEBUG is defined.
................................................................................
   588    590     p->pc = pc;
   589    591     p->errorAction = pOp->p2;
   590    592     if( pOp->p3 ){
   591    593       sqlite3SetString(&p->zErrMsg, pOp->p3, (char*)0);
   592    594     }
   593    595     rc = sqlite3VdbeHalt(p);
   594    596     assert( rc==SQLITE_BUSY || rc==SQLITE_OK );
          597  +  pTsd->nRef--;
   595    598     if( rc==SQLITE_BUSY ){
   596    599       p->rc = SQLITE_BUSY;
   597    600       return SQLITE_BUSY;
   598    601     }
   599    602     return p->rc ? SQLITE_ERROR : SQLITE_DONE;
   600    603   }
   601    604   
................................................................................
   895    898     ** results from the stack when the statement returns.
   896    899     */
   897    900     p->resOnStack = 1;
   898    901     p->nCallback++;
   899    902     p->popStack = pOp->p1;
   900    903     p->pc = pc + 1;
   901    904     p->pTos = pTos;
          905  +  pTsd->nRef--;
   902    906     return SQLITE_ROW;
   903    907   }
   904    908   
   905    909   /* Opcode: Concat P1 P2 *
   906    910   **
   907    911   ** Look at the first P1+2 elements of the stack.  Append them all 
   908    912   ** together with the lowest element first.  The original P1+2 elements
................................................................................
  1163   1167       assert( pOp[-1].p3type==P3_COLLSEQ );
  1164   1168       assert( pOp[-1].opcode==OP_CollSeq );
  1165   1169       ctx.pColl = (CollSeq *)pOp[-1].p3;
  1166   1170     }
  1167   1171     if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
  1168   1172     (*ctx.pFunc->xFunc)(&ctx, n, apVal);
  1169   1173     if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
  1170         -  if( sqlite3ThreadDataReadOnly()->mallocFailed ) goto no_mem;
         1174  +  if( pTsd->mallocFailed ) goto no_mem;
  1171   1175     popStack(&pTos, n);
  1172   1176   
  1173   1177     /* If any auxilary data functions have been called by this user function,
  1174   1178     ** immediately call the destructor for any non-static values.
  1175   1179     */
  1176   1180     if( ctx.pVdbeFunc ){
  1177   1181       sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p1);
................................................................................
  2322   2326       ** still running, and a transaction is active, return an error indicating
  2323   2327       ** that the other VMs must complete first. 
  2324   2328       */
  2325   2329       sqlite3SetString(&p->zErrMsg, "cannot ", rollback?"rollback":"commit", 
  2326   2330           " transaction - SQL statements in progress", (char*)0);
  2327   2331       rc = SQLITE_ERROR;
  2328   2332     }else if( i!=db->autoCommit ){
         2333  +    pTsd->nRef--;
  2329   2334       if( pOp->p2 ){
  2330   2335         assert( i==1 );
  2331   2336         sqlite3RollbackAll(db);
  2332   2337         db->autoCommit = 1;
  2333   2338       }else{
  2334   2339         db->autoCommit = i;
  2335   2340         if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
................................................................................
  2381   2386   
  2382   2387     if( pBt ){
  2383   2388       rc = sqlite3BtreeBeginTrans(pBt, pOp->p2);
  2384   2389       if( rc==SQLITE_BUSY ){
  2385   2390         p->pc = pc;
  2386   2391         p->rc = SQLITE_BUSY;
  2387   2392         p->pTos = pTos;
         2393  +      pTsd->nRef--;
  2388   2394         return SQLITE_BUSY;
  2389   2395       }
  2390   2396       if( rc!=SQLITE_OK && rc!=SQLITE_READONLY /* && rc!=SQLITE_BUSY */ ){
  2391   2397         goto abort_due_to_error;
  2392   2398       }
  2393   2399     }
  2394   2400     break;
................................................................................
  2588   2594       pCur->pIncrKey = &pCur->bogusIncrKey;
  2589   2595     }
  2590   2596     switch( rc ){
  2591   2597       case SQLITE_BUSY: {
  2592   2598         p->pc = pc;
  2593   2599         p->rc = SQLITE_BUSY;
  2594   2600         p->pTos = &pTos[1 + (pOp->p2<=0)]; /* Operands must remain on stack */
         2601  +      pTsd->nRef--;
  2595   2602         return SQLITE_BUSY;
  2596   2603       }
  2597   2604       case SQLITE_OK: {
  2598   2605         int flags = sqlite3BtreeFlags(pCur->pCursor);
  2599   2606         /* Sanity checking.  Only the lower four bits of the flags byte should
  2600   2607         ** be used.  Bit 3 (mask 0x08) is unpreditable.  The lower 3 bits
  2601   2608         ** (mask 0x07) should be either 5 (intkey+leafdata for tables) or
................................................................................
  4016   4023     zSql = sqlite3MPrintf(
  4017   4024        "SELECT name, rootpage, sql, %d FROM '%q'.%s WHERE %s",
  4018   4025        pOp->p1, db->aDb[iDb].zName, zMaster, pOp->p3);
  4019   4026     if( zSql==0 ) goto no_mem;
  4020   4027     sqlite3SafetyOff(db);
  4021   4028     assert( db->init.busy==0 );
  4022   4029     db->init.busy = 1;
  4023         -  assert(0==sqlite3ThreadDataReadOnly()->mallocFailed);
         4030  +  assert(0==pTsd->mallocFailed);
  4024   4031     rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
  4025   4032     sqliteFree(zSql);
  4026   4033     db->init.busy = 0;
  4027   4034     sqlite3SafetyOn(db);
  4028   4035     if( rc==SQLITE_NOMEM ){
  4029         -    sqlite3ThreadData()->mallocFailed = 1;
         4036  +    pTsd->mallocFailed = 1;
  4030   4037       goto no_mem;
  4031   4038     }
  4032   4039     break;  
  4033   4040   }
  4034   4041   
  4035   4042   #ifndef SQLITE_OMIT_ANALYZE
  4036   4043   /* Opcode: LoadAnalysis P1 * *
................................................................................
  4591   4598       p->rc = rc;
  4592   4599       rc = SQLITE_ERROR;
  4593   4600     }else{
  4594   4601       rc = SQLITE_DONE;
  4595   4602     }
  4596   4603     sqlite3VdbeHalt(p);
  4597   4604     p->pTos = pTos;
         4605  +  pTsd->nRef--;
  4598   4606     return rc;
  4599   4607   
  4600   4608     /* Jump to here if a malloc() fails.  It's hard to get a malloc()
  4601   4609     ** to fail on a modern VM computer, so this code is untested.
  4602   4610     */
  4603   4611   no_mem:
  4604   4612     sqlite3SetString(&p->zErrMsg, "out of memory", (char*)0);
................................................................................
  4612   4620     /* Fall thru into abort_due_to_error */
  4613   4621   
  4614   4622     /* Jump to here for any other kind of fatal error.  The "rc" variable
  4615   4623     ** should hold the error number.
  4616   4624     */
  4617   4625   abort_due_to_error:
  4618   4626     if( p->zErrMsg==0 ){
  4619         -    if( sqlite3ThreadDataReadOnly()->mallocFailed ) rc = SQLITE_NOMEM;
         4627  +    if( pTsd->mallocFailed ) rc = SQLITE_NOMEM;
  4620   4628       sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(rc), (char*)0);
  4621   4629     }
  4622   4630     goto vdbe_halt;
  4623   4631   
  4624   4632     /* Jump to here if the sqlite3_interrupt() API sets the interrupt
  4625   4633     ** flag.
  4626   4634     */