blob: 4b6fcf6c61e9702b6b39a27d6c53267992bc63a1 [file] [log] [blame]
drh9c7a60d2007-10-19 17:47:24 +00001/*
2** 2007 October 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** This version of the memory allocation subsystem omits all
16** use of malloc(). All dynamically allocatable memory is
17** contained in a static array, mem.aPool[]. The size of this
18** fixed memory pool is SQLITE_MEMORY_SIZE bytes.
19**
20** This version of the memory allocation subsystem is used if
21** and only if SQLITE_MEMORY_SIZE is defined.
22**
drhc0ad3e82007-10-20 16:11:39 +000023** $Id: mem3.c,v 1.4 2007/10/20 16:11:39 drh Exp $
drh9c7a60d2007-10-19 17:47:24 +000024*/
25
26/*
27** This version of the memory allocator is used only when
28** SQLITE_MEMORY_SIZE is defined.
29*/
30#if defined(SQLITE_MEMORY_SIZE)
31#include "sqliteInt.h"
32
33/*
34** Maximum size (in Mem3Blocks) of a "small" chunk.
35*/
36#define MX_SMALL 10
37
38
39/*
40** Number of freelist hash slots
41*/
42#define N_HASH 61
43
44/*
45** A memory allocation (also called a "chunk") consists of two or
46** more blocks where each block is 8 bytes. The first 8 bytes are
47** a header that is not returned to the user.
48**
49** A chunk is two or more blocks that is either checked out or
50** free. The first block has format u.hdr. u.hdr.size is the
51** size of the allocation in blocks if the allocation is free.
52** If the allocation is checked out, u.hdr.size is the negative
53** of the size. Similarly, u.hdr.prevSize is the size of the
54** immediately previous allocation.
55**
56** We often identify a chunk by its index in mem.aPool[]. When
57** this is done, the chunk index refers to the second block of
58** the chunk. In this way, the first chunk has an index of 1.
59** A chunk index of 0 means "no such chunk" and is the equivalent
60** of a NULL pointer.
61**
62** The second block of free chunks is of the form u.list. The
63** two fields form a double-linked list of chunks of related sizes.
64** Pointers to the head of the list are stored in mem.aiSmall[]
65** for smaller chunks and mem.aiHash[] for larger chunks.
66**
67** The second block of a chunk is user data if the chunk is checked
68** out.
69*/
70typedef struct Mem3Block Mem3Block;
71struct Mem3Block {
72 union {
73 struct {
74 int prevSize; /* Size of previous chunk in Mem3Block elements */
75 int size; /* Size of current chunk in Mem3Block elements */
76 } hdr;
77 struct {
78 int next; /* Index in mem.aPool[] of next free chunk */
79 int prev; /* Index in mem.aPool[] of previous free chunk */
80 } list;
81 } u;
82};
83
84/*
85** All of the static variables used by this module are collected
86** into a single structure named "mem". This is to keep the
87** static variables organized and to reduce namespace pollution
88** when this module is combined with other in the amalgamation.
89*/
90static struct {
91 /*
drha4e5d582007-10-20 15:41:57 +000092 ** True if we are evaluating an out-of-memory callback.
drh9c7a60d2007-10-19 17:47:24 +000093 */
drh9c7a60d2007-10-19 17:47:24 +000094 int alarmBusy;
95
96 /*
97 ** Mutex to control access to the memory allocation subsystem.
98 */
99 sqlite3_mutex *mutex;
100
101 /*
drha4e5d582007-10-20 15:41:57 +0000102 ** The minimum amount of free space that we have seen.
drh9c7a60d2007-10-19 17:47:24 +0000103 */
drha4e5d582007-10-20 15:41:57 +0000104 int mnMaster;
drh9c7a60d2007-10-19 17:47:24 +0000105
106 /*
107 ** iMaster is the index of the master chunk. Most new allocations
108 ** occur off of this chunk. szMaster is the size (in Mem3Blocks)
109 ** of the current master. iMaster is 0 if there is not master chunk.
110 ** The master chunk is not in either the aiHash[] or aiSmall[].
111 */
112 int iMaster;
113 int szMaster;
114
115 /*
116 ** Array of lists of free blocks according to the block size
117 ** for smaller chunks, or a hash on the block size for larger
118 ** chunks.
119 */
120 int aiSmall[MX_SMALL-1]; /* For sizes 2 through MX_SMALL, inclusive */
121 int aiHash[N_HASH]; /* For sizes MX_SMALL+1 and larger */
122
123 /*
124 ** Memory available for allocation
125 */
126 Mem3Block aPool[SQLITE_MEMORY_SIZE/sizeof(Mem3Block)+2];
127} mem;
128
129/*
130** Unlink the chunk at mem.aPool[i] from list it is currently
131** on. *pRoot is the list that i is a member of.
132*/
drha4e5d582007-10-20 15:41:57 +0000133static void memsys3UnlinkFromList(int i, int *pRoot){
drh9c7a60d2007-10-19 17:47:24 +0000134 int next = mem.aPool[i].u.list.next;
135 int prev = mem.aPool[i].u.list.prev;
136 if( prev==0 ){
137 *pRoot = next;
138 }else{
139 mem.aPool[prev].u.list.next = next;
140 }
141 if( next ){
142 mem.aPool[next].u.list.prev = prev;
143 }
144 mem.aPool[i].u.list.next = 0;
145 mem.aPool[i].u.list.prev = 0;
146}
147
148/*
149** Unlink the chunk at index i from
150** whatever list is currently a member of.
151*/
drha4e5d582007-10-20 15:41:57 +0000152static void memsys3Unlink(int i){
drh9c7a60d2007-10-19 17:47:24 +0000153 int size, hash;
154 size = mem.aPool[i-1].u.hdr.size;
155 assert( size==mem.aPool[i+size-1].u.hdr.prevSize );
156 assert( size>=2 );
157 if( size <= MX_SMALL ){
drha4e5d582007-10-20 15:41:57 +0000158 memsys3UnlinkFromList(i, &mem.aiSmall[size-2]);
drh9c7a60d2007-10-19 17:47:24 +0000159 }else{
160 hash = size % N_HASH;
drha4e5d582007-10-20 15:41:57 +0000161 memsys3UnlinkFromList(i, &mem.aiHash[hash]);
drh9c7a60d2007-10-19 17:47:24 +0000162 }
163}
164
165/*
166** Link the chunk at mem.aPool[i] so that is on the list rooted
167** at *pRoot.
168*/
drha4e5d582007-10-20 15:41:57 +0000169static void memsys3LinkIntoList(int i, int *pRoot){
drh9c7a60d2007-10-19 17:47:24 +0000170 mem.aPool[i].u.list.next = *pRoot;
171 mem.aPool[i].u.list.prev = 0;
172 if( *pRoot ){
173 mem.aPool[*pRoot].u.list.prev = i;
174 }
175 *pRoot = i;
176}
177
178/*
179** Link the chunk at index i into either the appropriate
180** small chunk list, or into the large chunk hash table.
181*/
drha4e5d582007-10-20 15:41:57 +0000182static void memsys3Link(int i){
drh9c7a60d2007-10-19 17:47:24 +0000183 int size, hash;
184 size = mem.aPool[i-1].u.hdr.size;
185 assert( size==mem.aPool[i+size-1].u.hdr.prevSize );
186 assert( size>=2 );
187 if( size <= MX_SMALL ){
drha4e5d582007-10-20 15:41:57 +0000188 memsys3LinkIntoList(i, &mem.aiSmall[size-2]);
drh9c7a60d2007-10-19 17:47:24 +0000189 }else{
190 hash = size % N_HASH;
drha4e5d582007-10-20 15:41:57 +0000191 memsys3LinkIntoList(i, &mem.aiHash[hash]);
drh9c7a60d2007-10-19 17:47:24 +0000192 }
193}
194
195/*
196** Enter the mutex mem.mutex. Allocate it if it is not already allocated.
197**
198** Also: Initialize the memory allocation subsystem the first time
199** this routine is called.
200*/
drha4e5d582007-10-20 15:41:57 +0000201static void memsys3Enter(void){
drh9c7a60d2007-10-19 17:47:24 +0000202 if( mem.mutex==0 ){
203 mem.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM);
204 mem.aPool[0].u.hdr.size = SQLITE_MEMORY_SIZE/8;
205 mem.aPool[SQLITE_MEMORY_SIZE/8].u.hdr.prevSize = SQLITE_MEMORY_SIZE/8;
206 mem.iMaster = 1;
207 mem.szMaster = SQLITE_MEMORY_SIZE/8;
drha4e5d582007-10-20 15:41:57 +0000208 mem.mnMaster = mem.szMaster;
drh9c7a60d2007-10-19 17:47:24 +0000209 }
210 sqlite3_mutex_enter(mem.mutex);
211}
212
213/*
214** Return the amount of memory currently checked out.
215*/
216sqlite3_int64 sqlite3_memory_used(void){
217 sqlite3_int64 n;
drha4e5d582007-10-20 15:41:57 +0000218 memsys3Enter();
219 n = SQLITE_MEMORY_SIZE - mem.szMaster*8;
drh9c7a60d2007-10-19 17:47:24 +0000220 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*/
229sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
230 sqlite3_int64 n;
drha4e5d582007-10-20 15:41:57 +0000231 memsys3Enter();
232 n = SQLITE_MEMORY_SIZE - mem.mnMaster*8;
drh9c7a60d2007-10-19 17:47:24 +0000233 if( resetFlag ){
drha4e5d582007-10-20 15:41:57 +0000234 mem.mnMaster = mem.szMaster;
drh9c7a60d2007-10-19 17:47:24 +0000235 }
236 sqlite3_mutex_leave(mem.mutex);
237 return n;
238}
239
240/*
drha4e5d582007-10-20 15:41:57 +0000241** Change the alarm callback.
242**
243** This is a no-op for the static memory allocator. The purpose
244** of the memory alarm is to support sqlite3_soft_heap_limit().
245** But with this memory allocator, the soft_heap_limit is really
246** a hard limit that is fixed at SQLITE_MEMORY_SIZE.
drh9c7a60d2007-10-19 17:47:24 +0000247*/
248int sqlite3_memory_alarm(
249 void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
250 void *pArg,
251 sqlite3_int64 iThreshold
252){
drh9c7a60d2007-10-19 17:47:24 +0000253 return SQLITE_OK;
254}
255
256/*
drha4e5d582007-10-20 15:41:57 +0000257** Called when we are unable to satisfy an allocation of nBytes.
drh9c7a60d2007-10-19 17:47:24 +0000258*/
drha4e5d582007-10-20 15:41:57 +0000259static void memsys3OutOfMemory(int nByte){
260 if( !mem.alarmBusy ){
261 mem.alarmBusy = 1;
262 sqlite3_mutex_leave(mem.mutex);
263 sqlite3_release_memory(nByte);
264 sqlite3_mutex_enter(mem.mutex);
265 mem.alarmBusy = 0;
266 }
drh9c7a60d2007-10-19 17:47:24 +0000267}
268
269/*
270** Return the size of an outstanding allocation, in bytes. The
drha4e5d582007-10-20 15:41:57 +0000271** size returned omits the 8-byte header overhead. This only
drh9c7a60d2007-10-19 17:47:24 +0000272** works for chunks that are currently checked out.
273*/
drha4e5d582007-10-20 15:41:57 +0000274static int memsys3Size(void *p){
drh9c7a60d2007-10-19 17:47:24 +0000275 Mem3Block *pBlock = (Mem3Block*)p;
276 assert( pBlock[-1].u.hdr.size<0 );
drhc0ad3e82007-10-20 16:11:39 +0000277 return (-1-pBlock[-1].u.hdr.size)*8;
drh9c7a60d2007-10-19 17:47:24 +0000278}
279
280/*
281** Chunk i is a free chunk that has been unlinked. Adjust its
282** size parameters for check-out and return a pointer to the
283** user portion of the chunk.
284*/
drha4e5d582007-10-20 15:41:57 +0000285static void *memsys3Checkout(int i, int nBlock){
drh9c7a60d2007-10-19 17:47:24 +0000286 assert( mem.aPool[i-1].u.hdr.size==nBlock );
287 assert( mem.aPool[i+nBlock-1].u.hdr.prevSize==nBlock );
288 mem.aPool[i-1].u.hdr.size = -nBlock;
289 mem.aPool[i+nBlock-1].u.hdr.prevSize = -nBlock;
290 return &mem.aPool[i];
291}
292
293/*
294** Carve a piece off of the end of the mem.iMaster free chunk.
295** Return a pointer to the new allocation. Or, if the master chunk
296** is not large enough, return 0.
297*/
drha4e5d582007-10-20 15:41:57 +0000298static void *memsys3FromMaster(int nBlock){
drh9c7a60d2007-10-19 17:47:24 +0000299 assert( mem.szMaster>=nBlock );
300 if( nBlock>=mem.szMaster-1 ){
301 /* Use the entire master */
drha4e5d582007-10-20 15:41:57 +0000302 void *p = memsys3Checkout(mem.iMaster, mem.szMaster);
drh9c7a60d2007-10-19 17:47:24 +0000303 mem.iMaster = 0;
304 mem.szMaster = 0;
drha4e5d582007-10-20 15:41:57 +0000305 mem.mnMaster = 0;
drh9c7a60d2007-10-19 17:47:24 +0000306 return p;
307 }else{
308 /* Split the master block. Return the tail. */
309 int newi;
310 newi = mem.iMaster + mem.szMaster - nBlock;
311 assert( newi > mem.iMaster+1 );
312 mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.prevSize = -nBlock;
313 mem.aPool[newi-1].u.hdr.size = -nBlock;
314 mem.szMaster -= nBlock;
315 mem.aPool[newi-1].u.hdr.prevSize = mem.szMaster;
316 mem.aPool[mem.iMaster-1].u.hdr.size = mem.szMaster;
drha4e5d582007-10-20 15:41:57 +0000317 if( mem.szMaster < mem.mnMaster ){
318 mem.mnMaster = mem.szMaster;
319 }
drh9c7a60d2007-10-19 17:47:24 +0000320 return (void*)&mem.aPool[newi];
321 }
322}
323
324/*
325** *pRoot is the head of a list of free chunks of the same size
326** or same size hash. In other words, *pRoot is an entry in either
327** mem.aiSmall[] or mem.aiHash[].
328**
329** This routine examines all entries on the given list and tries
330** to coalesce each entries with adjacent free chunks.
331**
332** If it sees a chunk that is larger than mem.iMaster, it replaces
333** the current mem.iMaster with the new larger chunk. In order for
334** this mem.iMaster replacement to work, the master chunk must be
335** linked into the hash tables. That is not the normal state of
336** affairs, of course. The calling routine must link the master
337** chunk before invoking this routine, then must unlink the (possibly
338** changed) master chunk once this routine has finished.
339*/
drha4e5d582007-10-20 15:41:57 +0000340static void memsys3Merge(int *pRoot){
drh9c7a60d2007-10-19 17:47:24 +0000341 int iNext, prev, size, i;
342
343 for(i=*pRoot; i>0; i=iNext){
344 iNext = mem.aPool[i].u.list.next;
345 size = mem.aPool[i-1].u.hdr.size;
346 assert( size>0 );
347 if( mem.aPool[i-1].u.hdr.prevSize>0 ){
drha4e5d582007-10-20 15:41:57 +0000348 memsys3UnlinkFromList(i, pRoot);
drh9c7a60d2007-10-19 17:47:24 +0000349 prev = i - mem.aPool[i-1].u.hdr.prevSize;
350 assert( prev>=0 );
351 if( prev==iNext ){
352 iNext = mem.aPool[prev].u.list.next;
353 }
drha4e5d582007-10-20 15:41:57 +0000354 memsys3Unlink(prev);
drh9c7a60d2007-10-19 17:47:24 +0000355 size = i + size - prev;
356 mem.aPool[prev-1].u.hdr.size = size;
357 mem.aPool[prev+size-1].u.hdr.prevSize = size;
drha4e5d582007-10-20 15:41:57 +0000358 memsys3Link(prev);
drh9c7a60d2007-10-19 17:47:24 +0000359 i = prev;
360 }
361 if( size>mem.szMaster ){
362 mem.iMaster = i;
363 mem.szMaster = size;
364 }
365 }
366}
367
368/*
369** Return a block of memory of at least nBytes in size.
370** Return NULL if unable.
371*/
drha4e5d582007-10-20 15:41:57 +0000372static void *memsys3Malloc(int nByte){
drh9c7a60d2007-10-19 17:47:24 +0000373 int i;
374 int nBlock;
375
376 assert( sizeof(Mem3Block)==8 );
377 if( nByte<=0 ){
378 nBlock = 2;
379 }else{
380 nBlock = (nByte + 15)/8;
381 }
382 assert( nBlock >= 2 );
383
384 /* STEP 1:
385 ** Look for an entry of the correct size in either the small
386 ** chunk table or in the large chunk hash table. This is
387 ** successful most of the time (about 9 times out of 10).
388 */
389 if( nBlock <= MX_SMALL ){
390 i = mem.aiSmall[nBlock-2];
391 if( i>0 ){
drha4e5d582007-10-20 15:41:57 +0000392 memsys3UnlinkFromList(i, &mem.aiSmall[nBlock-2]);
393 return memsys3Checkout(i, nBlock);
drh9c7a60d2007-10-19 17:47:24 +0000394 }
395 }else{
396 int hash = nBlock % N_HASH;
397 for(i=mem.aiHash[hash]; i>0; i=mem.aPool[i].u.list.next){
398 if( mem.aPool[i-1].u.hdr.size==nBlock ){
drha4e5d582007-10-20 15:41:57 +0000399 memsys3UnlinkFromList(i, &mem.aiHash[hash]);
400 return memsys3Checkout(i, nBlock);
drh9c7a60d2007-10-19 17:47:24 +0000401 }
402 }
403 }
404
405 /* STEP 2:
406 ** Try to satisfy the allocation by carving a piece off of the end
407 ** of the master chunk. This step usually works if step 1 fails.
408 */
409 if( mem.szMaster>=nBlock ){
drha4e5d582007-10-20 15:41:57 +0000410 return memsys3FromMaster(nBlock);
drh9c7a60d2007-10-19 17:47:24 +0000411 }
412
413
414 /* STEP 3:
415 ** Loop through the entire memory pool. Coalesce adjacent free
416 ** chunks. Recompute the master chunk as the largest free chunk.
417 ** Then try again to satisfy the allocation by carving a piece off
418 ** of the end of the master chunk. This step happens very
419 ** rarely (we hope!)
420 */
drha4e5d582007-10-20 15:41:57 +0000421 memsys3OutOfMemory(nBlock*16);
drh9c7a60d2007-10-19 17:47:24 +0000422 if( mem.iMaster ){
drha4e5d582007-10-20 15:41:57 +0000423 memsys3Link(mem.iMaster);
drh9c7a60d2007-10-19 17:47:24 +0000424 mem.iMaster = 0;
425 mem.szMaster = 0;
426 }
427 for(i=0; i<N_HASH; i++){
drha4e5d582007-10-20 15:41:57 +0000428 memsys3Merge(&mem.aiHash[i]);
drh9c7a60d2007-10-19 17:47:24 +0000429 }
430 for(i=0; i<MX_SMALL-1; i++){
drha4e5d582007-10-20 15:41:57 +0000431 memsys3Merge(&mem.aiSmall[i]);
drh9c7a60d2007-10-19 17:47:24 +0000432 }
433 if( mem.szMaster ){
drha4e5d582007-10-20 15:41:57 +0000434 memsys3Unlink(mem.iMaster);
drh9c7a60d2007-10-19 17:47:24 +0000435 if( mem.szMaster>=nBlock ){
drha4e5d582007-10-20 15:41:57 +0000436 return memsys3FromMaster(nBlock);
drh9c7a60d2007-10-19 17:47:24 +0000437 }
438 }
439
440 /* If none of the above worked, then we fail. */
441 return 0;
442}
443
444/*
445** Free an outstanding memory allocation.
446*/
drha4e5d582007-10-20 15:41:57 +0000447void memsys3Free(void *pOld){
drh9c7a60d2007-10-19 17:47:24 +0000448 Mem3Block *p = (Mem3Block*)pOld;
449 int i;
450 int size;
451 assert( p>mem.aPool && p<&mem.aPool[SQLITE_MEMORY_SIZE/8] );
452 i = p - mem.aPool;
453 size = -mem.aPool[i-1].u.hdr.size;
454 assert( size>=2 );
455 assert( mem.aPool[i+size-1].u.hdr.prevSize==-size );
456 mem.aPool[i-1].u.hdr.size = size;
457 mem.aPool[i+size-1].u.hdr.prevSize = size;
drha4e5d582007-10-20 15:41:57 +0000458 memsys3Link(i);
drh9c7a60d2007-10-19 17:47:24 +0000459
460 /* Try to expand the master using the newly freed chunk */
461 if( mem.iMaster ){
462 while( mem.aPool[mem.iMaster-1].u.hdr.prevSize>0 ){
463 size = mem.aPool[mem.iMaster-1].u.hdr.prevSize;
464 mem.iMaster -= size;
465 mem.szMaster += size;
drha4e5d582007-10-20 15:41:57 +0000466 memsys3Unlink(mem.iMaster);
drh9c7a60d2007-10-19 17:47:24 +0000467 mem.aPool[mem.iMaster-1].u.hdr.size = mem.szMaster;
468 mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.prevSize = mem.szMaster;
469 }
470 while( mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.size>0 ){
drha4e5d582007-10-20 15:41:57 +0000471 memsys3Unlink(mem.iMaster+mem.szMaster);
drh9c7a60d2007-10-19 17:47:24 +0000472 mem.szMaster += mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.size;
473 mem.aPool[mem.iMaster-1].u.hdr.size = mem.szMaster;
474 mem.aPool[mem.iMaster+mem.szMaster-1].u.hdr.prevSize = mem.szMaster;
475 }
476 }
477}
478
479/*
480** Allocate nBytes of memory
481*/
482void *sqlite3_malloc(int nBytes){
483 sqlite3_int64 *p = 0;
484 if( nBytes>0 ){
drha4e5d582007-10-20 15:41:57 +0000485 memsys3Enter();
486 p = memsys3Malloc(nBytes);
drh9c7a60d2007-10-19 17:47:24 +0000487 sqlite3_mutex_leave(mem.mutex);
488 }
489 return (void*)p;
490}
491
492/*
493** Free memory.
494*/
495void sqlite3_free(void *pPrior){
496 if( pPrior==0 ){
497 return;
498 }
499 assert( mem.mutex!=0 );
500 sqlite3_mutex_enter(mem.mutex);
drha4e5d582007-10-20 15:41:57 +0000501 memsys3Free(pPrior);
drh9c7a60d2007-10-19 17:47:24 +0000502 sqlite3_mutex_leave(mem.mutex);
503}
504
505/*
506** Change the size of an existing memory allocation
507*/
508void *sqlite3_realloc(void *pPrior, int nBytes){
509 int nOld;
510 void *p;
511 if( pPrior==0 ){
512 return sqlite3_malloc(nBytes);
513 }
514 if( nBytes<=0 ){
515 sqlite3_free(pPrior);
516 return 0;
517 }
518 assert( mem.mutex!=0 );
drha4e5d582007-10-20 15:41:57 +0000519 nOld = memsys3Size(pPrior);
drha4e5d582007-10-20 15:41:57 +0000520 if( nBytes<=nOld && nBytes>=nOld-128 ){
521 return pPrior;
522 }
drh9c7a60d2007-10-19 17:47:24 +0000523 sqlite3_mutex_enter(mem.mutex);
drha4e5d582007-10-20 15:41:57 +0000524 p = memsys3Malloc(nBytes);
525 if( p ){
526 if( nOld<nBytes ){
527 memcpy(p, pPrior, nOld);
528 }else{
529 memcpy(p, pPrior, nBytes);
drh9c7a60d2007-10-19 17:47:24 +0000530 }
drha4e5d582007-10-20 15:41:57 +0000531 memsys3Free(pPrior);
drh9c7a60d2007-10-19 17:47:24 +0000532 }
533 sqlite3_mutex_leave(mem.mutex);
534 return p;
535}
536
537/*
538** Open the file indicated and write a log of all unfreed memory
539** allocations into that log.
540*/
541void sqlite3_memdebug_dump(const char *zFilename){
542#ifdef SQLITE_DEBUG
543 FILE *out;
544 int i, j, size;
545 if( zFilename==0 || zFilename[0]==0 ){
546 out = stdout;
547 }else{
548 out = fopen(zFilename, "w");
549 if( out==0 ){
550 fprintf(stderr, "** Unable to output memory debug output log: %s **\n",
551 zFilename);
552 return;
553 }
554 }
drha4e5d582007-10-20 15:41:57 +0000555 memsys3Enter();
drh9c7a60d2007-10-19 17:47:24 +0000556 fprintf(out, "CHUNKS:\n");
557 for(i=1; i<=SQLITE_MEMORY_SIZE/8; i+=size){
558 size = mem.aPool[i-1].u.hdr.size;
559 if( size>=-1 && size<=1 ){
560 fprintf(out, "%p size error\n", &mem.aPool[i]);
561 assert( 0 );
562 break;
563 }
564 if( mem.aPool[i+(size<0?-size:size)-1].u.hdr.prevSize!=size ){
565 fprintf(out, "%p tail size does not match\n", &mem.aPool[i]);
566 assert( 0 );
567 break;
568 }
569 if( size<0 ){
570 size = -size;
571 fprintf(out, "%p %6d bytes checked out\n", &mem.aPool[i], size*8-8);
572 }else{
573 fprintf(out, "%p %6d bytes free%s\n", &mem.aPool[i], size*8-8,
574 i==mem.iMaster ? " **master**" : "");
575 }
576 }
577 for(i=0; i<MX_SMALL-1; i++){
578 if( mem.aiSmall[i]==0 ) continue;
579 fprintf(out, "small(%2d):", i);
580 for(j = mem.aiSmall[i]; j>0; j=mem.aPool[j].u.list.next){
581 fprintf(out, " %p(%d)", &mem.aPool[j], mem.aPool[j-1].u.hdr.size*8-8);
582 }
583 fprintf(out, "\n");
584 }
585 for(i=0; i<N_HASH; i++){
586 if( mem.aiHash[i]==0 ) continue;
587 fprintf(out, "hash(%2d):", i);
588 for(j = mem.aiHash[i]; j>0; j=mem.aPool[j].u.list.next){
589 fprintf(out, " %p(%d)", &mem.aPool[j], mem.aPool[j-1].u.hdr.size*8-8);
590 }
591 fprintf(out, "\n");
592 }
593 fprintf(out, "master=%d\n", mem.iMaster);
drha4e5d582007-10-20 15:41:57 +0000594 fprintf(out, "nowUsed=%d\n", SQLITE_MEMORY_SIZE - mem.szMaster*8);
595 fprintf(out, "mxUsed=%d\n", SQLITE_MEMORY_SIZE - mem.mnMaster*8);
drh9c7a60d2007-10-19 17:47:24 +0000596 sqlite3_mutex_leave(mem.mutex);
597 if( out==stdout ){
598 fflush(stdout);
599 }else{
600 fclose(out);
601 }
602#endif
603}
604
605
606#endif /* !SQLITE_MEMORY_SIZE */