engine/sqlite/src/mem4.cpp
changeset 2 29cda98b007e
equal deleted inserted replaced
1:5f8e5adbbed9 2:29cda98b007e
       
     1 /*
       
     2 ** 2007 August 14
       
     3 **
       
     4 ** The author disclaims copyright to this source code.  In place of
       
     5 ** a legal notice, here is a blessing:
       
     6 **
       
     7 **    May you do good and not evil.
       
     8 **    May you find forgiveness for yourself and forgive others.
       
     9 **    May you share freely, never taking more than you give.
       
    10 **
       
    11 *************************************************************************
       
    12 ** This file contains the C functions that implement a memory
       
    13 ** allocation subsystem for use by SQLite.  
       
    14 **
       
    15 ** $Id: mem4.cpp 1282 2008-11-13 09:31:33Z LarsPson $
       
    16 */
       
    17 
       
    18 /*
       
    19 ** This version of the memory allocator attempts to obtain memory
       
    20 ** from mmap() if the size of the allocation is close to the size
       
    21 ** of a virtual memory page.  If the size of the allocation is different
       
    22 ** from the virtual memory page size, then ordinary malloc() is used.
       
    23 ** Ordinary malloc is also used if space allocated to mmap() is
       
    24 ** exhausted.
       
    25 **
       
    26 ** Enable this memory allocation by compiling with -DSQLITE_MMAP_HEAP_SIZE=nnn
       
    27 ** where nnn is the maximum number of bytes of mmap-ed memory you want 
       
    28 ** to support.   This module may choose to use less memory than requested.
       
    29 **
       
    30 */
       
    31 #if defined(SQLITE_MMAP_HEAP_SIZE)
       
    32 
       
    33 #if defined(SQLITE_MEMDEBUG) || defined(SQLITE_MEMORY_SIZE)
       
    34 # error cannot use SQLITE_MMAP_HEAP_SIZE with either SQLITE_MEMDEBUG \
       
    35         or SQLITE_MEMORY_SIZE
       
    36 #endif
       
    37 
       
    38 /*
       
    39 ** This is a test version of the memory allocator that attempts to
       
    40 ** use mmap() and madvise() for allocations and frees of approximately
       
    41 ** the virtual memory page size.
       
    42 */
       
    43 #include <sys/types.h>
       
    44 #include <sys/mman.h>
       
    45 #include <errno.h>
       
    46 #include "sqliteInt.h"
       
    47 #include <unistd.h>
       
    48 
       
    49 
       
    50 /*
       
    51 ** All of the static variables used by this module are collected
       
    52 ** into a single structure named "mem".  This is to keep the
       
    53 ** static variables organized and to reduce namespace pollution
       
    54 ** when this module is combined with other in the amalgamation.
       
    55 */
       
    56 static struct {
       
    57   /*
       
    58   ** The alarm callback and its arguments.  The mem.mutex lock will
       
    59   ** be held while the callback is running.  Recursive calls into
       
    60   ** the memory subsystem are allowed, but no new callbacks will be
       
    61   ** issued.  The alarmBusy variable is set to prevent recursive
       
    62   ** callbacks.
       
    63   */
       
    64   sqlite3_int64 alarmThreshold;
       
    65   void (*alarmCallback)(void*, sqlite3_int64,int);
       
    66   void *alarmArg;
       
    67   int alarmBusy;
       
    68   
       
    69   /*
       
    70   ** Mutex to control access to the memory allocation subsystem.
       
    71   */
       
    72   sqlite3_mutex *mutex;
       
    73   
       
    74   /*
       
    75   ** Current allocation and high-water mark.
       
    76   */
       
    77   sqlite3_int64 nowUsed;
       
    78   sqlite3_int64 mxUsed;
       
    79 
       
    80   /*
       
    81   ** Current allocation and high-water marks for mmap allocated memory.
       
    82   */
       
    83   sqlite3_int64 nowUsedMMap;
       
    84   sqlite3_int64 mxUsedMMap;
       
    85 
       
    86   /*
       
    87   ** Size of a single mmap page.  Obtained from sysconf().
       
    88   */
       
    89   int szPage;
       
    90   int mnPage;
       
    91 
       
    92   /*
       
    93   ** The number of available mmap pages.
       
    94   */
       
    95   int nPage;
       
    96 
       
    97   /*
       
    98   ** Index of the first free page.  0 means no pages have been freed.
       
    99   */
       
   100   int firstFree;
       
   101 
       
   102   /* First unused page on the top of the heap.
       
   103   */
       
   104   int firstUnused;
       
   105 
       
   106   /*
       
   107   ** Bulk memory obtained from from mmap().
       
   108   */
       
   109   char *mmapHeap;   /* first byte of the heap */ 
       
   110 
       
   111 } mem;
       
   112 
       
   113 
       
   114 /*
       
   115 ** Enter the mutex mem.mutex. Allocate it if it is not already allocated.
       
   116 ** The mmap() region is initialized the first time this routine is called.
       
   117 */
       
   118 static void memsys4Enter(void){
       
   119   if( mem.mutex==0 ){
       
   120     mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);
       
   121   }
       
   122   sqlite3_mutex_enter(mem.mutex);
       
   123 }
       
   124 
       
   125 /*
       
   126 ** Attempt to free memory to the mmap heap.  This only works if
       
   127 ** the pointer p is within the range of memory addresses that
       
   128 ** comprise the mmap heap.  Return 1 if the memory was freed
       
   129 ** successfully.  Return 0 if the pointer is out of range.
       
   130 */
       
   131 static int mmapFree(void *p){
       
   132   char *z;
       
   133   int idx, *a;
       
   134   if( mem.mmapHeap==MAP_FAILED || mem.nPage==0 ){
       
   135     return 0;
       
   136   }
       
   137   z = (char*)p;
       
   138   idx = (z - mem.mmapHeap)/mem.szPage;
       
   139   if( idx<1 || idx>=mem.nPage ){
       
   140     return 0;
       
   141   }
       
   142   a = (int*)mem.mmapHeap;
       
   143   a[idx] = a[mem.firstFree];
       
   144   mem.firstFree = idx;
       
   145   mem.nowUsedMMap -= mem.szPage;
       
   146   madvise(p, mem.szPage, MADV_DONTNEED);
       
   147   return 1;
       
   148 }
       
   149 
       
   150 /*
       
   151 ** Attempt to allocate nBytes from the mmap heap.  Return a pointer
       
   152 ** to the allocated page.  Or, return NULL if the allocation fails.
       
   153 ** 
       
   154 ** The allocation will fail if nBytes is not the right size.
       
   155 ** Or, the allocation will fail if the mmap heap has been exhausted.
       
   156 */
       
   157 static void *mmapAlloc(int nBytes){
       
   158   int idx = 0;
       
   159   if( nBytes>mem.szPage || nBytes<mem.mnPage ){
       
   160     return 0;
       
   161   }
       
   162   if( mem.nPage==0 ){
       
   163     mem.szPage = sysconf(_SC_PAGE_SIZE);
       
   164     mem.mnPage = mem.szPage - mem.szPage/10;
       
   165     mem.nPage = SQLITE_MMAP_HEAP_SIZE/mem.szPage;
       
   166     if( mem.nPage * sizeof(int) > mem.szPage ){
       
   167       mem.nPage = mem.szPage/sizeof(int);
       
   168     }
       
   169     mem.mmapHeap =  mmap(0, mem.szPage*mem.nPage, PROT_WRITE|PROT_READ,
       
   170                          MAP_ANONYMOUS|MAP_SHARED, -1, 0);
       
   171     if( mem.mmapHeap==MAP_FAILED ){
       
   172       mem.firstUnused = errno;
       
   173     }else{
       
   174       mem.firstUnused = 1;
       
   175       mem.nowUsedMMap = mem.szPage;
       
   176     }
       
   177   }
       
   178   if( mem.mmapHeap==MAP_FAILED ){
       
   179     return 0;
       
   180   }
       
   181   if( mem.firstFree ){
       
   182     int idx = mem.firstFree;
       
   183     int *a = (int*)mem.mmapHeap;
       
   184     mem.firstFree = a[idx];
       
   185   }else if( mem.firstUnused<mem.nPage ){
       
   186     idx = mem.firstUnused++;
       
   187   }
       
   188   if( idx ){
       
   189     mem.nowUsedMMap += mem.szPage;
       
   190     if( mem.nowUsedMMap>mem.mxUsedMMap ){
       
   191       mem.mxUsedMMap = mem.nowUsedMMap;
       
   192     }
       
   193     return (void*)&mem.mmapHeap[idx*mem.szPage];
       
   194   }else{
       
   195     return 0;
       
   196   }
       
   197 }
       
   198 
       
   199 /*
       
   200 ** Release the mmap-ed memory region if it is currently allocated and
       
   201 ** is not in use.
       
   202 */
       
   203 static void mmapUnmap(void){
       
   204   if( mem.mmapHeap==MAP_FAILED ) return;
       
   205   if( mem.nPage==0 ) return;
       
   206   if( mem.nowUsedMMap>mem.szPage ) return;
       
   207   munmap(mem.mmapHeap, mem.nPage*mem.szPage);
       
   208   mem.nowUsedMMap = 0;
       
   209   mem.nPage = 0;
       
   210 }
       
   211     
       
   212 
       
   213 /*
       
   214 ** Return the amount of memory currently checked out.
       
   215 */
       
   216 sqlite3_int64 sqlite3_memory_used(void){
       
   217   sqlite3_int64 n;
       
   218   memsys4Enter();
       
   219   n = mem.nowUsed + mem.nowUsedMMap;
       
   220   sqlite3_mutex_leave(mem.mutex);  
       
   221   return n;
       
   222 }
       
   223 
       
   224 /*
       
   225 ** Return the maximum amount of memory that has ever been
       
   226 ** checked out since either the beginning of this process
       
   227 ** or since the most recent reset.
       
   228 */
       
   229 sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
       
   230   sqlite3_int64 n;
       
   231   memsys4Enter();
       
   232   n = mem.mxUsed + mem.mxUsedMMap;
       
   233   if( resetFlag ){
       
   234     mem.mxUsed = mem.nowUsed;
       
   235     mem.mxUsedMMap = mem.nowUsedMMap;
       
   236   }
       
   237   sqlite3_mutex_leave(mem.mutex);  
       
   238   return n;
       
   239 }
       
   240 
       
   241 /*
       
   242 ** Change the alarm callback
       
   243 */
       
   244 int sqlite3_memory_alarm(
       
   245   void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
       
   246   void *pArg,
       
   247   sqlite3_int64 iThreshold
       
   248 ){
       
   249   memsys4Enter();
       
   250   mem.alarmCallback = xCallback;
       
   251   mem.alarmArg = pArg;
       
   252   mem.alarmThreshold = iThreshold;
       
   253   sqlite3_mutex_leave(mem.mutex);
       
   254   return SQLITE_OK;
       
   255 }
       
   256 
       
   257 /*
       
   258 ** Trigger the alarm 
       
   259 */
       
   260 static void sqlite3MemsysAlarm(int nByte){
       
   261   void (*xCallback)(void*,sqlite3_int64,int);
       
   262   sqlite3_int64 nowUsed;
       
   263   void *pArg;
       
   264   if( mem.alarmCallback==0 || mem.alarmBusy  ) return;
       
   265   mem.alarmBusy = 1;
       
   266   xCallback = mem.alarmCallback;
       
   267   nowUsed = mem.nowUsed;
       
   268   pArg = mem.alarmArg;
       
   269   sqlite3_mutex_leave(mem.mutex);
       
   270   xCallback(pArg, nowUsed, nByte);
       
   271   sqlite3_mutex_enter(mem.mutex);
       
   272   mem.alarmBusy = 0;
       
   273 }
       
   274 
       
   275 /*
       
   276 ** Allocate nBytes of memory
       
   277 */
       
   278 static void *memsys4Malloc(int nBytes){
       
   279   sqlite3_int64 *p = 0;
       
   280   if( mem.alarmCallback!=0
       
   281          && mem.nowUsed+mem.nowUsedMMap+nBytes>=mem.alarmThreshold ){
       
   282     sqlite3MemsysAlarm(nBytes);
       
   283   }
       
   284   if( (p = mmapAlloc(nBytes))==0 ){
       
   285     p = malloc(nBytes+8);
       
   286     if( p==0 ){
       
   287       sqlite3MemsysAlarm(nBytes);
       
   288       p = malloc(nBytes+8);
       
   289     }
       
   290     if( p ){
       
   291       p[0] = nBytes;
       
   292       p++;
       
   293       mem.nowUsed += nBytes;
       
   294       if( mem.nowUsed>mem.mxUsed ){
       
   295         mem.mxUsed = mem.nowUsed;
       
   296       }
       
   297     }
       
   298   }
       
   299   return (void*)p; 
       
   300 }
       
   301 
       
   302 /*
       
   303 ** Return the size of a memory allocation
       
   304 */
       
   305 static int memsys4Size(void *pPrior){
       
   306   char *z = (char*)pPrior;
       
   307   int idx = mem.nPage ? (z - mem.mmapHeap)/mem.szPage : 0;
       
   308   int nByte;
       
   309   if( idx>=1 && idx<mem.nPage ){
       
   310     nByte = mem.szPage;
       
   311   }else{
       
   312     sqlite3_int64 *p = pPrior;
       
   313     p--;
       
   314     nByte = (int)*p;
       
   315   }
       
   316   return nByte;
       
   317 }
       
   318 
       
   319 /*
       
   320 ** Free memory.
       
   321 */
       
   322 static void memsys4Free(void *pPrior){
       
   323   sqlite3_int64 *p;
       
   324   int nByte;
       
   325   if( mmapFree(pPrior)==0 ){
       
   326     p = pPrior;
       
   327     p--;
       
   328     nByte = (int)*p;
       
   329     mem.nowUsed -= nByte;
       
   330     free(p);
       
   331     if( mem.nowUsed==0 ){
       
   332       mmapUnmap();
       
   333     }      
       
   334   }
       
   335 }
       
   336 
       
   337 /*
       
   338 ** Allocate nBytes of memory
       
   339 */
       
   340 void *sqlite3_malloc(int nBytes){
       
   341   sqlite3_int64 *p = 0;
       
   342   if( nBytes>0 ){
       
   343     memsys4Enter();
       
   344     p = memsys4Malloc(nBytes);
       
   345     sqlite3_mutex_leave(mem.mutex);
       
   346   }
       
   347   return (void*)p; 
       
   348 }
       
   349 
       
   350 /*
       
   351 ** Free memory.
       
   352 */
       
   353 void sqlite3_free(void *pPrior){
       
   354   if( pPrior==0 ){
       
   355     return;
       
   356   }
       
   357   assert( mem.mutex!=0 );
       
   358   sqlite3_mutex_enter(mem.mutex);
       
   359   memsys4Free(pPrior);
       
   360   sqlite3_mutex_leave(mem.mutex);  
       
   361 }
       
   362 
       
   363 
       
   364 
       
   365 /*
       
   366 ** Change the size of an existing memory allocation
       
   367 */
       
   368 void *sqlite3_realloc(void *pPrior, int nBytes){
       
   369   int nOld;
       
   370   sqlite3_int64 *p;
       
   371   if( pPrior==0 ){
       
   372     return sqlite3_malloc(nBytes);
       
   373   }
       
   374   if( nBytes<=0 ){
       
   375     sqlite3_free(pPrior);
       
   376     return 0;
       
   377   }
       
   378   nOld = memsys4Size(pPrior);
       
   379   if( nBytes<=nOld && nBytes>=nOld-128 ){
       
   380     return pPrior;
       
   381   }
       
   382   assert( mem.mutex!=0 );
       
   383   sqlite3_mutex_enter(mem.mutex);
       
   384   p = memsys4Malloc(nBytes);
       
   385   if( p ){
       
   386     if( nOld<nBytes ){
       
   387       memcpy(p, pPrior, nOld);
       
   388     }else{
       
   389       memcpy(p, pPrior, nBytes);
       
   390     }
       
   391     memsys4Free(pPrior);
       
   392   }
       
   393   assert( mem.mutex!=0 );
       
   394   sqlite3_mutex_leave(mem.mutex);
       
   395   return (void*)p;
       
   396 }
       
   397 
       
   398 #endif /* !SQLITE_MEMDEBUG && !SQLITE_OMIT_MEMORY_ALLOCATION */