/ Check-in [a06263f1]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Faster memory allocation from lookaside by not trying to keep track of the number of outstanding allocations, and rather computing that value only when requested.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: a06263f1efd2d45eac88b8d59e8fe8e458670fa3808c795feaa7f247fc36cbe9
User & Date: drh 2017-08-29 20:21:12
Context
2017-08-30
04:44
Small performance optimization in pcache1. check-in: ffd437da user: drh tags: trunk
2017-08-29
20:21
Faster memory allocation from lookaside by not trying to keep track of the number of outstanding allocations, and rather computing that value only when requested. check-in: a06263f1 user: drh tags: trunk
2017-08-28
17:00
Add the --enable-update-limit option to the ./configure script. check-in: 64a8ae68 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/build.c.

   594    594   ** contains lookaside memory.  (Table objects in the schema do not use
   595    595   ** lookaside memory, but some ephemeral Table objects do.)  Or the
   596    596   ** db parameter can be used with db->pnBytesFreed to measure the memory
   597    597   ** used by the Table object.
   598    598   */
   599    599   static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
   600    600     Index *pIndex, *pNext;
   601         -  TESTONLY( int nLookaside; ) /* Used to verify lookaside not used for schema */
   602    601   
          602  +#ifdef SQLITE_DEBUG
   603    603     /* Record the number of outstanding lookaside allocations in schema Tables
   604    604     ** prior to doing any free() operations.  Since schema Tables do not use
   605    605     ** lookaside, this number should not change. */
   606         -  TESTONLY( nLookaside = (db && (pTable->tabFlags & TF_Ephemeral)==0) ?
   607         -                         db->lookaside.nOut : 0 );
          606  +  int nLookaside = 0;
          607  +  if( db && (pTable->tabFlags & TF_Ephemeral)==0 ){
          608  +    nLookaside = sqlite3LookasideUsed(db, 0);
          609  +  }
          610  +#endif
   608    611   
   609    612     /* Delete all indices associated with this table. */
   610    613     for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
   611    614       pNext = pIndex->pNext;
   612    615       assert( pIndex->pSchema==pTable->pSchema
   613    616            || (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) );
   614    617       if( (db==0 || db->pnBytesFreed==0) && !IsVirtual(pTable) ){
................................................................................
   634    637     sqlite3ExprListDelete(db, pTable->pCheck);
   635    638   #ifndef SQLITE_OMIT_VIRTUALTABLE
   636    639     sqlite3VtabClear(db, pTable);
   637    640   #endif
   638    641     sqlite3DbFree(db, pTable);
   639    642   
   640    643     /* Verify that no lookaside memory was used by schema tables */
   641         -  assert( nLookaside==0 || nLookaside==db->lookaside.nOut );
          644  +  assert( nLookaside==0 || nLookaside==sqlite3LookasideUsed(db,0) );
   642    645   }
   643    646   void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
   644    647     /* Do not delete the table until the reference count reaches zero. */
   645    648     if( !pTable ) return;
   646    649     if( ((!db || db->pnBytesFreed==0) && (--pTable->nTabRef)>0) ) return;
   647    650     deleteTable(db, pTable);
   648    651   }

