sqlite/test/multiplex.test
drh f3717af48d When the multiplexor opens an auxiliary file, it now persists the name of that
file until it is closed, as it should.  Remove the limit on the number of
auxiliary files used by the multiplexor.

FossilOrigin-Name: 1ffa542bf913200a18ef77447aec4fc3ca1ed618
2011-07-20 16:35:31 +00:00

572 lines
18 KiB
Plaintext

# 2010 October 29
#
# 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.
#
#***********************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set g_chunk_size [ expr ($::SQLITE_MAX_PAGE_SIZE*16384) ]
set g_max_chunks 32
# This handles appending the chunk number
# to the end of the filename. if
# SQLITE_MULTIPLEX_EXT_OVWR is defined, then
# it overwrites the last 2 bytes of the
# file name with the chunk number.
proc multiplex_name {name chunk} {
if {$chunk==0} { return $name }
set num [format "%02d" $chunk]
ifcapable {multiplex_ext_overwrite} {
set name [string range $name 0 [expr [string length $name]-2-1]]
}
return $name$num
}
# This saves off the parameters and calls the
# underlying sqlite3_multiplex_control() API.
proc multiplex_set {db name chunk_size max_chunks} {
global g_chunk_size
global g_max_chunks
set g_chunk_size [ expr (($chunk_size+($::SQLITE_MAX_PAGE_SIZE-1)) & ~($::SQLITE_MAX_PAGE_SIZE-1)) ]
set g_max_chunks $max_chunks
set rc [catch {sqlite3_multiplex_control $db $name chunk_size $chunk_size} msg]
if { $rc==0 } {
set rc [catch {sqlite3_multiplex_control $db $name max_chunks $max_chunks} msg]
}
list $msg
}
# This attempts to delete the base file and
# and files with the chunk extension.
proc multiplex_delete {name} {
global g_max_chunks
forcedelete $name
for {set i 0} {$i<$g_max_chunks} {incr i} {
forcedelete [multiplex_name $name $i]
forcedelete [multiplex_name $name-journal $i]
forcedelete [multiplex_name $name-wal $i]
}
}
db close
multiplex_delete test.db
multiplex_delete test2.db
#-------------------------------------------------------------------------
# multiplex-1.1.*: Test initialize and shutdown.
do_test multiplex-1.1 { sqlite3_multiplex_initialize nosuchvfs 1 } {SQLITE_ERROR}
do_test multiplex-1.2 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK}
do_test multiplex-1.3 { sqlite3_multiplex_initialize "" 1 } {SQLITE_MISUSE}
do_test multiplex-1.4 { sqlite3_multiplex_shutdown } {SQLITE_OK}
do_test multiplex-1.5 { sqlite3_multiplex_initialize "" 0 } {SQLITE_OK}
do_test multiplex-1.6 { sqlite3_multiplex_shutdown } {SQLITE_OK}
do_test multiplex-1.7 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK}
do_test multiplex-1.8 { sqlite3_multiplex_shutdown } {SQLITE_OK}
do_test multiplex-1.9.1 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK}
do_test multiplex-1.9.2 { sqlite3 db test.db } {}
do_test multiplex-1.9.3 { multiplex_set db main 32768 16 } {SQLITE_OK}
do_test multiplex-1.9.4 { multiplex_set db main 32768 -1 } {SQLITE_OK}
do_test multiplex-1.9.5 { multiplex_set db main -1 16 } {SQLITE_MISUSE}
do_test multiplex-1.9.6 { multiplex_set db main 31 16 } {SQLITE_OK}
do_test multiplex-1.9.7 { multiplex_set db main 32768 100 } {SQLITE_OK}
do_test multiplex-1.9.8 { multiplex_set db main 1073741824 1 } {SQLITE_OK}
do_test multiplex-1.9.9 { db close } {}
do_test multiplex-1.9.10 { sqlite3_multiplex_shutdown } {SQLITE_OK}
do_test multiplex-1.10.1 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK}
do_test multiplex-1.10.2 { sqlite3 db test.db } {}
do_test multiplex-1.10.3 { lindex [ catchsql { SELECT multiplex_control(2, 32768); } ] 0 } {0}
do_test multiplex-1.10.4 { lindex [ catchsql { SELECT multiplex_control(3, -1); } ] 0 } {0}
do_test multiplex-1.10.5 { lindex [ catchsql { SELECT multiplex_control(2, -1); } ] 0 } {1}
do_test multiplex-1.10.6 { lindex [ catchsql { SELECT multiplex_control(2, 31); } ] 0 } {0}
do_test multiplex-1.10.7 { lindex [ catchsql { SELECT multiplex_control(3, 100); } ] 0 } {0}
do_test multiplex-1.10.8 { lindex [ catchsql { SELECT multiplex_control(2, 1073741824); } ] 0 } {0}
do_test multiplex-1.10.9 { db close } {}
do_test multiplex-1.10.10 { sqlite3_multiplex_shutdown } {SQLITE_OK}
do_test multiplex-1.11.1 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK}
do_test multiplex-1.11.2 { sqlite3 db test.db } {}
do_test multiplex-1.11.3 { sqlite3_multiplex_control db main enable 0 } {SQLITE_OK}
do_test multiplex-1.11.4 { sqlite3_multiplex_control db main enable 1 } {SQLITE_OK}
do_test multiplex-1.11.5 { sqlite3_multiplex_control db main enable -1 } {SQLITE_OK}
do_test multiplex-1.11.6 { db close } {}
do_test multiplex-1.11.7 { sqlite3_multiplex_shutdown } {SQLITE_OK}
do_test multiplex-1.12.1 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK}
do_test multiplex-1.12.2 { sqlite3 db test.db } {}
do_test multiplex-1.12.3 { lindex [ catchsql { SELECT multiplex_control(1, 0); } ] 0 } {0}
do_test multiplex-1.12.4 { lindex [ catchsql { SELECT multiplex_control(1, 1); } ] 0 } {0}
do_test multiplex-1.12.5 { lindex [ catchsql { SELECT multiplex_control(1, -1); } ] 0 } {0}
do_test multiplex-1.12.6 { db close } {}
do_test multiplex-1.12.7 { sqlite3_multiplex_shutdown } {SQLITE_OK}
do_test multiplex-1.13.1 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK}
do_test multiplex-1.13.2 { sqlite3 db test.db } {}
do_test multiplex-1.13.3 { lindex [ catchsql { SELECT multiplex_control(-1, 0); } ] 0 } {1}
do_test multiplex-1.13.4 { lindex [ catchsql { SELECT multiplex_control(4, 1); } ] 0 } {1}
do_test multiplex-1.13.6 { db close } {}
do_test multiplex-1.13.7 { sqlite3_multiplex_shutdown } {SQLITE_OK}
#-------------------------------------------------------------------------
# Some simple warm-body tests with a single database file in rollback
# mode:
#
# multiplex-2.1.*: Test simple writing to a multiplex file.
#
# multiplex-2.2.*: More writing.
#
# multiplex-2.3.*: Open and close a second db.
#
# multiplex-2.4.*: Try to shutdown the multiplex system before closing the db
# file. Check that this fails and the multiplex system still works
# afterwards. Then close the database and successfully shut
# down the multiplex system.
#
# multiplex-2.5.*: More reading/writing.
#
# multiplex-2.6.*: More reading/writing with varying small chunk sizes, as
# well as varying journal mode.
#
# multiplex-2.7.*: Disable/enable tests.
#
sqlite3_multiplex_initialize "" 1
multiplex_set db main 32768 16
file delete -force test.x
do_test multiplex-2.1.2 {
sqlite3 db test.x
execsql {
PRAGMA page_size=1024;
PRAGMA auto_vacuum=OFF;
PRAGMA journal_mode=DELETE;
}
execsql {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, randomblob(1100));
INSERT INTO t1 VALUES(2, randomblob(1100));
}
} {}
do_test multiplex-2.1.3 { file size [multiplex_name test.x 0] } {4096}
do_test multiplex-2.1.4 {
execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
} {}
do_test multiplex-2.2.1 {
execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
} {}
do_test multiplex-2.2.3 { file size [multiplex_name test.x 0] } {6144}
do_test multiplex-2.3.1 {
sqlite3 db2 test2.x
db2 close
} {}
do_test multiplex-2.4.1 {
sqlite3_multiplex_shutdown
} {SQLITE_MISUSE}
do_test multiplex-2.4.2 {
execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
} {}
do_test multiplex-2.4.4 { file size [multiplex_name test.x 0] } {7168}
do_test multiplex-2.4.99 {
db close
sqlite3_multiplex_shutdown
} {SQLITE_OK}
do_test multiplex-2.5.1 {
multiplex_delete test.x
sqlite3_multiplex_initialize "" 1
sqlite3 db test.x
multiplex_set db main 4096 16
} {SQLITE_OK}
do_test multiplex-2.5.2 {
execsql {
PRAGMA page_size = 1024;
PRAGMA journal_mode = delete;
PRAGMA auto_vacuum = off;
CREATE TABLE t1(a PRIMARY KEY, b);
}
} {delete}
do_test multiplex-2.5.3 {
execsql {
INSERT INTO t1 VALUES(1, 'one');
INSERT INTO t1 VALUES(2, randomblob(4000));
INSERT INTO t1 VALUES(3, 'three');
INSERT INTO t1 VALUES(4, randomblob(4000));
INSERT INTO t1 VALUES(5, 'five');
INSERT INTO t1 VALUES(6, randomblob($g_chunk_size));
INSERT INTO t1 VALUES(7, randomblob($g_chunk_size));
}
} {}
do_test multiplex-2.5.4 {
db eval {SELECT * FROM t1 WHERE a=1}
} {1 one}
do_test multiplex-2.5.5 {
db eval {SELECT * FROM t1 WHERE a=3}
} {3 three}
do_test multiplex-2.5.6 {
db eval {SELECT * FROM t1 WHERE a=5}
} {5 five}
do_test multiplex-2.5.7 {
db eval {SELECT a,length(b) FROM t1 WHERE a=2}
} {2 4000}
do_test multiplex-2.5.8 {
db eval {SELECT a,length(b) FROM t1 WHERE a=4}
} {4 4000}
do_test multiplex-2.5.9 { file size [multiplex_name test.x 0] } [list $g_chunk_size]
do_test multiplex-2.5.10 { file size [multiplex_name test.x 1] } [list $g_chunk_size]
do_test multiplex-2.5.99 {
db close
sqlite3_multiplex_shutdown
} {SQLITE_OK}
set all_journal_modes {delete persist truncate memory off}
foreach jmode $all_journal_modes {
for {set sz 151} {$sz<8000} {set sz [expr $sz+419]} {
do_test multiplex-2.6.1.$sz.$jmode {
multiplex_delete test.db
sqlite3_multiplex_initialize "" 1
sqlite3 db test.db
multiplex_set db main $sz 32
} {SQLITE_OK}
do_test multiplex-2.6.2.$sz.$jmode {
db eval {
PRAGMA page_size = 1024;
PRAGMA auto_vacuum = off;
}
db eval "PRAGMA journal_mode = $jmode;"
} $jmode
do_test multiplex-2.6.3.$sz.$jmode {
execsql {
CREATE TABLE t1(a PRIMARY KEY, b);
INSERT INTO t1 VALUES(1, 'one');
INSERT INTO t1 VALUES(2, randomblob($g_chunk_size));
}
} {}
do_test multiplex-2.6.4.$sz.$jmode {
db eval {SELECT b FROM t1 WHERE a=1}
} {one}
do_test multiplex-2.6.5.$sz.$jmode {
db eval {SELECT length(b) FROM t1 WHERE a=2}
} [list $g_chunk_size]
do_test multiplex-2.6.6.$sz.$jmode { file size [multiplex_name test.db 0] } [list $g_chunk_size]
do_test multiplex-2.6.99.$sz.$jmode {
db close
sqlite3_multiplex_shutdown
} {SQLITE_OK}
}
}
do_test multiplex-2.7.1 { multiplex_delete test.db } {}
do_test multiplex-2.7.2 { sqlite3_multiplex_initialize "" 1 } {SQLITE_OK}
do_test multiplex-2.7.3 { sqlite3 db test.db } {}
do_test multiplex-2.7.4 { lindex [ catchsql { SELECT multiplex_control(2, 65536); } ] 0 } {0}
do_test multiplex-2.7.5 { lindex [ catchsql { SELECT multiplex_control(1, 0); } ] 0 } {0}
do_test multiplex-2.7.6 {
execsql {
CREATE TABLE t1(a PRIMARY KEY, b);
INSERT INTO t1 VALUES(1, randomblob(1000));
}
} {}
# verify only one file, and file size is less than chunks size
do_test multiplex-2.7.7 { expr ([file size [multiplex_name test.db 0]] < 65536) } {1}
do_test multiplex-2.7.8 { file exists [multiplex_name test.db 1] } {0}
do_test multiplex-2.7.9 {
execsql {
INSERT INTO t1 VALUES(2, randomblob(65536));
}
} {}
# verify only one file, and file size exceeds chunks size
do_test multiplex-2.7.10 { expr ([file size [multiplex_name test.db 0]] > 65536) } {1}
do_test multiplex-2.7.11 { file exists [multiplex_name test.db 1] } {0}
do_test multiplex-2.7.12 { db close } {}
do_test multiplex-2.7.13 { sqlite3_multiplex_shutdown } {SQLITE_OK}
#-------------------------------------------------------------------------
# Try some tests with more than one connection to a database file. Still
# in rollback mode.
#
# multiplex-3.1.*: Two connections to a single database file.
#
# multiplex-3.2.*: Two connections to each of several database files (that
# are in the same multiplex group).
#
do_test multiplex-3.1.1 {
multiplex_delete test.db
sqlite3_multiplex_initialize "" 1
sqlite3 db test.db
multiplex_set db main 32768 16
} {SQLITE_OK}
do_test multiplex-3.1.2 {
execsql {
PRAGMA page_size = 1024;
PRAGMA journal_mode = delete;
PRAGMA auto_vacuum = off;
CREATE TABLE t1(a PRIMARY KEY, b);
INSERT INTO t1 VALUES(1, 'one');
}
file size [multiplex_name test.db 0]
} {3072}
do_test multiplex-3.1.3 {
sqlite3 db2 test.db
execsql { CREATE TABLE t2(a, b) } db2
} {}
do_test multiplex-3.1.4 {
execsql { CREATE TABLE t3(a, b) }
} {}
do_test multiplex-3.1.5 {
catchsql { CREATE TABLE t3(a, b) }
} {1 {table t3 already exists}}
do_test multiplex-3.1.6 {
db close
db2 close
} {}
do_test multiplex-3.2.1a {
multiplex_delete test.db
multiplex_delete test2.db
sqlite3 db1a test.db
sqlite3 db2a test2.db
foreach db {db1a db2a} {
execsql {
PRAGMA page_size = 1024;
PRAGMA journal_mode = delete;
PRAGMA auto_vacuum = off;
CREATE TABLE t1(a, b);
} $db
}
list [file size [multiplex_name test.db 0]] [file size [multiplex_name test2.db 0]]
} {2048 2048}
do_test multiplex-3.2.1b {
sqlite3 db1b test.db
sqlite3 db2b test2.db
} {}
do_test multiplex-3.2.2 { execsql { INSERT INTO t1 VALUES('x', 'y') } db1a } {}
do_test multiplex-3.2.3 { execsql { INSERT INTO t1 VALUES('v', 'w') } db1b } {}
do_test multiplex-3.2.4 { execsql { INSERT INTO t1 VALUES('t', 'u') } db2a } {}
do_test multiplex-3.2.5 { execsql { INSERT INTO t1 VALUES('r', 's') } db2b } {}
do_test multiplex-3.2.6 {
execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1a
} {}
do_test multiplex-3.2.7 {
execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1b
} {}
do_test multiplex-3.2.8 {
execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2a
} {}
do_test multiplex-3.2.9 {
execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2b
} {}
do_test multiplex-3.3.1 {
execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1a
execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db1b
execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2a
execsql { INSERT INTO t1 VALUES(randomblob(500), randomblob(500)) } db2b
} {}
do_test multiplex-3.2.X {
foreach db {db1a db2a db2b db1b} { catch { $db close } }
} {}
#-------------------------------------------------------------------------
#
sqlite3_multiplex_initialize "" 1
multiplex_set db main 32768 16
# Return a list of all currently defined multiplexs.
proc multiplex_list {} {
set allq {}
foreach q [sqlite3_multiplex_dump] {
lappend allq [lindex $q 0]
}
return [lsort $allq]
}
do_test multiplex-4.1.6 {
multiplex_delete test2.db
sqlite3 db test2.db
db eval {CREATE TABLE t2(x); INSERT INTO t2 VALUES('tab-t2');}
set res [multiplex_list]
list [regexp {test2.db} $res]
} {1}
do_test multiplex-4.1.6a {
sqlite3 db2 test2.db
db2 eval {SELECT * FROM t2}
} {tab-t2}
do_test multiplex-4.1.7 {
execsql {INSERT INTO t2 VALUES(zeroblob(200000))}
} {}
do_test multiplex-4.1.8 {
sqlite3 db2 test2.db
db2 eval {SELECT count(*) FROM t2}
} {2}
do_test multiplex-4.1.8a {
db2 eval { DELETE FROM t2 WHERE x = 'tab-t2' }
} {}
do_test multiplex-4.1.8b {
sqlite3 db2 test2.db
db2 eval {SELECT count(*) FROM t2}
} {1}
do_test multiplex-4.1.9 {
execsql {INSERT INTO t2 VALUES(zeroblob(200000))}
} {}
do_test multiplex-4.1.10 {
set res [multiplex_list]
list [regexp {test2.db} $res]
} {1}
do_test multiplex-4.1.11 {
db2 close
set res [multiplex_list]
list [regexp {test2.db} $res]
} {1}
do_test multiplex-4.1.12 {
db close
multiplex_list
} {}
#-------------------------------------------------------------------------
# The following tests test that the multiplex VFS handles malloc and IO
# errors.
#
sqlite3_multiplex_initialize "" 1
multiplex_set db main 32768 16
do_faultsim_test multiplex-5.1 -prep {
catch {db close}
} -body {
sqlite3 db test2.db
}
do_faultsim_test multiplex-5.2 -prep {
catch {db close}
} -body {
sqlite3 db test.db
}
catch { db close }
multiplex_delete test.db
multiplex_delete test2.db
do_test multiplex-5.3.prep {
sqlite3 db test.db
execsql {
PRAGMA auto_vacuum = 1;
PRAGMA page_size = 1024;
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(10, zeroblob(1200));
}
faultsim_save_and_close
} {}
do_faultsim_test multiplex-5.3 -prep {
faultsim_restore_and_reopen
} -body {
execsql { DELETE FROM t1 }
}
do_test multiplex-5.4.1 {
catch { db close }
multiplex_delete test.db
file mkdir test.db
list [catch { sqlite3 db test.db } msg] $msg
} {1 {unable to open database file}}
catch { file delete test.db }
do_faultsim_test multiplex-5.5 -prep {
catch { sqlite3_multiplex_shutdown }
} -body {
sqlite3_multiplex_initialize "" 1
multiplex_set db main 32768 16
}
#-------------------------------------------------------------------------
# Test that you can vacuum a multiplex'ed DB.
ifcapable vacuum {
sqlite3_multiplex_shutdown
do_test multiplex-6.0.0 {
multiplex_delete test.db
multiplex_delete test.x
sqlite3_multiplex_initialize "" 1
sqlite3 db test.x
multiplex_set db main 4096 16
} {SQLITE_OK}
do_test multiplex-6.1.0 {
execsql {
PRAGMA page_size=1024;
PRAGMA journal_mode=DELETE;
PRAGMA auto_vacuum=OFF;
}
execsql {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, randomblob($g_chunk_size));
INSERT INTO t1 VALUES(2, randomblob($g_chunk_size));
}
} {}
do_test multiplex-6.2.1 { file size [multiplex_name test.x 0] } [list $g_chunk_size]
do_test multiplex-6.2.2 { file size [multiplex_name test.x 1] } [list $g_chunk_size]
do_test multiplex-6.3.0 {
execsql { VACUUM }
} {}
do_test multiplex-6.99 {
db close
multiplex_delete test.x
sqlite3_multiplex_shutdown
} {SQLITE_OK}
}
catch { sqlite3_multiplex_shutdown }
finish_test