Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do fewer mallocs #2037

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 102 additions & 105 deletions libstuff/sqlite3.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
** separate file. This file contains only code for the core SQLite library.
**
** The content in this amalgamation comes from Fossil check-in
** fa87355f6286be1e92f22a71cbfbfb13d1a4.
** b40cd7395c44b1f2d019d8e809e03de0e083.
*/
#define SQLITE_CORE 1
#define SQLITE_AMALGAMATION 1
Expand Down Expand Up @@ -465,7 +465,7 @@ extern "C" {
*/
#define SQLITE_VERSION "3.47.0"
#define SQLITE_VERSION_NUMBER 3047000
#define SQLITE_SOURCE_ID "2024-12-13 18:13:51 fa87355f6286be1e92f22a71cbfbfb13d1a478d5fb5b38abedbd78bf903171fa"
#define SQLITE_SOURCE_ID "2024-12-20 19:37:41 b40cd7395c44b1f2d019d8e809e03de0e083c93693322a72ddb250a85640528f"

/*
** CAPI3REF: Run-Time Library Version Numbers
Expand Down Expand Up @@ -17859,6 +17859,9 @@ struct Schema {
u8 enc; /* Text encoding used by this database */
u16 schemaFlags; /* Flags associated with this schema */
int cache_size; /* Number of pages to use in the cache */
#ifdef SQLITE_ENABLE_STAT4
void *pStat4Space; /* Memory for stat4 Index.aSample[] arrays */
#endif
};

/*
Expand Down Expand Up @@ -18238,11 +18241,13 @@ struct sqlite3 {
#define SCHEMA_TIME_AFTER_STAT1 12
#define SCHEMA_TIME_AFTER_DEFAULTS 13

#define SCHEMA_TIME_STAT4_Q1_BODY 14
#define SCHEMA_TIME_AFTER_STAT4_Q1 15
#define SCHEMA_TIME_STAT4_Q2_BODY 16
#define SCHEMA_TIME_STAT4_SAMPLE_MALLOC 17
#define SCHEMA_TIME_AFTER_STAT4_Q2 18
#define SCHEMA_TIME_AFTER_STAT4_SPACE 14
#define SCHEMA_TIME_AFTER_STAT4_PREPARE 15

#define SCHEMA_TIME_STAT4_GROWUS 16
#define SCHEMA_TIME_STAT4_Q2_BODYUS 17
#define SCHEMA_TIME_AFTER_STAT4_Q2 18

#define SCHEMA_TIME_AFTER_STAT4 19

#define SCHEMA_TIME_END_ANALYZE_LOAD 20
Expand Down Expand Up @@ -93492,7 +93497,7 @@ SQLITE_PRIVATE void sqlite3CommitTimeLog(u64 *aCommit){
}
zStr = sqlite3_mprintf("%z%s%s%d%s", zStr, (zStr?", ":""),zHash,iVal,zU);
}
sqlite3_log(SQLITE_WARNING, "slow commit (v=19): (%s)", zStr);
sqlite3_log(SQLITE_WARNING, "slow commit (v=20): (%s)", zStr);
sqlite3_free(zStr);
}
}
Expand Down Expand Up @@ -93520,7 +93525,7 @@ SQLITE_PRIVATE void sqlite3PrepareTimeLog(const char *zSql, int nSql, u64 *aPrep
}
if( nByte<0 ){ nByte = sqlite3Strlen30(zSql); }
sqlite3_log(SQLITE_WARNING,
"slow prepare (v=19): (%s) [%.*s]", zStr, nByte, zSql
"slow prepare (v=20): (%s) [%.*s]", zStr, nByte, zSql
);
sqlite3_free(zStr);
}
Expand All @@ -93534,15 +93539,14 @@ SQLITE_PRIVATE void sqlite3SchemaTimeLog(u64 *aSchema, const char *zFile){
for(ii=1; ii<SCHEMA_TIME_N; ii++){
int val = aSchema[ii];
if( val!=0
&& ii!=SCHEMA_TIME_STAT4_Q1_BODY
&& ii!=SCHEMA_TIME_STAT4_Q2_BODY
&& ii!=SCHEMA_TIME_STAT4_SAMPLE_MALLOC
&& ii!=SCHEMA_TIME_STAT4_Q2_BODYUS
&& ii!=SCHEMA_TIME_STAT4_GROWUS
){
val -= i1;
}
zStr = sqlite3_mprintf("%z%s%d", zStr, (zStr?", ":""), val);
}
sqlite3_log(SQLITE_WARNING, "slow schema (%s) (v=19): (%s)", zFile, zStr);
sqlite3_log(SQLITE_WARNING, "slow schema (%s) (v=20): (%s)", zFile, zStr);
sqlite3_free(zStr);
}
}
Expand Down Expand Up @@ -122276,6 +122280,13 @@ static void openStatTable(
# define SQLITE_STAT4_SAMPLES 24
#endif

/*
** Assumed number of of samples when loading sqlite_stat4 data. It doesn't
** matter if there are more or fewer samples than this, but is more efficient
** if this estimate turns out to be true.
*/
#define SQLITE_STAT4_EST_SAMPLES SQLITE_STAT4_SAMPLES

