join.tcl
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:12k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. # See the file LICENSE for redistribution information.
  2. #
  3. # Copyright (c) 1996, 1997, 1998, 1999, 2000
  4. # Sleepycat Software.  All rights reserved.
  5. #
  6. # $Id: join.tcl,v 11.17 2000/08/25 14:21:51 sue Exp $
  7. #
  8. # We'll test 2-way, 3-way, and 4-way joins and figure that if those work,
  9. # everything else does as well.  We'll create test databases called
  10. # join1.db, join2.db, join3.db, and join4.db.  The number on the database
  11. # describes the duplication -- duplicates are of the form 0, N, 2N, 3N, ...
  12. # where N is the number of the database.  Primary.db is the primary database,
  13. # and null.db is the database that has no matching duplicates.
  14. #
  15. # We should test this on all btrees, all hash, and a combination thereof
  16. # Join test.
  17. proc jointest { {psize 8192} {with_dup_dups 0} {flags 0} } {
  18. global testdir
  19. global rand_init
  20. source ./include.tcl
  21. env_cleanup $testdir
  22. berkdb srand $rand_init
  23. # Use one environment for all database opens so we don't
  24. # need oodles of regions.
  25. set env [berkdb env -create -home $testdir]
  26. error_check_good env_open [is_valid_env $env] TRUE
  27. # With the new offpage duplicate code, we don't support
  28. # duplicate duplicates in sorted dup sets.  Thus, if with_dup_dups
  29. # is greater than one, run only with "-dup".
  30. if { $with_dup_dups > 1 } {
  31. set doptarray {"-dup"}
  32. } else {
  33. set doptarray {"-dup -dupsort" "-dup" RANDOMMIX RANDOMMIX }
  34. }
  35. # NB: these flags are internal only, ok
  36. foreach m "DB_BTREE DB_HASH DB_BOTH" {
  37. # run with two different random mixes.
  38. foreach dopt $doptarray {
  39. set opt [list "-env" $env $dopt]
  40. puts "Join test: ($m $dopt) psize $psize,
  41.     $with_dup_dups dup
  42.     dups, flags $flags."
  43. build_all $m $psize $opt oa $with_dup_dups
  44. # null.db is db_built fifth but is referenced by
  45. # zero;  set up the option array appropriately.
  46. set oa(0) $oa(5)
  47. # Build the primary
  48. puts "tBuilding the primary database $m"
  49. set oflags "-create -truncate -mode 0644 -env $env
  50.     [conv $m [berkdb random_int 1 2]]"
  51. set db [eval {berkdb_open} $oflags primary.db]
  52. error_check_good dbopen [is_valid_db $db] TRUE
  53. for { set i 0 } { $i < 1000 } { incr i } {
  54. set key [format "%04d" $i]
  55. set ret [$db put $key stub]
  56. error_check_good "primary put" $ret 0
  57. }
  58. error_check_good "primary close" [$db close] 0
  59. set did [open $dict]
  60. gets $did str
  61. do_join primary.db "1 0" $str oa $flags
  62.     $with_dup_dups
  63. gets $did str
  64. do_join primary.db "2 0" $str oa $flags
  65.     $with_dup_dups
  66. gets $did str
  67. do_join primary.db "3 0" $str oa $flags
  68.     $with_dup_dups
  69. gets $did str
  70. do_join primary.db "4 0" $str oa $flags
  71.     $with_dup_dups
  72. gets $did str
  73. do_join primary.db "1" $str oa $flags $with_dup_dups
  74. gets $did str
  75. do_join primary.db "2" $str oa $flags $with_dup_dups
  76. gets $did str
  77. do_join primary.db "3" $str oa $flags $with_dup_dups
  78. gets $did str
  79. do_join primary.db "4" $str oa $flags $with_dup_dups
  80. gets $did str
  81. do_join primary.db "1 2" $str oa $flags
  82.     $with_dup_dups
  83. gets $did str
  84. do_join primary.db "1 2 3" $str oa $flags
  85.     $with_dup_dups
  86. gets $did str
  87. do_join primary.db "1 2 3 4" $str oa $flags
  88.     $with_dup_dups
  89. gets $did str
  90. do_join primary.db "2 1" $str oa $flags
  91.     $with_dup_dups
  92. gets $did str
  93. do_join primary.db "3 2 1" $str oa $flags
  94.     $with_dup_dups
  95. gets $did str
  96. do_join primary.db "4 3 2 1" $str oa $flags
  97.     $with_dup_dups
  98. gets $did str
  99. do_join primary.db "1 3" $str oa $flags $with_dup_dups
  100. gets $did str
  101. do_join primary.db "3 1" $str oa $flags $with_dup_dups
  102. gets $did str
  103. do_join primary.db "1 4" $str oa $flags $with_dup_dups
  104. gets $did str
  105. do_join primary.db "4 1" $str oa $flags $with_dup_dups
  106. gets $did str
  107. do_join primary.db "2 3" $str oa $flags $with_dup_dups
  108. gets $did str
  109. do_join primary.db "3 2" $str oa $flags $with_dup_dups
  110. gets $did str
  111. do_join primary.db "2 4" $str oa $flags $with_dup_dups
  112. gets $did str
  113. do_join primary.db "4 2" $str oa $flags $with_dup_dups
  114. gets $did str
  115. do_join primary.db "3 4" $str oa $flags $with_dup_dups
  116. gets $did str
  117. do_join primary.db "4 3" $str oa $flags $with_dup_dups
  118. gets $did str
  119. do_join primary.db "2 3 4" $str oa $flags
  120.     $with_dup_dups
  121. gets $did str
  122. do_join primary.db "3 4 1" $str oa $flags
  123.     $with_dup_dups
  124. gets $did str
  125. do_join primary.db "4 2 1" $str oa $flags
  126.     $with_dup_dups
  127. gets $did str
  128. do_join primary.db "0 2 1" $str oa $flags
  129.     $with_dup_dups
  130. gets $did str
  131. do_join primary.db "3 2 0" $str oa $flags
  132.     $with_dup_dups
  133. gets $did str
  134. do_join primary.db "4 3 2 1" $str oa $flags
  135.     $with_dup_dups
  136. gets $did str
  137. do_join primary.db "4 3 0 1" $str oa $flags
  138.     $with_dup_dups
  139. gets $did str
  140. do_join primary.db "3 3 3" $str oa $flags
  141.     $with_dup_dups
  142. gets $did str
  143. do_join primary.db "2 2 3 3" $str oa $flags
  144.     $with_dup_dups
  145. gets $did str2
  146. gets $did str
  147. do_join primary.db "1 2" $str oa $flags
  148.     $with_dup_dups "3" $str2
  149. # You really don't want to run this section
  150. # with $with_dup_dups > 2.
  151. if { $with_dup_dups <= 2 } {
  152. gets $did str2
  153. gets $did str
  154. do_join primary.db "1 2 3" $str
  155.     oa $flags $with_dup_dups "3 3 1" $str2
  156. gets $did str2
  157. gets $did str
  158. do_join primary.db "4 0 2" $str
  159.     oa $flags $with_dup_dups "4 3 3" $str2
  160. gets $did str2
  161. gets $did str
  162. do_join primary.db "3 2 1" $str
  163.     oa $flags $with_dup_dups "0 2" $str2
  164. gets $did str2
  165. gets $did str
  166. do_join primary.db "2 2 3 3" $str
  167.     oa $flags $with_dup_dups "1 4 4" $str2
  168. gets $did str2
  169. gets $did str
  170. do_join primary.db "2 2 3 3" $str
  171.     oa $flags $with_dup_dups "0 0 4 4" $str2
  172. gets $did str2
  173. gets $did str
  174. do_join primary.db "2 2 3 3" $str2
  175.     oa $flags $with_dup_dups "2 4 4" $str
  176. gets $did str2
  177. gets $did str
  178. do_join primary.db "2 2 3 3" $str2
  179.     oa $flags $with_dup_dups "0 0 4 4" $str
  180. }
  181. close $did
  182. }
  183. }
  184. error_check_good env_close [$env close] 0
  185. }
  186. proc build_all { method psize opt oaname with_dup_dups {nentries 100} } {
  187. global testdir
  188. db_build join1.db $nentries 50 1 [conv $method 1]
  189.     $psize $opt $oaname $with_dup_dups
  190. db_build join2.db $nentries 25 2 [conv $method 2]
  191.     $psize $opt $oaname $with_dup_dups
  192. db_build join3.db $nentries 16 3 [conv $method 3]
  193.     $psize $opt $oaname $with_dup_dups
  194. db_build join4.db $nentries 12 4 [conv $method 4]
  195.     $psize $opt $oaname $with_dup_dups
  196. db_build null.db $nentries 0 5 [conv $method 5]
  197.     $psize $opt $oaname $with_dup_dups
  198. }
  199. proc conv { m i } {
  200. switch -- $m {
  201. DB_HASH { return "-hash"}
  202. "-hash" { return "-hash"}
  203. DB_BTREE { return "-btree"}
  204. "-btree" { return "-btree"}
  205. DB_BOTH {
  206. if { [expr $i % 2] == 0 } {
  207. return "-hash";
  208. } else {
  209. return "-btree";
  210. }
  211. }
  212. }
  213. }
  214. proc random_opts { } {
  215. set j [berkdb random_int 0 1]
  216. if { $j == 0 } {
  217. return " -dup"
  218. } else {
  219. return " -dup -dupsort"
  220. }
  221. }
  222. proc db_build { name nkeys ndups dup_interval method psize lopt oaname 
  223.     with_dup_dups } {
  224. source ./include.tcl
  225. # Get array of arg names (from two levels up the call stack)
  226. upvar 2 $oaname oa
  227. # Search for "RANDOMMIX" in $opt, and if present, replace
  228. # with " -dup" or " -dup -dupsort" at random.
  229. set i [lsearch $lopt RANDOMMIX]
  230. if { $i != -1 } {
  231. set lopt [lreplace $lopt $i $i [random_opts]]
  232. }
  233. # Save off db_open arguments for this database.
  234. set opt [eval concat $lopt]
  235. set oa($dup_interval) $opt
  236. # Create the database and open the dictionary
  237. set oflags "-create -truncate -mode 0644 $method
  238.     -pagesize $psize"
  239. set db [eval {berkdb_open} $oflags $opt $name]
  240. error_check_good dbopen [is_valid_db $db] TRUE
  241. set did [open $dict]
  242. set count 0
  243. puts -nonewline "tBuilding $name: $nkeys keys "
  244. puts -nonewline "with $ndups duplicates at interval of $dup_interval"
  245. if { $with_dup_dups > 0 } {
  246. puts ""
  247. puts "ttand $with_dup_dups duplicate duplicates."
  248. } else {
  249. puts "."
  250. }
  251. for { set count 0 } { [gets $did str] != -1 && $count < $nkeys } {
  252.     incr count} {
  253. set str $str$name
  254. # We need to make sure that the dups are inserted in a
  255. # random, or near random, order.  Do this by generating
  256. # them and putting each in a list, then sorting the list
  257. # at random.
  258. set duplist {}
  259. for { set i 0 } { $i < $ndups } { incr i } {
  260. set data [format "%04d" [expr $i * $dup_interval]]
  261. lappend duplist $data
  262. }
  263. # randomize the list
  264. for { set i 0 } { $i < $ndups } {incr i } {
  265. # set j [berkdb random_int $i [expr $ndups - 1]]
  266. set j [expr ($i % 2) + $i]
  267. if { $j >= $ndups } { set j $i }
  268. set dupi [lindex $duplist $i]
  269. set dupj [lindex $duplist $j]
  270. set duplist [lreplace $duplist $i $i $dupj]
  271. set duplist [lreplace $duplist $j $j $dupi]
  272. }
  273. foreach data $duplist {
  274. if { $with_dup_dups != 0 } {
  275. for { set j 0 }
  276.     { $j < $with_dup_dups }
  277.     {incr j} {
  278. set ret [$db put $str $data]
  279. error_check_good put$j $ret 0
  280. }
  281. } else {
  282. set ret [$db put $str $data]
  283. error_check_good put $ret 0
  284. }
  285. }
  286. if { $ndups == 0 } {
  287. set ret [$db put $str NODUP]
  288. error_check_good put $ret 0
  289. }
  290. }
  291. close $did
  292. error_check_good close:$name [$db close] 0
  293. }
  294. proc do_join { primary dbs key oanm flags with_dup_dups {dbs2 ""} {key2 ""} } {
  295. global testdir
  296. source ./include.tcl
  297. upvar $oanm oa
  298. puts -nonewline "tJoining: $dbs on $key"
  299. if { $dbs2 == "" } {
  300.     puts ""
  301. } else {
  302.     puts " with $dbs2 on $key2"
  303. }
  304. # Open all the databases
  305. set p [berkdb_open -unknown $testdir/$primary]
  306. error_check_good "primary open" [is_valid_db $p] TRUE
  307. set dblist ""
  308. set curslist ""
  309. set ndx [llength $dbs]
  310. foreach i [concat $dbs $dbs2] {
  311. set opt $oa($i)
  312. set db [eval {berkdb_open -unknown} $opt [n_to_name $i]]
  313. error_check_good "[n_to_name $i] open" [is_valid_db $db] TRUE
  314. set curs [$db cursor]
  315. error_check_good "$db cursor" 
  316.     [is_substr $curs "$db.c"] 1
  317. lappend dblist $db
  318. lappend curslist $curs
  319. if { $ndx > 0 } {
  320.     set realkey [concat $key[n_to_name $i]]
  321. } else {
  322.     set realkey [concat $key2[n_to_name $i]]
  323. }
  324. set pair [$curs get -set $realkey]
  325. error_check_good cursor_set:$realkey:$pair 
  326. [llength [lindex $pair 0]] 2
  327. incr ndx -1
  328. }
  329. set join_curs [eval {$p join} $curslist]
  330. error_check_good join_cursor 
  331.     [is_substr $join_curs "$p.c"] 1
  332. # Calculate how many dups we expect.
  333. # We go through the list of indices.  If we find a 0, then we
  334. # expect 0 dups.  For everything else, we look at pairs of numbers,
  335. # if the are relatively prime, multiply them and figure out how
  336. # many times that goes into 50.  If they aren't relatively prime,
  337. # take the number of times the larger goes into 50.
  338. set expected 50
  339. set last 1
  340. foreach n [concat $dbs $dbs2] {
  341. if { $n == 0 } {
  342. set expected 0
  343. break
  344. }
  345. if { $last == $n } {
  346. continue
  347. }
  348. if { [expr $last % $n] == 0 || [expr $n % $last] == 0 } {
  349. if { $n > $last } {
  350. set last $n
  351. set expected [expr 50 / $last]
  352. }
  353. } else {
  354. set last [expr $n * $last / [gcd $n $last]]
  355. set expected [expr 50 / $last]
  356. }
  357. }
  358. # If $with_dup_dups is greater than zero, each datum has
  359. # been inserted $with_dup_dups times.  So we expect the number
  360. # of dups to go up by a factor of ($with_dup_dups)^(number of databases)
  361. if { $with_dup_dups > 0 } {
  362. foreach n [concat $dbs $dbs2] {
  363. set expected [expr $expected * $with_dup_dups]
  364. }
  365. }
  366. set ndups 0
  367. if { $flags == " -join_item"} {
  368. set l 1
  369. } else {
  370. set flags ""
  371. set l 2
  372. }
  373. for { set pair [eval {$join_curs get} $flags] } { 
  374. [llength [lindex $pair 0]] == $l } {
  375.     set pair [eval {$join_curs get} $flags] } {
  376. set k [lindex [lindex $pair 0] 0]
  377. foreach i $dbs {
  378. error_check_bad valid_dup:$i:$dbs $i 0
  379. set kval [string trimleft $k 0]
  380. if { [string length $kval] == 0 } {
  381. set kval 0
  382. }
  383. error_check_good valid_dup:$i:$dbs [expr $kval % $i] 0
  384. }
  385. incr ndups
  386. }
  387. error_check_good number_of_dups:$dbs $ndups $expected
  388. error_check_good close_primary [$p close] 0
  389. foreach i $curslist {
  390. error_check_good close_cursor:$i [$i close] 0
  391. }
  392. foreach i $dblist {
  393. error_check_good close_index:$i [$i close] 0
  394. }
  395. }
  396. proc n_to_name { n } {
  397. global testdir
  398. if { $n == 0 } {
  399. return null.db;
  400. } else {
  401. return join$n.db;
  402. }
  403. }
  404. proc gcd { a b } {
  405. set g 1
  406. for { set i 2 } { $i <= $a } { incr i } {
  407. if { [expr $a % $i] == 0 && [expr $b % $i] == 0 } {
  408. set g $i
  409. }
  410. }
  411. return $g
  412. }