Index: src/malloc.c ================================================================== --- src/malloc.c +++ src/malloc.c @@ -257,14 +257,13 @@ /* ** Do a memory allocation with statistics and alarms. Assume the ** lock is already held. */ -static int mallocWithAlarm( +static void *mallocWithAlarm( void *(*xAlloc)(int), /* Memory allocation function */ - int n, /* Bytes of memory to allocate */ - void **pp /* OUT: Pointer to allocation */ + int n /* Bytes of memory to allocate */ ){ int nFull; void *p; assert( sqlite3_mutex_held(mem0.mutex) ); @@ -292,12 +291,12 @@ if( p ){ nFull = sqlite3MallocSize(p); sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nFull); sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, 1); } - *pp = p; - return nFull; + + return p; } /* ** Use allocator function xAlloc to allocate n bytes of memory. */ @@ -315,11 +314,11 @@ ** 255 bytes of overhead. SQLite itself will never use anything near ** this amount. The only way to reach the limit is with sqlite3_malloc() */ p = 0; }else if( sqlite3GlobalConfig.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); - mallocWithAlarm(xAlloc, n, &p); + p = mallocWithAlarm(xAlloc, n); sqlite3_mutex_leave(mem0.mutex); }else{ p = xAlloc(n); } assert( EIGHT_BYTE_ALIGNMENT(p) ); /* IMP: R-04675-44850 */ @@ -386,12 +385,15 @@ sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n); sqlite3_mutex_leave(mem0.mutex); }else{ if( sqlite3GlobalConfig.bMemstat ){ sqlite3StatusSet(SQLITE_STATUS_SCRATCH_SIZE, n); - n = mallocWithAlarm(sqlite3GlobalConfig.m.xMalloc, n, &p); - if( p ) sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, n); + p = mallocWithAlarm(sqlite3GlobalConfig.m.xMalloc, n); + if( p ){ + n = sqlite3MallocSize(p); + sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, n); + } sqlite3_mutex_leave(mem0.mutex); }else{ sqlite3_mutex_leave(mem0.mutex); p = sqlite3GlobalConfig.m.xMalloc(n); } @@ -595,12 +597,43 @@ #endif return sqlite3Realloc(pOld, n); } /* -** Allocate and, if bZero is true, zero memory. If the allocation -** fails, set the mallocFailed flag in the connection pointer. +** Attempt to allocate an n byte block from the lookaside buffer of +** connection db. If successful, return a pointer to the new allocation. +** Otherwise, return a NULL pointer. +*/ +#ifndef SQLITE_OMIT_LOOKASIDE +static void *lookasideAlloc(sqlite3 *db, int n){ + if( db->lookaside.bEnabled ){ + if( n>db->lookaside.sz ){ + db->lookaside.anStat[1]++; + }else{ + LookasideSlot *pBuf; + if( (pBuf = db->lookaside.pFree)==0 ){ + db->lookaside.anStat[2]++; + }else{ + db->lookaside.pFree = pBuf->pNext; + db->lookaside.nOut++; + db->lookaside.anStat[0]++; + if( db->lookaside.nOut>db->lookaside.mxOut ){ + db->lookaside.mxOut = db->lookaside.nOut; + } + } + return (void*)pBuf; + } + } + return 0; +} +#else +# define lookasideAlloc(x,y) 0 +#endif + +/* +** Allocate and zero memory. If the allocation fails, set the +** mallocFailed flag in the connection pointer. ** ** If db!=0 and db->mallocFailed is true (indicating a prior malloc ** failure on the same database connection) then always return 0. ** Hence for a particular database connection, once malloc starts ** failing, it fails consistently until mallocFailed is reset. @@ -612,69 +645,55 @@ ** if( b ) a[10] = 9; ** ** In other words, if a subsequent malloc (ex: "b") worked, it is assumed ** that all prior mallocs (ex: "a") worked too. */ -static void *dbMalloc(sqlite3 *db, int n, int bZero){ +void *sqlite3DbMallocZero(sqlite3 *db, int n){ void *p; - assert( db==0 || sqlite3_mutex_held(db->mutex) ); - assert( db==0 || db->pnBytesFreed==0 ); -#ifndef SQLITE_OMIT_LOOKASIDE - if( db ){ - LookasideSlot *pBuf; - if( db->mallocFailed ){ - return 0; - } - if( db->lookaside.bEnabled ){ - if( n>db->lookaside.sz ){ - db->lookaside.anStat[1]++; - }else if( (pBuf = db->lookaside.pFree)==0 ){ - db->lookaside.anStat[2]++; - }else{ - db->lookaside.pFree = pBuf->pNext; - db->lookaside.nOut++; - db->lookaside.anStat[0]++; - if( db->lookaside.nOut>db->lookaside.mxOut ){ - db->lookaside.mxOut = db->lookaside.nOut; - } - if( bZero ) memset(pBuf, 0, n); - return (void*)pBuf; - } + if( db==0 ){ + p = memAllocate(sqlite3GlobalConfig.m.xCalloc, n); + }else if( db->mallocFailed ){ + p = 0; + }else{ + if( (p = lookasideAlloc(db, n)) ){ + memset(p, 0, n); + }else{ + p = memAllocate(sqlite3GlobalConfig.m.xCalloc, n); + if( !p ) db->mallocFailed = 1; } } -#else - if( db && db->mallocFailed ){ - return 0; - } -#endif - if( bZero ){ - p = sqlite3MallocZero(n); - }else{ - p = sqlite3Malloc(n); - } - if( !p && db ){ - db->mallocFailed = 1; - } + sqlite3MemdebugSetType(p, MEMTYPE_DB | ((db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP)); return p; -} - -/* -** Allocate and zero memory. If the allocation fails, set the -** mallocFailed flag in the connection pointer. -*/ -void *sqlite3DbMallocZero(sqlite3 *db, int n){ - return dbMalloc(db, n, 1); } /* ** Allocate memory. If the allocation fails, make the mallocFailed ** flag in the connection pointer. +** +** If db!=0 and db->mallocFailed is true (indicating a prior malloc +** failure on the same database connection) then always return 0. +** See also comments above sqlite3DbMallocZero() for details. */ void *sqlite3DbMallocRaw(sqlite3 *db, int n){ - return dbMalloc(db, n, 0); + void *p; + if( db==0 ){ + p = memAllocate(sqlite3GlobalConfig.m.xMalloc, n); + }else if( db->mallocFailed ){ + p = 0; + }else{ + p = lookasideAlloc(db, n); + if( !p ){ + p = memAllocate(sqlite3GlobalConfig.m.xMalloc, n); + if( !p ) db->mallocFailed = 1; + } + } + + sqlite3MemdebugSetType(p, MEMTYPE_DB | + ((db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP)); + return p; } /* ** Resize the block of memory pointed to by p to n bytes. If the ** resize fails, set the mallocFailed flag in the connection object. Index: src/mem1.c ================================================================== --- src/mem1.c +++ src/mem1.c @@ -100,47 +100,64 @@ #endif #endif /* __APPLE__ or not __APPLE__ */ /* -** Like malloc() (if bZero==0) or calloc() (if bZero!=0), except remember -** the size of the allocation so that we can find it later using -** sqlite3MemSize(). +** A memory allocation of nByte bytes has failed. Log an error message +** using sqlite3_log(). +*/ +static void logAllocationError(int nByte){ + testcase( sqlite3GlobalConfig.xLog!=0 ); + sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte); +} + +/* +** Allocate nByte bytes of memory. +** +** For this low-level routine, we are guaranteed that nByte>0 because +** cases of nByte<=0 will be intercepted and dealt with by higher level +** routines. +*/ +static void *sqlite3MemMalloc(int nByte){ + i64 *p; +#ifdef SQLITE_MALLOCSIZE + p = SQLITE_MALLOC(nByte); + if( p==0 ){ +#else + nByte = ROUND8(nByte); + p = SQLITE_MALLOC(nByte+8); + if( p ){ + *(p++) = (i64)nByte; + }else{ +#endif + logAllocationError(nByte); + } + return (void *)p; +} + +/* +** Allocate and zero nByte bytes of memory. ** ** For this low-level routine, we are guaranteed that nByte>0 because ** cases of nByte<=0 will be intercepted and dealt with by higher level ** routines. */ -static void *memMalloc(int nByte, int bZero){ +static void *sqlite3MemCalloc(int nByte){ + i64 *p; #ifdef SQLITE_MALLOCSIZE - void *p = (bZero ? SQLITE_CALLOC( nByte ) : SQLITE_MALLOC( nByte )); + p = SQLITE_CALLOC(nByte); if( p==0 ){ - testcase( sqlite3GlobalConfig.xLog!=0 ); - sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte); - } - return p; #else - sqlite3_int64 *p; - assert( nByte>0 ); nByte = ROUND8(nByte); - p = (bZero ? SQLITE_CALLOC( nByte+8 ) : SQLITE_MALLOC( nByte+8 )); + p = SQLITE_CALLOC(nByte+8); if( p ){ - p[0] = nByte; - p++; + *(p++) = (i64)nByte; }else{ - testcase( sqlite3GlobalConfig.xLog!=0 ); - sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes of memory", nByte); +#endif + logAllocationError(nByte); } return (void *)p; -#endif -} - -static void *sqlite3MemMalloc(int nByte){ - return memMalloc(nByte, 0); -} -static void *sqlite3MemCalloc(int nByte){ - return memMalloc(nByte, 1); } /* ** Like free() but works for allocations obtained from sqlite3MemMalloc() ** or sqlite3MemRealloc().