# 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('automerge', 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('automerge', 2); INSERT INTO x8(x8, rank) VALUES('merge', 1); INSERT INTO x8(x8, rank) VALUES('automerge', 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 an auto-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 'automerge' 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('automerge', 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('automerge', 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('automerge', 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('automerge', 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 } } finish_test