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