diff options
Diffstat (limited to '')
-rw-r--r-- | ext/fts5/test/fts5merge.test | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/ext/fts5/test/fts5merge.test b/ext/fts5/test/fts5merge.test new file mode 100644 index 0000000..3b86167 --- /dev/null +++ b/ext/fts5/test/fts5merge.test @@ -0,0 +1,243 @@ +# 2014 Dec 20 +# +# 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. +# +#*********************************************************************** +# +# Test that focus on incremental merges of segments. +# + +source [file join [file dirname [info script]] fts5_common.tcl] +set testprefix fts5merge + +# If SQLITE_ENABLE_FTS5 is defined, omit this file. +ifcapable !fts5 { + finish_test + return +} + +db func repeat [list string repeat] + +#------------------------------------------------------------------------- +# Create an fts index so that: +# +# * the index consists of two top-level segments +# * each segment contains records related to $nRowPerSeg rows +# * all rows consist of tokens "x" and "y" only. +# +# Then run ('merge', 1) until everything is completely merged. +# +proc do_merge1_test {testname nRowPerSeg} { + set ::nRowPerSeg [expr $nRowPerSeg] + do_execsql_test $testname.0 { + DROP TABLE IF EXISTS x8; + CREATE VIRTUAL TABLE x8 USING fts5(i); + INSERT INTO x8(x8, rank) VALUES('pgsz', 32); + + WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<$::nRowPerSeg) + INSERT INTO x8 SELECT repeat('x y ', i % 16) FROM ii; + + WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<$::nRowPerSeg) + INSERT INTO x8 SELECT repeat('x y ', i % 16) FROM ii; + + INSERT INTO x8(x8, rank) VALUES('usermerge', 2); + } + + for {set tn 1} {[lindex [fts5_level_segs x8] 0]>0} {incr tn} { + do_execsql_test $testname.$tn { + INSERT INTO x8(x8, rank) VALUES('merge', 1); + INSERT INTO x8(x8) VALUES('integrity-check'); + } + if {$tn>5} break + } + + do_test $testname.x [list expr "$tn < 5"] 1 +} + +do_merge1_test 1.1 1 +do_merge1_test 1.2 2 +do_merge1_test 1.3 3 +do_merge1_test 1.4 4 +do_merge1_test 1.5 10 +do_merge1_test 1.6 20 +do_merge1_test 1.7 100 + +#------------------------------------------------------------------------- +# +proc do_merge2_test {testname nRow} { + db func rnddoc fts5_rnddoc + + do_execsql_test $testname.0 { + DROP TABLE IF EXISTS x8; + CREATE VIRTUAL TABLE x8 USING fts5(i); + INSERT INTO x8(x8, rank) VALUES('pgsz', 32); + } + + set ::nRow $nRow + do_test $testname.1 { + for {set i 0} {$i < $::nRow} {incr i} { + execsql { INSERT INTO x8 VALUES( rnddoc(($i%16) + 5) ) } + while {[not_merged x8]} { + execsql { + INSERT INTO x8(x8, rank) VALUES('usermerge', 2); + INSERT INTO x8(x8, rank) VALUES('merge', 1); + INSERT INTO x8(x8, rank) VALUES('usermerge', 16); + INSERT INTO x8(x8) VALUES('integrity-check'); + } + } + } + } {} +} +proc not_merged {tbl} { + set segs [fts5_level_segs $tbl] + foreach s $segs { if {$s>1} { return 1 } } + return 0 +} + +do_merge2_test 2.1 5 +do_merge2_test 2.2 10 +do_merge2_test 2.3 20 + +#------------------------------------------------------------------------- +# Test that a merge will complete any merge that has already been +# started, even if the number of input segments is less than the current +# value of the 'usermerge' configuration parameter. +# +db func rnddoc fts5_rnddoc + +do_execsql_test 3.1 { + DROP TABLE IF EXISTS x8; + CREATE VIRTUAL TABLE x8 USING fts5(i); + INSERT INTO x8(x8, rank) VALUES('pgsz', 32); + INSERT INTO x8 VALUES(rnddoc(100)); + INSERT INTO x8 VALUES(rnddoc(100)); +} +do_test 3.2 { + execsql { + INSERT INTO x8(x8, rank) VALUES('usermerge', 4); + INSERT INTO x8(x8, rank) VALUES('merge', 1); + } + fts5_level_segs x8 +} {2} + +do_test 3.3 { + execsql { + INSERT INTO x8(x8, rank) VALUES('usermerge', 2); + INSERT INTO x8(x8, rank) VALUES('merge', 1); + } + fts5_level_segs x8 +} {2 1} + +do_test 3.4 { + execsql { INSERT INTO x8(x8, rank) VALUES('usermerge', 4) } + while {[not_merged x8]} { + execsql { INSERT INTO x8(x8, rank) VALUES('merge', 1) } + } + fts5_level_segs x8 +} {0 1} + +#------------------------------------------------------------------------- +# +proc mydoc {} { + set x [lindex {a b c d e f g h i j} [expr int(rand()*10)]] + return [string repeat "$x " 30] +} +db func mydoc mydoc + +proc mycount {} { + set res [list] + foreach x {a b c d e f g h i j} { + lappend res [db one {SELECT count(*) FROM x8 WHERE x8 MATCH $x}] + } + set res +} + + #1 32 +foreach {tn pgsz} { + 2 1000 +} { + do_execsql_test 4.$tn.1 { + DROP TABLE IF EXISTS x8; + CREATE VIRTUAL TABLE x8 USING fts5(i); + INSERT INTO x8(x8, rank) VALUES('pgsz', $pgsz); + } + + do_execsql_test 4.$tn.2 { + INSERT INTO x8(x8, rank) VALUES('merge', 1); + } + + do_execsql_test 4.$tn.3 { + WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<100) + INSERT INTO x8 SELECT mydoc() FROM ii; + WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<100) + INSERT INTO x8 SELECT mydoc() FROM ii; + INSERT INTO x8(x8, rank) VALUES('usermerge', 2); + } + + set expect [mycount] + for {set i 0} {$i < 20} {incr i} { + do_test 4.$tn.4.$i { + execsql { INSERT INTO x8(x8, rank) VALUES('merge', 1); } + mycount + } $expect + break + } +# db eval {SELECT fts5_decode(rowid, block) AS r FROM x8_data} { puts $r } +} + +#------------------------------------------------------------------------- +# Test that the 'merge' command does not modify the database if there is +# no work to do. + +do_execsql_test 5.1 { + CREATE VIRTUAL TABLE x9 USING fts5(one, two); + INSERT INTO x9(x9, rank) VALUES('pgsz', 32); + INSERT INTO x9(x9, rank) VALUES('automerge', 2); + INSERT INTO x9(x9, rank) VALUES('usermerge', 2); + INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100)); + INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100)); + INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100)); + INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100)); + INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100)); + INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100)); + INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100)); + INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100)); +} + +do_test 5.2 { + while 1 { + set nChange [db total_changes] + execsql { INSERT INTO x9(x9, rank) VALUES('merge', 1); } + set nChange [expr [db total_changes] - $nChange] + #puts $nChange + if {$nChange<2} break + } +} {} + + +#-------------------------------------------------------------------------- +# Test that running 'merge' on an empty database does not cause a +# problem. +# +reset_db +do_execsql_test 6.0 { + CREATE VIRTUAL TABLE g1 USING fts5(a, b); +} +do_execsql_test 6.1 { + INSERT INTO g1(g1, rank) VALUES('merge', 10); +} +do_execsql_test 6.2 { + INSERT INTO g1(g1, rank) VALUES('merge', -10); +} +do_execsql_test 6.3 { + INSERT INTO g1(g1) VALUES('integrity-check'); +} + + + +finish_test |