Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix memory leaks on this branch. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | reuse-schema |
Files: | files | file ages | folders |
SHA3-256: |
e9c5e1891ff4f7e57131031f068efea8 |
User & Date: | dan 2019-02-05 19:15:36.531 |
Context
2019-02-05
| ||
19:51 | Merge latest trunk into this branch. (check-in: c089cc4fbe user: dan tags: reuse-schema) | |
19:15 | Fix memory leaks on this branch. (check-in: e9c5e1891f user: dan tags: reuse-schema) | |
2019-02-04
| ||
21:02 | Fix a problem with reloading the schema on this branch. (check-in: 5dfbef8349 user: dan tags: reuse-schema) | |
Changes
Changes to src/callback.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | ** ** This file contains functions used to access the internal hash tables ** of user defined functions and collation sequences. */ #include "sqliteInt.h" struct SchemaPool { int nRef; /* Number of pointers to this object */ u64 cksum; /* Checksum for this Schema contents */ Schema *pSchema; /* Linked list of Schema objects */ Schema sSchema; /* The single dummy schema object */ SchemaPool *pNext; /* Next element in schemaPoolList */ }; /* ** Invoke the 'collation needed' callback to request a collation sequence ** in the encoding enc of name zName, length nName. */ static void callCollNeeded(sqlite3 *db, int enc, const char *zName){ assert( !db->xCollNeeded || !db->xCollNeeded16 ); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | ** ** This file contains functions used to access the internal hash tables ** of user defined functions and collation sequences. */ #include "sqliteInt.h" /* ** Connections opened with the SQLITE_OPEN_REUSE_SCHEMA flag specified ** may use SchemaPool objects for any database that is not the temp db ** (iDb==1). For such databases (type "struct Db") there are three states ** the Schema/SchemaPool object may be in. ** ** 1) pSPool==0, pSchema points to an empty object allocated by ** sqlite3_malloc(). DB_SchemaLoaded flag is clear. ** ** 2) pSPool!=0, pSchema points to a populated object owned by the ** SchemaPool. DB_SchemaLoaded flag is set. ** ** 3) pSPool!=0, pSchema points to the SchemaPool's static object ** (SchemaPool.sSchema). */ struct SchemaPool { int nRef; /* Number of pointers to this object */ u64 cksum; /* Checksum for this Schema contents */ Schema *pSchema; /* Linked list of Schema objects */ Schema sSchema; /* The single dummy schema object */ SchemaPool *pNext; /* Next element in schemaPoolList */ }; #ifdef SQLITE_DEBUG static void assert_schema_state_ok(sqlite3 *db){ if( IsReuseSchema(db) ){ int i; for(i=0; i<db->nDb; i++){ if( i!=1 ){ Db *pDb = &db->aDb[i]; Btree *pBt = pDb->pBt; if( pDb->pSPool ){ if( DbHasProperty(db, i, DB_SchemaLoaded)==0 ){ assert( pDb->pSchema->tblHash.count==0 ); assert( pDb->pSchema==&pDb->pSPool->sSchema ); }else{ assert( pBt==0 || pDb->pSchema!=sqlite3BtreeSchema(pBt, 0, 0) ); assert( pDb->pSchema!=&pDb->pSPool->sSchema ); } }else{ assert( DbHasProperty(db, i, DB_SchemaLoaded)==0 ); assert( pDb->pSchema->tblHash.count==0 ); assert( pBt==0 || pDb->pSchema!=sqlite3BtreeSchema(pBt, 0, 0) ); assert( pDb->pSchema!=&pDb->pSPool->sSchema ); } } } } } #else # define assert_schema_state_ok(x) #endif /* ** Invoke the 'collation needed' callback to request a collation sequence ** in the encoding enc of name zName, length nName. */ static void callCollNeeded(sqlite3 *db, int enc, const char *zName){ assert( !db->xCollNeeded || !db->xCollNeeded16 ); |
︙ | ︙ | |||
489 490 491 492 493 494 495 | void sqlite3SchemaZero(sqlite3 *db, int iDb){ Db *pDb = &db->aDb[iDb]; if( IsReuseSchema(db) && iDb!=1 ){ if( pDb->pSPool ){ Schema *pNew = sqlite3SchemaGet(db, 0); if( pNew ){ | | | 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 | void sqlite3SchemaZero(sqlite3 *db, int iDb){ Db *pDb = &db->aDb[iDb]; if( IsReuseSchema(db) && iDb!=1 ){ if( pDb->pSPool ){ Schema *pNew = sqlite3SchemaGet(db, 0); if( pNew ){ sqlite3SchemaDisconnect(db, iDb, 0); pDb->pSchema = pNew; } return; } } sqlite3SchemaClear(pDb->pSchema); } |
︙ | ︙ | |||
522 523 524 525 526 527 528 529 530 531 532 533 534 535 | } } static void schemaDelete(Schema *pSchema){ sqlite3SchemaClear((void*)pSchema); sqlite3_free(pSchema); } /* ** The schema for database iDb of database handle db, which was opened ** with SQLITE_OPEN_REUSE_SCHEMA, has just been parsed. This function either ** finds a matching SchemaPool object on the global list (schemaPoolList) or ** else allocates a new one and sets the Db.pSPool variable accordingly. */ | > > > > > > > > > > > > | 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 | } } static void schemaDelete(Schema *pSchema){ sqlite3SchemaClear((void*)pSchema); sqlite3_free(pSchema); } static void schemaRelease(Db *pDb){ assert( pDb->pSPool && pDb->pSchema ); assert( pDb->pSchema->schemaFlags & DB_SchemaLoaded ); assert( sqlite3_mutex_held(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER)) ); pDb->pSchema->pNext = pDb->pSPool->pSchema; pDb->pSPool->pSchema = pDb->pSchema; pDb->pSchema = &pDb->pSPool->sSchema; assert( (pDb->pSchema->schemaFlags & DB_SchemaLoaded)==0 ); } /* ** The schema for database iDb of database handle db, which was opened ** with SQLITE_OPEN_REUSE_SCHEMA, has just been parsed. This function either ** finds a matching SchemaPool object on the global list (schemaPoolList) or ** else allocates a new one and sets the Db.pSPool variable accordingly. */ |
︙ | ︙ | |||
576 577 578 579 580 581 582 | sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); db->aDb[iDb].pSPool = p; return (p ? SQLITE_OK : SQLITE_NOMEM); } | | > > | < > | | > > > > | > | > > > > > > > > > > > > | > | | | | | | | | | | | | | > | | > > | 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 | sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); db->aDb[iDb].pSPool = p; return (p ? SQLITE_OK : SQLITE_NOMEM); } int sqlite3SchemaDisconnect(sqlite3 *db, int iDb, int bNew){ int rc = SQLITE_OK; if( IsReuseSchema(db) && iDb!=1 ){ Db *pDb = &db->aDb[iDb]; SchemaPool *pSPool = pDb->pSPool; assert_schema_state_ok(db); assert( pDb->pSchema ); if( pSPool==0 ){ if( bNew==0 ){ schemaDelete(pDb->pSchema); pDb->pSchema = 0; } }else{ sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); if( DbHasProperty(db, iDb, DB_SchemaLoaded) ){ schemaRelease(pDb); } if( bNew ){ Schema *pNew = sqlite3SchemaGet(db, 0); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ pDb->pSchema = pNew; } } if( rc==SQLITE_OK ){ assert( pSPool->nRef>=1 ); pDb->pSPool = 0; pSPool->nRef--; if( pSPool->nRef<=0 ){ Schema *pNext; SchemaPool **pp; while( pSPool->pSchema ){ Schema *pNext = pSPool->pSchema->pNext; schemaDelete(pSPool->pSchema); pSPool->pSchema = pNext; } for(pp=&schemaPoolList; (*pp)!=pSPool; pp=&((*pp)->pNext)); *pp = pSPool->pNext; sqlite3_free(pSPool); } } sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); } } return rc; } /* ** Extract and return a pointer to a schema object from the SchemaPool passed ** as the only argument, if one is available. If one is not available, return ** NULL. */ |
︙ | ︙ | |||
623 624 625 626 627 628 629 630 631 632 633 | sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); } return pRet; } void sqlite3SchemaReleaseAll(sqlite3 *db){ int i; for(i=0; i<db->nDb; i++){ if( i!=1 ){ Db *pDb = &db->aDb[i]; if( pDb->pSPool && pDb->pSchema && DbHasProperty(db,i,DB_SchemaLoaded) ){ | > > < < | < < < > | 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 | sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); } return pRet; } void sqlite3SchemaReleaseAll(sqlite3 *db){ int i; assert_schema_state_ok(db); sqlite3_mutex_enter( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); for(i=0; i<db->nDb; i++){ if( i!=1 ){ Db *pDb = &db->aDb[i]; if( pDb->pSPool && pDb->pSchema && DbHasProperty(db,i,DB_SchemaLoaded) ){ schemaRelease(pDb); } } } sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); } /* ** Find and return the schema associated with a BTree. Create ** a new one if necessary. */ Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){ |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
1181 1182 1183 1184 1185 1186 1187 | /* Close all database connections */ for(j=0; j<db->nDb; j++){ struct Db *pDb = &db->aDb[j]; if( pDb->pBt ){ sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; if( j!=1 ){ | | | 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 | /* Close all database connections */ for(j=0; j<db->nDb; j++){ struct Db *pDb = &db->aDb[j]; if( pDb->pBt ){ sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; if( j!=1 ){ sqlite3SchemaDisconnect(db, j, 0); pDb->pSchema = 0; } } } /* Clear the TEMP schema separately and last */ if( db->aDb[1].pSchema ){ sqlite3SchemaClear(db->aDb[1].pSchema); |
︙ | ︙ |
Changes to src/prepare.c.
︙ | ︙ | |||
188 189 190 191 192 193 194 | assert( IsReuseSchema(db) ); /* See if there is a free schema object in the schema-pool. If not, ** disconnect from said schema pool and continue. This function will ** connect to a (possibly different) schema-pool before returning. */ if( (pDb->pSchema = sqlite3SchemaExtract(pDb->pSPool)) ){ return SQLITE_OK; } | | < < < < | < > | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | assert( IsReuseSchema(db) ); /* See if there is a free schema object in the schema-pool. If not, ** disconnect from said schema pool and continue. This function will ** connect to a (possibly different) schema-pool before returning. */ if( (pDb->pSchema = sqlite3SchemaExtract(pDb->pSPool)) ){ return SQLITE_OK; } rc = sqlite3SchemaDisconnect(db, iDb, 1); if( rc!=SQLITE_OK ) goto error_out; assert( pDb->pSchema && pDb->pSPool==0 ); } db->init.busy = 1; /* Construct the in-memory representation schema tables (sqlite_master or ** sqlite_temp_master) by invoking the parser directly. The appropriate ** table name will be inserted automatically by the parser so we can just |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
4290 4291 4292 4293 4294 4295 4296 | int sqlite3AnalysisLoad(sqlite3*,int iDB); void sqlite3DeleteIndexSamples(sqlite3*,Index*); void sqlite3DefaultRowEst(Index*); void sqlite3RegisterLikeFunctions(sqlite3*, int); int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); void sqlite3SchemaClear(void *); int sqlite3SchemaConnect(sqlite3*, int, u64); | | | 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 | int sqlite3AnalysisLoad(sqlite3*,int iDB); void sqlite3DeleteIndexSamples(sqlite3*,Index*); void sqlite3DefaultRowEst(Index*); void sqlite3RegisterLikeFunctions(sqlite3*, int); int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); void sqlite3SchemaClear(void *); int sqlite3SchemaConnect(sqlite3*, int, u64); int sqlite3SchemaDisconnect(sqlite3 *, int, int); void sqlite3SchemaZero(sqlite3*, int); Schema *sqlite3SchemaExtract(SchemaPool*); void sqlite3SchemaReleaseAll(sqlite3 *); void sqlite3SchemaWritable(Parse*, int); Schema *sqlite3SchemaGet(sqlite3 *, Btree *); int sqlite3SchemaToIndex(sqlite3 *db, Schema *); KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int,int); |
︙ | ︙ |
Changes to test/reuse1.test.
︙ | ︙ | |||
32 33 34 35 36 37 38 | PRAGMA schema_version; } {2} do_test 1.2 { db close db2 close sqlite3 db2 test.db2 -reuse-schema 1 | | | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | PRAGMA schema_version; } {2} do_test 1.2 { db close db2 close sqlite3 db2 test.db2 -reuse-schema 1 sqlite3 db test.db -reuse-schema 1 } {} do_execsql_test -db db2 1.3.1 { INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 6); } |
︙ | ︙ |
Changes to test/tester.tcl.
︙ | ︙ | |||
2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 | foreach f $lStack { set frames($f) 1 } } set tbl2 "CREATE TABLE ${database}.frame(frame INTEGER PRIMARY KEY, line);\n" set tbl3 "CREATE TABLE ${database}.file(name PRIMARY KEY, content);\n" foreach f [array names frames] { set addr [format %x $f] | > > | | 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 | foreach f $lStack { set frames($f) 1 } } set tbl2 "CREATE TABLE ${database}.frame(frame INTEGER PRIMARY KEY, line);\n" set tbl3 "CREATE TABLE ${database}.file(name PRIMARY KEY, content);\n" set pid [pid] foreach f [array names frames] { set addr [format %x $f] set cmd "eu-addr2line --pid=$pid $addr" set line [eval exec $cmd] append sql "INSERT INTO ${database}.frame VALUES($f, '$line');\n" set file [lindex [split $line :] 0] set files($file) 1 } |
︙ | ︙ |