Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
hash-join-node.cc
Go to the documentation of this file.
1 // Copyright 2012 Cloudera Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "exec/hash-join-node.h"
16 
17 #include <sstream>
18 
19 #include "codegen/llvm-codegen.h"
21 #include "exprs/expr.h"
22 #include "runtime/row-batch.h"
23 #include "runtime/runtime-state.h"
24 #include "util/debug-util.h"
25 #include "util/runtime-profile.h"
26 
27 #include "gen-cpp/PlanNodes_types.h"
28 
29 #include "common/names.h"
30 
31 DECLARE_string(cgroup_hierarchy_path);
32 DEFINE_bool(enable_probe_side_filtering, true,
33  "Enables pushing build side filters to probe side");
34 
35 using namespace impala;
36 using namespace llvm;
37 
38 const char* HashJoinNode::LLVM_CLASS_NAME = "class.impala::HashJoinNode";
39 
41  ObjectPool* pool, const TPlanNode& tnode, const DescriptorTbl& descs)
42  : BlockingJoinNode("HashJoinNode", tnode.hash_join_node.join_op, pool, tnode, descs),
43  codegen_process_build_batch_fn_(NULL),
44  process_build_batch_fn_(NULL),
45  process_probe_batch_fn_(NULL) {
46  // The hash join node does not support cross or anti joins
47  DCHECK_NE(join_op_, TJoinOp::CROSS_JOIN);
48  DCHECK_NE(join_op_, TJoinOp::LEFT_ANTI_JOIN);
49  DCHECK_NE(join_op_, TJoinOp::RIGHT_SEMI_JOIN);
50  DCHECK_NE(join_op_, TJoinOp::RIGHT_ANTI_JOIN);
51  DCHECK_NE(join_op_, TJoinOp::NULL_AWARE_LEFT_ANTI_JOIN);
52 
54  (join_op_ == TJoinOp::LEFT_OUTER_JOIN || join_op_ == TJoinOp::FULL_OUTER_JOIN);
55  match_one_build_ = (join_op_ == TJoinOp::LEFT_SEMI_JOIN);
57  (join_op_ == TJoinOp::RIGHT_OUTER_JOIN || join_op_ == TJoinOp::FULL_OUTER_JOIN);
58  can_add_probe_filters_ = tnode.hash_join_node.add_probe_filters;
59  can_add_probe_filters_ &= FLAGS_enable_probe_side_filtering;
60 }
61 
62 Status HashJoinNode::Init(const TPlanNode& tnode) {
64  DCHECK(tnode.__isset.hash_join_node);
65  const vector<TEqJoinCondition>& eq_join_conjuncts =
66  tnode.hash_join_node.eq_join_conjuncts;
67  for (int i = 0; i < eq_join_conjuncts.size(); ++i) {
68  ExprContext* ctx;
69  RETURN_IF_ERROR(Expr::CreateExprTree(pool_, eq_join_conjuncts[i].left, &ctx));
70  probe_expr_ctxs_.push_back(ctx);
71  RETURN_IF_ERROR(Expr::CreateExprTree(pool_, eq_join_conjuncts[i].right, &ctx));
72  build_expr_ctxs_.push_back(ctx);
73  }
75  Expr::CreateExprTrees(pool_, tnode.hash_join_node.other_join_conjuncts,
77  return Status::OK;
78 }
79 
81  SCOPED_TIMER(runtime_profile_->total_time_counter());
83 
85  ADD_COUNTER(runtime_profile(), "BuildBuckets", TUnit::UNIT);
87  ADD_COUNTER(runtime_profile(), "LoadFactor", TUnit::DOUBLE_VALUE);
88 
89  // build and probe exprs are evaluated in the context of the rows produced by our
90  // right and left children, respectively
95 
96  // other_join_conjunct_ctxs_ are evaluated in the context of rows assembled from all
97  // build and probe tuples; full_row_desc is not necessarily the same as the output row
98  // desc, e.g., because semi joins only return the build xor probe tuples
99  RowDescriptor full_row_desc(child(0)->row_desc(), child(1)->row_desc());
101  other_join_conjunct_ctxs_, state, full_row_desc, expr_mem_tracker()));
102 
103  // TODO: default buckets
104  bool stores_nulls =
105  join_op_ == TJoinOp::RIGHT_OUTER_JOIN || join_op_ == TJoinOp::FULL_OUTER_JOIN;
107  child(1)->row_desc().tuple_descriptors().size(), stores_nulls,
108  false, state->fragment_hash_seed(), mem_tracker()));
109 
110  if (state->codegen_enabled()) {
111  LlvmCodeGen* codegen;
112  RETURN_IF_ERROR(state->GetCodegen(&codegen));
113 
114  // Codegen for hashing rows
115  Function* hash_fn = hash_tbl_->CodegenHashCurrentRow(state);
116  if (hash_fn == NULL) return Status::OK;
117 
118  // Codegen for build path
120  if (codegen_process_build_batch_fn_ != NULL) {
122  reinterpret_cast<void**>(&process_build_batch_fn_));
123  AddRuntimeExecOption("Build Side Codegen Enabled");
124  }
125 
126  // Codegen for probe path (only for left joins)
127  if (!match_all_build_) {
128  Function* codegen_process_probe_batch_fn = CodegenProcessProbeBatch(state, hash_fn);
129  if (codegen_process_probe_batch_fn != NULL) {
130  codegen->AddFunctionToJit(codegen_process_probe_batch_fn,
131  reinterpret_cast<void**>(&process_probe_batch_fn_));
132  AddRuntimeExecOption("Probe Side Codegen Enabled");
133  }
134  }
135  }
136 
137  return Status::OK;
138 }
139 
141  DCHECK(false) << "NYI";
142  return Status("NYI");
143 }
144 
146  if (is_closed()) return;
147  if (hash_tbl_.get() != NULL) hash_tbl_->Close();
152 }
153 
158 
159  // Do a full scan of child(1) and store everything in hash_tbl_
160  // The hash join node needs to keep in memory all build tuples, including the tuple
161  // row ptrs. The row ptrs are copied into the hash table's internal structure so they
162  // don't need to be stored in the build_pool_.
163  RowBatch build_batch(child(1)->row_desc(), state->batch_size(), mem_tracker());
164  RETURN_IF_ERROR(child(1)->Open(state));
165  while (true) {
166  RETURN_IF_CANCELLED(state);
168  bool eos;
169  RETURN_IF_ERROR(child(1)->GetNext(state, &build_batch, &eos));
171  // take ownership of tuple data of build_batch
172  build_pool_->AcquireData(build_batch.tuple_data_pool(), false);
174 
175  // Call codegen version if possible
176  if (process_build_batch_fn_ == NULL) {
177  ProcessBuildBatch(&build_batch);
178  } else {
179  process_build_batch_fn_(this, &build_batch);
180  }
181  VLOG_ROW << hash_tbl_->DebugString(true, false, &child(1)->row_desc());
182 
186  build_batch.Reset();
187  DCHECK(!build_batch.AtCapacity());
188  if (eos) break;
189  }
190 
191  // We've finished constructing the build side. Set the bitmap of the build side values
192  // so that the probe side can use this as an additional predicate.
193  // We only do this if the build side is sufficiently small.
194  // TODO: Better heuristic? Currently we simply compare the size of the HT with a
195  // constant value.
197  if (hash_tbl_->size() < state->slot_filter_bitmap_size()) {
198  AddRuntimeExecOption("Build-Side Filter Pushed Down");
199  hash_tbl_->AddBitmapFilters();
200  } else {
201  VLOG(2) << "Disabling probe filter push down because build table is too large: "
202  << hash_tbl_->size();
203  }
204  }
205  return Status::OK;
206 }
207 
209  if (first_probe_row == NULL) {
210  hash_tbl_iterator_ = hash_tbl_->Begin();
211  } else {
212  matched_probe_ = false;
213  hash_tbl_iterator_ = hash_tbl_->Find(first_probe_row);
214  }
215  return Status::OK;
216 }
217 
218 Status HashJoinNode::GetNext(RuntimeState* state, RowBatch* out_batch, bool* eos) {
219  SCOPED_TIMER(runtime_profile_->total_time_counter());
220  RETURN_IF_ERROR(ExecDebugAction(TExecNodePhase::GETNEXT, state));
221  RETURN_IF_CANCELLED(state);
223  if (ReachedLimit()) {
224  *eos = true;
225  return Status::OK;
226  }
227  *eos = false;
228 
229  // These cases are simpler and use a more efficient processing loop
230  if (!match_all_build_) {
231  if (eos_) {
232  *eos = true;
233  return Status::OK;
234  }
235  return LeftJoinGetNext(state, out_batch, eos);
236  }
237 
238  ExprContext* const* other_conjunct_ctxs = &other_join_conjunct_ctxs_[0];
239  int num_other_conjunct_ctxs = other_join_conjunct_ctxs_.size();
240 
242  int num_conjunct_ctxs = conjunct_ctxs_.size();
243 
244  // Explicitly manage the timer counter to avoid measuring time in the child
245  // GetNext call.
247 
248  while (!eos_) {
249  // create output rows as long as:
250  // 1) we haven't already created an output row for the probe row and are doing
251  // a semi-join;
252  // 2) there are more matching build rows
253  while (!hash_tbl_iterator_.AtEnd()) {
254  int row_idx = out_batch->AddRow();
255  TupleRow* out_row = out_batch->GetRow(row_idx);
256 
257  TupleRow* matched_build_row = hash_tbl_iterator_.GetRow();
258  CreateOutputRow(out_row, current_probe_row_, matched_build_row);
259  if (!EvalConjuncts(other_conjunct_ctxs, num_other_conjunct_ctxs, out_row)) {
260  hash_tbl_iterator_.Next<true>();
261  continue;
262  }
263  // we have a match for the purpose of the (outer?) join as soon as we
264  // satisfy the JOIN clause conjuncts
265  matched_probe_ = true;
266  if (match_all_build_) {
267  // remember that we matched this build row
269  VLOG_ROW << "joined build row: " << matched_build_row;
270  }
271 
272  hash_tbl_iterator_.Next<true>();
273  if (EvalConjuncts(conjunct_ctxs, num_conjunct_ctxs, out_row)) {
274  out_batch->CommitLastRow();
275  VLOG_ROW << "match row: " << PrintRow(out_row, row_desc());
278  if (out_batch->AtCapacity() || ReachedLimit()) {
279  *eos = ReachedLimit();
280  return Status::OK;
281  }
282  }
283  }
284 
285  // check whether we need to output the current probe row before
286  // getting a new probe batch
288  int row_idx = out_batch->AddRow();
289  TupleRow* out_row = out_batch->GetRow(row_idx);
290  CreateOutputRow(out_row, current_probe_row_, NULL);
291  if (EvalConjuncts(conjunct_ctxs, num_conjunct_ctxs, out_row)) {
292  out_batch->CommitLastRow();
293  VLOG_ROW << "match row: " << PrintRow(out_row, row_desc());
296  matched_probe_ = true;
297  if (out_batch->AtCapacity() || ReachedLimit()) {
298  *eos = ReachedLimit();
299  return Status::OK;
300  }
301  }
302  }
303 
304  if (probe_batch_pos_ == probe_batch_->num_rows()) {
305  // pass on resources, out_batch might still need them
306  probe_batch_->TransferResourceOwnership(out_batch);
307  probe_batch_pos_ = 0;
308  if (out_batch->AtCapacity()) return Status::OK;
309  // get new probe batch
310  if (!probe_side_eos_) {
311  while (true) {
312  probe_timer.Stop();
314  probe_timer.Start();
315  if (probe_batch_->num_rows() == 0) {
316  // Empty batches can still contain IO buffers, which need to be passed up to
317  // the caller; transferring resources can fill up out_batch.
318  probe_batch_->TransferResourceOwnership(out_batch);
319  if (probe_side_eos_) {
320  eos_ = true;
321  break;
322  }
323  if (out_batch->AtCapacity()) return Status::OK;
324  continue;
325  } else {
327  break;
328  }
329  }
330  } else {
331  eos_ = true;
332  }
333  // finish up right outer join
334  if (eos_ && match_all_build_) {
335  hash_tbl_iterator_ = hash_tbl_->Begin();
336  }
337  }
338 
339  if (eos_) break;
340 
341  // join remaining rows in probe batch_
344  matched_probe_ = false;
346  }
347 
348  *eos = true;
349  if (match_all_build_) {
350  // output remaining unmatched build rows
351  TupleRow* build_row = NULL;
352  while (!out_batch->AtCapacity() && !hash_tbl_iterator_.AtEnd()) {
353  build_row = hash_tbl_iterator_.GetRow();
354  bool matched = hash_tbl_iterator_.matched();
355  hash_tbl_iterator_.Next<false>();
356  if (matched) continue;
357 
358  int row_idx = out_batch->AddRow();
359  TupleRow* out_row = out_batch->GetRow(row_idx);
360  CreateOutputRow(out_row, NULL, build_row);
361  if (EvalConjuncts(conjunct_ctxs, num_conjunct_ctxs, out_row)) {
362  out_batch->CommitLastRow();
363  VLOG_ROW << "match row: " << PrintRow(out_row, row_desc());
366  if (ReachedLimit()) {
367  *eos = true;
368  return Status::OK;
369  }
370  }
371  }
372  // we're done if there are no more rows left to check
373  *eos = hash_tbl_iterator_.AtEnd();
374  }
375  return Status::OK;
376 }
377 
379  RowBatch* out_batch, bool* eos) {
380  *eos = eos_;
381 
383  while (!eos_) {
384  // Compute max rows that should be added to out_batch
385  int64_t max_added_rows = out_batch->capacity() - out_batch->num_rows();
386  if (limit() != -1) max_added_rows = min(max_added_rows, limit() - rows_returned());
387 
388  // Continue processing this row batch
389  if (process_probe_batch_fn_ == NULL) {
391  ProcessProbeBatch(out_batch, probe_batch_.get(), max_added_rows);
392  } else {
393  // Use codegen'd function
395  process_probe_batch_fn_(this, out_batch, probe_batch_.get(), max_added_rows);
396  }
398 
399  if (ReachedLimit() || out_batch->AtCapacity()) {
400  *eos = ReachedLimit();
401  break;
402  }
403 
404  // Check to see if we're done processing the current probe batch
405  if (hash_tbl_iterator_.AtEnd() && probe_batch_pos_ == probe_batch_->num_rows()) {
406  probe_batch_->TransferResourceOwnership(out_batch);
407  probe_batch_pos_ = 0;
408  if (out_batch->AtCapacity()) break;
409  if (probe_side_eos_) {
410  *eos = eos_ = true;
411  break;
412  } else {
413  probe_timer.Stop();
415  probe_timer.Start();
417  }
418  }
419  }
420 
421  return Status::OK;
422 }
423 
424 void HashJoinNode::AddToDebugString(int indentation_level, stringstream* out) const {
425  *out << " hash_tbl=";
426  *out << string(indentation_level * 2, ' ');
427  *out << "HashTbl("
428  << " build_exprs=" << Expr::DebugString(build_expr_ctxs_)
429  << " probe_exprs=" << Expr::DebugString(probe_expr_ctxs_);
430  *out << ")";
431 }
432 
433 // This codegen'd function should only be used for left join cases so it assumes that
434 // the probe row is non-null. For a left outer join, the IR looks like:
435 // define void @CreateOutputRow(%"class.impala::BlockingJoinNode"* %this_ptr,
436 // %"class.impala::TupleRow"* %out_arg,
437 // %"class.impala::TupleRow"* %probe_arg,
438 // %"class.impala::TupleRow"* %build_arg) {
439 // entry:
440 // %out = bitcast %"class.impala::TupleRow"* %out_arg to i8**
441 // %probe = bitcast %"class.impala::TupleRow"* %probe_arg to i8**
442 // %build = bitcast %"class.impala::TupleRow"* %build_arg to i8**
443 // %0 = bitcast i8** %out to i8*
444 // %1 = bitcast i8** %probe to i8*
445 // call void @llvm.memcpy.p0i8.p0i8.i32(i8* %0, i8* %1, i32 16, i32 16, i1 false)
446 // %is_build_null = icmp eq i8** %build, null
447 // br i1 %is_build_null, label %build_null, label %build_not_null
448 //
449 // build_not_null: ; preds = %entry
450 // %dst_tuple_ptr1 = getelementptr i8** %out, i32 1
451 // %src_tuple_ptr = getelementptr i8** %build, i32 0
452 // %2 = load i8** %src_tuple_ptr
453 // store i8* %2, i8** %dst_tuple_ptr1
454 // ret void
455 //
456 // build_null: ; preds = %entry
457 // %dst_tuple_ptr = getelementptr i8** %out, i32 1
458 // call void @llvm.memcpy.p0i8.p0i8.i32(
459 // i8* %dst_tuple_ptr, i8* %1, i32 16, i32 16, i1 false)
460 // ret void
461 // }
463  Type* tuple_row_type = codegen->GetType(TupleRow::LLVM_CLASS_NAME);
464  DCHECK(tuple_row_type != NULL);
465  PointerType* tuple_row_ptr_type = PointerType::get(tuple_row_type, 0);
466 
467  Type* this_type = codegen->GetType(BlockingJoinNode::LLVM_CLASS_NAME);
468  DCHECK(this_type != NULL);
469  PointerType* this_ptr_type = PointerType::get(this_type, 0);
470 
471  // TupleRows are really just an array of pointers. Easier to work with them
472  // this way.
473  PointerType* tuple_row_working_type = PointerType::get(codegen->ptr_type(), 0);
474 
475  // Construct function signature to match CreateOutputRow()
476  LlvmCodeGen::FnPrototype prototype(codegen, "CreateOutputRow", codegen->void_type());
477  prototype.AddArgument(LlvmCodeGen::NamedVariable("this_ptr", this_ptr_type));
478  prototype.AddArgument(LlvmCodeGen::NamedVariable("out_arg", tuple_row_ptr_type));
479  prototype.AddArgument(LlvmCodeGen::NamedVariable("probe_arg", tuple_row_ptr_type));
480  prototype.AddArgument(LlvmCodeGen::NamedVariable("build_arg", tuple_row_ptr_type));
481 
482  LLVMContext& context = codegen->context();
483  LlvmCodeGen::LlvmBuilder builder(context);
484  Value* args[4];
485  Function* fn = prototype.GeneratePrototype(&builder, args);
486  Value* out_row_arg = builder.CreateBitCast(args[1], tuple_row_working_type, "out");
487  Value* probe_row_arg = builder.CreateBitCast(args[2], tuple_row_working_type, "probe");
488  Value* build_row_arg = builder.CreateBitCast(args[3], tuple_row_working_type, "build");
489 
490  int num_probe_tuples = child(0)->row_desc().tuple_descriptors().size();
491  int num_build_tuples = child(1)->row_desc().tuple_descriptors().size();
492 
493  // Copy probe row
494  codegen->CodegenMemcpy(&builder, out_row_arg, probe_row_arg, probe_tuple_row_size_);
495  Value* build_row_idx[] = { codegen->GetIntConstant(TYPE_INT, num_probe_tuples) };
496  Value* build_row_dst = builder.CreateGEP(out_row_arg, build_row_idx, "build_dst_ptr");
497 
498  // Copy build row.
499  BasicBlock* build_not_null_block = BasicBlock::Create(context, "build_not_null", fn);
500  BasicBlock* build_null_block = NULL;
501 
502  if (match_all_probe_) {
503  // build tuple can be null
504  build_null_block = BasicBlock::Create(context, "build_null", fn);
505  Value* is_build_null = builder.CreateIsNull(build_row_arg, "is_build_null");
506  builder.CreateCondBr(is_build_null, build_null_block, build_not_null_block);
507 
508  // Set tuple build ptrs to NULL
509  // TODO: this should be replaced with memset() but I can't get the llvm intrinsic
510  // to work.
511  builder.SetInsertPoint(build_null_block);
512  for (int i = 0; i < num_build_tuples; ++i) {
513  Value* array_idx[] =
514  { codegen->GetIntConstant(TYPE_INT, i + num_probe_tuples) };
515  Value* dst = builder.CreateGEP(out_row_arg, array_idx, "dst_tuple_ptr");
516  builder.CreateStore(codegen->null_ptr_value(), dst);
517  }
518  builder.CreateRetVoid();
519  } else {
520  // build row can't be NULL
521  builder.CreateBr(build_not_null_block);
522  }
523 
524  // Copy build tuple ptrs
525  builder.SetInsertPoint(build_not_null_block);
526  codegen->CodegenMemcpy(&builder, build_row_dst, build_row_arg, build_tuple_row_size_);
527  builder.CreateRetVoid();
528 
529  return codegen->FinalizeFunction(fn);
530 }
531 
533  Function* hash_fn) {
534  LlvmCodeGen* codegen;
535  if (!state->GetCodegen(&codegen).ok()) return NULL;
536 
537  // Get cross compiled function
538  Function* process_build_batch_fn = codegen->GetFunction(
539  IRFunction::HASH_JOIN_PROCESS_BUILD_BATCH);
540  DCHECK(process_build_batch_fn != NULL);
541 
542  // Codegen for evaluating build rows
543  Function* eval_row_fn = hash_tbl_->CodegenEvalTupleRow(state, true);
544  if (eval_row_fn == NULL) return NULL;
545 
546  int replaced = 0;
547  // Replace call sites
548  process_build_batch_fn = codegen->ReplaceCallSites(process_build_batch_fn, false,
549  eval_row_fn, "EvalBuildRow", &replaced);
550  DCHECK_EQ(replaced, 1);
551 
552  process_build_batch_fn = codegen->ReplaceCallSites(process_build_batch_fn, false,
553  hash_fn, "HashCurrentRow", &replaced);
554  DCHECK_EQ(replaced, 1);
555 
556  return codegen->OptimizeFunctionWithExprs(process_build_batch_fn);
557 }
558 
559 Function* HashJoinNode::CodegenProcessProbeBatch(RuntimeState* state, Function* hash_fn) {
560  LlvmCodeGen* codegen;
561  if (!state->GetCodegen(&codegen).ok()) return NULL;
562 
563  // Get cross compiled function
564  Function* process_probe_batch_fn =
565  codegen->GetFunction(IRFunction::HASH_JOIN_PROCESS_PROBE_BATCH);
566  DCHECK(process_probe_batch_fn != NULL);
567 
568  // Codegen HashTable::Equals
569  Function* equals_fn = hash_tbl_->CodegenEquals(state);
570  if (equals_fn == NULL) return NULL;
571 
572  // Codegen for evaluating build rows
573  Function* eval_row_fn = hash_tbl_->CodegenEvalTupleRow(state, false);
574  if (eval_row_fn == NULL) return NULL;
575 
576  // Codegen CreateOutputRow
577  Function* create_output_row_fn = CodegenCreateOutputRow(codegen);
578  if (create_output_row_fn == NULL) return NULL;
579 
580  // Codegen evaluating other join conjuncts
581  Function* eval_other_conjuncts_fn = ExecNode::CodegenEvalConjuncts(
582  state, other_join_conjunct_ctxs_, "EvalOtherConjuncts");
583  if (eval_other_conjuncts_fn == NULL) return NULL;
584 
585  // Codegen evaluating conjuncts
586  Function* eval_conjuncts_fn = ExecNode::CodegenEvalConjuncts(state, conjunct_ctxs_);
587  if (eval_conjuncts_fn == NULL) return NULL;
588 
589  // Replace all call sites with codegen version
590  int replaced = 0;
591  process_probe_batch_fn = codegen->ReplaceCallSites(process_probe_batch_fn, false,
592  hash_fn, "HashCurrentRow", &replaced);
593  DCHECK_EQ(replaced, 1);
594 
595  process_probe_batch_fn = codegen->ReplaceCallSites(process_probe_batch_fn, false,
596  eval_row_fn, "EvalProbeRow", &replaced);
597  DCHECK_EQ(replaced, 1);
598 
599  process_probe_batch_fn = codegen->ReplaceCallSites(process_probe_batch_fn, false,
600  create_output_row_fn, "CreateOutputRow", &replaced);
601  DCHECK_EQ(replaced, 3);
602 
603  process_probe_batch_fn = codegen->ReplaceCallSites(process_probe_batch_fn, false,
604  eval_conjuncts_fn, "EvalConjuncts", &replaced);
605  DCHECK_EQ(replaced, 2);
606 
607  process_probe_batch_fn = codegen->ReplaceCallSites(process_probe_batch_fn, false,
608  eval_other_conjuncts_fn, "EvalOtherJoinConjuncts", &replaced);
609  DCHECK_EQ(replaced, 2);
610 
611  process_probe_batch_fn = codegen->ReplaceCallSites(process_probe_batch_fn, false,
612  equals_fn, "Equals", &replaced);
613  DCHECK_EQ(replaced, 2);
614 
615  return codegen->OptimizeFunctionWithExprs(process_probe_batch_fn);
616 }
uint32_t slot_filter_bitmap_size() const
virtual void AddToDebugString(int indentation_level, std::stringstream *out) const
void AddRuntimeExecOption(const std::string &option)
Appends option to 'runtime_exec_options_'.
Definition: exec-node.cc:188
RuntimeProfile::Counter * hash_tbl_load_factor_counter_
int num_rows() const
Definition: row-batch.h:215
int64_t num_rows_returned_
Definition: exec-node.h:223
static const char * LLVM_CLASS_NAME
OldHashTable::Iterator hash_tbl_iterator_
MemTracker * mem_tracker()
Definition: exec-node.h:162
void CreateOutputRow(TupleRow *out_row, TupleRow *probe_row, TupleRow *build_row)
llvm::Function * CodegenProcessProbeBatch(RuntimeState *state, llvm::Function *hash_fn)
Utility struct that wraps a variable name and llvm type.
Definition: llvm-codegen.h:149
boost::scoped_ptr< RuntimeProfile > runtime_profile_
Definition: exec-node.h:225
static Status Open(const std::vector< ExprContext * > &ctxs, RuntimeState *state)
Convenience function for opening multiple expr trees.
virtual Status Prepare(RuntimeState *state)
#define RETURN_IF_ERROR(stmt)
some generally useful macros
Definition: status.h:242
HashJoinNode(ObjectPool *pool, const TPlanNode &tnode, const DescriptorTbl &descs)
TupleRow * GetRow(int row_idx)
Definition: row-batch.h:140
bool AtEnd() const
Returns true if this iterator is at the end, i.e. GetRow() cannot be called.
std::vector< ExprContext * > probe_expr_ctxs_
virtual void Close(RuntimeState *state)
bool AtCapacity()
Definition: row-batch.h:120
virtual Status Init(const TPlanNode &tnode)
RuntimeProfile::Counter * build_timer_
DECLARE_string(cgroup_hierarchy_path)
const RowDescriptor & row_desc() const
Definition: exec-node.h:156
#define COUNTER_ADD(c, v)
Status ExecDebugAction(TExecNodePhase::type phase, RuntimeState *state)
Definition: exec-node.cc:378
bool ReachedLimit()
Definition: exec-node.h:159
llvm::Function * CodegenProcessBuildBatch(RuntimeState *state, llvm::Function *hash_fn)
#define SCOPED_TIMER(c)
llvm::Value * null_ptr_value()
Definition: llvm-codegen.h:382
const std::vector< ExprContext * > & conjunct_ctxs() const
Definition: exec-node.h:152
static void Close(const std::vector< ExprContext * > &ctxs, RuntimeState *state)
Convenience function for closing multiple expr trees.
boost::scoped_ptr< OldHashTable > hash_tbl_
RuntimeProfile::Counter * probe_timer_
virtual Status Reset(RuntimeState *state)
LLVM code generator. This is the top level object to generate jitted code.
Definition: llvm-codegen.h:107
boost::scoped_ptr< MemPool > build_pool_
RuntimeProfile::Counter * probe_row_counter_
MemTracker * expr_mem_tracker()
Definition: exec-node.h:163
static const char * LLVM_CLASS_NAME
Definition: tuple-row.h:76
virtual Status Prepare(RuntimeState *state)
int ProcessProbeBatch(RowBatch *out_batch, RowBatch *probe_batch, int max_added_rows)
virtual Status Init(const TPlanNode &tnode)
void AddArgument(const NamedVariable &var)
Add argument.
Definition: llvm-codegen.h:171
static llvm::Function * CodegenEvalConjuncts(RuntimeState *state, const std::vector< ExprContext * > &conjunct_ctxs, const char *name="EvalConjuncts")
Definition: exec-node.cc:452
void CodegenMemcpy(LlvmBuilder *, llvm::Value *dst, llvm::Value *src, int size)
RuntimeProfile::Counter * build_buckets_counter_
ProcessProbeBatchFn process_probe_batch_fn_
Jitted ProcessProbeBatch function pointer. Null if codegen is disabled.
The hash table does not support removes. The hash table is not thread safe.
std::vector< ExprContext * > other_join_conjunct_ctxs_
non-equi-join conjuncts from the JOIN clause
#define RETURN_IF_CANCELLED(state)
ObjectPool pool
#define ADD_COUNTER(profile, name, unit)
uint32_t fragment_hash_seed() const
llvm::Function * GetFunction(IRFunction::Type)
void AddFunctionToJit(llvm::Function *fn, void **fn_ptr)
virtual Status QueryMaintenance(RuntimeState *state)
Definition: exec-node.cc:401
#define VLOG_ROW
Definition: logging.h:59
bool is_closed()
Definition: exec-node.h:242
void CommitLastRow()
Definition: row-batch.h:109
void ProcessBuildBatch(RowBatch *build_batch)
Construct the build hash table, adding all the rows in 'build_batch'.
virtual Status Open(RuntimeState *state)
llvm::Function * codegen_process_build_batch_fn_
llvm function for build batch
int64_t rows_returned() const
Definition: exec-node.h:157
#define COUNTER_SET(c, v)
int batch_size() const
Definition: runtime-state.h:98
DEFINE_bool(enable_probe_side_filtering, true,"Enables pushing build side filters to probe side")
static Status CreateExprTree(ObjectPool *pool, const TExpr &texpr, ExprContext **ctx)
Definition: expr.cc:129
RuntimeProfile::Counter * rows_returned_counter_
Definition: exec-node.h:226
void IR_ALWAYS_INLINE Next()
ExecNode * child(int i)
Definition: exec-node.h:241
llvm::Function * CodegenCreateOutputRow(LlvmCodeGen *codegen)
Codegen function to create output row.
virtual Status InitGetNext(TupleRow *first_probe_row)
const std::vector< TupleDescriptor * > & tuple_descriptors() const
Return descriptors for all tuples in this row, in order of appearance.
Definition: descriptors.h:412
virtual Status GetNext(RuntimeState *state, RowBatch *row_batch, bool *eos)
std::string GetLeftChildRowString(TupleRow *row)
int capacity() const
Definition: row-batch.h:216
bool codegen_enabled() const
Returns true if codegen is enabled for this query.
static const char * LLVM_CLASS_NAME
static const Status OK
Definition: status.h:87
ObjectPool * pool_
Definition: exec-node.h:211
std::vector< ExprContext * > build_expr_ctxs_
llvm::Type * GetType(const ColumnType &type)
Returns llvm type for the column type.
Status GetCodegen(LlvmCodeGen **codegen, bool initialize=true)
virtual Status ConstructBuildSide(RuntimeState *state)
llvm::Value * GetIntConstant(PrimitiveType type, int64_t val)
Returns the constant 'val' of 'type'.
static Status CreateExprTrees(ObjectPool *pool, const std::vector< TExpr > &texprs, std::vector< ExprContext * > *ctxs)
Definition: expr.cc:149
RuntimeProfile::Counter * build_row_counter_
llvm::Function * FinalizeFunction(llvm::Function *function)
static bool EvalConjuncts(ExprContext *const *ctxs, int num_ctxs, TupleRow *row)
Definition: exec-node.cc:393
virtual void Close(RuntimeState *state)
static Status Prepare(const std::vector< ExprContext * > &ctxs, RuntimeState *state, const RowDescriptor &row_desc, MemTracker *tracker)
boost::scoped_ptr< RowBatch > probe_batch_
llvm::Function * ReplaceCallSites(llvm::Function *caller, bool update_in_place, llvm::Function *new_fn, const std::string &target_name, int *num_replaced)
string PrintRow(TupleRow *row, const RowDescriptor &d)
Definition: debug-util.cc:192
bool ok() const
Definition: status.h:172
llvm::Type * void_type()
Definition: llvm-codegen.h:394
std::vector< ExprContext * > conjunct_ctxs_
Definition: exec-node.h:212
Status LeftJoinGetNext(RuntimeState *state, RowBatch *row_batch, bool *eos)
llvm::LLVMContext & context()
Definition: llvm-codegen.h:214
ProcessBuildBatchFn process_build_batch_fn_
virtual std::string DebugString() const
Definition: expr.cc:385
llvm::Function * OptimizeFunctionWithExprs(llvm::Function *fn)
llvm::PointerType * ptr_type()
Definition: llvm-codegen.h:393
int64_t limit() const
Definition: exec-node.h:158
bool match_one_build_
Match at most one build row to each probe row. Used in LEFT_SEMI_JOIN.
RuntimeProfile * runtime_profile()
Definition: exec-node.h:161