OmniSciDB  c1a53651b2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
QueryHint.h
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef OMNISCI_QUERYHINT_H
18 #define OMNISCI_QUERYHINT_H
19 
20 #include <algorithm>
21 #include <optional>
22 
23 #include <boost/algorithm/string.hpp>
24 
26 
27 // we expect query hint enum val starts with zero,
28 // and let remaining enum value to be auto-incremented
29 enum QueryHint {
30  kCpuMode = 0,
53  kHintCount, // should be at the last elem before INVALID enum value to count #
54  // supported hints correctly
55  kInvalidHint // this should be the last elem of this enum
56 };
57 
58 static const std::unordered_map<std::string, QueryHint> SupportedQueryHints = {
59  {"cpu_mode", QueryHint::kCpuMode},
60  {"columnar_output", QueryHint::kColumnarOutput},
61  {"rowwise_output", QueryHint::kRowwiseOutput},
62  {"overlaps_bucket_threshold", QueryHint::kOverlapsBucketThreshold},
63  {"overlaps_max_size", QueryHint::kOverlapsMaxSize},
64  {"overlaps_allow_gpu_build", QueryHint::kOverlapsAllowGpuBuild},
65  {"overlaps_no_cache", QueryHint::kOverlapsNoCache},
66  {"overlaps_keys_per_bin", QueryHint::kOverlapsKeysPerBin},
67  {"keep_result", QueryHint::kKeepResult},
68  {"keep_table_function_result", QueryHint::kKeepTableFuncResult},
69  {"aggregate_tree_fanout", QueryHint::kAggregateTreeFanout},
70  {"cuda_block_size", QueryHint::kCudaBlockSize},
71  {"cuda_grid_size_multiplier", QueryHint::kCudaGridSize},
72  {"cuda_opt_block_and_grid_sizes", kOptCudaBlockAndGridSizes},
73  {"watchdog", QueryHint::kWatchdog},
74  {"dynamic_watchdog", QueryHint::kDynamicWatchdog},
75  {"watchdog_off", QueryHint::kWatchdogOff},
76  {"dynamic_watchdog_off", QueryHint::kDynamicWatchdogOff},
77  {"query_time_limit", QueryHint::kQueryTimeLimit},
78  {"allow_loop_join", QueryHint::kAllowLoopJoin},
79  {"disable_loop_join", QueryHint::kDisableLoopJoin},
80  {"loop_join_inner_table_max_num_rows", QueryHint::kLoopJoinInnerTableMaxNumRows},
81  {"max_join_hashtable_size", QueryHint::kMaxJoinHashTableSize}};
82 
85  std::string hint_name;
86 
87  HintIdentifier(bool global_hint, const std::string& hint_name)
88  : global_hint(global_hint), hint_name(hint_name){};
89 };
90 
92  // this class represents parsed query hint's specification
93  // our query AST analyzer translates query hint string to understandable form which we
94  // called "ExplainedQueryHint"
95  public:
96  // default constructor used for deserialization only
99  , global_hint_{false}
100  , is_marker_{false}
101  , has_kv_type_options_{false} {}
102 
104  bool global_hint,
105  bool is_marker,
106  bool has_kv_type_options)
107  : hint_(hint)
108  , global_hint_(global_hint)
109  , is_marker_(is_marker)
110  , has_kv_type_options_(has_kv_type_options) {}
111 
113  bool global_hint,
114  bool is_marker,
115  bool has_kv_type_options,
116  std::vector<std::string>& list_options)
117  : hint_(hint)
118  , global_hint_(global_hint)
119  , is_marker_(is_marker)
120  , has_kv_type_options_(has_kv_type_options)
121  , list_options_(std::move(list_options)) {}
122 
124  bool global_hint,
125  bool is_marker,
126  bool has_kv_type_options,
127  std::unordered_map<std::string, std::string>& kv_options)
128  : hint_(hint)
129  , global_hint_(global_hint)
130  , is_marker_(is_marker)
131  , has_kv_type_options_(has_kv_type_options)
132  , kv_options_(std::move(kv_options)) {}
133 
134  void setListOptions(std::vector<std::string>& list_options) {
135  list_options_ = list_options;
136  }
137 
138  void setKVOptions(std::unordered_map<std::string, std::string>& kv_options) {
139  kv_options_ = kv_options;
140  }
141 
142  void setInheritPaths(std::vector<int>& interit_paths) {
143  inherit_paths_ = interit_paths;
144  }
145 
146  const std::vector<std::string>& getListOptions() const { return list_options_; }
147 
148  const std::vector<int>& getInteritPath() const { return inherit_paths_; }
149 
150  const std::unordered_map<std::string, std::string>& getKVOptions() const {
151  return kv_options_;
152  }
153 
154  const QueryHint getHint() const { return hint_; }
155 
156  bool isGlobalHint() const { return global_hint_; }
157 
158  bool hasOptions() const { return is_marker_; }
159 
160  bool hasKvOptions() const { return has_kv_type_options_; }
161 
162  private:
164  // Set true if this hint affects globally
165  // Otherwise it just affects the node which this hint is included (aka table hint)
167  // set true if this has no extra options (neither list_options nor kv_options)
169  // Set true if it is not a marker and has key-value type options
170  // Otherwise (it is not a marker but has list type options), we set this be false
172  std::vector<int> inherit_paths_; // currently not used
173  std::vector<std::string> list_options_;
174  std::unordered_map<std::string, std::string> kv_options_;
175 };
176 
178  // for each query hint, we first translate the raw query hint info
179  // to understandable form called "ExplainedQueryHint"
180  // and we get all necessary info from it and organize it into "RegisteredQueryHint"
181  // so by using "RegisteredQueryHint", we can know and access which query hint is
182  // registered and its detailed info such as the hint's parameter values given by user
183  // NOTE: after changing query hint fields, we "SHOULD" also update the corresponding
184  // "QueryHintSerializer" accordingly
186  : cpu_mode(false)
189  , keep_result(false)
191  , watchdog(std::nullopt)
192  , dynamic_watchdog(std::nullopt)
193  , query_time_limit(0)
194  , cuda_block_size(0)
198  , overlaps_bucket_threshold(std::numeric_limits<double>::max())
203  , use_loop_join(std::nullopt)
205  , max_join_hash_table_size(std::numeric_limits<size_t>::max())
207 
209  CHECK_EQ(registered_hint.size(), global_hints.registered_hint.size());
210  // apply registered global hint to the local hint if necessary
211  // we prioritize global hint when both side of hints are enabled simultaneously
212  RegisteredQueryHint updated_query_hints(*this);
213 
214  constexpr int num_hints = static_cast<int>(QueryHint::kHintCount);
215  for (int i = 0; i < num_hints; ++i) {
216  if (global_hints.registered_hint.at(i)) {
217  updated_query_hints.registered_hint.at(i) = true;
218  switch (static_cast<QueryHint>(i)) {
219  case QueryHint::kCpuMode:
220  updated_query_hints.cpu_mode = true;
221  break;
223  updated_query_hints.columnar_output = true;
224  break;
226  updated_query_hints.rowwise_output = true;
227  break;
229  updated_query_hints.cuda_block_size = global_hints.cuda_block_size;
230  break;
232  updated_query_hints.cuda_grid_size_multiplier =
233  global_hints.cuda_grid_size_multiplier;
234  break;
236  updated_query_hints.opt_cuda_grid_and_block_size = true;
237  break;
239  updated_query_hints.overlaps_bucket_threshold =
240  global_hints.overlaps_bucket_threshold;
241  break;
243  updated_query_hints.overlaps_max_size = global_hints.overlaps_max_size;
244  break;
246  updated_query_hints.overlaps_allow_gpu_build = true;
247  break;
249  updated_query_hints.overlaps_no_cache = true;
250  break;
252  updated_query_hints.overlaps_keys_per_bin =
253  global_hints.overlaps_keys_per_bin;
254  break;
256  updated_query_hints.keep_result = global_hints.keep_result;
257  break;
259  updated_query_hints.keep_table_function_result =
260  global_hints.keep_table_function_result;
261  break;
263  updated_query_hints.aggregate_tree_fanout =
264  global_hints.aggregate_tree_fanout;
265  break;
268  updated_query_hints.watchdog = global_hints.watchdog;
269  break;
272  updated_query_hints.dynamic_watchdog = global_hints.dynamic_watchdog;
273  break;
275  updated_query_hints.query_time_limit = global_hints.query_time_limit;
276  break;
279  updated_query_hints.use_loop_join = global_hints.use_loop_join;
280  break;
282  updated_query_hints.loop_join_inner_table_max_num_rows =
284  break;
286  updated_query_hints.max_join_hash_table_size =
287  global_hints.max_join_hash_table_size;
288  break;
289  default:
290  UNREACHABLE();
291  }
292  }
293  }
294  return updated_query_hints;
295  }
296 
297  // general query execution
298  bool cpu_mode;
303  std::optional<bool> watchdog;
304  std::optional<bool> dynamic_watchdog;
306 
307  // control CUDA behavior
311 
312  // window function framing
314 
315  // overlaps hash join
316  double overlaps_bucket_threshold; // defined in "OverlapsJoinHashTable.h"
321 
322  // generic hash join
323  std::optional<bool> use_loop_join;
326 
327  std::vector<bool> registered_hint;
328 
330 
331  public:
332  static QueryHint translateQueryHint(const std::string& hint_name) {
333  const auto lowered_hint_name = boost::algorithm::to_lower_copy(hint_name);
334  auto it = SupportedQueryHints.find(lowered_hint_name);
335  return it == SupportedQueryHints.end() ? QueryHint::kInvalidHint : it->second;
336  }
337 
338  bool isAnyQueryHintDelivered() const {
339  const auto identity = [](const bool b) { return b; };
340  return std::any_of(registered_hint.begin(), registered_hint.end(), identity);
341  }
342 
343  void registerHint(const QueryHint hint) {
344  const auto hint_class = static_cast<int>(hint);
345  registered_hint.at(hint_class) = true;
346  }
347 
348  bool isHintRegistered(const QueryHint hint) const {
349  const auto hint_class = static_cast<int>(hint);
350  return registered_hint.at(hint_class);
351  }
352 };
353 
354 // a map from hint_name to its detailed info
355 using Hints = std::unordered_map<QueryHint, ExplainedQueryHint>;
356 
357 #endif // OMNISCI_QUERYHINT_H
std::unordered_map< std::string, std::string > kv_options_
Definition: QueryHint.h:174
#define CHECK_EQ(x, y)
Definition: Logger.h:301
bool isGlobalHint() const
Definition: QueryHint.h:156
bool overlaps_allow_gpu_build
Definition: QueryHint.h:318
const std::vector< int > & getInteritPath() const
Definition: QueryHint.h:148
const std::unordered_map< std::string, std::string > & getKVOptions() const
Definition: QueryHint.h:150
#define UNREACHABLE()
Definition: Logger.h:337
void setListOptions(std::vector< std::string > &list_options)
Definition: QueryHint.h:134
double overlaps_keys_per_bin
Definition: QueryHint.h:320
std::optional< bool > dynamic_watchdog
Definition: QueryHint.h:304
double cuda_grid_size_multiplier
Definition: QueryHint.h:309
size_t cuda_block_size
Definition: QueryHint.h:308
ExplainedQueryHint(QueryHint hint, bool global_hint, bool is_marker, bool has_kv_type_options)
Definition: QueryHint.h:103
std::vector< bool > registered_hint
Definition: QueryHint.h:327
void setKVOptions(std::unordered_map< std::string, std::string > &kv_options)
Definition: QueryHint.h:138
unsigned g_trivial_loop_join_threshold
Definition: Execute.cpp:89
ExplainedQueryHint(QueryHint hint, bool global_hint, bool is_marker, bool has_kv_type_options, std::vector< std::string > &list_options)
Definition: QueryHint.h:112
size_t max_join_hash_table_size
Definition: QueryHint.h:325
bool opt_cuda_grid_and_block_size
Definition: QueryHint.h:310
bool hasKvOptions() const
Definition: QueryHint.h:160
bool keep_table_function_result
Definition: QueryHint.h:302
size_t query_time_limit
Definition: QueryHint.h:305
static const std::unordered_map< std::string, QueryHint > SupportedQueryHints
Definition: QueryHint.h:58
static QueryHint translateQueryHint(const std::string &hint_name)
Definition: QueryHint.h:332
std::vector< std::string > list_options_
Definition: QueryHint.h:173
void registerHint(const QueryHint hint)
Definition: QueryHint.h:343
bool hasOptions() const
Definition: QueryHint.h:158
HintIdentifier(bool global_hint, const std::string &hint_name)
Definition: QueryHint.h:87
double g_overlaps_target_entries_per_bin
Definition: Execute.cpp:106
size_t g_overlaps_max_table_size_bytes
Definition: Execute.cpp:105
std::optional< bool > watchdog
Definition: QueryHint.h:303
static RegisteredQueryHint defaults()
Definition: QueryHint.h:329
size_t overlaps_max_size
Definition: QueryHint.h:317
bool isHintRegistered(const QueryHint hint) const
Definition: QueryHint.h:348
std::unordered_map< QueryHint, ExplainedQueryHint > Hints
Definition: QueryHint.h:355
QueryHint
Definition: QueryHint.h:29
std::optional< bool > use_loop_join
Definition: QueryHint.h:323
RegisteredQueryHint operator||(const RegisteredQueryHint &global_hints) const
Definition: QueryHint.h:208
bool g_enable_watchdog false
Definition: Execute.cpp:79
bool global_hint
Definition: QueryHint.h:84
size_t loop_join_inner_table_max_num_rows
Definition: QueryHint.h:324
std::vector< int > inherit_paths_
Definition: QueryHint.h:172
bool has_kv_type_options_
Definition: QueryHint.h:171
bool any_of(std::vector< Analyzer::Expr * > const &target_exprs)
double overlaps_bucket_threshold
Definition: QueryHint.h:316
QueryHint hint_
Definition: QueryHint.h:163
size_t aggregate_tree_fanout
Definition: QueryHint.h:313
const QueryHint getHint() const
Definition: QueryHint.h:154
std::string hint_name
Definition: QueryHint.h:85
const std::vector< std::string > & getListOptions() const
Definition: QueryHint.h:146
void setInheritPaths(std::vector< int > &interit_paths)
Definition: QueryHint.h:142
ExplainedQueryHint(QueryHint hint, bool global_hint, bool is_marker, bool has_kv_type_options, std::unordered_map< std::string, std::string > &kv_options)
Definition: QueryHint.h:123
bool isAnyQueryHintDelivered() const
Definition: QueryHint.h:338