blob: 0cc26eff4c22ec10b8d95c3e87101810ea61d27b [file] [log] [blame]
danielk197746abae82007-08-21 13:30:07 +00001# 2007 August 21
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# The focus of this file is testing some specific characteristics of the
13# IO traffic generated by SQLite (making sure SQLite is not writing out
14# more database pages than it has to, stuff like that).
15#
danielk197746abae82007-08-21 13:30:07 +000016
17set testdir [file dirname $argv0]
18source $testdir/tester.tcl
19
danielk1977bf260972008-01-22 11:50:13 +000020db close
21sqlite3_simulate_device
22sqlite3 db test.db -vfs devsym
23
danielk19772ca0f862007-08-23 08:06:44 +000024# Test summary:
25#
26# io-1.* - Test that quick-balance does not journal pages unnecessarily.
danielk19776897ca32007-08-23 16:27:21 +000027#
28# io-2.* - Test the "atomic-write optimization".
29#
30# io-3.* - Test the IO traffic enhancements triggered when the
31# IOCAP_SEQUENTIAL device capability flag is set (no
32# fsync() calls on the journal file).
33#
34# io-4.* - Test the IO traffic enhancements triggered when the
35# IOCAP_SAFE_APPEND device capability flag is set (fewer
36# fsync() calls on the journal file, no need to set nRec
37# field in the single journal header).
danielk19779663b8f2007-08-24 11:52:28 +000038#
39# io-5.* - Test that the default page size is selected and used
40# correctly.
danielk19772ca0f862007-08-23 08:06:44 +000041#
42
danielk197746abae82007-08-21 13:30:07 +000043set ::nWrite 0
44proc nWrite {db} {
45 set bt [btree_from_db $db]
drh27641702007-08-22 02:56:42 +000046 db_enter $db
danielk197746abae82007-08-21 13:30:07 +000047 array set stats [btree_pager_stats $bt]
drh27641702007-08-22 02:56:42 +000048 db_leave $db
danielk197746abae82007-08-21 13:30:07 +000049 set res [expr $stats(write) - $::nWrite]
50 set ::nWrite $stats(write)
51 set res
52}
53
danielk19772ca0f862007-08-23 08:06:44 +000054set ::nSync 0
55proc nSync {} {
56 set res [expr {$::sqlite_sync_count - $::nSync}]
57 set ::nSync $::sqlite_sync_count
58 set res
59}
60
danielk197746abae82007-08-21 13:30:07 +000061do_test io-1.1 {
62 execsql {
drhc2ded2a2007-10-03 21:18:19 +000063 PRAGMA auto_vacuum = OFF;
danielk197746abae82007-08-21 13:30:07 +000064 PRAGMA page_size = 1024;
65 CREATE TABLE abc(a,b);
66 }
67 nWrite db
68} {2}
69
70# Insert into the table 4 records of aproximately 240 bytes each.
71# This should completely fill the root-page of the table. Each
72# INSERT causes 2 db pages to be written - the root-page of "abc"
73# and page 1 (db change-counter page).
74do_test io-1.2 {
75 set ret [list]
76 execsql { INSERT INTO abc VALUES(1,randstr(230,230)); }
77 lappend ret [nWrite db]
78 execsql { INSERT INTO abc VALUES(2,randstr(230,230)); }
79 lappend ret [nWrite db]
80 execsql { INSERT INTO abc VALUES(3,randstr(230,230)); }
81 lappend ret [nWrite db]
82 execsql { INSERT INTO abc VALUES(4,randstr(230,230)); }
83 lappend ret [nWrite db]
84} {2 2 2 2}
85
86# Insert another 240 byte record. This causes two leaf pages
87# to be added to the root page of abc. 4 pages in total
88# are written to the db file - the two leaf pages, the root
89# of abc and the change-counter page.
90do_test io-1.3 {
91 execsql { INSERT INTO abc VALUES(5,randstr(230,230)); }
92 nWrite db
93} {4}
94
95# Insert another 3 240 byte records. After this, the tree consists of
96# the root-node, which is close to empty, and two leaf pages, both of
97# which are full.
98do_test io-1.4 {
99 set ret [list]
100 execsql { INSERT INTO abc VALUES(6,randstr(230,230)); }
101 lappend ret [nWrite db]
102 execsql { INSERT INTO abc VALUES(7,randstr(230,230)); }
103 lappend ret [nWrite db]
104 execsql { INSERT INTO abc VALUES(8,randstr(230,230)); }
105 lappend ret [nWrite db]
106} {2 2 2}
107
danielk197746abae82007-08-21 13:30:07 +0000108# This insert should use the quick-balance trick to add a third leaf
109# to the b-tree used to store table abc. It should only be necessary to
110# write to 3 pages to do this: the change-counter, the root-page and
111# the new leaf page.
112do_test io-1.5 {
113 execsql { INSERT INTO abc VALUES(9,randstr(230,230)); }
114 nWrite db
115} {3}
116
drhd6b93862007-08-29 17:59:42 +0000117ifcapable atomicwrite {
danielk19772ca0f862007-08-23 08:06:44 +0000118
119#----------------------------------------------------------------------
120# Test cases io-2.* test the atomic-write optimization.
121#
122do_test io-2.1 {
123 execsql { DELETE FROM abc; VACUUM; }
124} {}
125
126# Clear the write and sync counts.
127nWrite db ; nSync
128
129# The following INSERT updates 2 pages and requires 4 calls to fsync():
130#
131# 1) The directory in which the journal file is created,
132# 2) The journal file (to sync the page data),
133# 3) The journal file (to sync the journal file header),
134# 4) The database file.
135#
136do_test io-2.2 {
137 execsql { INSERT INTO abc VALUES(1, 2) }
138 list [nWrite db] [nSync]
139} {2 4}
140
141# Set the device-characteristic mask to include the SQLITE_IOCAP_ATOMIC,
142# then do another INSERT similar to the one in io-2.2. This should
143# only write 1 page and require a single fsync().
144#
145# The single fsync() is the database file. Only one page is reported as
146# written because page 1 - the change-counter page - is written using
147# an out-of-band method that bypasses the write counter.
148#
149sqlite3_simulate_device -char atomic
150do_test io-2.3 {
151 execsql { INSERT INTO abc VALUES(3, 4) }
152 list [nWrite db] [nSync]
153} {1 1}
154
155# Test that the journal file is not created and the change-counter is
156# updated when the atomic-write optimization is used.
157#
158do_test io-2.4.1 {
159 execsql {
160 BEGIN;
161 INSERT INTO abc VALUES(5, 6);
162 }
danielk1977bf260972008-01-22 11:50:13 +0000163 sqlite3 db2 test.db -vfs devsym
danielk19772ca0f862007-08-23 08:06:44 +0000164 execsql { SELECT * FROM abc } db2
165} {1 2 3 4}
166do_test io-2.4.2 {
167 file exists test.db-journal
168} {0}
169do_test io-2.4.3 {
170 execsql { COMMIT }
171 execsql { SELECT * FROM abc } db2
172} {1 2 3 4 5 6}
173db2 close
174
175# Test that the journal file is created and sync()d if the transaction
176# modifies more than one database page, even if the IOCAP_ATOMIC flag
177# is set.
178#
179do_test io-2.5.1 {
180 execsql { CREATE TABLE def(d, e) }
181 nWrite db ; nSync
182 execsql {
183 BEGIN;
184 INSERT INTO abc VALUES(7, 8);
185 }
186 file exists test.db-journal
187} {0}
188do_test io-2.5.2 {
189 execsql { INSERT INTO def VALUES('a', 'b'); }
190 file exists test.db-journal
191} {1}
192do_test io-2.5.3 {
193 execsql { COMMIT }
194 list [nWrite db] [nSync]
195} {3 4}
196
197# Test that the journal file is created and sync()d if the transaction
198# modifies a single database page and also appends a page to the file.
199# Internally, this case is handled differently to the one above. The
200# journal file is not actually created until the 'COMMIT' statement
201# is executed.
202#
drh5e0ccc22010-03-29 19:36:52 +0000203# Changed 2010-03-27: The size of the database is now stored in
204# bytes 28..31 and so when a page is added to the database, page 1
205# is immediately modified and the journal file immediately comes into
206# existance. To fix this test, the BEGIN is changed into a a
207# BEGIN IMMEDIATE and the INSERT is omitted.
208#
danielk19772ca0f862007-08-23 08:06:44 +0000209do_test io-2.6.1 {
210 execsql {
drh5e0ccc22010-03-29 19:36:52 +0000211 BEGIN IMMEDIATE;
212 -- INSERT INTO abc VALUES(9, randstr(1000,1000));
danielk19772ca0f862007-08-23 08:06:44 +0000213 }
214 file exists test.db-journal
215} {0}
216do_test io-2.6.2 {
217 # Create a file at "test.db-journal". This will prevent SQLite from
218 # opening the journal for exclusive access. As a result, the COMMIT
219 # should fail with SQLITE_CANTOPEN and the transaction rolled back.
220 #
danielk197785943732009-03-28 07:03:41 +0000221 file mkdir test.db-journal
drh5e0ccc22010-03-29 19:36:52 +0000222 catchsql {
223 INSERT INTO abc VALUES(9, randstr(1000,1000));
224 COMMIT
225 }
danielk19772ca0f862007-08-23 08:06:44 +0000226} {1 {unable to open database file}}
227do_test io-2.6.3 {
228 file delete -force test.db-journal
229 catchsql { COMMIT }
drh5e0ccc22010-03-29 19:36:52 +0000230} {0 {}}
danielk19772ca0f862007-08-23 08:06:44 +0000231do_test io-2.6.4 {
232 execsql { SELECT * FROM abc }
233} {1 2 3 4 5 6 7 8}
234
danielk19772ca0f862007-08-23 08:06:44 +0000235# Test that if the database modification is part of multi-file commit,
236# the journal file is always created. In this case, the journal file
237# is created during execution of the COMMIT statement, so we have to
238# use the same technique to check that it is created as in the above
239# block.
240file delete -force test2.db test2.db-journal
danielk19775a8f9372007-10-09 08:29:32 +0000241ifcapable attach {
242 do_test io-2.7.1 {
243 execsql {
244 ATTACH 'test2.db' AS aux;
245 PRAGMA aux.page_size = 1024;
246 CREATE TABLE aux.abc2(a, b);
247 BEGIN;
248 INSERT INTO abc VALUES(9, 10);
249 }
250 file exists test.db-journal
251 } {0}
252 do_test io-2.7.2 {
253 execsql { INSERT INTO abc2 SELECT * FROM abc }
254 file exists test2.db-journal
255 } {0}
256 do_test io-2.7.3 {
257 execsql { SELECT * FROM abc UNION ALL SELECT * FROM abc2 }
258 } {1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10}
259 do_test io-2.7.4 {
danielk197785943732009-03-28 07:03:41 +0000260 file mkdir test2.db-journal
danielk19775a8f9372007-10-09 08:29:32 +0000261 catchsql { COMMIT }
262 } {1 {unable to open database file}}
263 do_test io-2.7.5 {
264 file delete -force test2.db-journal
265 catchsql { COMMIT }
266 } {1 {cannot commit - no transaction is active}}
267 do_test io-2.7.6 {
268 execsql { SELECT * FROM abc UNION ALL SELECT * FROM abc2 }
269 } {1 2 3 4 5 6 7 8}
270}
danielk19772ca0f862007-08-23 08:06:44 +0000271
272# Try an explicit ROLLBACK before the journal file is created.
273#
274do_test io-2.8.1 {
275 execsql {
276 BEGIN;
277 DELETE FROM abc;
278 }
279 file exists test.db-journal
280} {0}
281do_test io-2.8.2 {
282 execsql { SELECT * FROM abc }
283} {}
284do_test io-2.8.3 {
285 execsql {
286 ROLLBACK;
287 SELECT * FROM abc;
288 }
289} {1 2 3 4 5 6 7 8}
290
danielk1977f8940ae2007-08-23 11:07:10 +0000291# Test that the atomic write optimisation is not enabled if the sector
292# size is larger than the page-size.
293#
294do_test io-2.9.1 {
drh8a526872009-01-11 00:42:02 +0000295 db close
296 sqlite3 db test.db
danielk1977f8940ae2007-08-23 11:07:10 +0000297 sqlite3_simulate_device -char atomic -sectorsize 2048
298 execsql {
299 BEGIN;
300 INSERT INTO abc VALUES(9, 10);
301 }
302 file exists test.db-journal
303} {1}
304do_test io-2.9.2 {
305 execsql { ROLLBACK; }
306 db close
307 file delete -force test.db test.db-journal
danielk1977bf260972008-01-22 11:50:13 +0000308 sqlite3 db test.db -vfs devsym
danielk1977f8940ae2007-08-23 11:07:10 +0000309 execsql {
drhc2ded2a2007-10-03 21:18:19 +0000310 PRAGMA auto_vacuum = OFF;
danielk1977f8940ae2007-08-23 11:07:10 +0000311 PRAGMA page_size = 2048;
312 CREATE TABLE abc(a, b);
313 }
314 execsql {
315 BEGIN;
316 INSERT INTO abc VALUES(9, 10);
317 }
318 file exists test.db-journal
319} {0}
320do_test io-2.9.3 {
321 execsql { COMMIT }
322} {}
323
324# Test a couple of the more specific IOCAP_ATOMIC flags
325# (i.e IOCAP_ATOMIC2K etc.).
326#
327do_test io-2.10.1 {
328 sqlite3_simulate_device -char atomic1k
329 execsql {
330 BEGIN;
331 INSERT INTO abc VALUES(11, 12);
332 }
333 file exists test.db-journal
334} {1}
335do_test io-2.10.2 {
336 execsql { ROLLBACK }
337 sqlite3_simulate_device -char atomic2k
338 execsql {
339 BEGIN;
340 INSERT INTO abc VALUES(11, 12);
341 }
342 file exists test.db-journal
343} {0}
danielk19776897ca32007-08-23 16:27:21 +0000344do_test io-2.10.3 {
345 execsql { ROLLBACK }
346} {}
danielk1977880c15b2007-09-01 18:24:55 +0000347
348do_test io-2.11.0 {
349 execsql {
350 PRAGMA locking_mode = exclusive;
351 PRAGMA locking_mode;
352 }
353} {exclusive exclusive}
danielk1977880c15b2007-09-01 18:24:55 +0000354do_test io-2.11.1 {
355 execsql {
356 INSERT INTO abc VALUES(11, 12);
357 }
358 file exists test.db-journal
359} {0}
danielk1977880c15b2007-09-01 18:24:55 +0000360
361do_test io-2.11.2 {
362 execsql {
363 PRAGMA locking_mode = normal;
364 INSERT INTO abc VALUES(13, 14);
365 }
366 file exists test.db-journal
367} {0}
368
drhd6b93862007-08-29 17:59:42 +0000369} ;# /* ifcapable atomicwrite */
danielk19776897ca32007-08-23 16:27:21 +0000370
371#----------------------------------------------------------------------
372# Test cases io-3.* test the IOCAP_SEQUENTIAL optimization.
373#
374sqlite3_simulate_device -char sequential -sectorsize 0
danielk19774152e672007-09-12 17:01:45 +0000375ifcapable pager_pragmas {
376 do_test io-3.1 {
377 db close
378 file delete -force test.db test.db-journal
danielk1977bf260972008-01-22 11:50:13 +0000379 sqlite3 db test.db -vfs devsym
drhc2ded2a2007-10-03 21:18:19 +0000380 db eval {
381 PRAGMA auto_vacuum=OFF;
382 }
drh54626242008-07-30 17:28:04 +0000383 # File size might be 1 due to the hack to work around ticket #3260.
384 # Search for #3260 in os_unix.c for additional information.
385 expr {[file size test.db]>1}
danielk19774152e672007-09-12 17:01:45 +0000386 } {0}
387 do_test io-3.2 {
388 execsql { CREATE TABLE abc(a, b) }
389 nSync
390 execsql {
danielk19778c0a7912008-08-20 14:49:23 +0000391 PRAGMA temp_store = memory;
danielk19774152e672007-09-12 17:01:45 +0000392 PRAGMA cache_size = 10;
393 BEGIN;
394 INSERT INTO abc VALUES('hello', 'world');
395 INSERT INTO abc SELECT * FROM abc;
396 INSERT INTO abc SELECT * FROM abc;
397 INSERT INTO abc SELECT * FROM abc;
398 INSERT INTO abc SELECT * FROM abc;
399 INSERT INTO abc SELECT * FROM abc;
400 INSERT INTO abc SELECT * FROM abc;
401 INSERT INTO abc SELECT * FROM abc;
402 INSERT INTO abc SELECT * FROM abc;
403 INSERT INTO abc SELECT * FROM abc;
404 INSERT INTO abc SELECT * FROM abc;
405 INSERT INTO abc SELECT * FROM abc;
406 }
407 # File has grown - showing there was a cache-spill - but there
danielk19773e37f5d2008-09-18 11:18:41 +0000408 # have been no calls to fsync(). The file is probably about 30KB.
409 # But some VFS implementations (symbian) buffer writes so the actual
410 # size may be a little less than that. So this test case just tests
411 # that the file is now greater than 20000 bytes in size.
412 list [expr [file size test.db]>20000] [nSync]
413 } {1 0}
danielk19774152e672007-09-12 17:01:45 +0000414 do_test io-3.3 {
415 # The COMMIT requires a single fsync() - to the database file.
416 execsql { COMMIT }
417 list [file size test.db] [nSync]
418 } {39936 1}
419}
danielk19776897ca32007-08-23 16:27:21 +0000420
421#----------------------------------------------------------------------
422# Test cases io-4.* test the IOCAP_SAFE_APPEND optimization.
423#
424sqlite3_simulate_device -char safe_append
425
426# With the SAFE_APPEND flag set, simple transactions require 3, rather
427# than 4, calls to fsync(). The fsync() calls are on:
428#
drhdec6fae2007-09-03 17:02:50 +0000429# 1) The directory in which the journal file is created, (unix only)
danielk19776897ca32007-08-23 16:27:21 +0000430# 2) The journal file (to sync the page data),
431# 3) The database file.
432#
433# Normally, when the SAFE_APPEND flag is not set, there is another fsync()
434# on the journal file between steps (2) and (3) above.
435#
shane6c533202009-08-19 04:24:48 +0000436set expected_sync_count 2
drhdec6fae2007-09-03 17:02:50 +0000437if {$::tcl_platform(platform)=="unix"} {
shane6c533202009-08-19 04:24:48 +0000438 ifcapable dirsync {
439 incr expected_sync_count
440 }
drhdec6fae2007-09-03 17:02:50 +0000441}
shane6c533202009-08-19 04:24:48 +0000442
danielk19776897ca32007-08-23 16:27:21 +0000443do_test io-4.1 {
444 execsql { DELETE FROM abc }
445 nSync
446 execsql { INSERT INTO abc VALUES('a', 'b') }
447 nSync
drhdec6fae2007-09-03 17:02:50 +0000448} $expected_sync_count
danielk19776897ca32007-08-23 16:27:21 +0000449
450# With SAFE_APPEND set, the nRec field of the journal file header should
451# be set to 0xFFFFFFFF before the first journal sync. The nRec field
452# occupies bytes 8-11 of the journal file.
453#
454do_test io-4.2.1 {
455 execsql { BEGIN }
456 execsql { INSERT INTO abc VALUES('c', 'd') }
457 file exists test.db-journal
458} {1}
drhdec6fae2007-09-03 17:02:50 +0000459if {$::tcl_platform(platform)=="unix"} {
460 do_test io-4.2.2 {
drh039edbb2007-11-27 23:11:45 +0000461 hexio_read test.db-journal 8 4
462 } {FFFFFFFF}
drhdec6fae2007-09-03 17:02:50 +0000463}
danielk19776897ca32007-08-23 16:27:21 +0000464do_test io-4.2.3 {
465 execsql { COMMIT }
466 nSync
drhdec6fae2007-09-03 17:02:50 +0000467} $expected_sync_count
danielk19776897ca32007-08-23 16:27:21 +0000468sqlite3_simulate_device -char safe_append
469
470# With SAFE_APPEND set, there should only ever be one journal-header
471# written to the database, even though the sync-mode is "full".
472#
473do_test io-4.3.1 {
474 execsql {
475 INSERT INTO abc SELECT * FROM abc;
476 INSERT INTO abc SELECT * FROM abc;
477 INSERT INTO abc SELECT * FROM abc;
478 INSERT INTO abc SELECT * FROM abc;
479 INSERT INTO abc SELECT * FROM abc;
480 INSERT INTO abc SELECT * FROM abc;
481 INSERT INTO abc SELECT * FROM abc;
482 INSERT INTO abc SELECT * FROM abc;
483 INSERT INTO abc SELECT * FROM abc;
484 INSERT INTO abc SELECT * FROM abc;
485 INSERT INTO abc SELECT * FROM abc;
486 }
487 expr {[file size test.db]/1024}
488} {43}
danielk19774152e672007-09-12 17:01:45 +0000489ifcapable pager_pragmas {
490 do_test io-4.3.2 {
491 execsql {
492 PRAGMA synchronous = full;
493 PRAGMA cache_size = 10;
494 PRAGMA synchronous;
495 }
496 } {2}
497}
danielk19776897ca32007-08-23 16:27:21 +0000498do_test io-4.3.3 {
499 execsql {
500 BEGIN;
501 UPDATE abc SET a = 'x';
502 }
503 file exists test.db-journal
504} {1}
danielk19773e37f5d2008-09-18 11:18:41 +0000505if {$tcl_platform(platform) != "symbian"} {
506 # This test is not run on symbian because the file-buffer makes it
507 # difficult to predict the exact size of the file as reported by
508 # [file size].
509 do_test io-4.3.4 {
510 # The UPDATE statement in the statement above modifies 41 pages
511 # (all pages in the database except page 1 and the root page of
512 # abc). Because the cache_size is set to 10, this must have required
513 # at least 4 cache-spills. If there were no journal headers written
514 # to the journal file after the cache-spill, then the size of the
515 # journal file is give by:
516 #
517 # <jrnl file size> = <jrnl header size> + nPage * (<page-size> + 8)
518 #
519 # If the journal file contains additional headers, this formula
520 # will not predict the size of the journal file.
521 #
522 file size test.db-journal
523 } [expr 512 + (1024+8)*41]
524}
danielk1977f8940ae2007-08-23 11:07:10 +0000525
danielk19779663b8f2007-08-24 11:52:28 +0000526#----------------------------------------------------------------------
527# Test cases io-5.* test that the default page size is selected and
528# used correctly.
529#
530set tn 0
531foreach {char sectorsize pgsize} {
532 {} 512 1024
533 {} 1024 1024
534 {} 2048 2048
535 {} 8192 8192
536 {} 16384 8192
537 {atomic} 512 8192
538 {atomic512} 512 1024
539 {atomic2K} 512 2048
540 {atomic2K} 4096 4096
541 {atomic2K atomic} 512 8192
542 {atomic64K} 512 1024
543} {
544 incr tn
drhc2ded2a2007-10-03 21:18:19 +0000545 if {$pgsize>$::SQLITE_MAX_PAGE_SIZE} continue
danielk19779663b8f2007-08-24 11:52:28 +0000546 db close
547 file delete -force test.db test.db-journal
548 sqlite3_simulate_device -char $char -sectorsize $sectorsize
danielk1977bf260972008-01-22 11:50:13 +0000549 sqlite3 db test.db -vfs devsym
drhc2ded2a2007-10-03 21:18:19 +0000550 db eval {
551 PRAGMA auto_vacuum=OFF;
552 }
drhd6b93862007-08-29 17:59:42 +0000553 ifcapable !atomicwrite {
554 if {[regexp {^atomic} $char]} continue
555 }
danielk19779663b8f2007-08-24 11:52:28 +0000556 do_test io-5.$tn {
557 execsql {
558 CREATE TABLE abc(a, b, c);
559 }
560 expr {[file size test.db]/2}
561 } $pgsize
562}
563
danielk19772ca0f862007-08-23 08:06:44 +0000564sqlite3_simulate_device -char {} -sectorsize 0
danielk197746abae82007-08-21 13:30:07 +0000565finish_test