/ Check-in [e9c5e189]
Login

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

Overview
Comment:Fix memory leaks on this branch.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | reuse-schema
Files: files | file ages | folders
SHA3-256:e9c5e1891ff4f7e57131031f068efea87027ddab0cd7846e0514a105853be47d
User & Date: dan 2019-02-05 19:15:36
Wiki:reuse-schema
Context
2019-02-05
19:51
Merge latest trunk into this branch. check-in: c089cc4f user: dan tags: reuse-schema
19:15
Fix memory leaks on this branch. check-in: e9c5e189 user: dan tags: reuse-schema
2019-02-04
21:02
Fix a problem with reloading the schema on this branch. check-in: 5dfbef83 user: dan tags: reuse-schema
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/callback.c.

    12     12   **
    13     13   ** This file contains functions used to access the internal hash tables
    14     14   ** of user defined functions and collation sequences.
    15     15   */
    16     16   
    17     17   #include "sqliteInt.h"
    18     18   
           19  +/*
           20  +** Connections opened with the SQLITE_OPEN_REUSE_SCHEMA flag specified
           21  +** may use SchemaPool objects for any database that is not the temp db
           22  +** (iDb==1). For such databases (type "struct Db") there are three states
           23  +** the Schema/SchemaPool object may be in.
           24  +**
           25  +**   1) pSPool==0, pSchema points to an empty object allocated by
           26  +**      sqlite3_malloc(). DB_SchemaLoaded flag is clear.
           27  +**
           28  +**   2) pSPool!=0, pSchema points to a populated object owned by the
           29  +**      SchemaPool. DB_SchemaLoaded flag is set.
           30  +**
           31  +**   3) pSPool!=0, pSchema points to the SchemaPool's static object
           32  +**      (SchemaPool.sSchema).
           33  +*/
    19     34   struct SchemaPool {
    20     35     int nRef;                       /* Number of pointers to this object */
    21     36     u64 cksum;                      /* Checksum for this Schema contents */
    22     37     Schema *pSchema;                /* Linked list of Schema objects */
    23     38     Schema sSchema;                 /* The single dummy schema object */
    24     39     SchemaPool *pNext;              /* Next element in schemaPoolList */
    25     40   };
           41  +
           42  +#ifdef SQLITE_DEBUG
           43  +static void assert_schema_state_ok(sqlite3 *db){
           44  +  if( IsReuseSchema(db) ){
           45  +    int i;
           46  +    for(i=0; i<db->nDb; i++){
           47  +      if( i!=1 ){
           48  +        Db *pDb = &db->aDb[i];
           49  +        Btree *pBt = pDb->pBt;
           50  +        if( pDb->pSPool ){
           51  +          if( DbHasProperty(db, i, DB_SchemaLoaded)==0 ){
           52  +            assert( pDb->pSchema->tblHash.count==0 );
           53  +            assert( pDb->pSchema==&pDb->pSPool->sSchema );
           54  +          }else{
           55  +            assert( pBt==0 || pDb->pSchema!=sqlite3BtreeSchema(pBt, 0, 0) );
           56  +            assert( pDb->pSchema!=&pDb->pSPool->sSchema );
           57  +          }
           58  +        }else{
           59  +          assert( DbHasProperty(db, i, DB_SchemaLoaded)==0 );
           60  +          assert( pDb->pSchema->tblHash.count==0 );
           61  +          assert( pBt==0 || pDb->pSchema!=sqlite3BtreeSchema(pBt, 0, 0) );
           62  +          assert( pDb->pSchema!=&pDb->pSPool->sSchema );
           63  +        }
           64  +      }
           65  +    }
           66  +  }
           67  +}
           68  +#else
           69  +# define assert_schema_state_ok(x)
           70  +#endif
    26     71   
    27     72   /*
    28     73   ** Invoke the 'collation needed' callback to request a collation sequence
    29     74   ** in the encoding enc of name zName, length nName.
    30     75   */
    31     76   static void callCollNeeded(sqlite3 *db, int enc, const char *zName){
    32     77     assert( !db->xCollNeeded || !db->xCollNeeded16 );
................................................................................
   489    534   
   490    535   void sqlite3SchemaZero(sqlite3 *db, int iDb){
   491    536     Db *pDb = &db->aDb[iDb];
   492    537     if( IsReuseSchema(db) && iDb!=1 ){
   493    538       if( pDb->pSPool ){
   494    539         Schema *pNew = sqlite3SchemaGet(db, 0);
   495    540         if( pNew ){
   496         -        sqlite3SchemaDisconnect(db, iDb);
          541  +        sqlite3SchemaDisconnect(db, iDb, 0);
   497    542           pDb->pSchema = pNew;
   498    543         }
   499    544         return;
   500    545       }
   501    546     }
   502    547     sqlite3SchemaClear(pDb->pSchema);
   503    548   }
................................................................................
   522    567     }
   523    568   }
   524    569   
   525    570   static void schemaDelete(Schema *pSchema){
   526    571     sqlite3SchemaClear((void*)pSchema);
   527    572     sqlite3_free(pSchema);
   528    573   }
          574  +
          575  +static void schemaRelease(Db *pDb){
          576  +  assert( pDb->pSPool && pDb->pSchema );
          577  +  assert( pDb->pSchema->schemaFlags & DB_SchemaLoaded );
          578  +  assert( sqlite3_mutex_held(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)) );
          579  +
          580  +  pDb->pSchema->pNext = pDb->pSPool->pSchema;
          581  +  pDb->pSPool->pSchema = pDb->pSchema;
          582  +  pDb->pSchema = &pDb->pSPool->sSchema;
          583  +
          584  +  assert( (pDb->pSchema->schemaFlags & DB_SchemaLoaded)==0 );
          585  +}
   529    586   
   530    587   /*
   531    588   ** The schema for database iDb of database handle db, which was opened
   532    589   ** with SQLITE_OPEN_REUSE_SCHEMA, has just been parsed. This function either
   533    590   ** finds a matching SchemaPool object on the global list (schemaPoolList) or
   534    591   ** else allocates a new one and sets the Db.pSPool variable accordingly.
   535    592   */
