--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/sql/SQLite364/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 <sys/types.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <unistd.h>
+
+
+/*
+** 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.mnPage ){
+ return 0;
+ }
+ if( mem.nPage==0 ){
+ mem.szPage = sysconf(_SC_PAGE_SIZE);
+ mem.mnPage = mem.szPage - mem.szPage/10;
+ mem.nPage = SQLITE_MMAP_HEAP_SIZE/mem.szPage;
+ if( mem.nPage * sizeof(int) > 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.firstUnused<mem.nPage ){
+ idx = mem.firstUnused++;
+ }
+ if( idx ){
+ mem.nowUsedMMap += mem.szPage;
+ if( mem.nowUsedMMap>mem.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 && idx<mem.nPage ){
+ nByte = mem.szPage;
+ }else{
+ sqlite3_int64 *p = pPrior;
+ p--;
+ nByte = (int)*p;
+ }
+ return nByte;
+}
+
+/*
+** Free memory.
+*/
+static void memsys4Free(void *pPrior){
+ sqlite3_int64 *p;
+ int nByte;
+ if( mmapFree(pPrior)==0 ){
+ p = pPrior;
+ p--;
+ nByte = (int)*p;
+ mem.nowUsed -= nByte;
+ free(p);
+ if( mem.nowUsed==0 ){
+ mmapUnmap();
+ }
+ }
+}
+
+/*
+** Allocate nBytes of memory
+*/
+void *sqlite3_malloc(int nBytes){
+ sqlite3_int64 *p = 0;
+ if( nBytes>0 ){
+ 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<nBytes ){
+ memcpy(p, pPrior, nOld);
+ }else{
+ memcpy(p, pPrior, nBytes);
+ }
+ memsys4Free(pPrior);
+ }
+ assert( mem.mutex!=0 );
+ sqlite3_mutex_leave(mem.mutex);
+ return (void*)p;
+}
+
+#endif /* SQLITE_MMAP_HEAP_SIZE */