Repository: incubator-quickstep Updated Branches: refs/heads/lip-refactor-generator fb6b2848d -> 95f61b73c (forced update)
Fix the memory leak in FastSeparateChaining hash table. - Destruction of payload in hash table. - Separate phases of payload destruction of aggregation hash tables. - First the payloads will be destructed by respective aggregation handles. - Second the hash table itself will be destructed. - Remove FastSeparateChaining::DestroyValues function. Project: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/commit/5b247917 Tree: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/tree/5b247917 Diff: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/diff/5b247917 Branch: refs/heads/lip-refactor-generator Commit: 5b247917823e2fe1aa110bd44ab5347d84cfbc3b Parents: d3a0920 Author: Harshad Deshmukh <hbdeshm...@apache.org> Authored: Fri Sep 23 16:35:48 2016 -0500 Committer: Harshad Deshmukh <hbdeshm...@apache.org> Committed: Thu Oct 20 14:45:01 2016 -0500 ---------------------------------------------------------------------- expressions/aggregation/AggregationHandle.hpp | 8 + .../aggregation/AggregationHandleAvg.hpp | 8 + .../aggregation/AggregationHandleMax.hpp | 7 + .../aggregation/AggregationHandleMin.hpp | 7 + .../aggregation/AggregationHandleSum.hpp | 8 + query_execution/QueryContext.hpp | 14 ++ .../DestroyAggregationStateOperator.cpp | 7 + storage/AggregationOperationState.cpp | 13 +- storage/AggregationOperationState.hpp | 12 +- storage/CMakeLists.txt | 1 + storage/FastSeparateChainingHashTable.hpp | 238 +++---------------- storage/HashTableBase.hpp | 6 + 12 files changed, 113 insertions(+), 216 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/5b247917/expressions/aggregation/AggregationHandle.hpp ---------------------------------------------------------------------- diff --git a/expressions/aggregation/AggregationHandle.hpp b/expressions/aggregation/AggregationHandle.hpp index 48ce7fe..4b51179 100644 --- a/expressions/aggregation/AggregationHandle.hpp +++ b/expressions/aggregation/AggregationHandle.hpp @@ -406,6 +406,14 @@ class AggregationHandle { virtual void initPayload(std::uint8_t *byte_ptr) const {} /** + * @brief Destroy the payload (in the aggregation hash table) for the given + * aggregation handle. + * + * @param byte_ptr The pointer to the aggregation state in the hash table. + **/ + virtual void destroyPayload(std::uint8_t *byte_ptr) const {} + + /** * @brief Inform the aggregation handle to block (prohibit) updates on the * aggregation state. **/ http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/5b247917/expressions/aggregation/AggregationHandleAvg.hpp ---------------------------------------------------------------------- diff --git a/expressions/aggregation/AggregationHandleAvg.hpp b/expressions/aggregation/AggregationHandleAvg.hpp index 3c6e0c2..47132c6 100644 --- a/expressions/aggregation/AggregationHandleAvg.hpp +++ b/expressions/aggregation/AggregationHandleAvg.hpp @@ -161,6 +161,14 @@ class AggregationHandleAvg : public AggregationConcreteHandle { *count_ptr = blank_state_.count_; } + void destroyPayload(std::uint8_t *byte_ptr) const override { + TypedValue *sum_ptr = + reinterpret_cast<TypedValue *>(byte_ptr + blank_state_.sum_offset_); + if (sum_ptr != nullptr) { + sum_ptr->~TypedValue(); + } + } + AggregationState* accumulateColumnVectors( const std::vector<std::unique_ptr<ColumnVector>> &column_vectors) const override; http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/5b247917/expressions/aggregation/AggregationHandleMax.hpp ---------------------------------------------------------------------- diff --git a/expressions/aggregation/AggregationHandleMax.hpp b/expressions/aggregation/AggregationHandleMax.hpp index 5fb9f44..d851a0c 100644 --- a/expressions/aggregation/AggregationHandleMax.hpp +++ b/expressions/aggregation/AggregationHandleMax.hpp @@ -129,6 +129,13 @@ class AggregationHandleMax : public AggregationConcreteHandle { *max_ptr = t1; } + void destroyPayload(std::uint8_t *byte_ptr) const override { + TypedValue *max_ptr = reinterpret_cast<TypedValue *>(byte_ptr); + if (max_ptr != nullptr) { + max_ptr->~TypedValue(); + } + } + AggregationState* accumulateColumnVectors( const std::vector<std::unique_ptr<ColumnVector>> &column_vectors) const override; http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/5b247917/expressions/aggregation/AggregationHandleMin.hpp ---------------------------------------------------------------------- diff --git a/expressions/aggregation/AggregationHandleMin.hpp b/expressions/aggregation/AggregationHandleMin.hpp index 173911d..e3472ec 100644 --- a/expressions/aggregation/AggregationHandleMin.hpp +++ b/expressions/aggregation/AggregationHandleMin.hpp @@ -131,6 +131,13 @@ class AggregationHandleMin : public AggregationConcreteHandle { *min_ptr = t1; } + void destroyPayload(std::uint8_t *byte_ptr) const override { + TypedValue *min_ptr = reinterpret_cast<TypedValue *>(byte_ptr); + if (min_ptr != nullptr) { + min_ptr->~TypedValue(); + } + } + AggregationState* accumulateColumnVectors( const std::vector<std::unique_ptr<ColumnVector>> &column_vectors) const override; http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/5b247917/expressions/aggregation/AggregationHandleSum.hpp ---------------------------------------------------------------------- diff --git a/expressions/aggregation/AggregationHandleSum.hpp b/expressions/aggregation/AggregationHandleSum.hpp index 6c334a6..f0d23e1 100644 --- a/expressions/aggregation/AggregationHandleSum.hpp +++ b/expressions/aggregation/AggregationHandleSum.hpp @@ -153,6 +153,14 @@ class AggregationHandleSum : public AggregationConcreteHandle { *null_ptr = true; } + void destroyPayload(std::uint8_t *byte_ptr) const override { + TypedValue *sum_ptr = + reinterpret_cast<TypedValue *>(byte_ptr + blank_state_.sum_offset_); + if (sum_ptr != nullptr) { + sum_ptr->~TypedValue(); + } + } + AggregationState* accumulateColumnVectors( const std::vector<std::unique_ptr<ColumnVector>> &column_vectors) const override; http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/5b247917/query_execution/QueryContext.hpp ---------------------------------------------------------------------- diff --git a/query_execution/QueryContext.hpp b/query_execution/QueryContext.hpp index 78794f1..7cc44ad 100644 --- a/query_execution/QueryContext.hpp +++ b/query_execution/QueryContext.hpp @@ -187,6 +187,20 @@ class QueryContext { } /** + * @brief Destroy the payloads from the aggregation hash tables. + * + * @warning After calling these methods, the hash table will be in an invalid + * state. No other operation should be performed on them. + * + * @param id The ID of the AggregationOperationState. + **/ + inline void destroyAggregationHashTablePayload(const aggregation_state_id id) { + DCHECK_LT(id, aggregation_states_.size()); + DCHECK(aggregation_states_[id]); + aggregation_states_[id]->destroyAggregationHashTablePayload(); + } + + /** * @brief Whether the given GeneratorFunctionHandle id is valid. * * @param id The GeneratorFunctionHandle id. http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/5b247917/relational_operators/DestroyAggregationStateOperator.cpp ---------------------------------------------------------------------- diff --git a/relational_operators/DestroyAggregationStateOperator.cpp b/relational_operators/DestroyAggregationStateOperator.cpp index 62ca9e7..49be43d 100644 --- a/relational_operators/DestroyAggregationStateOperator.cpp +++ b/relational_operators/DestroyAggregationStateOperator.cpp @@ -58,6 +58,13 @@ bool DestroyAggregationStateOperator::getAllWorkOrderProtos(WorkOrderProtosConta } void DestroyAggregationStateWorkOrder::execute() { + // NOTE(harshad) : The destroyAggregationHashTablePayload call is separate + // from the destroyAggregationState call. The reason is that the aggregation + // hash tables don't own the AggregationHandle objects. However the hash table + // class requires the handles for destroying the payload (see the + // destroyPayload methods in AggregationHandle classes). Therefore, we first + // destroy the payloads in the hash table and then destroy the hash table. + query_context_->destroyAggregationHashTablePayload(aggr_state_index_); query_context_->destroyAggregationState(aggr_state_index_); } http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/5b247917/storage/AggregationOperationState.cpp ---------------------------------------------------------------------- diff --git a/storage/AggregationOperationState.cpp b/storage/AggregationOperationState.cpp index 7908db1..249026d 100644 --- a/storage/AggregationOperationState.cpp +++ b/storage/AggregationOperationState.cpp @@ -166,8 +166,7 @@ AggregationOperationState::AggregationOperationState( } // Initialize the corresponding distinctify hash table if this is a - // DISTINCT - // aggregation. + // DISTINCT aggregation. if (*is_distinct_it) { std::vector<const Type *> key_types(group_by_types); key_types.insert( @@ -595,4 +594,14 @@ void AggregationOperationState::finalizeHashTable( output_destination->bulkInsertTuples(&complete_result); } +void AggregationOperationState::destroyAggregationHashTablePayload() { + if (group_by_hashtable_pool_ != nullptr) { + auto all_hash_tables = group_by_hashtable_pool_->getAllHashTables(); + DCHECK(all_hash_tables != nullptr); + for (std::size_t ht_index = 0; ht_index < all_hash_tables->size(); ++ht_index) { + (*all_hash_tables)[ht_index]->destroyPayload(); + } + } +} + } // namespace quickstep http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/5b247917/storage/AggregationOperationState.hpp ---------------------------------------------------------------------- diff --git a/storage/AggregationOperationState.hpp b/storage/AggregationOperationState.hpp index cbbfc22..3b0f286 100644 --- a/storage/AggregationOperationState.hpp +++ b/storage/AggregationOperationState.hpp @@ -167,6 +167,11 @@ class AggregationOperationState { **/ void finalizeAggregate(InsertDestination *output_destination); + /** + * @brief Destroy the payloads in the aggregation hash tables. + **/ + void destroyAggregationHashTablePayload(); + static void mergeGroupByHashTables(AggregationStateHashTableBase *src, AggregationStateHashTableBase *dst); @@ -185,6 +190,9 @@ class AggregationOperationState { void finalizeSingleState(InsertDestination *output_destination); void finalizeHashTable(InsertDestination *output_destination); + // A vector of group by hash table pools. + std::unique_ptr<HashTablePool> group_by_hashtable_pool_; + // Common state for all aggregates in this operation: the input relation, the // filter predicate (if any), and the list of GROUP BY expressions (if any). const CatalogRelationSchema &input_relation_; @@ -193,7 +201,6 @@ class AggregationOperationState { // Each individual aggregate in this operation has an AggregationHandle and // some number of Scalar arguments. - // std::vector<std::unique_ptr<AggregationHandle>> handles_; std::vector<AggregationHandle *> handles_; std::vector<std::vector<std::unique_ptr<const Scalar>>> arguments_; @@ -221,9 +228,6 @@ class AggregationOperationState { std::vector<std::unique_ptr<AggregationStateHashTableBase>> group_by_hashtables_; - // A vector of group by hash table pools. - std::unique_ptr<HashTablePool> group_by_hashtable_pool_; - StorageManager *storage_manager_; DISALLOW_COPY_AND_ASSIGN(AggregationOperationState); http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/5b247917/storage/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/storage/CMakeLists.txt b/storage/CMakeLists.txt index e85e005..325a7cb 100644 --- a/storage/CMakeLists.txt +++ b/storage/CMakeLists.txt @@ -660,6 +660,7 @@ target_link_libraries(quickstep_storage_FastHashTableFactory quickstep_types_TypeFactory quickstep_utility_Macros) target_link_libraries(quickstep_storage_FastSeparateChainingHashTable + quickstep_expressions_aggregation_AggregationHandle quickstep_storage_FastHashTable quickstep_storage_HashTable quickstep_storage_HashTableBase http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/5b247917/storage/FastSeparateChainingHashTable.hpp ---------------------------------------------------------------------- diff --git a/storage/FastSeparateChainingHashTable.hpp b/storage/FastSeparateChainingHashTable.hpp index a41535c..17ee1d2 100644 --- a/storage/FastSeparateChainingHashTable.hpp +++ b/storage/FastSeparateChainingHashTable.hpp @@ -27,6 +27,7 @@ #include <utility> #include <vector> +#include "expressions/aggregation/AggregationHandle.hpp" #include "storage/FastHashTable.hpp" #include "storage/HashTable.hpp" #include "storage/HashTableBase.hpp" @@ -67,35 +68,7 @@ class FastSeparateChainingHashTable const std::vector<AggregationHandle *> &handles, StorageManager *storage_manager); - FastSeparateChainingHashTable(const std::vector<const Type *> &key_types, - void *hash_table_memory, - const std::size_t hash_table_memory_size, - const bool new_hash_table, - const bool hash_table_memory_zeroed); - - // Delegating constructors for single scalar keys. - FastSeparateChainingHashTable(const Type &key_type, - const std::size_t num_entries, - StorageManager *storage_manager) - : FastSeparateChainingHashTable(std::vector<const Type *>(1, &key_type), - num_entries, - storage_manager) {} - - FastSeparateChainingHashTable(const Type &key_type, - void *hash_table_memory, - const std::size_t hash_table_memory_size, - const bool new_hash_table, - const bool hash_table_memory_zeroed) - : FastSeparateChainingHashTable(std::vector<const Type *>(1, &key_type), - hash_table_memory, - hash_table_memory_size, - new_hash_table, - hash_table_memory_zeroed) {} - ~FastSeparateChainingHashTable() override { - DestroyValues(buckets_, - header_->buckets_allocated.load(std::memory_order_relaxed), - bucket_size_); std::free(init_payload_); } @@ -167,6 +140,23 @@ class FastSeparateChainingHashTable const std::size_t total_variable_key_size, HashTablePreallocationState *prealloc_state) override; + void destroyPayload() override { + void *hash_buckets = buckets_; + const std::size_t num_buckets = + header_->buckets_allocated.load(std::memory_order_relaxed); + const std::size_t bucket_size = bucket_size_; + void *bucket_ptr = static_cast<char *>(hash_buckets) + kValueOffset; + for (std::size_t bucket_num = 0; bucket_num < num_buckets; ++bucket_num) { + void *value_internal_ptr = bucket_ptr; + for (std::size_t handle_num = 0; handle_num < handles_.size(); ++handle_num) { + value_internal_ptr = + static_cast<char *>(value_internal_ptr) + this->payload_offsets_[handle_num]; + handles_[handle_num]->destroyPayload(static_cast<std::uint8_t *>(value_internal_ptr)); + } + bucket_ptr = static_cast<char *>(bucket_ptr) + bucket_size; + } + } + private: struct Header { std::size_t num_slots; @@ -190,13 +180,6 @@ class FastSeparateChainingHashTable 1) * kBucketAlignment; } - // If ValueT is not trivially destructible, invoke its destructor for all - // values held in the specified buckets (including those in "empty" buckets - // that were default constructed). If ValueT is trivially destructible, this - // is a no-op. - void DestroyValues(void *buckets, - const std::size_t num_buckets, - const std::size_t bucket_size); // Attempt to find an empty bucket to insert 'hash_code' into, starting after // '*bucket' in the chain (or, if '*bucket' is NULL, starting from the slot @@ -242,6 +225,8 @@ class FastSeparateChainingHashTable // at least 'extra_variable_storage' bytes of variable-length storage free. bool isFull(const std::size_t extra_variable_storage) const; + const std::vector<AggregationHandle *> &handles_; + // Helper object to manage key storage. HashTableKeyManager<serializable, force_key_copy> key_manager_; @@ -309,12 +294,14 @@ FastSeparateChainingHashTable<resizable, true), kBucketAlignment(alignof(std::atomic<std::size_t>)), kValueOffset(sizeof(std::atomic<std::size_t>) + sizeof(std::size_t)), + handles_(handles), key_manager_(this->key_types_, kValueOffset + this->total_payload_size_), bucket_size_(ComputeBucketSize(key_manager_.getFixedKeySize())) { init_payload_ = static_cast<std::uint8_t *>(calloc(this->total_payload_size_, 1)); + DCHECK(init_payload_ != nullptr); int k = 0; - for (auto handle : handles) { + for (auto handle : this->handles_) { handle->initPayload(init_payload_ + this->payload_offsets_[k]); k++; } @@ -433,155 +420,6 @@ template <bool resizable, bool serializable, bool force_key_copy, bool allow_duplicate_keys> -FastSeparateChainingHashTable<resizable, - serializable, - force_key_copy, - allow_duplicate_keys>:: - FastSeparateChainingHashTable(const std::vector<const Type *> &key_types, - void *hash_table_memory, - const std::size_t hash_table_memory_size, - const bool new_hash_table, - const bool hash_table_memory_zeroed) - : FastHashTable<resizable, - serializable, - force_key_copy, - allow_duplicate_keys>(key_types, - hash_table_memory, - hash_table_memory_size, - new_hash_table, - hash_table_memory_zeroed, - false, - false, - true), - kBucketAlignment(alignof(std::atomic<std::size_t>) < alignof(std::uint8_t) - ? alignof(std::uint8_t) - : alignof(std::atomic<std::size_t>)), - kValueOffset(sizeof(std::atomic<std::size_t>) + sizeof(std::size_t)), - key_manager_(this->key_types_, kValueOffset + sizeof(std::uint8_t)), - bucket_size_(ComputeBucketSize(key_manager_.getFixedKeySize())) { - // Bucket size always rounds up to the alignment requirement of the atomic - // size_t "next" pointer at the front or a ValueT, whichever is larger. - // - // Make sure that the larger of the two alignment requirements also satisfies - // the smaller. - static_assert( - alignof(std::atomic<std::size_t>) < alignof(std::uint8_t) - ? alignof(std::uint8_t) % alignof(std::atomic<std::size_t>) == 0 - : alignof(std::atomic<std::size_t>) % alignof(std::uint8_t) == 0, - "Alignment requirement of std::atomic<std::size_t> does not " - "evenly divide with alignment requirement of ValueT."); - - // Give base HashTable information about what key components are stored - // inline from 'key_manager_'. - this->setKeyInline(key_manager_.getKeyInline()); - - // FIXME(chasseur): If we are reconstituting a HashTable using a block of - // memory whose start was aligned differently than the memory block that was - // originally used (modulo alignof(Header)), we could wind up with all of our - // data structures misaligned. If memory is inside a - // StorageBlock/StorageBlob, this will never occur, since the StorageManager - // always allocates slots aligned to kCacheLineBytes. Similarly, this isn't - // a problem for memory inside any other allocation aligned to at least - // alignof(Header) == kCacheLineBytes. - - void *aligned_memory_start = this->hash_table_memory_; - std::size_t available_memory = this->hash_table_memory_size_; - - if (align(alignof(Header), - sizeof(Header), - aligned_memory_start, - available_memory) == nullptr) { - FATAL_ERROR("Attempted to create a non-resizable " - << "SeparateChainingHashTable with " - << available_memory - << " bytes of memory at " - << aligned_memory_start - << " which either can not fit a " - << "SeparateChainingHashTable::Header or meet its alignement " - << "requirement."); - } else if (aligned_memory_start != this->hash_table_memory_) { - // In general, we could get memory of any alignment, although at least - // cache-line aligned would be nice. - DEV_WARNING("StorageBlob memory adjusted by " - << (this->hash_table_memory_size_ - available_memory) - << " bytes to meet alignment requirement for " - << "SeparateChainingHashTable::Header."); - } - - header_ = static_cast<Header *>(aligned_memory_start); - aligned_memory_start = - static_cast<char *>(aligned_memory_start) + sizeof(Header); - available_memory -= sizeof(Header); - - if (new_hash_table) { - std::size_t estimated_bucket_capacity = - available_memory / - (kHashTableLoadFactor * sizeof(std::atomic<std::size_t>) + - bucket_size_ + key_manager_.getEstimatedVariableKeySize()); - std::size_t num_slots = get_previous_prime_number( - estimated_bucket_capacity * kHashTableLoadFactor); - - // Fill in the header. - header_->num_slots = num_slots; - header_->num_buckets = num_slots / kHashTableLoadFactor; - header_->buckets_allocated.store(0, std::memory_order_relaxed); - header_->variable_length_bytes_allocated.store(0, - std::memory_order_relaxed); - } - - // Locate the slot array. - slots_ = static_cast<std::atomic<std::size_t> *>(aligned_memory_start); - aligned_memory_start = static_cast<char *>(aligned_memory_start) + - sizeof(std::atomic<std::size_t>) * header_->num_slots; - available_memory -= sizeof(std::atomic<std::size_t>) * header_->num_slots; - - if (new_hash_table && !hash_table_memory_zeroed) { - std::memset( - slots_, 0x0, sizeof(std::atomic<std::size_t>) * header_->num_slots); - } - - // Locate the buckets. - buckets_ = aligned_memory_start; - // Extra-paranoid: sizeof(Header) should almost certainly be a multiple of - // kBucketAlignment, unless ValueT has some members with seriously big - // (> kCacheLineBytes) alignment requirements specified using alignas(). - if (align(kBucketAlignment, bucket_size_, buckets_, available_memory) == - nullptr) { - FATAL_ERROR("Attempted to create a non-resizable " - << "SeparateChainingHashTable with " - << this->hash_table_memory_size_ - << " bytes of memory at " - << this->hash_table_memory_ - << ", which can hold an aligned " - << "SeparateChainingHashTable::Header but does not have " - << "enough remaining space for even a single hash bucket."); - } else if (buckets_ != aligned_memory_start) { - DEV_WARNING( - "Bucket array start position adjusted to meet alignment " - "requirement for SeparateChainingHashTable's value type."); - if (header_->num_buckets * bucket_size_ > available_memory) { - DEBUG_ASSERT(new_hash_table); - --(header_->num_buckets); - } - } - available_memory -= bucket_size_ * header_->num_buckets; - - // Make sure "next" pointers in buckets are zeroed-out. - if (new_hash_table && !hash_table_memory_zeroed) { - std::memset(buckets_, 0x0, header_->num_buckets * bucket_size_); - } - - // Locate variable-length key storage region. - key_manager_.setVariableLengthStorageInfo( - static_cast<char *>(buckets_) + header_->num_buckets * bucket_size_, - available_memory, - &(header_->variable_length_bytes_allocated)); -} - -template <bool resizable, - bool serializable, - bool force_key_copy, - bool allow_duplicate_keys> void FastSeparateChainingHashTable<resizable, serializable, force_key_copy, @@ -589,7 +427,7 @@ void FastSeparateChainingHashTable<resizable, const std::size_t used_buckets = header_->buckets_allocated.load(std::memory_order_relaxed); // Destroy existing values, if necessary. - DestroyValues(buckets_, used_buckets, bucket_size_); + destroyPayload(); // Zero-out slot array. std::memset( @@ -995,10 +833,11 @@ std::uint8_t* FastSeparateChainingHashTable<resizable, // Copy the supplied 'initial_value' into place. std::uint8_t *value = static_cast<unsigned char *>(bucket) + kValueOffset; - if (init_value_ptr == nullptr) + if (init_value_ptr == nullptr) { memcpy(value, init_payload_, this->total_payload_size_); - else + } else { memcpy(value, init_value_ptr, this->total_payload_size_); + } // Update the previous chain pointer to point to the new bucket. pending_chain_ptr->store(pending_chain_ptr_finish_value, @@ -1466,8 +1305,7 @@ void FastSeparateChainingHashTable< original_variable_storage_used); } - // Destroy values in the original hash table, if neccesary, - DestroyValues(buckets_, original_buckets_used, bucket_size_); + destroyPayload(); // Make resized structures active. std::swap(this->blob_, resized_blob); @@ -1562,26 +1400,6 @@ template <bool resizable, bool serializable, bool force_key_copy, bool allow_duplicate_keys> -void FastSeparateChainingHashTable< - resizable, - serializable, - force_key_copy, - allow_duplicate_keys>::DestroyValues(void *hash_buckets, - const std::size_t num_buckets, - const std::size_t bucket_size) { - if (!std::is_trivially_destructible<std::uint8_t>::value) { - void *value_ptr = static_cast<char *>(hash_buckets) + kValueOffset; - for (std::size_t bucket_num = 0; bucket_num < num_buckets; ++bucket_num) { - static_cast<std::uint8_t *>(value_ptr)->~uint8_t(); - value_ptr = static_cast<char *>(value_ptr) + bucket_size; - } - } -} - -template <bool resizable, - bool serializable, - bool force_key_copy, - bool allow_duplicate_keys> inline bool FastSeparateChainingHashTable<resizable, serializable, force_key_copy, http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/5b247917/storage/HashTableBase.hpp ---------------------------------------------------------------------- diff --git a/storage/HashTableBase.hpp b/storage/HashTableBase.hpp index cd0a141..a3180bb 100644 --- a/storage/HashTableBase.hpp +++ b/storage/HashTableBase.hpp @@ -99,6 +99,12 @@ class HashTableBase { return false; } + /** + * @brief Destroy the payload stored in the hash table. + **/ + virtual void destroyPayload() { + } + protected: HashTableBase() {}