OLD | NEW |
(Empty) | |
| 1 # 2014 Dec 20 |
| 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 # Test that focus on incremental merges of segments. |
| 13 # |
| 14 |
| 15 source [file join [file dirname [info script]] fts5_common.tcl] |
| 16 set testprefix fts5merge |
| 17 |
| 18 # If SQLITE_ENABLE_FTS5 is defined, omit this file. |
| 19 ifcapable !fts5 { |
| 20 finish_test |
| 21 return |
| 22 } |
| 23 |
| 24 db func repeat [list string repeat] |
| 25 |
| 26 #------------------------------------------------------------------------- |
| 27 # Create an fts index so that: |
| 28 # |
| 29 # * the index consists of two top-level segments |
| 30 # * each segment contains records related to $nRowPerSeg rows |
| 31 # * all rows consist of tokens "x" and "y" only. |
| 32 # |
| 33 # Then run ('merge', 1) until everything is completely merged. |
| 34 # |
| 35 proc do_merge1_test {testname nRowPerSeg} { |
| 36 set ::nRowPerSeg [expr $nRowPerSeg] |
| 37 do_execsql_test $testname.0 { |
| 38 DROP TABLE IF EXISTS x8; |
| 39 CREATE VIRTUAL TABLE x8 USING fts5(i); |
| 40 INSERT INTO x8(x8, rank) VALUES('pgsz', 32); |
| 41 |
| 42 WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<$::nRowPerSeg) |
| 43 INSERT INTO x8 SELECT repeat('x y ', i % 16) FROM ii; |
| 44 |
| 45 WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<$::nRowPerSeg) |
| 46 INSERT INTO x8 SELECT repeat('x y ', i % 16) FROM ii; |
| 47 |
| 48 INSERT INTO x8(x8, rank) VALUES('usermerge', 2); |
| 49 } |
| 50 |
| 51 for {set tn 1} {[lindex [fts5_level_segs x8] 0]>0} {incr tn} { |
| 52 do_execsql_test $testname.$tn { |
| 53 INSERT INTO x8(x8, rank) VALUES('merge', 1); |
| 54 INSERT INTO x8(x8) VALUES('integrity-check'); |
| 55 } |
| 56 if {$tn>5} break |
| 57 } |
| 58 |
| 59 do_test $testname.x [list expr "$tn < 5"] 1 |
| 60 } |
| 61 |
| 62 do_merge1_test 1.1 1 |
| 63 do_merge1_test 1.2 2 |
| 64 do_merge1_test 1.3 3 |
| 65 do_merge1_test 1.4 4 |
| 66 do_merge1_test 1.5 10 |
| 67 do_merge1_test 1.6 20 |
| 68 do_merge1_test 1.7 100 |
| 69 |
| 70 #------------------------------------------------------------------------- |
| 71 # |
| 72 proc do_merge2_test {testname nRow} { |
| 73 db func rnddoc fts5_rnddoc |
| 74 |
| 75 do_execsql_test $testname.0 { |
| 76 DROP TABLE IF EXISTS x8; |
| 77 CREATE VIRTUAL TABLE x8 USING fts5(i); |
| 78 INSERT INTO x8(x8, rank) VALUES('pgsz', 32); |
| 79 } |
| 80 |
| 81 set ::nRow $nRow |
| 82 do_test $testname.1 { |
| 83 for {set i 0} {$i < $::nRow} {incr i} { |
| 84 execsql { INSERT INTO x8 VALUES( rnddoc(($i%16) + 5) ) } |
| 85 while {[not_merged x8]} { |
| 86 execsql { |
| 87 INSERT INTO x8(x8, rank) VALUES('usermerge', 2); |
| 88 INSERT INTO x8(x8, rank) VALUES('merge', 1); |
| 89 INSERT INTO x8(x8, rank) VALUES('usermerge', 16); |
| 90 INSERT INTO x8(x8) VALUES('integrity-check'); |
| 91 } |
| 92 } |
| 93 } |
| 94 } {} |
| 95 } |
| 96 proc not_merged {tbl} { |
| 97 set segs [fts5_level_segs $tbl] |
| 98 foreach s $segs { if {$s>1} { return 1 } } |
| 99 return 0 |
| 100 } |
| 101 |
| 102 do_merge2_test 2.1 5 |
| 103 do_merge2_test 2.2 10 |
| 104 do_merge2_test 2.3 20 |
| 105 |
| 106 #------------------------------------------------------------------------- |
| 107 # Test that a merge will complete any merge that has already been |
| 108 # started, even if the number of input segments is less than the current |
| 109 # value of the 'usermerge' configuration parameter. |
| 110 # |
| 111 db func rnddoc fts5_rnddoc |
| 112 |
| 113 do_execsql_test 3.1 { |
| 114 DROP TABLE IF EXISTS x8; |
| 115 CREATE VIRTUAL TABLE x8 USING fts5(i); |
| 116 INSERT INTO x8(x8, rank) VALUES('pgsz', 32); |
| 117 INSERT INTO x8 VALUES(rnddoc(100)); |
| 118 INSERT INTO x8 VALUES(rnddoc(100)); |
| 119 } |
| 120 do_test 3.2 { |
| 121 execsql { |
| 122 INSERT INTO x8(x8, rank) VALUES('usermerge', 4); |
| 123 INSERT INTO x8(x8, rank) VALUES('merge', 1); |
| 124 } |
| 125 fts5_level_segs x8 |
| 126 } {2} |
| 127 |
| 128 do_test 3.3 { |
| 129 execsql { |
| 130 INSERT INTO x8(x8, rank) VALUES('usermerge', 2); |
| 131 INSERT INTO x8(x8, rank) VALUES('merge', 1); |
| 132 } |
| 133 fts5_level_segs x8 |
| 134 } {2 1} |
| 135 |
| 136 do_test 3.4 { |
| 137 execsql { INSERT INTO x8(x8, rank) VALUES('usermerge', 4) } |
| 138 while {[not_merged x8]} { |
| 139 execsql { INSERT INTO x8(x8, rank) VALUES('merge', 1) } |
| 140 } |
| 141 fts5_level_segs x8 |
| 142 } {0 1} |
| 143 |
| 144 #------------------------------------------------------------------------- |
| 145 # |
| 146 proc mydoc {} { |
| 147 set x [lindex {a b c d e f g h i j} [expr int(rand()*10)]] |
| 148 return [string repeat "$x " 30] |
| 149 } |
| 150 db func mydoc mydoc |
| 151 |
| 152 proc mycount {} { |
| 153 set res [list] |
| 154 foreach x {a b c d e f g h i j} { |
| 155 lappend res [db one {SELECT count(*) FROM x8 WHERE x8 MATCH $x}] |
| 156 } |
| 157 set res |
| 158 } |
| 159 |
| 160 #1 32 |
| 161 foreach {tn pgsz} { |
| 162 2 1000 |
| 163 } { |
| 164 do_execsql_test 4.$tn.1 { |
| 165 DROP TABLE IF EXISTS x8; |
| 166 CREATE VIRTUAL TABLE x8 USING fts5(i); |
| 167 INSERT INTO x8(x8, rank) VALUES('pgsz', $pgsz); |
| 168 } |
| 169 |
| 170 do_execsql_test 4.$tn.2 { |
| 171 INSERT INTO x8(x8, rank) VALUES('merge', 1); |
| 172 } |
| 173 |
| 174 do_execsql_test 4.$tn.3 { |
| 175 WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<100) |
| 176 INSERT INTO x8 SELECT mydoc() FROM ii; |
| 177 WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<100) |
| 178 INSERT INTO x8 SELECT mydoc() FROM ii; |
| 179 INSERT INTO x8(x8, rank) VALUES('usermerge', 2); |
| 180 } |
| 181 |
| 182 set expect [mycount] |
| 183 for {set i 0} {$i < 20} {incr i} { |
| 184 do_test 4.$tn.4.$i { |
| 185 execsql { INSERT INTO x8(x8, rank) VALUES('merge', 1); } |
| 186 mycount |
| 187 } $expect |
| 188 break |
| 189 } |
| 190 # db eval {SELECT fts5_decode(rowid, block) AS r FROM x8_data} { puts $r } |
| 191 } |
| 192 |
| 193 #------------------------------------------------------------------------- |
| 194 # Test that the 'merge' command does not modify the database if there is |
| 195 # no work to do. |
| 196 |
| 197 do_execsql_test 5.1 { |
| 198 CREATE VIRTUAL TABLE x9 USING fts5(one, two); |
| 199 INSERT INTO x9(x9, rank) VALUES('pgsz', 32); |
| 200 INSERT INTO x9(x9, rank) VALUES('automerge', 2); |
| 201 INSERT INTO x9(x9, rank) VALUES('usermerge', 2); |
| 202 INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100)); |
| 203 INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100)); |
| 204 INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100)); |
| 205 INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100)); |
| 206 INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100)); |
| 207 INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100)); |
| 208 INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100)); |
| 209 INSERT INTO x9 VALUES(rnddoc(100), rnddoc(100)); |
| 210 } |
| 211 |
| 212 do_test 5.2 { |
| 213 while 1 { |
| 214 set nChange [db total_changes] |
| 215 execsql { INSERT INTO x9(x9, rank) VALUES('merge', 1); } |
| 216 set nChange [expr [db total_changes] - $nChange] |
| 217 #puts $nChange |
| 218 if {$nChange<2} break |
| 219 } |
| 220 } {} |
| 221 |
| 222 |
| 223 #-------------------------------------------------------------------------- |
| 224 # Test that running 'merge' on an empty database does not cause a |
| 225 # problem. |
| 226 # |
| 227 reset_db |
| 228 do_execsql_test 6.0 { |
| 229 CREATE VIRTUAL TABLE g1 USING fts5(a, b); |
| 230 } |
| 231 do_execsql_test 6.1 { |
| 232 INSERT INTO g1(g1, rank) VALUES('merge', 10); |
| 233 } |
| 234 do_execsql_test 6.2 { |
| 235 INSERT INTO g1(g1, rank) VALUES('merge', -10); |
| 236 } |
| 237 do_execsql_test 6.3 { |
| 238 INSERT INTO g1(g1) VALUES('integrity-check'); |
| 239 } |
| 240 |
| 241 |
| 242 |
| 243 finish_test |
| 244 |
OLD | NEW |