blob: e2bbe25854f9259b725f0fce41f8c2cf6323b75e [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#ifndef IMPALA_EXEC_OLD_HASH_TABLE_INLINE_H
#define IMPALA_EXEC_OLD_HASH_TABLE_INLINE_H
#include "exec/old-hash-table.h"
namespace impala {
inline OldHashTable::Iterator OldHashTable::Find(TupleRow* probe_row) {
uint32_t hash;
if (!EvalAndHashProbe(probe_row, &hash)) return End();
int64_t bucket_idx = hash & (num_buckets_ - 1);
Bucket* bucket = &buckets_[bucket_idx];
Node* node = bucket->node;
while (node != NULL) {
if (node->hash == hash && Equals(GetRow(node))) {
return Iterator(this, bucket_idx, node, hash);
}
node = node->next;
}
return End();
}
inline OldHashTable::Iterator OldHashTable::Begin() {
int64_t bucket_idx = -1;
Bucket* bucket = NextBucket(&bucket_idx);
if (bucket != NULL) return Iterator(this, bucket_idx, bucket->node, 0);
return End();
}
inline OldHashTable::Iterator OldHashTable::FirstUnmatched() {
int64_t bucket_idx = -1;
Bucket* bucket = NextBucket(&bucket_idx);
while (bucket != NULL) {
Node* node = bucket->node;
while (node != NULL && node->matched) {
node = node->next;
}
if (node == NULL) {
bucket = NextBucket(&bucket_idx);
} else {
DCHECK(!node->matched);
return Iterator(this, bucket_idx, node, 0);
}
}
return End();
}
inline OldHashTable::Bucket* OldHashTable::NextBucket(int64_t* bucket_idx) {
++*bucket_idx;
for (; *bucket_idx < num_buckets_; ++*bucket_idx) {
if (buckets_[*bucket_idx].node != NULL) return &buckets_[*bucket_idx];
}
*bucket_idx = -1;
return NULL;
}
inline bool OldHashTable::InsertImpl(void* data) {
uint32_t hash = HashCurrentRow();
int64_t bucket_idx = hash & (num_buckets_ - 1);
if (node_remaining_current_page_ == 0) {
GrowNodeArray();
if (UNLIKELY(mem_limit_exceeded_)) return false;
}
next_node_->hash = hash;
next_node_->data = data;
next_node_->matched = false;
AddToBucket(&buckets_[bucket_idx], next_node_);
DCHECK_GT(node_remaining_current_page_, 0);
--node_remaining_current_page_;
++next_node_;
++num_nodes_;
return true;
}
inline void OldHashTable::AddToBucket(Bucket* bucket, Node* node) {
num_filled_buckets_ += (bucket->node == NULL);
node->next = bucket->node;
bucket->node = node;
}
inline bool OldHashTable::EvalAndHashBuild(TupleRow* row, uint32_t* hash) {
bool has_null = EvalBuildRow(row);
if (!stores_nulls_ && has_null) return false;
*hash = HashCurrentRow();
return true;
}
inline bool OldHashTable::EvalAndHashProbe(TupleRow* row, uint32_t* hash) {
bool has_null = EvalProbeRow(row);
if (has_null && !(stores_nulls_ && finds_some_nulls_)) return false;
*hash = HashCurrentRow();
return true;
}
inline void OldHashTable::MoveNode(Bucket* from_bucket, Bucket* to_bucket,
Node* node, Node* previous_node) {
if (previous_node != NULL) {
previous_node->next = node->next;
} else {
// Update bucket directly
from_bucket->node = node->next;
num_filled_buckets_ -= (node->next == NULL);
}
AddToBucket(to_bucket, node);
}
template<bool check_match>
inline void OldHashTable::Iterator::Next() {
if (bucket_idx_ == -1) return;
// TODO: this should prefetch the next tuplerow
// Iterator is not from a full table scan, evaluate equality now. Only the current
// bucket needs to be scanned. 'expr_values_buffer_' contains the results
// for the current probe row.
if (check_match) {
// TODO: this should prefetch the next node
Node* node = node_->next;
while (node != NULL) {
if (node->hash == scan_hash_ && table_->Equals(table_->GetRow(node))) {
node_ = node;
return;
}
node = node->next;
}
*this = table_->End();
} else {
// Move onto the next chained node
if (node_->next != NULL) {
node_ = node_->next;
return;
}
// Move onto the next bucket
Bucket* bucket = table_->NextBucket(&bucket_idx_);
if (bucket == NULL) {
bucket_idx_ = -1;
node_ = NULL;
} else {
node_ = bucket->node;
}
}
}
inline bool OldHashTable::Iterator::NextUnmatched() {
if (bucket_idx_ == -1) return false;
while (true) {
while (node_->next != NULL && node_->next->matched) {
node_ = node_->next;
}
if (node_->next == NULL) {
// Move onto the next bucket.
Bucket* bucket = table_->NextBucket(&bucket_idx_);
if (bucket == NULL) {
bucket_idx_ = -1;
node_ = NULL;
return false;
} else {
node_ = bucket->node;
if (node_ != NULL && !node_->matched) return true;
}
} else {
DCHECK(!node_->next->matched);
node_ = node_->next;
return true;
}
}
}
}
#endif