| 2 |      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 */
 |