SQLite4
Check-in [e9efc61a51]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add files "mem.h" and "mem.c". These are not currently linked into the build and have never been tested. At the moment they should be considered working notes, not real code. The code contained in these files might get folded into the build, or it might be deleted.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: e9efc61a5182b4f1a0f90bcf2df09d112a7488a1
User & Date: drh 2013-01-01 18:24:48
Context
2013-01-01
18:41
Fix a memory leak in fts5.c. check-in: 7bc0e58875 user: dan tags: trunk
18:24
Add files "mem.h" and "mem.c". These are not currently linked into the build and have never been tested. At the moment they should be considered working notes, not real code. The code contained in these files might get folded into the build, or it might be deleted. check-in: e9efc61a51 user: drh tags: trunk
10:24
Fix a problem that occurs with transactions that use more than 32MB of shared memory. check-in: bc0f61fc3b user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added src/mem.c.





































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
/*
** 2013-01-01
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file contains the implementation of the "sqlite4_mm" memory
** allocator object.
*/
#include "sqlite4.h"
#include "mem.h"
#include <stdlib.h>

/*************************************************************************
** The SQLITE4_MM_SYSTEM memory allocator.  This allocator uses the
** malloc/realloc/free from the system library.  It also tries to use
** the memory allocation sizer from the system library if such a routine
** exists.  If there is no msize in the system library, then each allocation
** is increased in size by 8 bytes and the size of the allocation is stored
** in those initial 8 bytes.
**
** C-preprocessor macro summary:
**
**    HAVE_MALLOC_USABLE_SIZE     The configure script sets this symbol if
**                                the malloc_usable_size() interface exists
**                                on the target platform.  Or, this symbol
**                                can be set manually, if desired.
**                                If an equivalent interface exists by
**                                a different name, using a separate -D
**                                option to rename it.  This symbol will
**                                be enabled automatically on windows
**                                systems, and malloc_usable_size() will
**                                be redefined to _msize(), unless the
**                                SQLITE4_WITHOUT_MSIZE macro is defined.
**    
**    SQLITE4_WITHOUT_ZONEMALLOC   Some older macs lack support for the zone
**                                memory allocator.  Set this symbol to enable
**                                building on older macs.
**
**    SQLITE4_WITHOUT_MSIZE        Set this symbol to disable the use of
**                                _msize() on windows systems.  This might
**                                be necessary when compiling for Delphi,
**                                for example.
*/

/*
** Windows systems have malloc_usable_size() but it is called _msize().
** The use of _msize() is automatic, but can be disabled by compiling
** with -DSQLITE4_WITHOUT_MSIZE
*/
#if !defined(HAVE_MALLOC_USABLE_SIZE) && SQLITE4_OS_WIN \
      && !defined(SQLITE4_WITHOUT_MSIZE)
# define HAVE_MALLOC_USABLE_SIZE 1
# define SQLITE4_MALLOCSIZE _msize
#endif

#if defined(__APPLE__) && !defined(SQLITE4_WITHOUT_ZONEMALLOC)

/*
** Use the zone allocator available on apple products unless the
** SQLITE4_WITHOUT_ZONEMALLOC symbol is defined.
*/
#include <sys/sysctl.h>
#include <malloc/malloc.h>
#include <libkern/OSAtomic.h>
static malloc_zone_t* _sqliteZone_;
#define SQLITE4_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x))
#define SQLITE4_FREE(x) malloc_zone_free(_sqliteZone_, (x));
#define SQLITE4_REALLOC(x,y) malloc_zone_realloc(_sqliteZone_, (x), (y))
#define SQLITE4_MALLOCSIZE(x) \
        (_sqliteZone_ ? _sqliteZone_->size(_sqliteZone_,x) : malloc_size(x))

#else /* if not __APPLE__ */

/*
** Use standard C library malloc and free on non-Apple systems.  
** Also used by Apple systems if SQLITE4_WITHOUT_ZONEMALLOC is defined.
*/
#define SQLITE4_MALLOC(x)    malloc(x)
#define SQLITE4_FREE(x)      free(x)
#define SQLITE4_REALLOC(x,y) realloc((x),(y))

#ifdef HAVE_MALLOC_USABLE_SIZE
# ifndef SQLITE4_MALLOCSIZE
#  include <malloc.h>
#  define SQLITE4_MALLOCSIZE(x) malloc_usable_size(x)
# endif
#else
# undef SQLITE4_MALLOCSIZE
#endif

#endif /* __APPLE__ or not __APPLE__ */

