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