/*
** Three SQL functions - stat_init(), stat_push(), and stat_get() -
** share an instance of the following structure to hold their state
Expand Down Expand Up @@ -123695,7 +123706,9 @@ SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){
IndexSample *p = &pIdx->aSample[j];
sqlite3DbFree(db, p->p);
}
sqlite3DbFree(db, pIdx->aSample);
if( pIdx->nSampleAlloc!=SQLITE_STAT4_EST_SAMPLES ){
sqlite3DbFree(db, pIdx->aSample);
}
}
if( db->pnBytesFreed==0 ){
pIdx->nSample = 0;
Expand Down Expand Up @@ -123789,7 +123802,7 @@ static Index *findIndexOrPrimaryKey(
** Grow the pIdx->aSample[] array. Return SQLITE_OK if successful, or
** SQLITE_NOMEM otherwise.
*/
static int growSampleArray(sqlite3 *db, Index *pIdx){
static int growSampleArray(sqlite3 *db, Index *pIdx, int *piOff){
int nIdxCol = pIdx->nSampleCol;
int nNew = 0;
IndexSample *aNew = 0;
Expand All @@ -123799,31 +123812,24 @@ static int growSampleArray(sqlite3 *db, Index *pIdx){
int i;
u64 t;

/* In production set the initial allocation to SQLITE_STAT4_SAMPLES. This
** means that reallocation will almost never be required. But for debug
** builds, set the initial allocation size to 6 entries so that the
** reallocation code gets tested. todo: use real tests for this. */
assert( pIdx->nSample==pIdx->nSampleAlloc );
#ifdef SQLITE_DEBUG
nNew = 6;
#else
nNew = SQLITE_STAT4_SAMPLES;
#endif
nNew = SQLITE_STAT4_EST_SAMPLES;
if( pIdx->nSample ){
nNew = pIdx->nSample*2;
}

/* Set nByte to the required amount of space */
nByte = ROUND8(sizeof(IndexSample) * nNew);
nByte += sizeof(tRowcnt) * nIdxCol * 3 * nNew;
nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */

if( db->aSchemaTime ){
t = sqlite3STimeNow();
}
aNew = (IndexSample*)sqlite3DbMallocRaw(db, nByte);
if( aNew==0 ) return SQLITE_NOMEM_BKPT;
if( db->aSchemaTime ){
db->aSchemaTime[SCHEMA_TIME_STAT4_SAMPLE_MALLOC] += (sqlite3STimeNow() - t);
if( nNew==SQLITE_STAT4_EST_SAMPLES ){
aNew = (IndexSample*)&((u8*)pIdx->pSchema->pStat4Space)[*piOff];
*piOff += nByte;
assert( *piOff<=sqlite3_msize(pIdx->pSchema->pStat4Space) );
}else{
aNew = (IndexSample*)sqlite3DbMallocRaw(db, nByte);
if( aNew==0 ) return SQLITE_NOMEM_BKPT;
}

pPtr = (u8*)aNew;
Expand All @@ -123850,15 +123856,53 @@ static int growSampleArray(sqlite3 *db, Index *pIdx){
}
assert( ((u8*)pSpace)-nByte==(u8*)aNew );

sqlite3DbFree(db, pIdx->aSample);
if( pIdx->nSample!=SQLITE_STAT4_EST_SAMPLES ){
sqlite3DbFree(db, pIdx->aSample);
}
pIdx->aSample = aNew;
pIdx->nSampleAlloc = nNew;
return SQLITE_OK;
}

/*
** Load the content from either the sqlite_stat4
** into the relevant Index.aSample[] arrays.
** Allocate the space that will likely be required for the Index.aSample[]
** arrays populated by loading data from the sqlite_stat4 table. Return
** SQLITE_OK if successful, or SQLITE_NOMEM otherwise.
*/
static int stat4AllocSpace(sqlite3 *db, const char *zDb){
int iDb = sqlite3FindDbName(db, zDb);
Schema *pSchema = db->aDb[iDb].pSchema;
int nByte = 0;
HashElem *k;

assert( iDb>=0 );
assert( pSchema->pStat4Space==0 );
for(k=sqliteHashFirst(&pSchema->idxHash); k; k=sqliteHashNext(k)){
Index *pIdx = sqliteHashData(k);
int nIdxCol;
if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
nIdxCol = pIdx->nKeyCol;
}else{
nIdxCol = pIdx->nColumn;
}
nByte += ROUND8(sizeof(IndexSample) * SQLITE_STAT4_EST_SAMPLES);
nByte += sizeof(tRowcnt) * nIdxCol * 3 * SQLITE_STAT4_EST_SAMPLES;
nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */
}

if( nByte>0 ){
pSchema->pStat4Space = sqlite3_malloc(nByte);
if( pSchema->pStat4Space==0 ){
return SQLITE_NOMEM_BKPT;
}
}

return SQLITE_OK;
}

/*
** Load the content from the sqlite_stat4 into the relevant Index.aSample[]
** arrays.
**
** Arguments zSql1 and zSql2 must point to SQL statements that return
** data equivalent to the following:
Expand All @@ -123879,78 +123923,16 @@ static int loadStatTbl(
char *zSql; /* Text of the SQL statement */
Index *pPrevIdx = 0; /* Previous index in the loop */
IndexSample *pSample; /* A slot in pIdx->aSample[] */
int iBlockOff = 0; /* Offset into Schema.pStat4Space */

assert( db->lookaside.bDisable );
#if 0
zSql = sqlite3MPrintf(db, zSql1, zDb);
if( !zSql ){
return SQLITE_NOMEM_BKPT;
}
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
sqlite3DbFree(db, zSql);
if( rc ) return rc;

while( sqlite3_step(pStmt)==SQLITE_ROW ){
int nIdxCol = 1; /* Number of columns in stat4 records */

char *zIndex; /* Index name */
Index *pIdx; /* Pointer to the index object */
int nSample; /* Number of samples */
int nByte; /* Bytes of space required */
int i; /* Bytes of space required */
tRowcnt *pSpace; /* Available allocated memory space */
u8 *pPtr; /* Available memory as a u8 for easier manipulation */

u64 t = sqlite3STimeNow();

zIndex = (char *)sqlite3_column_text(pStmt, 0);
if( zIndex==0 ) continue;
nSample = sqlite3_column_int(pStmt, 1);
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
assert( pIdx==0 || pIdx->nSample==0 );
if( pIdx==0 ) continue;
if( pIdx->aSample!=0 ){
/* The same index appears in sqlite_stat4 under multiple names */
continue;
}
assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 );
if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
nIdxCol = pIdx->nKeyCol;
}else{
nIdxCol = pIdx->nColumn;
}
pIdx->nSampleCol = nIdxCol;
pIdx->mxSample = nSample;
nByte = ROUND8(sizeof(IndexSample) * nSample);
nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample;
nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */

pIdx->aSample = sqlite3DbMallocZero(db, nByte);
if( pIdx->aSample==0 ){
sqlite3_finalize(pStmt);
return SQLITE_NOMEM_BKPT;
}
pPtr = (u8*)pIdx->aSample;
pPtr += ROUND8(nSample*sizeof(pIdx->aSample[0]));
pSpace = (tRowcnt*)pPtr;
assert( EIGHT_BYTE_ALIGNMENT( pSpace ) );
pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
pIdx->pTable->tabFlags |= TF_HasStat4;
for(i=0; i<nSample; i++){
pIdx->aSample[i].anEq = pSpace; pSpace += nIdxCol;
pIdx->aSample[i].anLt = pSpace; pSpace += nIdxCol;
pIdx->aSample[i].anDLt = pSpace; pSpace += nIdxCol;
}
assert( ((u8*)pSpace)-nByte==(u8*)(pIdx->aSample) );
if( db->aSchemaTime ){
db->aSchemaTime[SCHEMA_TIME_STAT4_Q1_BODY] += (sqlite3STimeNow() - t);
}
}
rc = sqlite3_finalize(pStmt);
if( rc ) return rc;
#endif
/* Allocate the Schema.pStat4Space block that will be used for the
** Index.aSample[] arrays populated by this call. */
rc = stat4AllocSpace(db, zDb);
if( rc!=SQLITE_OK ) return rc;

