summaryrefslogtreecommitdiffstats
path: root/ext/fts5/test/fts5merge.test
diff options
context:
space:
mode:
Diffstat (limited to 'ext/fts5/test/fts5merge.test')
-rw-r--r--ext/fts5/test/fts5merge.test243
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