/*
** Implementations of core routines
*/
static void *mmSysMalloc(sqlite4_mm *pMM, sqlite4_int64 iSize){
#ifdef SQLITE4_MALLOCSIZE
  return SQLITE4_MALLOC(iSize);
#else
  unsigned char *pRes = SQLITE4_MALLOC(iSize+8);
  if( pRes ){
    *(sqlite4_int64*)pRes = iSize;
    pRes += 8;
  }
  return pRes;
#endif
}
static void *mmSysRealloc(sqlite4_mm *pMM, void *pOld, sqlite4_int64 iSz){
#ifdef SQLITE4_MALLOCSIZE
  return SQLITE4_REALLOC(pOld, iSz);
#else
  unsigned char *pRes;
  if( pOld==0 ) return mmSysMalloc(pMM, iSz);
  pRes = (unsigned char*)pOld;
  pRes -= 8;
  pRes = SQLITE4_REALLOC(pRes, iSz+8);
  if( pRes ){
    *(sqlite4_int64*)pRes = iSz;
    pRes += 8;
  }
  return pRes;
#endif 
}
static void mmSysFree(sqlite4_mm *pNotUsed, void *pOld){
#ifdef SQLITE4_MALLOCSIZE
  SQLITE4_FREE(pOld);
#else
  unsigned char *pRes;
  if( pOld==0 ) return;
  pRes = (unsigned char *)pOld;
  pRes -= 8;
  SQLITE4_FREE(pRes);
#endif
}
static sqlite4_int64 mmSysMsize(sqlite4_mm *pNotUsed, void *pOld){
#ifdef SQLITE4_MALLOCSIZE
  return SQLITE4_MALLOCSIZE(pOld);
#else
  unsigned char *pX;
  if( pOld==0 ) return 0;
  pX = (unsigned char *)pOld;
  pX -= 8;
  return *(sqlite4_int64*)pX;
#endif
}

static const sqlite4_mm_methods mmSysMethods = {
  /* iVersion */    1,
  /* xMalloc  */    mmSysMalloc,
  /* xRealloc */    mmSysRealloc,
  /* xFree    */    mmSysFree,
  /* xMsize   */    mmSysMsize,
  /* xMember  */    0,
  /* xBenign  */    0,
  /* xFinal   */    0
};
static sqlite4_mm mmSystem =  {
  /* pMethods */    &mmSysMethods
};

/*************************************************************************
** The SQLITE4_MM_OVERFLOW memory allocator.
**
** This memory allocator has two child memory allocators, A and B.  Always
** try to fulfill the request using A first, then overflow to B if the request
** on A fails.  The A allocator must support the xMember method.
*/
struct mmOvfl {
  sqlite4_mm base;    /* Base class - must be first */
  int (*xMemberOfA)(sqlite4_mm*, const void*);
  sqlite4_mm *pA;     /* Primary memory allocator */
  sqlite4_mm *pB;     /* Backup memory allocator in case pA fails */
};

