1# 2005 November 30 2# 3# The author disclaims copyright to this source code. In place of 4# a legal notice, here is a blessing: 5# 6# May you do good and not evil. 7# May you find forgiveness for yourself and forgive others. 8# May you share freely, never taking more than you give. 9# 10#*********************************************************************** 11# 12# This file contains test cases focused on the two memory-management APIs, 13# sqlite3_soft_heap_limit() and sqlite3_release_memory(). 14# 15# $Id: malloc5.test,v 1.12 2007/08/12 20:07:59 drh Exp $ 16 17#--------------------------------------------------------------------------- 18# NOTES ON EXPECTED BEHAVIOUR 19# 20#--------------------------------------------------------------------------- 21 22 23set testdir [file dirname $argv0] 24source $testdir/tester.tcl 25db close 26 27# Only run these tests if memory debugging is turned on. 28if {[info command sqlite_malloc_stat]==""} { 29 puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..." 30 finish_test 31 return 32} 33 34# Skip these tests if OMIT_MEMORY_MANAGEMENT was defined at compile time. 35ifcapable !memorymanage { 36 finish_test 37 return 38} 39 40sqlite3_soft_heap_limit 0 41sqlite3 db test.db 42 43do_test malloc5-1.1 { 44 # Simplest possible test. Call sqlite3_release_memory when there is exactly 45 # one unused page in a single pager cache. This test case set's the 46 # value of the ::pgalloc variable, which is used in subsequent tests. 47 # 48 # Note: Even though executing this statement on an empty database 49 # modifies 2 pages (the root of sqlite_master and the new root page), 50 # the sqlite_master root (page 1) is never freed because the btree layer 51 # retains a reference to it for the entire transaction. 52 execsql { 53 PRAGMA auto_vacuum=OFF; 54 BEGIN; 55 CREATE TABLE abc(a, b, c); 56 } 57 set ::pgalloc [sqlite3_release_memory] 58 expr $::pgalloc > 0 59} {1} 60do_test malloc5-1.2 { 61 # Test that the transaction started in the above test is still active. 62 # Because the page freed had been written to, freeing it required a 63 # journal sync and exclusive lock on the database file. Test the file 64 # appears to be locked. 65 sqlite3 db2 test.db 66 catchsql { 67 SELECT * FROM abc; 68 } db2 69} {1 {database is locked}} 70do_test malloc5-1.3 { 71 # Again call [sqlite3_release_memory] when there is exactly one unused page 72 # in the cache. The same amount of memory is required, but no journal-sync 73 # or exclusive lock should be established. 74 execsql { 75 COMMIT; 76 BEGIN; 77 SELECT * FROM abc; 78 } 79 sqlite3_release_memory 80} $::pgalloc 81do_test malloc5-1.4 { 82 # Database should not be locked this time. 83 catchsql { 84 SELECT * FROM abc; 85 } db2 86} {0 {}} 87do_test malloc5-1.5 { 88 # Manipulate the cache so that it contains two unused pages. One requires 89 # a journal-sync to free, the other does not. 90 db2 close 91 execsql { 92 SELECT * FROM abc; 93 CREATE TABLE def(d, e, f); 94 } 95 sqlite3_release_memory 500 96} $::pgalloc 97do_test malloc5-1.6 { 98 # Database should not be locked this time. The above test case only 99 # requested 500 bytes of memory, which can be obtained by freeing the page 100 # that does not require an fsync(). 101 sqlite3 db2 test.db 102 catchsql { 103 SELECT * FROM abc; 104 } db2 105} {0 {}} 106do_test malloc5-1.7 { 107 # Release another 500 bytes of memory. This time we require a sync(), 108 # so the database file will be locked afterwards. 109 db2 close 110 sqlite3_release_memory 500 111} $::pgalloc 112do_test malloc5-1.8 { 113 sqlite3 db2 test.db 114 catchsql { 115 SELECT * FROM abc; 116 } db2 117} {1 {database is locked}} 118do_test malloc5-1.9 { 119 execsql { 120 COMMIT; 121 } 122} {} 123 124do_test malloc5-2.1 { 125 # Put some data in tables abc and def. Both tables are still wholly 126 # contained within their root pages. 127 execsql { 128 INSERT INTO abc VALUES(1, 2, 3); 129 INSERT INTO abc VALUES(4, 5, 6); 130 INSERT INTO def VALUES(7, 8, 9); 131 INSERT INTO def VALUES(10,11,12); 132 } 133} {} 134do_test malloc5-2.2 { 135 # Load the root-page for table def into the cache. Then query table abc. 136 # Halfway through the query call sqlite3_release_memory(). The goal of this 137 # test is to make sure we don't free pages that are in use (specifically, 138 # the root of table abc). 139 set nRelease 0 140 execsql { 141 BEGIN; 142 SELECT * FROM def; 143 } 144 set data [list] 145 db eval {SELECT * FROM abc} { 146 incr nRelease [sqlite3_release_memory] 147 lappend data $a $b $c 148 } 149 execsql { 150 COMMIT; 151 } 152 list $nRelease $data 153} [list $pgalloc [list 1 2 3 4 5 6]] 154 155do_test malloc5-3.1 { 156 # Simple test to show that if two pagers are opened from within this 157 # thread, memory is freed from both when sqlite3_release_memory() is 158 # called. 159 execsql { 160 BEGIN; 161 SELECT * FROM abc; 162 } 163 execsql { 164 SELECT * FROM sqlite_master; 165 BEGIN; 166 SELECT * FROM def; 167 } db2 168 sqlite3_release_memory 169} [expr $::pgalloc * 2] 170do_test malloc5-3.2 { 171 concat \ 172 [execsql {SELECT * FROM abc; COMMIT}] \ 173 [execsql {SELECT * FROM def; COMMIT} db2] 174} {1 2 3 4 5 6 7 8 9 10 11 12} 175 176db2 close 177sqlite_malloc_outstanding -clearmaxbytes 178 179# The following two test cases each execute a transaction in which 180# 10000 rows are inserted into table abc. The first test case is used 181# to ensure that more than 1MB of dynamic memory is used to perform 182# the transaction. 183# 184# The second test case sets the "soft-heap-limit" to 100,000 bytes (0.1 MB) 185# and tests to see that this limit is not exceeded at any point during 186# transaction execution. 187# 188# Before executing malloc5-4.* we save the value of the current soft heap 189# limit in variable ::soft_limit. The original value is restored after 190# running the tests. 191# 192set ::soft_limit [sqlite3_soft_heap_limit -1] 193execsql {PRAGMA cache_size=2000} 194do_test malloc5-4.1 { 195 execsql {BEGIN;} 196 execsql {DELETE FROM abc;} 197 for {set i 0} {$i < 10000} {incr i} { 198 execsql "INSERT INTO abc VALUES($i, $i, '[string repeat X 100]');" 199 } 200 execsql {COMMIT;} 201 set ::nMaxBytes [sqlite_malloc_outstanding -maxbytes] 202 if {$::nMaxBytes==""} {set ::nMaxBytes 1000001} 203 expr $::nMaxBytes > 1000000 204} {1} 205do_test malloc5-4.2 { 206 sqlite3_release_memory 207 sqlite_malloc_outstanding -clearmaxbytes 208 sqlite3_soft_heap_limit 100000 209 execsql {BEGIN;} 210 for {set i 0} {$i < 10000} {incr i} { 211 execsql "INSERT INTO abc VALUES($i, $i, '[string repeat X 100]');" 212 } 213 execsql {COMMIT;} 214 set ::nMaxBytes [sqlite_malloc_outstanding -maxbytes] 215 if {$::nMaxBytes==""} {set ::nMaxBytes 0} 216 expr $::nMaxBytes <= 100000 217} {1} 218do_test malloc5-4.3 { 219 # Check that the content of table abc is at least roughly as expected. 220 execsql { 221 SELECT count(*), sum(a), sum(b) FROM abc; 222 } 223} [list 20000 [expr int(20000.0 * 4999.5)] [expr int(20000.0 * 4999.5)]] 224 225# Restore the soft heap limit. 226sqlite3_soft_heap_limit $::soft_limit 227 228# Test that there are no problems calling sqlite3_release_memory when 229# there are open in-memory databases. 230# 231# At one point these tests would cause a seg-fault. 232# 233do_test malloc5-5.1 { 234 db close 235 sqlite3 db :memory: 236 execsql { 237 BEGIN; 238 CREATE TABLE abc(a, b, c); 239 INSERT INTO abc VALUES('abcdefghi', 1234567890, NULL); 240 INSERT INTO abc SELECT * FROM abc; 241 INSERT INTO abc SELECT * FROM abc; 242 INSERT INTO abc SELECT * FROM abc; 243 INSERT INTO abc SELECT * FROM abc; 244 INSERT INTO abc SELECT * FROM abc; 245 INSERT INTO abc SELECT * FROM abc; 246 INSERT INTO abc SELECT * FROM abc; 247 } 248 sqlite3_release_memory 249} 0 250do_test malloc5-5.1 { 251 sqlite3_soft_heap_limit 5000 252 execsql { 253 COMMIT; 254 PRAGMA temp_store = memory; 255 SELECT * FROM abc ORDER BY a; 256 } 257 expr 1 258} {1} 259 260sqlite3_soft_heap_limit $::soft_limit 261finish_test 262catch {db close} 263