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