static void *mmOvflMalloc(sqlite4_mm *pMM, sqlite4_int64 iSz){
  const struct mmOvfl *pOvfl = (const struct mmOvfl*)pMM;
  void *pRes;
  pRes = pOvfl->pA->pMethods->xMalloc(pOvfl->pA, iSz);
  if( pRes==0 ){
    pRes = pOvfl->pB->pMethods->xMalloc(pOvfl->pB, iSz);
  }
  return pRes;
}
static void *mmOvflRealloc(sqlite4_mm *pMM, void *pOld, sqlite4_int64 iSz){
  const struct mmOvfl *pOvfl;
  void *pRes;
  if( pOld==0 ) return mmOvflMalloc(pMM, iSz);
  pOvfl = (const struct mmOvfl*)pMM;
  if( pOvfl->xMemberOfA(pOvfl->pA, pOld) ){
    pRes = pOvfl->pA->pMethods->xRealloc(pOvfl->pA, pOld, iSz);
  }else{
    pRes = pOvfl->pB->pMethods->xRealloc(pOvfl->pB, pOld, iSz);
  }
  return pRes;
}
static void mmOvflFree(sqlite4_mm *pMM, void *pOld){
  const struct mmOvfl *pOvfl;
  if( pOld==0 ) return;
  pOvfl = (const struct mmOvfl*)pMM;
  if( pOvfl->xMemberOfA(pOvfl->pA, pOld) ){
    pOvfl->pA->pMethods->xFree(pOvfl->pA, pOld);
  }else{
    pOvfl->pB->pMethods->xFree(pOvfl->pB, pOld);
  }
}
static sqlite4_int64 mmOvflMsize(sqlite4_mm *pMM, void *pOld){
  const struct mmOvfl *pOvfl;
  sqlite4_int64 iSz;
  if( pOld==0 ) return 0;
  pOvfl = (const struct mmOvfl*)pMM;
  if( pOvfl->xMemberOfA(pOvfl->pA, pOld) ){
    iSz = sqlite4_mm_msize(pOvfl->pA, pOld);
  }else{
    iSz = sqlite4_mm_msize(pOvfl->pB, pOld);
  }
  return iSz;
}
static int mmOvflMember(sqlite4_mm *pMM, const void *pOld){
  const struct mmOvfl *pOvfl;
  int iRes;
  if( pOld==0 ) return 0;
  pOvfl = (const struct mmOvfl*)pMM;
  if( pOvfl->xMemberOfA(pOvfl->pA, pOld) ){
    iRes = 1;
  }else{
    iRes = sqlite4_mm_member(pOvfl->pB, pOld);
  }
  return iRes;
}
static void mmOvflBenign(sqlite4_mm *pMM, int bEnable){
  struct mmOvfl *pOvfl = (struct mmOvfl*)pMM;
  sqlite4_mm_benign_failures(pOvfl->pA, bEnable);
  sqlite4_mm_benign_failures(pOvfl->pB, bEnable);
}
static void mmOvflFinal(sqlite4_mm *pMM){
  struct mmOvfl *pOvfl = (struct mmOvfl*)pMM;
  sqlite4_mm *pA = pOvfl->pA;
  sqlite4_mm *pB = pOvfl->pB;
  mmOvflFree(pMM, pMM);
  sqlite4_mm_destroy(pA);
  sqlite4_mm_destroy(pB);
}
static const sqlite4_mm_methods mmOvflMethods = {
  /* iVersion */    1,
  /* xMalloc  */    mmOvflMalloc,
  /* xRealloc */    mmOvflRealloc,
  /* xFree    */    mmOvflFree,
  /* xMsize   */    mmOvflMsize,
  /* xMember  */    mmOvflMember,
  /* xBenign  */    mmOvflBenign,
  /* xFinal   */    mmOvflFinal
};
static sqlite4_mm *mmOvflNew(sqlite4_mm *pA, sqlite4_mm *pB){
  struct mmOvfl *pOvfl;
  if( pA->pMethods->xMember==0 ) return 0;
  pOvfl = sqlite4_mm_malloc(pA, sizeof(*pOvfl));
  if( pOvfl==0 ){
    pOvfl = sqlite4_mm_malloc(pB, sizeof(*pOvfl));
  }
  if( pOvfl ){
    pOvfl->base.pMethods = &mmOvflMethods;
    pOvfl->xMemberOfA = pA->pMethods->xMember;
    pOvfl->pA = pA;
    pOvfl->pB = pB;
  }
  return &pOvfl->base;
}


/*************************************************************************
** The SQLITE4_MM_ONESIZE memory allocator.
**
** All memory allocations are rounded up to a single size, "sz".  A request
** for an allocation larger than sz bytes fails.  All allocations come out
** of a single initial buffer with "cnt" chunks of "sz" bytes each.
**
** Space to hold the sqlite4_mm object comes from the first block in the
** allocation space.
*/
struct mmOnesz {
  sqlite4_mm base;            /* Base class.  Must be first. */
  const void *pSpace;         /* Space to allocate */
  const void *pLast;          /* Last possible allocation */
  struct mmOneszBlock *pFree; /* List of free blocks */
  int sz;                     /* Size of each allocation */
};

/* A free block in the buffer */
struct mmOneszBlock {
  struct mmOneszBlock *pNext;  /* Next on the freelist */
};