Changes to src/main.c.

   654    654   ** space for the lookaside memory is obtained from sqlite3_malloc().
   655    655   ** If pStart is not NULL then it is sz*cnt bytes of memory to use for
   656    656   ** the lookaside memory.
   657    657   */
   658    658   static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
   659    659   #ifndef SQLITE_OMIT_LOOKASIDE
   660    660     void *pStart;
   661         -  if( db->lookaside.nOut ){
          661  +  
          662  +  if( sqlite3LookasideUsed(db,0)>0 ){
   662    663       return SQLITE_BUSY;
   663    664     }
   664    665     /* Free any existing lookaside buffer for this handle before
   665    666     ** allocating a new one so we don't have to have space for 
   666    667     ** both at the same time.
   667    668     */
   668    669     if( db->lookaside.bMalloced ){
................................................................................
   682    683       pStart = sqlite3Malloc( sz*cnt );  /* IMP: R-61949-35727 */
   683    684       sqlite3EndBenignMalloc();
   684    685       if( pStart ) cnt = sqlite3MallocSize(pStart)/sz;
   685    686     }else{
   686    687       pStart = pBuf;
   687    688     }
   688    689     db->lookaside.pStart = pStart;
          690  +  db->lookaside.pInit = 0;
   689    691     db->lookaside.pFree = 0;
   690    692     db->lookaside.sz = (u16)sz;
   691    693     if( pStart ){
   692    694       int i;
   693    695       LookasideSlot *p;
   694    696       assert( sz > (int)sizeof(LookasideSlot*) );
          697  +    db->lookaside.nSlot = cnt;
   695    698       p = (LookasideSlot*)pStart;
   696    699       for(i=cnt-1; i>=0; i--){
   697         -      p->pNext = db->lookaside.pFree;
   698         -      db->lookaside.pFree = p;
          700  +      p->pNext = db->lookaside.pInit;
          701  +      db->lookaside.pInit = p;
   699    702         p = (LookasideSlot*)&((u8*)p)[sz];
   700    703       }
   701    704       db->lookaside.pEnd = p;
   702    705       db->lookaside.bDisable = 0;
   703    706       db->lookaside.bMalloced = pBuf==0 ?1:0;
   704    707     }else{
   705    708       db->lookaside.pStart = db;
   706    709       db->lookaside.pEnd = db;
   707    710       db->lookaside.bDisable = 1;
   708    711       db->lookaside.bMalloced = 0;
          712  +    db->lookaside.nSlot = 0;
   709    713     }
   710    714   #endif /* SQLITE_OMIT_LOOKASIDE */
   711    715     return SQLITE_OK;
   712    716   }
   713    717   
   714    718   /*
   715    719   ** Return the mutex associated with a database connection.
................................................................................
  1221   1225     ** the same sqliteMalloc() as the one that allocates the database 
  1222   1226     ** structure?
  1223   1227     */
  1224   1228     sqlite3DbFree(db, db->aDb[1].pSchema);
  1225   1229     sqlite3_mutex_leave(db->mutex);
  1226   1230     db->magic = SQLITE_MAGIC_CLOSED;
  1227   1231     sqlite3_mutex_free(db->mutex);
  1228         -  assert( db->lookaside.nOut==0 );  /* Fails on a lookaside memory leak */
         1232  +  assert( sqlite3LookasideUsed(db,0)==0 );
  1229   1233     if( db->lookaside.bMalloced ){
  1230   1234       sqlite3_free(db->lookaside.pStart);
  1231   1235     }
  1232   1236     sqlite3_free(db);
  1233   1237   }
  1234   1238   
  1235   1239   /*

Changes to src/malloc.c.

   350    350         LookasideSlot *pBuf = (LookasideSlot*)p;
   351    351   #ifdef SQLITE_DEBUG
   352    352         /* Trash all content in the buffer being freed */
   353    353         memset(p, 0xaa, db->lookaside.sz);
   354    354   #endif
   355    355         pBuf->pNext = db->lookaside.pFree;
   356    356         db->lookaside.pFree = pBuf;
   357         -      db->lookaside.nOut--;
   358    357         return;
   359    358       }
   360    359     }
   361    360     assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
   362    361     assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
   363    362     assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
   364    363     sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
................................................................................
   511    510     assert( db!=0 );
   512    511     assert( sqlite3_mutex_held(db->mutex) );
   513    512     assert( db->pnBytesFreed==0 );
   514    513     if( db->lookaside.bDisable==0 ){
   515    514       assert( db->mallocFailed==0 );
   516    515       if( n>db->lookaside.sz ){
   517    516         db->lookaside.anStat[1]++;
   518         -    }else if( (pBuf = db->lookaside.pFree)==0 ){
   519         -      db->lookaside.anStat[2]++;
   520         -    }else{
          517  +    }else if( (pBuf = db->lookaside.pFree)!=0 ){
   521    518         db->lookaside.pFree = pBuf->pNext;
   522         -      db->lookaside.nOut++;
          519  +      db->lookaside.anStat[0]++;
          520  +      return (void*)pBuf;
          521  +    }else if( (pBuf = db->lookaside.pInit)!=0 ){
          522  +      db->lookaside.pInit = pBuf->pNext;
   523    523         db->lookaside.anStat[0]++;
   524         -      if( db->lookaside.nOut>db->lookaside.mxOut ){
   525         -        db->lookaside.mxOut = db->lookaside.nOut;
   526         -      }
   527    524         return (void*)pBuf;
          525  +    }else{
          526  +      db->lookaside.anStat[2]++;
   528    527       }
   529    528     }else if( db->mallocFailed ){
   530    529       return 0;
   531    530     }
   532    531   #else
   533    532     assert( db!=0 );
   534    533     assert( sqlite3_mutex_held(db->mutex) );

