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