SQLite

Check-in [d025866b09]
Login

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

Overview
Comment:Fix the functionality associated with sqlite3_release_memory() and sqlite3_soft_heap_limit(). It is automatically disabled if the SQLITE_CONFIG_PAGECACHE option is used. (CVS 5576)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: d025866b09352b32a6d35b97144eaad2fafb7165
User & Date: danielk1977 2008-08-21 12:19:44.000
Context
2008-08-21
12:32
Patch to mkfunction to try and detect miscompiles. Add an unimportant assert back to pcache.c. (CVS 5577) (check-in: a2f375fffb user: drh tags: trunk)
12:19
Fix the functionality associated with sqlite3_release_memory() and sqlite3_soft_heap_limit(). It is automatically disabled if the SQLITE_CONFIG_PAGECACHE option is used. (CVS 5576) (check-in: d025866b09 user: danielk1977 tags: trunk)
04:41
Move an assert() in sqlite3PcacheDirtyPage() so that it does not occur before local variable declarations. Ticket #3325. (CVS 5575) (check-in: 899fa19d1a user: danielk1977 tags: trunk)
Changes
Side-by-Side Diff Ignore Whitespace Patch
Changes to src/malloc.c.
8
9
10
11
12
13
14
15

16
17
18
19
20
21
22
8
9
10
11
12
13
14

15
16
17
18
19
20
21
22







-
+







**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
**
** Memory allocation functions used throughout sqlite.
**
** $Id: malloc.c,v 1.35 2008/08/20 14:49:24 danielk1977 Exp $
** $Id: malloc.c,v 1.36 2008/08/21 12:19:44 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
#include <ctype.h>

/*
** This routine runs when the memory allocator sees that the
58
59
60
61
62
63
64


65
66



67
68
69
70
71
72
73
58
59
60
61
62
63
64
65
66


67
68
69
70
71
72
73
74
75
76







+
+
-
-
+
+
+







/*
** Attempt to release up to n bytes of non-essential memory currently
** held by SQLite. An example of non-essential memory is memory used to
** cache database pages that are not currently in use.
*/
int sqlite3_release_memory(int n){
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
  int nRet = 0;
#if 0
  int nRet = sqlite3VdbeReleaseMemory(n);
  nRet += sqlite3PagerReleaseMemory(n-nRet);
  nRet += sqlite3VdbeReleaseMemory(n);
#endif
  nRet += sqlite3PcacheReleaseMemory(n-nRet);
  return nRet;
#else
  return SQLITE_OK;
#endif
}