sqlite3PrepareTimeSet(db->aSchemaTime, SCHEMA_TIME_AFTER_STAT4_Q1);
sqlite3PrepareTimeSet(db->aSchemaTime, SCHEMA_TIME_AFTER_STAT4_SPACE);

zSql = sqlite3MPrintf(db, zSql2, zDb);
if( !zSql ){
Expand All @@ -123960,6 +123942,8 @@ static int loadStatTbl(
sqlite3DbFree(db, zSql);
if( rc ) return rc;

sqlite3PrepareTimeSet(db->aSchemaTime, SCHEMA_TIME_AFTER_STAT4_PREPARE);

while( sqlite3_step(pStmt)==SQLITE_ROW ){
char *zIndex; /* Index name */
Index *pIdx; /* Pointer to the index object */
Expand All @@ -123972,14 +123956,19 @@ static int loadStatTbl(
if( pIdx==0 ) continue;

if( pIdx->nSample==pIdx->nSampleAlloc ){
u64 t2;
pIdx->pTable->tabFlags |= TF_HasStat4;
assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 );
if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
pIdx->nSampleCol = pIdx->nKeyCol;
}else{
pIdx->nSampleCol = pIdx->nColumn;
}
if( growSampleArray(db, pIdx) ) break;
t2 = sqlite3STimeNow();
if( growSampleArray(db, pIdx, &iBlockOff) ) break;
if( db->aSchemaTime ){
db->aSchemaTime[SCHEMA_TIME_STAT4_GROWUS] += (sqlite3STimeNow() - t);
}
}

if( pIdx!=pPrevIdx ){
Expand Down Expand Up @@ -124012,7 +124001,7 @@ static int loadStatTbl(
pIdx->nSample++;

if( db->aSchemaTime ){
db->aSchemaTime[SCHEMA_TIME_STAT4_Q2_BODY] += (sqlite3STimeNow() - t);
db->aSchemaTime[SCHEMA_TIME_STAT4_Q2_BODYUS] += (sqlite3STimeNow() - t);
}
}
rc = sqlite3_finalize(pStmt);
Expand Down Expand Up @@ -124089,6 +124078,10 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
pIdx->aSample = 0;
#endif
}
#ifdef SQLITE_ENABLE_STAT4
sqlite3_free(pSchema->pStat4Space);
pSchema->pStat4Space = 0;
#endif

sqlite3PrepareTimeSet(db->aSchemaTime, SCHEMA_TIME_AFTER_CLEAR_STATS);

Expand Down Expand Up @@ -131355,6 +131348,10 @@ SQLITE_PRIVATE void sqlite3SchemaClear(void *p){
pSchema->iGeneration++;
}
pSchema->schemaFlags &= ~(DB_SchemaLoaded|DB_ResetWanted);
#ifdef SQLITE_ENABLE_STAT4
sqlite3_free(pSchema->pStat4Space);
pSchema->pStat4Space = 0;
#endif
}

/*
Expand Down Expand Up @@ -258029,7 +258026,7 @@ static void fts5SourceIdFunc(
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
sqlite3_result_text(pCtx, "fts5: 2024-12-13 18:13:51 fa87355f6286be1e92f22a71cbfbfb13d1a478d5fb5b38abedbd78bf903171fa", -1, SQLITE_TRANSIENT);
sqlite3_result_text(pCtx, "fts5: 2024-12-20 19:37:41 b40cd7395c44b1f2d019d8e809e03de0e083c93693322a72ddb250a85640528f", -1, SQLITE_TRANSIENT);
}

/*
Expand Down
2 changes: 1 addition & 1 deletion libstuff/sqlite3.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ extern "C" {
*/
#define SQLITE_VERSION "3.47.0"
#define SQLITE_VERSION_NUMBER 3047000
#define SQLITE_SOURCE_ID "2024-12-13 18:13:51 fa87355f6286be1e92f22a71cbfbfb13d1a478d5fb5b38abedbd78bf903171fa"
#define SQLITE_SOURCE_ID "2024-12-20 19:37:41 b40cd7395c44b1f2d019d8e809e03de0e083c93693322a72ddb250a85640528f"

/*
** CAPI3REF: Run-Time Library Version Numbers
Expand Down