static void *mmOneszMalloc(sqlite4_mm *pMM, sqlite4_int64 iSz){
  struct mmOnesz *pOnesz = (struct mmOnesz*)pMM;
  void *pRes;
  if( iSz>pOnesz->sz ) return 0;
  if( pOnesz->pFree==0 ) return 0;
  pRes = pOnesz->pFree;
  pOnesz->pFree = pOnesz->pFree->pNext;
  return pRes;
}
static void mmOneszFree(sqlite4_mm *pMM, void *pOld){
  struct mmOnesz *pOnesz = (struct mmOnesz*)pMM;
  if( pOld ){
    struct mmOneszBlock *pBlock = (struct mmOneszBlock*)pOld;
    pBlock->pNext = pOnesz->pFree;
    pOnesz->pFree = pBlock;
  }
}
static void *mmOneszRealloc(sqlite4_mm *pMM, void *pOld, sqlite4_int64 iSz){
  struct mmOnesz *pOnesz = (struct mmOnesz*)pMM;
  if( pOld==0 ) return mmOneszMalloc(pMM, iSz);
  if( iSz<=0 ){
    mmOneszFree(pMM, pOld);
    return 0;
  }
  if( iSz>pOnesz->sz ) return 0;
  return pOld;
}
static sqlite4_int64 mmOneszMsize(sqlite4_mm *pMM, void *pOld){
  struct mmOnesz *pOnesz = (struct mmOnesz*)pMM;
  return pOld ? pOnesz->sz : 0;  
}
static int mmOneszMember(sqlite4_mm *pMM, const void *pOld){
  struct mmOnesz *pOnesz = (struct mmOnesz*)pMM;
  return pOld && pOld>=pOnesz->pSpace && pOld<=pOnesz->pLast;
}
static const sqlite4_mm_methods mmOneszMethods = {
  /* iVersion */    1,
  /* xMalloc  */    mmOneszMalloc,
  /* xRealloc */    mmOneszRealloc,
  /* xFree    */    mmOneszFree,
  /* xMsize   */    mmOneszMsize,
  /* xMember  */    mmOneszMember,
  /* xBenign  */    0,
  /* xFinal   */    0
};
static sqlite4_mm *mmOneszNew(void *pSpace, int sz, int cnt){
  struct mmOnesz *pOnesz;
  unsigned char *pMem;
  if( sz<sizeof(*pOnesz) ) return 0;
  if( cnt<2 ) return 0;
  pMem = (unsigned char*)pSpace;
  pOnesz = (struct mmOnesz*)pMem;
  pMem += sz;
  pOnesz->base.pMethods = &mmOneszMethods;
  pOnesz->pSpace = (const void*)pMem;
  pOnesz->sz = sz;
  pOnesz->pLast = (const void*)(pMem + sz*(cnt-2));
  pOnesz->pFree = 0;
  while( cnt ){
    struct mmOneszBlock *pBlock = (struct mmOneszBlock*)pMem;
    pBlock->pNext = pOnesz->pFree;
    pOnesz->pFree = pBlock;
    cnt--;
    pMem += sz;
  }
  return &pOnesz->base;
}

/*************************************************************************
** Main interfaces.
*/
void *sqlite4_mm_malloc(sqlite4_mm *pMM, sqlite4_int64 iSize){
  if( pMM==0 ) pMM = &mmSystem;
  return pMM->pMethods->xMalloc(pMM,iSize);
}
void *sqlite4_mm_realloc(sqlite4_mm *pMM, void *pOld, sqlite4_int64 iSize){
  if( pMM==0 ) pMM = &mmSystem;
  return pMM->pMethods->xRealloc(pMM,pOld,iSize);
}
void sqlite4_mm_free(sqlite4_mm *pMM, void *pOld){
  if( pMM==0 ) pMM = &mmSystem;
  pMM->pMethods->xFree(pMM,pOld);
}
sqlite4_int64 sqlite4_mm_msize(sqlite4_mm *pMM, void *pOld){
  if( pMM==0 ) pMM = &mmSystem;
  return pMM->pMethods->xMsize(pMM,pOld);
}
int sqlite4_mm_member(sqlite4_mm *pMM, const void *pOld){
  return (pMM && pMM->pMethods->xMember!=0) ?
            pMM->pMethods->xMember(pMM,pOld) : -1;
}
void sqlite4_mm_benign_failure(sqlite4_mm *pMM, int bEnable){
  if( pMM && pMM->pMethods->xBenign ){
    pMM->pMethods->xBenign(pMM, bEnable);
  }
}
void sqlite4_mm_destroy(sqlite4_mm *pMM){
  if( pMM && pMM->pMethods->xFinal ) pMM->pMethods->xFinal(pMM);
}