Changes to src/sqliteInt.h.

  1241   1241   ** schema information, the Lookaside.bEnabled flag is cleared so that
  1242   1242   ** lookaside allocations are not used to construct the schema objects.
  1243   1243   */
  1244   1244   struct Lookaside {
  1245   1245     u32 bDisable;           /* Only operate the lookaside when zero */
  1246   1246     u16 sz;                 /* Size of each buffer in bytes */
  1247   1247     u8 bMalloced;           /* True if pStart obtained from sqlite3_malloc() */
  1248         -  int nOut;               /* Number of buffers currently checked out */
  1249         -  int mxOut;              /* Highwater mark for nOut */
  1250         -  int anStat[3];          /* 0: hits.  1: size misses.  2: full misses */
         1248  +  u32 nSlot;              /* Number of lookaside slots allocated */
         1249  +  u32 anStat[3];          /* 0: hits.  1: size misses.  2: full misses */
         1250  +  LookasideSlot *pInit;   /* List of buffers not previously used */
  1251   1251     LookasideSlot *pFree;   /* List of available buffers */
  1252   1252     void *pStart;           /* First byte of available memory space */
  1253   1253     void *pEnd;             /* First byte past end of available space */
  1254   1254   };
  1255   1255   struct LookasideSlot {
  1256   1256     LookasideSlot *pNext;    /* Next buffer in the list of free buffers */
  1257   1257   };
................................................................................
  3571   3571   # define sqlite3MemoryBarrier()
  3572   3572   #endif
  3573   3573   
  3574   3574   sqlite3_int64 sqlite3StatusValue(int);
  3575   3575   void sqlite3StatusUp(int, int);
  3576   3576   void sqlite3StatusDown(int, int);
  3577   3577   void sqlite3StatusHighwater(int, int);
         3578  +int sqlite3LookasideUsed(sqlite3*,int*);
  3578   3579   
  3579   3580   /* Access to mutexes used by sqlite3_status() */
  3580   3581   sqlite3_mutex *sqlite3Pcache1Mutex(void);
  3581   3582   sqlite3_mutex *sqlite3MallocMutex(void);
  3582   3583   
  3583   3584   #ifndef SQLITE_OMIT_FLOATING_POINT
  3584   3585     int sqlite3IsNaN(double);

Changes to src/status.c.

   165    165     rc = sqlite3_status64(op, &iCur, &iHwtr, resetFlag);
   166    166     if( rc==0 ){
   167    167       *pCurrent = (int)iCur;
   168    168       *pHighwater = (int)iHwtr;
   169    169     }
   170    170     return rc;
   171    171   }
          172  +
          173  +/*
          174  +** Return the number of LookasideSlot elements on the linked list
          175  +*/
          176  +static u32 countLookasideSlots(LookasideSlot *p){
          177  +  u32 cnt = 0;
          178  +  while( p ){
          179  +    p = p->pNext;
          180  +    cnt++;
          181  +  }
          182  +  return cnt;
          183  +}
          184  +
          185  +/*
          186  +** Count the number of slots of lookaside memory that are outstanding
          187  +*/
          188  +int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){
          189  +  u32 nInit = countLookasideSlots(db->lookaside.pInit);
          190  +  u32 nFree = countLookasideSlots(db->lookaside.pFree);
          191  +  if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit;
          192  +  return db->lookaside.nSlot - (nInit+nFree);
          193  +}
   172    194   
   173    195   /*
   174    196   ** Query status information for a single database connection
   175    197   */
   176    198   int sqlite3_db_status(
   177    199     sqlite3 *db,          /* The database connection whose status is desired */
   178    200     int op,               /* Status verb */
................................................................................
   185    207     if( !sqlite3SafetyCheckOk(db) || pCurrent==0|| pHighwater==0 ){
   186    208       return SQLITE_MISUSE_BKPT;
   187    209     }
   188    210   #endif
   189    211     sqlite3_mutex_enter(db->mutex);
   190    212     switch( op ){
   191    213       case SQLITE_DBSTATUS_LOOKASIDE_USED: {
   192         -      *pCurrent = db->lookaside.nOut;
   193         -      *pHighwater = db->lookaside.mxOut;
          214  +      *pCurrent = sqlite3LookasideUsed(db, pHighwater);
   194    215         if( resetFlag ){
   195         -        db->lookaside.mxOut = db->lookaside.nOut;
          216  +        LookasideSlot *p = db->lookaside.pFree;
          217  +        if( p ){
          218  +          while( p->pNext ) p = p->pNext;
          219  +          p->pNext = db->lookaside.pInit;
          220  +          db->lookaside.pInit = db->lookaside.pFree;
          221  +          db->lookaside.pFree = 0;
          222  +        }
   196    223         }
   197    224         break;
   198    225       }
   199    226   
   200    227       case SQLITE_DBSTATUS_LOOKASIDE_HIT:
   201    228       case SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE:
   202    229       case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: {