1
|
1 |
|
require 'formatador' |
|
|
|
|
2
|
1 |
|
require 'ostruct' |
3
|
1 |
|
require 'json' |
4
|
|
|
|
5
|
1 |
|
module NoSE |
6
|
1 |
|
module CLI |
7
|
|
|
# Add a command to run the advisor for a given workload |
8
|
1 |
|
class NoSECLI < Thor |
9
|
1 |
|
desc 'search NAME', 'run the workload NAME' |
10
|
|
|
|
11
|
1 |
|
long_desc <<-LONGDESC |
12
|
|
|
`nose search` is the primary command to run the NoSE advisor. It will |
13
|
|
|
load the given workload, enumerate indexes for each statement, and |
14
|
|
|
construct and solve an ILP to produce statement execution plans. |
15
|
|
|
LONGDESC |
16
|
|
|
|
17
|
1 |
|
shared_option :mix |
18
|
1 |
|
shared_option :format |
19
|
1 |
|
shared_option :output |
20
|
|
|
|
21
|
1 |
|
option :max_space, type: :numeric, default: Float::INFINITY, |
22
|
|
|
aliases: '-s', |
23
|
|
|
desc: 'maximum space allocated to indexes' |
24
|
1 |
|
option :enumerated, type: :boolean, default: false, aliases: '-e', |
25
|
|
|
desc: 'whether enumerated indexes should be output' |
26
|
1 |
|
option :read_only, type: :boolean, default: false, |
27
|
|
|
desc: 'whether to ignore update statements' |
28
|
1 |
|
option :objective, type: :string, default: 'cost', |
29
|
|
|
enum: %w(cost space indexes), |
30
|
|
|
desc: 'the objective function to use in the ILP' |
31
|
|
|
|
32
|
1 |
|
def search(name) |
|
|
|
|
33
|
|
|
# Get the workload and cost model |
34
|
7 |
|
workload = Workload.load name |
35
|
|
View Code Duplication |
workload.mix = options[:mix].to_sym \ |
|
|
|
|
36
|
7 |
|
unless options[:mix] == 'default' && workload.mix != :default |
37
|
7 |
|
workload.remove_updates if options[:read_only] |
38
|
7 |
|
cost_model = get_class_from_config options, 'cost', :cost_model |
39
|
|
|
|
40
|
|
|
# Execute the advisor |
41
|
7 |
|
objective = Search::Objective.const_get options[:objective].upcase |
42
|
7 |
|
result = search_result workload, cost_model, options[:max_space], |
43
|
|
|
objective |
44
|
6 |
|
output_search_result result, options unless result.nil? |
45
|
|
|
end |
46
|
|
|
|
47
|
1 |
|
private |
48
|
|
|
|
49
|
|
|
# Output results from the search procedure |
50
|
|
|
# @return [void] |
51
|
1 |
|
def output_search_result(result, options) |
52
|
|
|
# Output the results in the specified format |
53
|
6 |
|
file = if options[:output].nil? |
54
|
6 |
|
$stdout |
55
|
|
|
else |
56
|
|
|
File.open(options[:output], 'w') |
57
|
|
|
end |
58
|
|
|
|
59
|
6 |
|
begin |
60
|
6 |
|
backend = get_backend options, result |
61
|
6 |
|
send(('output_' + options[:format]).to_sym, |
62
|
|
|
result, file, options[:enumerated], backend) |
63
|
|
|
rescue |
64
|
|
|
nil |
65
|
|
|
ensure |
66
|
6 |
|
file.close unless options[:output].nil? |
67
|
6 |
|
end |
68
|
|
|
end |
69
|
|
|
end |
70
|
|
|
end |
71
|
|
|
end |
72
|
|
|
|