/*
** Create a new memory allocation object.  eType determines the type of
** memory allocator and the arguments.
*/
sqlite4_mm *sqlite4_mm_new(sqlite4_mm_type eType, ...){
  va_list ap;
  sqlite4_mm *pMM;

  va_start(ap, eType);
  switch( eType ){
    case SQLITE4_MM_SYSTEM: {
      pMM = &mmSystem;
      break;
    }
    case SQLITE4_MM_OVERFLOW: {
      sqlite4_mm *pA = va_arg(ap, sqlite4_mm*);
      sqlite4_mm *pB = va_arg(ap, sqlite4_mm*);
      pMM = mmOvflNew(pA, pB);
      break;
    }
    case SQLITE4_MM_ONESIZE: {
      void *pSpace = va_arg(ap, void*);
      int sz = va_arg(ap, int);
      int cnt = va_arg(ap, int);
      pMM = mmOneszNew(pSpace, sz, cnt);
      break;
    }
    default: {
      pMM = 0;
      break;
    }
  }
  va_end(ap);
  return pMM;
}

Added src/mem.h.



























































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/*
** 2013-01-01
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the SQLite4 memory
** management logic.
**
** Some of this will eventually fold into sqliteInt.h.
*/


/*
** object declarations
*/
typedef struct sqlite4_mm sqlite4_mm;
typedef struct sqlite4_mm_methods sqlite4_mm_methods;

/*
** Base class.  Each implementation extends this with additional
** fields specific to its own needs.  This needs to be public so that
** applications can supply their on customized memory allocators.
*/
struct sqlite4_mm {
  const sqlite4_mm_methods *pMethods;
};

/*
** An instance of the following object defines a BESPOKE memory alloator
*/
struct sqlite4_mm_methods {
  int iVersion;
  void *(*xMalloc)(sqlite4_mm*, sqlite4_int64);
  void *(*xRealloc)(sqlite4_mm*, void*, sqlite4_int64);
  void (*xFree)(sqlite4_mm*, void*);
  sqlite4_int64 (*xMsize)(sqlite4_mm*, void*);
  int (*xMember)(sqlite4_mm*, const void*);
  void (*xBenign)(sqlite4_mm*, int);
  void (*xFinal)(sqlite4_mm*);
};

/*
** Available memory management types:
*/
typedef enum {
  SQLITE4_MM_SYSTEM,         /* Use the system malloc() */
  SQLITE4_MM_ONESIZE,        /* All allocations map to a fixed size */
  SQLITE4_MM_OVERFLOW,       /* Two allocators. Use A first; failover to B */
  SQLITE4_MM_COMPACT,        /* Like memsys3 from SQLite3 */
  SQLITE4_MM_ROBSON,         /* Like memsys5 from SQLite3 */
  SQLITE4_MM_LINEAR,         /* Allocate from a fixed buffer w/o free */
  SQLITE4_MM_DEBUG,          /* Debugging memory allocator */
  SQLITE4_MM_STATS,          /* Keep memory statistics */
  SQLITE4_MM_BESPOKE         /* Caller-defined implementation */
} sqlite4_mm_type;

/*
** Allocate a new memory manager.  Return NULL if unable.
*/
sqlite4_mm *sqlite4_mm_new(sqlite4_mm_type, ...);

/*
** Free the sqlite4_mm object.
**
** All outstanding memory for the allocator must be freed prior to
** invoking this interface, or else the behavior is undefined.
*/
void sqlite4_mm_destroy(sqlite4_mm*);

/*
** Core memory allocation routines:
*/
void *sqlite4_mm_malloc(sqlite4_mm*, sqlite4_int64);
void *sqlite4_mm_realloc(sqlite4_mm*, void*, sqlite4_int64);
void sqlite4_mm_free(sqlite4_mm*, void*);

/*
** Return the size of a memory allocation.
**
** All memory allocators in SQLite4 must be able to report their size.
** When using system malloc() on system that lack the malloc_usable_size()
** routine or its equivalent, then the sqlite4_mm object allocates 8 extra
** bytes for each memory allocation and stores the allocation size in those
** initial 8 bytes.
*/
sqlite4_int64 sqlite4_mm_msize(sqlite4_mm*, void*);

/*
** Check to see if pOld is a memory allocation from pMM.  If it is, return
** 1.  If not, return 0.  If we cannot determine an answer, return -1.
**
** If pOld is not a valid memory allocation or is a memory allocation that
** has previously been freed, then the result of this routine is undefined.
*/
int sqlite4_mm_member(sqlite4_mm *pMM, const void *pOld);

/*
** Enable or disable benign failure mode.  Benign failure mode can be
** nested.  In benign failure mode, OOM errors do not necessarily propagate
** back out to the application but can be dealt with internally.  Memory
** allocations that occur in benign failure mode are considered "optional".
*/
void sqlite4_mm_benign_failures(sqlite4_mm*, int bEnable);