................................................................................
   576    633   
   577    634     sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
   578    635   
   579    636     db->aDb[iDb].pSPool = p;
   580    637     return (p ? SQLITE_OK : SQLITE_NOMEM);
   581    638   }
   582    639   
   583         -void sqlite3SchemaDisconnect(sqlite3 *db, int iDb){
   584         -  Db *pDb = &db->aDb[iDb];
   585         -  if( pDb->pSPool ){
          640  +int sqlite3SchemaDisconnect(sqlite3 *db, int iDb, int bNew){
          641  +  int rc = SQLITE_OK;
          642  +  if( IsReuseSchema(db) && iDb!=1 ){
          643  +    Db *pDb = &db->aDb[iDb];
   586    644       SchemaPool *pSPool = pDb->pSPool;
   587         -    pDb->pSPool = 0;
   588         -    assert( iDb!=1 );
          645  +    assert_schema_state_ok(db);
          646  +    assert( pDb->pSchema );
   589    647   
   590         -    sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
   591         -    assert( pSPool->nRef>=1 );
   592         -    pSPool->nRef--;
   593         -    if( pSPool->nRef<=0 ){
   594         -      Schema *pNext;
   595         -      SchemaPool **pp;
   596         -      while( pSPool->pSchema ){
   597         -        Schema *pNext = pSPool->pSchema->pNext;
   598         -        schemaDelete(pSPool->pSchema);
   599         -        pSPool->pSchema = pNext;
          648  +    if( pSPool==0 ){
          649  +      if( bNew==0 ){
          650  +        schemaDelete(pDb->pSchema);
          651  +        pDb->pSchema = 0;
          652  +      }
          653  +    }else{
          654  +      sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
          655  +      if( DbHasProperty(db, iDb, DB_SchemaLoaded) ){
          656  +        schemaRelease(pDb);
          657  +      }
          658  +      if( bNew ){
          659  +        Schema *pNew = sqlite3SchemaGet(db, 0);
          660  +        if( pNew==0 ){
          661  +          rc = SQLITE_NOMEM;
          662  +        }else{
          663  +          pDb->pSchema = pNew;
          664  +        }
          665  +      }
          666  +      if( rc==SQLITE_OK ){
          667  +        assert( pSPool->nRef>=1 );
          668  +        pDb->pSPool = 0;
          669  +        pSPool->nRef--;
          670  +        if( pSPool->nRef<=0 ){
          671  +          Schema *pNext;
          672  +          SchemaPool **pp;
          673  +          while( pSPool->pSchema ){
          674  +            Schema *pNext = pSPool->pSchema->pNext;
          675  +            schemaDelete(pSPool->pSchema);
          676  +            pSPool->pSchema = pNext;
          677  +          }
          678  +          for(pp=&schemaPoolList; (*pp)!=pSPool; pp=&((*pp)->pNext));
          679  +          *pp = pSPool->pNext;
          680  +          sqlite3_free(pSPool);
          681  +        }
   600    682         }
   601         -      for(pp=&schemaPoolList; (*pp)!=pSPool; pp=&((*pp)->pNext));
   602         -      *pp = pSPool->pNext;
   603         -      sqlite3_free(pSPool);
          683  +      sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
   604    684       }
   605         -    sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
   606    685     }
          686  +  return rc;
   607    687   }
   608    688   
   609    689   /*
   610    690   ** Extract and return a pointer to a schema object from the SchemaPool passed
   611    691   ** as the only argument, if one is available. If one is not available, return
   612    692   ** NULL.
   613    693   */
................................................................................
   623    703       sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
   624    704     }
   625    705     return pRet;
   626    706   }
   627    707   
   628    708   void sqlite3SchemaReleaseAll(sqlite3 *db){
   629    709     int i;
          710  +  assert_schema_state_ok(db);
          711  +  sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
   630    712     for(i=0; i<db->nDb; i++){
   631    713       if( i!=1 ){
   632    714         Db *pDb = &db->aDb[i];
   633    715         if( pDb->pSPool && pDb->pSchema && DbHasProperty(db,i,DB_SchemaLoaded) ){
   634         -        sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
   635         -        pDb->pSchema->pNext = pDb->pSPool->pSchema;
   636         -        pDb->pSPool->pSchema = pDb->pSchema;
   637         -        pDb->pSchema = &pDb->pSPool->sSchema;
   638         -        assert( DbHasProperty(db, i, DB_SchemaLoaded)==0 );
   639         -        sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
          716  +        schemaRelease(pDb);
   640    717         }
   641    718       }
   642    719     }
          720  +  sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) );
   643    721   }
   644    722   
   645    723   /*
   646    724   ** Find and return the schema associated with a BTree.  Create
   647    725   ** a new one if necessary.
   648    726   */
   649    727   Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){

Changes to src/main.c.

  1181   1181     /* Close all database connections */
  1182   1182     for(j=0; j<db->nDb; j++){
  1183   1183       struct Db *pDb = &db->aDb[j];
  1184   1184       if( pDb->pBt ){
  1185   1185         sqlite3BtreeClose(pDb->pBt);
  1186   1186         pDb->pBt = 0;
  1187   1187         if( j!=1 ){
  1188         -        sqlite3SchemaDisconnect(db, j);
         1188  +        sqlite3SchemaDisconnect(db, j, 0);
  1189   1189           pDb->pSchema = 0;
  1190   1190         }
  1191   1191       }
  1192   1192     }
  1193   1193     /* Clear the TEMP schema separately and last */
  1194   1194     if( db->aDb[1].pSchema ){
  1195   1195       sqlite3SchemaClear(db->aDb[1].pSchema);

Changes to src/prepare.c.

   188    188       assert( IsReuseSchema(db) );
   189    189       /* See if there is a free schema object in the schema-pool. If not,
   190    190       ** disconnect from said schema pool and continue. This function will
   191    191       ** connect to a (possibly different) schema-pool before returning. */
   192    192       if( (pDb->pSchema = sqlite3SchemaExtract(pDb->pSPool)) ){
   193    193         return SQLITE_OK;
   194    194       }
   195         -    sqlite3SchemaDisconnect(db, iDb);
   196         -    assert( pDb->pSchema==0 && pDb->pSPool==0 );
   197         -    pDb->pSchema = sqlite3SchemaGet(db, 0);
   198         -    if( pDb->pSchema==0 ){
   199         -      rc = SQLITE_NOMEM_BKPT;
   200         -      goto error_out;
   201         -    }
          195  +    rc = sqlite3SchemaDisconnect(db, iDb, 1);
          196  +    if( rc!=SQLITE_OK ) goto error_out;
          197  +    assert( pDb->pSchema && pDb->pSPool==0 );
   202    198     }
   203    199   
   204    200     db->init.busy = 1;
   205    201   
   206    202     /* Construct the in-memory representation schema tables (sqlite_master or
   207    203     ** sqlite_temp_master) by invoking the parser directly.  The appropriate
   208    204     ** table name will be inserted automatically by the parser so we can just

Changes to src/sqliteInt.h.

  4290   4290   int sqlite3AnalysisLoad(sqlite3*,int iDB);
  4291   4291   void sqlite3DeleteIndexSamples(sqlite3*,Index*);
  4292   4292   void sqlite3DefaultRowEst(Index*);
  4293   4293   void sqlite3RegisterLikeFunctions(sqlite3*, int);
  4294   4294   int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);
  4295   4295   void sqlite3SchemaClear(void *);
  4296   4296   int sqlite3SchemaConnect(sqlite3*, int, u64);
  4297         -void sqlite3SchemaDisconnect(sqlite3 *, int);
         4297  +int sqlite3SchemaDisconnect(sqlite3 *, int, int);
  4298   4298   void sqlite3SchemaZero(sqlite3*, int);
  4299   4299   Schema *sqlite3SchemaExtract(SchemaPool*);
  4300   4300   void sqlite3SchemaReleaseAll(sqlite3 *);
  4301   4301   void sqlite3SchemaWritable(Parse*, int);
  4302   4302   Schema *sqlite3SchemaGet(sqlite3 *, Btree *);
  4303   4303   int sqlite3SchemaToIndex(sqlite3 *db, Schema *);
  4304   4304   KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int,int);

Changes to test/reuse1.test.

    32     32     PRAGMA schema_version;
    33     33   } {2}
    34     34   
    35     35   do_test 1.2 {
    36     36     db close
    37     37     db2 close
    38     38     sqlite3 db2 test.db2 -reuse-schema 1
    39         -  sqlite3 db  test.db -reuse-schema 1
           39  +  sqlite3 db test.db -reuse-schema 1
    40     40   } {}
    41     41   
    42     42   do_execsql_test -db db2 1.3.1 {
    43     43     INSERT INTO t1 VALUES(1, 2, 3);
    44     44     INSERT INTO t1 VALUES(4, 5, 6);
    45     45   }
    46     46   

Changes to test/tester.tcl.

  2043   2043       foreach f $lStack {
  2044   2044         set frames($f) 1
  2045   2045       }
  2046   2046     }
  2047   2047   
  2048   2048     set tbl2 "CREATE TABLE ${database}.frame(frame INTEGER PRIMARY KEY, line);\n"
  2049   2049     set tbl3 "CREATE TABLE ${database}.file(name PRIMARY KEY, content);\n"
         2050  +
         2051  +  set pid [pid]
  2050   2052   
  2051   2053     foreach f [array names frames] {
  2052   2054       set addr [format %x $f]
  2053         -    set cmd "addr2line -e [info nameofexec] $addr"
         2055  +    set cmd "eu-addr2line --pid=$pid $addr"
  2054   2056       set line [eval exec $cmd]
  2055   2057       append sql "INSERT INTO ${database}.frame VALUES($f, '$line');\n"
  2056   2058   
  2057   2059       set file [lindex [split $line :] 0]
  2058   2060       set files($file) 1
  2059   2061     }
  2060   2062