diff -r 000000000000 -r 08ec8eefde2f persistentstorage/sql/SQLite/mem4.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/persistentstorage/sql/SQLite/mem4.c Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,393 @@ +/* +** 2007 August 14 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file contains the C functions that implement a memory +** allocation subsystem for use by SQLite. +** +** $Id: mem4.c,v 1.3 2008/06/18 17:09:10 danielk1977 Exp $ +*/ +#include "sqliteInt.h" + +/* +** This version of the memory allocator attempts to obtain memory +** from mmap() if the size of the allocation is close to the size +** of a virtual memory page. If the size of the allocation is different +** from the virtual memory page size, then ordinary malloc() is used. +** Ordinary malloc is also used if space allocated to mmap() is +** exhausted. +** +** Enable this memory allocation by compiling with -DSQLITE_MMAP_HEAP_SIZE=nnn +** where nnn is the maximum number of bytes of mmap-ed memory you want +** to support. This module may choose to use less memory than requested. +** +*/ +#ifdef SQLITE_MMAP_HEAP_SIZE + +/* +** This is a test version of the memory allocator that attempts to +** use mmap() and madvise() for allocations and frees of approximately +** the virtual memory page size. +*/ +#include +#include +#include +#include + + +/* +** All of the static variables used by this module are collected +** into a single structure named "mem". This is to keep the +** static variables organized and to reduce namespace pollution +** when this module is combined with other in the amalgamation. +*/ +static struct { + /* + ** The alarm callback and its arguments. The mem.mutex lock will + ** be held while the callback is running. Recursive calls into + ** the memory subsystem are allowed, but no new callbacks will be + ** issued. The alarmBusy variable is set to prevent recursive + ** callbacks. + */ + sqlite3_int64 alarmThreshold; + void (*alarmCallback)(void*, sqlite3_int64,int); + void *alarmArg; + int alarmBusy; + + /* + ** Mutex to control access to the memory allocation subsystem. + */ + sqlite3_mutex *mutex; + + /* + ** Current allocation and high-water mark. + */ + sqlite3_int64 nowUsed; + sqlite3_int64 mxUsed; + + /* + ** Current allocation and high-water marks for mmap allocated memory. + */ + sqlite3_int64 nowUsedMMap; + sqlite3_int64 mxUsedMMap; + + /* + ** Size of a single mmap page. Obtained from sysconf(). + */ + int szPage; + int mnPage; + + /* + ** The number of available mmap pages. + */ + int nPage; + + /* + ** Index of the first free page. 0 means no pages have been freed. + */ + int firstFree; + + /* First unused page on the top of the heap. + */ + int firstUnused; + + /* + ** Bulk memory obtained from from mmap(). + */ + char *mmapHeap; /* first byte of the heap */ + +} mem; + + +/* +** Enter the mutex mem.mutex. Allocate it if it is not already allocated. +** The mmap() region is initialized the first time this routine is called. +*/ +static void memsys4Enter(void){ + if( mem.mutex==0 ){ + mem.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); + } + sqlite3_mutex_enter(mem.mutex); +} + +/* +** Attempt to free memory to the mmap heap. This only works if +** the pointer p is within the range of memory addresses that +** comprise the mmap heap. Return 1 if the memory was freed +** successfully. Return 0 if the pointer is out of range. +*/ +static int mmapFree(void *p){ + char *z; + int idx, *a; + if( mem.mmapHeap==MAP_FAILED || mem.nPage==0 ){ + return 0; + } + z = (char*)p; + idx = (z - mem.mmapHeap)/mem.szPage; + if( idx<1 || idx>=mem.nPage ){ + return 0; + } + a = (int*)mem.mmapHeap; + a[idx] = a[mem.firstFree]; + mem.firstFree = idx; + mem.nowUsedMMap -= mem.szPage; + madvise(p, mem.szPage, MADV_DONTNEED); + return 1; +} + +/* +** Attempt to allocate nBytes from the mmap heap. Return a pointer +** to the allocated page. Or, return NULL if the allocation fails. +** +** The allocation will fail if nBytes is not the right size. +** Or, the allocation will fail if the mmap heap has been exhausted. +*/ +static void *mmapAlloc(int nBytes){ + int idx = 0; + if( nBytes>mem.szPage || nBytes mem.szPage ){ + mem.nPage = mem.szPage/sizeof(int); + } + mem.mmapHeap = mmap(0, mem.szPage*mem.nPage, PROT_WRITE|PROT_READ, + MAP_ANONYMOUS|MAP_SHARED, -1, 0); + if( mem.mmapHeap==MAP_FAILED ){ + mem.firstUnused = errno; + }else{ + mem.firstUnused = 1; + mem.nowUsedMMap = mem.szPage; + } + } + if( mem.mmapHeap==MAP_FAILED ){ + return 0; + } + if( mem.firstFree ){ + int idx = mem.firstFree; + int *a = (int*)mem.mmapHeap; + mem.firstFree = a[idx]; + }else if( mem.firstUnusedmem.mxUsedMMap ){ + mem.mxUsedMMap = mem.nowUsedMMap; + } + return (void*)&mem.mmapHeap[idx*mem.szPage]; + }else{ + return 0; + } +} + +/* +** Release the mmap-ed memory region if it is currently allocated and +** is not in use. +*/ +static void mmapUnmap(void){ + if( mem.mmapHeap==MAP_FAILED ) return; + if( mem.nPage==0 ) return; + if( mem.nowUsedMMap>mem.szPage ) return; + munmap(mem.mmapHeap, mem.nPage*mem.szPage); + mem.nowUsedMMap = 0; + mem.nPage = 0; +} + + +/* +** Return the amount of memory currently checked out. +*/ +sqlite3_int64 sqlite3_memory_used(void){ + sqlite3_int64 n; + memsys4Enter(); + n = mem.nowUsed + mem.nowUsedMMap; + sqlite3_mutex_leave(mem.mutex); + return n; +} + +/* +** Return the maximum amount of memory that has ever been +** checked out since either the beginning of this process +** or since the most recent reset. +*/ +sqlite3_int64 sqlite3_memory_highwater(int resetFlag){ + sqlite3_int64 n; + memsys4Enter(); + n = mem.mxUsed + mem.mxUsedMMap; + if( resetFlag ){ + mem.mxUsed = mem.nowUsed; + mem.mxUsedMMap = mem.nowUsedMMap; + } + sqlite3_mutex_leave(mem.mutex); + return n; +} + +/* +** Change the alarm callback +*/ +int sqlite3_memory_alarm( + void(*xCallback)(void *pArg, sqlite3_int64 used,int N), + void *pArg, + sqlite3_int64 iThreshold +){ + memsys4Enter(); + mem.alarmCallback = xCallback; + mem.alarmArg = pArg; + mem.alarmThreshold = iThreshold; + sqlite3_mutex_leave(mem.mutex); + return SQLITE_OK; +} + +/* +** Trigger the alarm +*/ +static void sqlite3MemsysAlarm(int nByte){ + void (*xCallback)(void*,sqlite3_int64,int); + sqlite3_int64 nowUsed; + void *pArg; + if( mem.alarmCallback==0 || mem.alarmBusy ) return; + mem.alarmBusy = 1; + xCallback = mem.alarmCallback; + nowUsed = mem.nowUsed; + pArg = mem.alarmArg; + sqlite3_mutex_leave(mem.mutex); + xCallback(pArg, nowUsed, nByte); + sqlite3_mutex_enter(mem.mutex); + mem.alarmBusy = 0; +} + +/* +** Allocate nBytes of memory +*/ +static void *memsys4Malloc(int nBytes){ + sqlite3_int64 *p = 0; + if( mem.alarmCallback!=0 + && mem.nowUsed+mem.nowUsedMMap+nBytes>=mem.alarmThreshold ){ + sqlite3MemsysAlarm(nBytes); + } + if( (p = mmapAlloc(nBytes))==0 ){ + p = malloc(nBytes+8); + if( p==0 ){ + sqlite3MemsysAlarm(nBytes); + p = malloc(nBytes+8); + } + if( p ){ + p[0] = nBytes; + p++; + mem.nowUsed += nBytes; + if( mem.nowUsed>mem.mxUsed ){ + mem.mxUsed = mem.nowUsed; + } + } + } + return (void*)p; +} + +/* +** Return the size of a memory allocation +*/ +static int memsys4Size(void *pPrior){ + char *z = (char*)pPrior; + int idx = mem.nPage ? (z - mem.mmapHeap)/mem.szPage : 0; + int nByte; + if( idx>=1 && idx0 ){ + memsys4Enter(); + p = memsys4Malloc(nBytes); + sqlite3_mutex_leave(mem.mutex); + } + return (void*)p; +} + +/* +** Free memory. +*/ +void sqlite3_free(void *pPrior){ + if( pPrior==0 ){ + return; + } + assert( mem.mutex!=0 ); + sqlite3_mutex_enter(mem.mutex); + memsys4Free(pPrior); + sqlite3_mutex_leave(mem.mutex); +} + + + +/* +** Change the size of an existing memory allocation +*/ +void *sqlite3_realloc(void *pPrior, int nBytes){ + int nOld; + sqlite3_int64 *p; + if( pPrior==0 ){ + return sqlite3_malloc(nBytes); + } + if( nBytes<=0 ){ + sqlite3_free(pPrior); + return 0; + } + nOld = memsys4Size(pPrior); + if( nBytes<=nOld && nBytes>=nOld-128 ){ + return pPrior; + } + assert( mem.mutex!=0 ); + sqlite3_mutex_enter(mem.mutex); + p = memsys4Malloc(nBytes); + if( p ){ + if( nOld