Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix soft-heap-limit related test suite failures. (CVS 5582) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
2091d9a5260b1d7e27ff5ca93e60dae1 |
User & Date: | danielk1977 2008-08-21 15:54:01.000 |
Context
2008-08-21
| ||
18:49 | Initialize the global built-in function table at start-time instead of at compile-time. This is less prone to malfunction when compile-time parameters very. (CVS 5583) (check-in: ef6936e50a user: drh tags: trunk) | |
15:54 | Fix soft-heap-limit related test suite failures. (CVS 5582) (check-in: 2091d9a526 user: danielk1977 tags: trunk) | |
15:13 | Increase the version number in preparation for the next release. (CVS 5581) (check-in: d68dad73d0 user: drh tags: trunk) | |
Changes
Changes to src/pcache.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 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. ** | | | 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.6 2008/08/21 15:54:01 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** A complete page cache is an instance of this structure. */ struct PCache { |
︙ | ︙ | |||
93 94 95 96 97 98 99 100 101 102 103 104 105 106 | ** from within a call to sqlite3PcacheFetch() on the same pager. A call ** to sqlite3PcacheLock() may block if such an xStress() call is currently ** underway. ** ** Before the xStress callback of a pager-cache (PCache) is invoked, the ** SQLITE_MUTEX_STATIC_MEM2 mutex is obtained and the SQLITE_MUTEX_STATIC_LRU ** mutex released (in that order) before making the call. */ #define pcacheEnterGlobal() sqlite3_mutex_enter(pcache.mutex_lru) #define pcacheExitGlobal() sqlite3_mutex_leave(pcache.mutex_lru) /* ** Increment the reference count on both page p and its cache by n. | > > > | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | ** from within a call to sqlite3PcacheFetch() on the same pager. A call ** to sqlite3PcacheLock() may block if such an xStress() call is currently ** underway. ** ** Before the xStress callback of a pager-cache (PCache) is invoked, the ** SQLITE_MUTEX_STATIC_MEM2 mutex is obtained and the SQLITE_MUTEX_STATIC_LRU ** mutex released (in that order) before making the call. ** ** Deadlock within the module is avoided by never blocking on the MEM2 ** mutex while the LRU mutex is held. */ #define pcacheEnterGlobal() sqlite3_mutex_enter(pcache.mutex_lru) #define pcacheExitGlobal() sqlite3_mutex_leave(pcache.mutex_lru) /* ** Increment the reference count on both page p and its cache by n. |
︙ | ︙ | |||
318 319 320 321 322 323 324 | } /* ** Allocate a page cache line. Look in the page cache memory pool first ** and use an element from it first if available. If nothing is available ** in the page cache memory pool, go to the general purpose memory allocator. */ | | > > > > > > > > > > > > | | 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 | } /* ** Allocate a page cache line. Look in the page cache memory pool first ** and use an element from it first if available. If nothing is available ** in the page cache memory pool, go to the general purpose memory allocator. */ void *pcacheMalloc(int sz, PCache *pCache){ assert( sqlite3_mutex_held(pcache.mutex_lru) ); 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; /* Allocate a new buffer using sqlite3Malloc. Before doing so, exit the ** global pcache mutex and unlock the pager-cache object pCache. This is ** so that if the attempt to allocate a new buffer causes the the ** configured soft-heap-limit to be breached, it will be possible to ** reclaim memory from this pager-cache. Because sqlite3PcacheLock() ** might block on the MEM2 mutex, it has to be called before re-entering ** the global LRU mutex. */ pcacheExitGlobal(); sqlite3PcacheUnlock(pCache); p = sqlite3Malloc(sz); sqlite3PcacheLock(pCache); pcacheEnterGlobal(); if( p ){ sz = sqlite3MallocSize(p); sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz); } return p; } } void *sqlite3PageMalloc(sz){ void *p; pcacheEnterGlobal(); p = pcacheMalloc(sz, 0); pcacheExitGlobal(); return p; } /* ** Release a pager memory allocation */ |
︙ | ︙ | |||
373 374 375 376 377 378 379 | pcacheFree(p); pcacheExitGlobal(); } /* ** Allocate a new page. */ | | | | | < | | 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 | pcacheFree(p); pcacheExitGlobal(); } /* ** Allocate a new page. */ static PgHdr *pcachePageAlloc(PCache *pCache){ PgHdr *p; int sz = sizeof(*p) + pCache->szPage + pCache->szExtra; assert( sqlite3_mutex_held(pcache.mutex_lru) ); p = pcacheMalloc(sz, pCache); if( p==0 ) return 0; memset(p, 0, sizeof(PgHdr)); p->pData = (void*)&p[1]; p->pExtra = (void*)&((char*)p->pData)[pCache->szPage]; pcache.nPage++; if( pCache->bPurgeable ){ pcache.nPurgeable++; } return p; } /* |
︙ | ︙ | |||
497 498 499 500 501 502 503 | if( p && (p->pCache->szPage!=szPage || p->pCache->szExtra!=szExtra) ){ pcachePageFree(p); p = 0; } if( !p ){ | < | | 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 | if( p && (p->pCache->szPage!=szPage || p->pCache->szExtra!=szExtra) ){ pcachePageFree(p); p = 0; } if( !p ){ p = pcachePageAlloc(pCache); } pcacheExitGlobal(); return p; } /*************************************************** General Interfaces ****** |
︙ | ︙ | |||
562 563 564 565 566 567 568 569 570 571 572 573 574 575 | if( bPurgeable ){ pcacheEnterGlobal(); pcache.mxPagePurgeable += p->nMax; pcacheExitGlobal(); } /* Add the new pager-cache to the list of caches starting at pcache.pAll */ sqlite3_mutex_enter(pcache.mutex_mem2); p->pNextAll = pcache.pAll; if( pcache.pAll ){ pcache.pAll->pPrevAll = p; } p->pPrevAll = 0; pcache.pAll = p; | > | 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 | if( bPurgeable ){ pcacheEnterGlobal(); pcache.mxPagePurgeable += p->nMax; pcacheExitGlobal(); } /* Add the new pager-cache to the list of caches starting at pcache.pAll */ assert( sqlite3_mutex_notheld(pcache.mutex_lru) ); sqlite3_mutex_enter(pcache.mutex_mem2); p->pNextAll = pcache.pAll; if( pcache.pAll ){ pcache.pAll->pPrevAll = p; } p->pPrevAll = 0; pcache.pAll = p; |
︙ | ︙ | |||
854 855 856 857 858 859 860 861 862 863 864 865 866 867 | sqlite3_free(pCache->apHash); pcacheExitGlobal(); /* Now remove the pager-cache structure itself from the list of ** all such structures headed by pcache.pAll. This required the ** MUTEX_STATIC_MEM2 mutex. */ sqlite3_mutex_enter(pcache.mutex_mem2); assert(pCache==pcache.pAll || pCache->pPrevAll); assert(pCache->pNextAll==0 || pCache->pNextAll->pPrevAll==pCache); assert(pCache->pPrevAll==0 || pCache->pPrevAll->pNextAll==pCache); if( pCache->pPrevAll ){ pCache->pPrevAll->pNextAll = pCache->pNextAll; }else{ | > | 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 | sqlite3_free(pCache->apHash); pcacheExitGlobal(); /* Now remove the pager-cache structure itself from the list of ** all such structures headed by pcache.pAll. This required the ** MUTEX_STATIC_MEM2 mutex. */ assert( sqlite3_mutex_notheld(pcache.mutex_lru) ); sqlite3_mutex_enter(pcache.mutex_mem2); assert(pCache==pcache.pAll || pCache->pPrevAll); assert(pCache->pNextAll==0 || pCache->pNextAll->pPrevAll==pCache); assert(pCache->pPrevAll==0 || pCache->pPrevAll->pNextAll==pCache); if( pCache->pPrevAll ){ pCache->pPrevAll->pNextAll = pCache->pNextAll; }else{ |
︙ | ︙ | |||
1147 1148 1149 1150 1151 1152 1153 | pCache->nMax = mxPage; } /* ** Lock a pager-cache. */ void sqlite3PcacheLock(PCache *pCache){ | > > | | | | | | | > > | | > | 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 1195 1196 | pCache->nMax = mxPage; } /* ** Lock a pager-cache. */ void sqlite3PcacheLock(PCache *pCache){ if( pCache ){ assert( sqlite3_mutex_notheld(pcache.mutex_lru) ); pCache->iInUseDB++; if( pCache->iInUseMM && pCache->iInUseDB==1 ){ pCache->iInUseDB = 0; sqlite3_mutex_enter(pcache.mutex_mem2); assert( pCache->iInUseMM==0 && pCache->iInUseDB==0 ); pCache->iInUseDB = 1; sqlite3_mutex_leave(pcache.mutex_mem2); } } } /* ** Unlock a pager-cache. */ void sqlite3PcacheUnlock(PCache *pCache){ if( 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. |
︙ | ︙ |
Changes to test/malloc5.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # # This file contains test cases focused on the two memory-management APIs, # sqlite3_soft_heap_limit() and sqlite3_release_memory(). # | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you share freely, never taking more than you give. # #*********************************************************************** # # This file contains test cases focused on the two memory-management APIs, # sqlite3_soft_heap_limit() and sqlite3_release_memory(). # # $Id: malloc5.test,v 1.19 2008/08/21 15:54:01 danielk1977 Exp $ #--------------------------------------------------------------------------- # NOTES ON EXPECTED BEHAVIOUR # #--------------------------------------------------------------------------- |
︙ | ︙ | |||
202 203 204 205 206 207 208 | execsql {COMMIT;} set nMaxBytes [sqlite3_memory_highwater 1] puts -nonewline " (Highwater mark: $nMaxBytes) " expr $nMaxBytes > 1000000 } {1} do_test malloc5-4.2 { sqlite3_release_memory | | | 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | execsql {COMMIT;} set nMaxBytes [sqlite3_memory_highwater 1] puts -nonewline " (Highwater mark: $nMaxBytes) " expr $nMaxBytes > 1000000 } {1} do_test malloc5-4.2 { sqlite3_release_memory sqlite3_soft_heap_limit 110000 sqlite3_memory_highwater 1 execsql {BEGIN;} for {set i 0} {$i < 10000} {incr i} { execsql "INSERT INTO abc VALUES($i, $i, '[string repeat X 100]');" } execsql {COMMIT;} set nMaxBytes [sqlite3_memory_highwater 1] |
︙ | ︙ | |||
227 228 229 230 231 232 233 | # used to store cached page data are both small and transient. # # Summary: the actual high-water mark for memory usage may be slightly # higher than the soft-heap-limit. The specific allocations that cause # the problem are the calls to sqlite3_malloc() inserted into selected # sqlite3OsXXX() functions in test builds. # | | | 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | # used to store cached page data are both small and transient. # # Summary: the actual high-water mark for memory usage may be slightly # higher than the soft-heap-limit. The specific allocations that cause # the problem are the calls to sqlite3_malloc() inserted into selected # sqlite3OsXXX() functions in test builds. # expr $nMaxBytes <= 110100 } {1} do_test malloc5-4.3 { # Check that the content of table abc is at least roughly as expected. execsql { SELECT count(*), sum(a), sum(b) FROM abc; } } [list 20000 [expr int(20000.0 * 4999.5)] [expr int(20000.0 * 4999.5)]] |
︙ | ︙ | |||
292 293 294 295 296 297 298 299 300 301 302 303 304 305 | # This block of test-cases (malloc5-6.1.*) prepares two database files # for the subsequent tests. do_test malloc5-6.1.1 { sqlite3 db test.db execsql { PRAGMA page_size=1024; PRAGMA default_cache_size=10; BEGIN; CREATE TABLE abc(a PRIMARY KEY, b, c); INSERT INTO abc VALUES(randstr(50,50), randstr(75,75), randstr(100,100)); INSERT INTO abc SELECT randstr(50,50), randstr(75,75), randstr(100,100) FROM abc; INSERT INTO abc SELECT randstr(50,50), randstr(75,75), randstr(100,100) FROM abc; | > > > | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | # This block of test-cases (malloc5-6.1.*) prepares two database files # for the subsequent tests. do_test malloc5-6.1.1 { sqlite3 db test.db execsql { PRAGMA page_size=1024; PRAGMA default_cache_size=10; } execsql { PRAGMA temp_store = memory; BEGIN; CREATE TABLE abc(a PRIMARY KEY, b, c); INSERT INTO abc VALUES(randstr(50,50), randstr(75,75), randstr(100,100)); INSERT INTO abc SELECT randstr(50,50), randstr(75,75), randstr(100,100) FROM abc; INSERT INTO abc SELECT randstr(50,50), randstr(75,75), randstr(100,100) FROM abc; |
︙ | ︙ | |||
321 322 323 324 325 326 327 | do_test malloc5-6.1.2 { list [execsql {PRAGMA cache_size}] [execsql {PRAGMA cache_size} db2] } {10 10} do_test malloc5-6.2.1 { execsql { SELECT * FROM abc } db2 execsql {SELECT * FROM abc} db | | | > | | | | < | | | 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 | do_test malloc5-6.1.2 { list [execsql {PRAGMA cache_size}] [execsql {PRAGMA cache_size} db2] } {10 10} do_test malloc5-6.2.1 { execsql { SELECT * FROM abc } db2 execsql {SELECT * FROM abc} db expr [nPage db] + [nPage db2] } {20} do_test malloc5-6.2.2 { # If we now try to reclaim some memory, it should come from the db2 cache. sqlite3_release_memory 3000 expr [nPage db] + [nPage db2] } {17} do_test malloc5-6.2.3 { # Access the db2 cache again, so that all the db2 pages have been used # more recently than all the db pages. Then try to reclaim 3000 bytes. # This time, 3 pages should be pulled from the db cache. execsql { SELECT * FROM abc } db2 sqlite3_release_memory 3000 expr [nPage db] + [nPage db2] } {17} do_test malloc5-6.3.1 { # Now open a transaction and update 2 pages in the db2 cache. Then # do a SELECT on the db cache so that all the db pages are more recently # used than the db2 pages. When we try to free memory, SQLite should # free the non-dirty db2 pages, then the db pages, then finally use # sync() to free up the dirty db2 pages. The only page that cannot be # freed is page1 of db2. Because there is an open transaction, the # btree layer holds a reference to page 1 in the db2 cache. execsql { BEGIN; UPDATE abc SET c = randstr(100,100) WHERE rowid = 1 OR rowid = (SELECT max(rowid) FROM abc); } db2 execsql { SELECT * FROM abc } db expr [nPage db] + [nPage db2] } {20} do_test malloc5-6.3.2 { # Try to release 7700 bytes. This should release all the # non-dirty pages held by db2. sqlite3_release_memory [expr 7*1100] list [nPage db] [nPage db2] } {10 3} do_test malloc5-6.3.3 { |
︙ | ︙ |
Changes to test/permutations.test.
1 2 3 4 5 6 7 8 9 10 11 | # 2008 June 21 # # 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. # #*********************************************************************** # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # 2008 June 21 # # 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: permutations.test,v 1.21 2008/08/21 15:54:01 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Argument processing. # set ::testmode [lindex $argv 0] |
︙ | ︙ | |||
137 138 139 140 141 142 143 144 145 146 147 148 149 150 | ############################################################################# # Start of tests # Run some tests using pre-allocated page and scratch blocks. # run_tests "memsubsys1" -description { Tests using pre-allocated page and scratch blocks } -initialize { catch {db close} sqlite3_shutdown sqlite3_config_pagecache 4096 24 sqlite3_config_scratch 25000 1 sqlite3_initialize } -shutdown { | > > > | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | ############################################################################# # Start of tests # Run some tests using pre-allocated page and scratch blocks. # run_tests "memsubsys1" -description { Tests using pre-allocated page and scratch blocks } -exclude { ioerr5.test malloc5.test } -initialize { catch {db close} sqlite3_shutdown sqlite3_config_pagecache 4096 24 sqlite3_config_scratch 25000 1 sqlite3_initialize } -shutdown { |
︙ | ︙ |