diff options
author | Jan Lindström <jan.lindstrom@mariadb.com> | 2015-06-24 07:16:08 +0300 |
---|---|---|
committer | Jan Lindström <jan.lindstrom@mariadb.com> | 2015-06-24 07:16:08 +0300 |
commit | 2e4984c185ddcd2da789017cd147338846ff409a (patch) | |
tree | 0293831900c860600efbaa747ea886d9d1cbf5bd /storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_size_estimator.rb | |
parent | 792b53e80806df893ee62c9a1c1bd117114c8c6d (diff) | |
parent | a6087e7dc1ef3561d8189c8db15e9591d0f9b520 (diff) | |
download | mariadb-git-2e4984c185ddcd2da789017cd147338846ff409a.tar.gz |
Merge tag 'mariadb-10.0.20' into 10.0-FusionIO10.0-FusionIO
Conflicts:
storage/innobase/os/os0file.cc
storage/xtradb/os/os0file.cc
storage/xtradb/srv/srv0start.cc
Diffstat (limited to 'storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_size_estimator.rb')
-rw-r--r-- | storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_size_estimator.rb | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_size_estimator.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_size_estimator.rb new file mode 100644 index 00000000000..73b44cae3dd --- /dev/null +++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_size_estimator.rb @@ -0,0 +1,155 @@ +module Groonga + class ExpressionSizeEstimator + def initialize(expression, table) + @expression = expression + @table = table + @table_size = @table.size + end + + def estimate + builder = ScanInfoBuilder.new(@expression, Operator::OR, 0) + data_list = builder.build + return @table_size if data_list.nil? + + or_data_list = group_data_list(data_list) + or_sizes = or_data_list.collect do |and_data_list| + and_sizes = and_data_list.collect do |data| + size = estimate_data(data) + if data.logical_op == Operator::AND_NOT + size = @table_size - size + size = 0 if size < 0 + end + size + end + and_sizes.min + end + or_sizes.max + end + + private + def group_data_list(data_list) + or_data_list = [[]] + data_list.each do |data| + next if data.op == Operator::NOP + + and_data_list = or_data_list.last + if and_data_list.empty? + and_data_list << data + else + case data.logical_op + when Operator::AND, Operator::AND_NOT + and_data_list << data + else + and_data_list = [data] + or_data_list << and_data_list + end + end + end + or_data_list + end + + def estimate_data(data) + search_index = data.search_indexes.first + return @table_size if search_index.nil? + + index_column = resolve_index_column(search_index.index_column, + data.op) + return @table_size if index_column.nil? + + size = nil + case data.op + when Operator::MATCH + size = estimate_match(data, index_column) + when Operator::REGEXP + size = estimate_regexp(data, index_column) + when Operator::EQUAL + size = estimate_equal(data, index_column) + when Operator::LESS, + Operator::LESS_EQUAL, + Operator::GREATER, + Operator::GREATER_EQUAL + size = estimate_range(data, index_column) + when Operator::CALL + procedure = data.args.first + if procedure.is_a?(Procedure) and procedure.name == "between" + size = estimate_between(data, index_column) + end + end + size || @table_size + end + + def resolve_index_column(index_column, operator) + while index_column.is_a?(Accessor) + index_info = index_column.find_index(operator) + return nil if index_info.nil? + index_column = index_info.index + end + + index_column + end + + def estimate_match(data, index_column) + index_column.estimate_size(:query => data.query.value) + end + + def estimate_regexp(data, index_column) + index_column.estimate_size(:query => data.query.value, + :mode => data.op) + end + + def estimate_equal(data, index_column) + lexicon = index_column.lexicon + term_id = lexicon[data.query] + return 0 if term_id.nil? + + index_column.estimate_size(:term_id => term_id) + end + + def estimate_range(data, index_column) + lexicon = index_column.lexicon + value = data.query.value + options = {} + case data.op + when Operator::LESS + options[:max] = value + options[:flags] = TableCursorFlags::LT + when Operator::LESS_EQUAL + options[:max] = value + options[:flags] = TableCursorFlags::LE + when Operator::GREATER + options[:min] = value + options[:flags] = TableCursorFlags::GT + when Operator::GREATER_EQUAL + options[:min] = value + options[:flags] = TableCursorFlags::GE + end + TableCursor.open(lexicon, options) do |cursor| + index_column.estimate_size(:lexicon_cursor => cursor) + end + end + + def estimate_between(data, index_column) + lexicon = index_column.lexicon + _, _, min, min_border, max, max_border = data.args + options = { + :min => min, + :max => max, + :flags => 0, + } + if min_border == "include" + options[:flags] |= TableCursorFlags::LT + else + options[:flags] |= TableCursorFlags::LE + end + if max_border == "include" + options[:flags] |= TableCursorFlags::GT + else + options[:flags] |= TableCursorFlags::GE + end + + TableCursor.open(lexicon, options) do |cursor| + index_column.estimate_size(:lexicon_cursor => cursor) + end + end + end +end |