/*
Changes to src/pager.c.
14
15
16
17
18
19
20
21

22
23
24
25
26
27
28
14
15
16
17
18
19
20

21
22
23
24
25
26
27
28







-
+







** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.472 2008/08/21 04:35:19 danielk1977 Exp $
** @(#) $Id: pager.c,v 1.473 2008/08/21 12:19:44 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/
2449
2450
2451
2452
2453
2454
2455
2456

2457

2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471

















2472
2473
2474
2475
2476
2477
2478
2449
2450
2451
2452
2453
2454
2455

2456
2457
2458














2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482







-
+

+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







** by the pcache layer.
*/
static int pagerStress(void *p){
  Pager *pPager = (Pager *)p;
  PgHdr *pPg = sqlite3PcacheDirtyPage(pPager->pPCache);
  int rc = SQLITE_OK;

  if( pPg && pPager->errCode==SQLITE_OK ){
  if( pPg ){
    assert( pPg->flags&PGHDR_DIRTY );
    if( pPager->errCode==SQLITE_OK ){
    if( pPg->flags&PGHDR_NEED_SYNC ){
      rc = syncJournal(pPager);
      if( rc==SQLITE_OK && pPager->fullSync 
       && !(sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
      ){
        pPager->nRec = 0;
        rc = writeJournalHdr(pPager);
      }
    }
    if( rc==SQLITE_OK ){
      rc = pager_write_pagelist(pPg);
    }
    if( rc!=SQLITE_OK ){
      pager_error(pPager, rc);
      if( pPg->flags&PGHDR_NEED_SYNC ){
        rc = syncJournal(pPager);
        if( rc==SQLITE_OK && pPager->fullSync && 
          !(sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
        ){
          pPager->nRec = 0;
          rc = writeJournalHdr(pPager);
        }
      }
      if( rc==SQLITE_OK ){
        rc = pager_write_pagelist(pPg);
      }
      if( rc!=SQLITE_OK ){
        pager_error(pPager, rc);
      }
    }else{
      sqlite3PcacheMakeClean(pPg);
    }
  }
  return rc;
}


/*
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2523
2524
2525
2526
2527
2528
2529















2530
2531
2532
2533
2534
2535
2536







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







      }
    }
  }

  return rc;
}

#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/*
** This function is called to free superfluous dynamically allocated memory
** held by the pager system. Memory in use by any SQLite pager allocated
** by the current thread may be sqlite3_free()ed.
**
** nReq is the number of bytes of memory required. Once this much has
** been released, the function returns. The return value is the total number 
** of bytes of memory released.
*/
int sqlite3PagerReleaseMemory(int nReq){
  return 0;
}
#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */

/*
** Read the content of page pPg out of the database file.
*/
static int readDbPage(Pager *pPager, PgHdr *pPg, Pgno pgno){
  int rc;
  i64 offset;
  assert( MEMDB==0 );
Changes to src/pager.h.
9
10
11
12
13
14
15
16

17
18
19
20
21
22
23
9
10
11
12
13
14
15

16
17
18
19
20
21
22
23







-
+







**    May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the sqlite page cache
** subsystem.  The page cache subsystem reads and writes a file a page
** at a time and provides a journal for rollback.
**
** @(#) $Id: pager.h,v 1.78 2008/08/20 14:49:25 danielk1977 Exp $
** @(#) $Id: pager.h,v 1.79 2008/08/21 12:19:44 danielk1977 Exp $
*/

#ifndef _PAGER_H_
#define _PAGER_H_

/*
** If defined as non-zero, auto-vacuum is enabled by default. Otherwise
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
111
112
113
114
115
116
117




118
119
120
121
122
123
124







-
-
-
-







int sqlite3PagerLockingMode(Pager *, int);
int sqlite3PagerJournalMode(Pager *, int);
i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
void *sqlite3PagerTempSpace(Pager*);
int sqlite3PagerSync(Pager *pPager);
void sqlite3PagerAlwaysRollback(Pager *pPager);

#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO)
  int sqlite3PagerReleaseMemory(int);
#endif

#ifdef SQLITE_HAS_CODEC
  void sqlite3PagerSetCodec(Pager*,void*(*)(void*,void*,Pgno,int),void*);
#endif

#if !defined(NDEBUG) || defined(SQLITE_TEST)
  Pgno sqlite3PagerPagenumber(DbPage*);
  int sqlite3PagerIswriteable(DbPage*);
Changes to src/pcache.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14

15
16
17
18
19
20
21
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21













-
+







/*
** 2008 August 05
**
** 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 implements that page cache.
**
** @(#) $Id: pcache.c,v 1.3 2008/08/21 04:41:02 danielk1977 Exp $
** @(#) $Id: pcache.c,v 1.4 2008/08/21 12:19:44 danielk1977 Exp $
*/
#include "sqliteInt.h"

/*
** A complete page cache is an instance of this structure.
*/
struct PCache {
327
328
329
330
331
332
333


334


335
336
337
338
339
340
341
327
328
329
330
331
332
333
334
335

336
337
338
339
340
341
342
343
344







+
+
-
+
+







  if( sz<=pcache.szSlot && pcache.pFree ){
    PgFreeslot *p = pcache.pFree;
    pcache.pFree = p->pNext;
    sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, sz);
    sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
    return (void*)p;
  }else{
    void *p;
    pcacheExitGlobal();
    void *p = sqlite3Malloc(sz);
    p = sqlite3Malloc(sz);
    pcacheEnterGlobal();
    if( p ){
      sz = sqlite3MallocSize(p);
      sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
    }
    return p;
  }
}
401
402
403
404
405
406
407



























































408
409
410
411
412
413
414
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
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







  if( p->pCache->bPurgeable ){
    pcache.nPurgeable--;
  }
  pcacheFree(p->apSave[0]);
  pcacheFree(p->apSave[1]);
  pcacheFree(p);
}

/*
** Return the number of bytes that will be returned to the heap when
** the argument is passed to pcachePageFree().
*/
static int pcachePageSize(PgHdr *p){
  assert( sqlite3_mutex_held(pcache.mutex_lru) );
  assert( !pcache.pStart );
  assert( p->apSave[0]==0 );
  assert( p->apSave[1]==0 );
  assert( p && p->pCache );
  return sqlite3MallocSize(p);
}

static PgHdr *pcacheRecycle(PCache *pCache){
  PCache *pCsr;
  PgHdr *p = 0;

  assert( pcache.isInit );
  assert( sqlite3_mutex_held(pcache.mutex_lru) );

  if( !pcache.pLruTail && SQLITE_OK==sqlite3_mutex_try(pcache.mutex_mem2) ){

    /* Invoke xStress() callbacks until the LRU list contains at least one
    ** page that can be reused or until the xStress() callback of all
    ** caches has been invoked.
    */
    for(pCsr=pcache.pAll; pCsr&&!pcache.pLruTail; pCsr=pCsr->pNextAll){
      assert( pCsr->iInUseMM==0 );
      pCsr->iInUseMM = 1;
      if( pCsr->xStress && (pCsr->iInUseDB==0 || pCache==pCsr) ){
        pcacheExitGlobal();
        pCsr->xStress(pCsr->pStress);
        pcacheEnterGlobal();
      }
      pCsr->iInUseMM = 0;
    }

    sqlite3_mutex_leave(pcache.mutex_mem2);
  }

  p = pcache.pLruTail;

  if( p ){
    pcacheRemoveFromLruList(p);
    pcacheRemoveFromHash(p);
    pcacheRemoveFromList(&p->pCache->pClean, p);

    /* If the always-rollback flag is set on the page being recycled, set 
    ** the always-rollback flag on the corresponding pager.
    */
    if( p->flags&PGHDR_ALWAYS_ROLLBACK ){
      assert(p->pPager);
      sqlite3PagerAlwaysRollback(p->pPager);
    }
  }

  return p;
}

/*
** Obtain space for a page. Try to recycle an old page if the limit on the 
** number of pages has been reached. If the limit has not been reached or
** there are no pages eligible for recycling, allocate a new page.
**
** Return a pointer to the new page, or NULL if an OOM condition occurs.
424
425
426
427
428
429
430
431
432
433
434


435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456

457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474



475
476
477
478
479
480
481
482
486
487
488
489
490
491
492




493
494






















495
496
497
















498
499
500

501
502
503
504
505
506
507







-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+


-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-







  assert( sqlite3_mutex_notheld(pcache.mutex_lru) );

  pcacheEnterGlobal();

  if( (pcache.mxPage && pcache.nPage>=pcache.mxPage) 
   || (!pcache.mxPage && bPurg && pcache.nPurgeable>=pcache.mxPagePurgeable)
  ){
    PCache *pCsr;

    /* If the above test succeeds, then a page will be obtained by recycling
    ** an existing page.
    /* If the above test succeeds, then try to obtain a buffer by recycling
    ** an existing page. */
    */
    if( !pcache.pLruTail && SQLITE_OK==sqlite3_mutex_try(pcache.mutex_mem2) ){

      /* Invoke xStress() callbacks until the LRU list contains at least one
      ** page that can be reused or until the xStress() callback of all
      ** caches has been invoked.
      */
      for(pCsr=pcache.pAll; pCsr&&!pcache.pLruTail; pCsr=pCsr->pNextAll){
        assert( pCsr->iInUseMM==0 );
        pCsr->iInUseMM = 1;
        if( pCsr->xStress && (pCsr->iInUseDB==0 || pCache==pCsr) ){
          pcacheExitGlobal();
          pCsr->xStress(pCsr->pStress);
          pcacheEnterGlobal();
        }
        pCsr->iInUseMM = 0;
      }

      sqlite3_mutex_leave(pcache.mutex_mem2);
    }

    p = pcache.pLruTail;
    p = pcacheRecycle(pCache);
  }

  if( p ){
    pcacheRemoveFromLruList(p);
    pcacheRemoveFromHash(p);
    pcacheRemoveFromList(&p->pCache->pClean, p);

    /* If the always-rollback flag is set on the page being recycled, set 
    ** the always-rollback flag on the corresponding pager.
    */
    if( p->flags&PGHDR_ALWAYS_ROLLBACK ){
      assert(p->pPager);
      sqlite3PagerAlwaysRollback(p->pPager);
    }

    if( p->pCache->szPage!=szPage || p->pCache->szExtra!=szExtra ){
      pcachePageFree(p);
      p = 0;
  if( p && (p->pCache->szPage!=szPage || p->pCache->szExtra!=szExtra) ){
    pcachePageFree(p);
    p = 0;
    }
  }

  if( !p ){
    /* Allocate a new page object. */
    p = pcachePageAlloc(szPage, szExtra, bPurg);
  }

1137
1138
1139
1140
1141
1142
1143


























1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
** Unlock a pager-cache.
*/
void sqlite3PcacheUnlock(PCache *pCache){
  pCache->iInUseDB--;
  assert( pCache->iInUseDB>=0 );
}

#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/*
** This function is called to free superfluous dynamically allocated memory
** held by the pager system. Memory in use by any SQLite pager allocated
** by the current thread may be sqlite3_free()ed.
**
** nReq is the number of bytes of memory required. Once this much has
** been released, the function returns. The return value is the total number 
** of bytes of memory released.
*/
int sqlite3PcacheReleaseMemory(int nReq){
  int nFree = 0;
  if( pcache.pStart==0 ){
    PgHdr *p;
    pcacheEnterGlobal();
    while( (nReq<0 || nFree<nReq) && (p=pcacheRecycle(0)) ){
      nFree += pcachePageSize(p);
      pcachePageFree(p);
    }
    pcacheExitGlobal();
  }
  return nFree;
}
#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */

Changes to src/pcache.h.
8
9
10
11
12
13
14
15

16
17
18
19
20
21
22
8
9
10
11
12
13
14

15
16
17
18
19
20
21
22







-
+







**    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 sqlite page cache
** subsystem. 
**
** @(#) $Id: pcache.h,v 1.1 2008/08/20 14:49:25 danielk1977 Exp $
** @(#) $Id: pcache.h,v 1.2 2008/08/21 12:19:44 danielk1977 Exp $
*/

#ifndef _PCACHE_H_

typedef struct PgHdr PgHdr;
typedef struct PCache PCache;

166
167
168
169
170
171
172


173
174
175
166
167
168
169
170
171
172
173
174
175
176
177







+
+



/* Lock and unlock a pager-cache object. The PcacheLock() function may 
** block if the lock is temporarily available. While a pager-cache is locked,
** the system guarantees that any configured xStress() callback will not
** be invoked by any thread other than the one holding the lock.
*/
void sqlite3PcacheLock(PCache *);
void sqlite3PcacheUnlock(PCache *);

int sqlite3PcacheReleaseMemory(int);

#endif /* _PCACHE_H_ */

Changes to src/vdbeapi.c.
9
10
11
12
13
14
15
16

17
18
19
20
21

22
23
24
25
26
27
28
9
10
11
12
13
14
15

16
17
18
19
20

21
22
23
24
25
26
27
28







-
+




-
+







**    May you share freely, never taking more than you give.
**
*************************************************************************
**
** This file contains code use to implement APIs that are part of the
** VDBE.
**
** $Id: vdbeapi.c,v 1.139 2008/08/11 18:44:58 drh Exp $
** $Id: vdbeapi.c,v 1.140 2008/08/21 12:19:44 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "vdbeInt.h"

#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
#if 0 && defined(SQLITE_ENABLE_MEMORY_MANAGEMENT)
/*
** The following structure contains pointers to the end points of a
** doubly-linked list of all compiled SQL statements that may be holding
** buffers eligible for release when the sqlite3_release_memory() interface is
** invoked. Access to this list is protected by the SQLITE_MUTEX_STATIC_LRU2
** mutex.
**
Changes to test/mutex1.test.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
19











-
+







# 2008 June 17
#
# 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.
#
#***********************************************************************
#
# $Id: mutex1.test,v 1.11 2008/08/20 14:49:25 danielk1977 Exp $
# $Id: mutex1.test,v 1.12 2008/08/21 12:19:44 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

if {[info exists tester_do_binarylog]} {
  finish_test
  return
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
95
96
97
98
99
100
101





102
103
104
105
106
107
108







-
-
-
-
-







set enable_shared_cache [sqlite3_enable_shared_cache 1]
ifcapable threadsafe {
  foreach {mode mutexes} {
    singlethread {}
    multithread  {fast static_lru static_master static_mem static_mem2 static_prng }
    serialized   {fast recursive static_lru static_master static_mem static_mem2 static_prng }
  } {
    ifcapable memorymanage {
      if {$mode ne "singlethread"} {
        lappend mutexes static_lru static_lru2 static_mem2
      }
    }

    do_test mutex1.2.$mode.1 {
      catch {db close}
      sqlite3_shutdown
      sqlite3_config $mode
    } SQLITE_OK