Repository: incubator-quickstep
Updated Branches:
  refs/heads/untyped-agg 17ffbb05d -> 140069b95


Initial commit


Project: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-quickstep/commit/140069b9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/tree/140069b9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/diff/140069b9

Branch: refs/heads/untyped-agg
Commit: 140069b955dd7084c3d13a846b486feb10a13fa0
Parents: 17ffbb0
Author: Jianqiao Zhu <jianq...@cs.wisc.edu>
Authored: Sat Oct 15 22:10:36 2016 -0500
Committer: Jianqiao Zhu <jianq...@cs.wisc.edu>
Committed: Sat Oct 15 22:10:53 2016 -0500

----------------------------------------------------------------------
 expressions/aggregation/AggregationHandle.hpp |   4 +
 storage/AggregationHashTable.hpp              | 330 +++++++++++++++++++++
 storage/AggregationOperationState.cpp         |   5 +
 storage/CMakeLists.txt                        |  35 +++
 storage/HashTableBase.hpp                     |  19 ++
 storage/HashTablePool.hpp                     |  13 +
 storage/HashTableUntypedKeyManager.hpp        | 154 ++++++++++
 storage/StorageBlock.cpp                      |  17 ++
 storage/StorageBlock.hpp                      |   1 +
 types/CMakeLists.txt                          |  26 ++
 types/DateType.hpp                            |   8 +
 types/DatetimeIntervalType.hpp                |   8 +
 types/DatetimeLit.hpp                         |   8 +
 types/DatetimeType.hpp                        |   8 +
 types/IntervalLit.hpp                         |   4 +
 types/NullType.hpp                            |   4 +
 types/NumericSuperType.hpp                    |   8 +
 types/Type.hpp                                |  13 +
 types/TypeFunctors.cpp                        | 179 +++++++++++
 types/TypeFunctors.hpp                        |  47 +++
 types/YearMonthIntervalType.hpp               |   8 +
 utility/CMakeLists.txt                        |   2 +
 utility/InlineMemcpy.hpp                      |  80 +++++
 23 files changed, 981 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/expressions/aggregation/AggregationHandle.hpp
----------------------------------------------------------------------
diff --git a/expressions/aggregation/AggregationHandle.hpp 
b/expressions/aggregation/AggregationHandle.hpp
index 48ce7fe..19f28ff 100644
--- a/expressions/aggregation/AggregationHandle.hpp
+++ b/expressions/aggregation/AggregationHandle.hpp
@@ -115,6 +115,10 @@ class AggregationHandle {
    **/
   virtual AggregationState* createInitialState() const = 0;
 
+  virtual std::size_t getStateSize() const {
+    return 0;
+  }
+
   /**
    * @brief Create a new HashTable for aggregation with GROUP BY.
    *

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/storage/AggregationHashTable.hpp
----------------------------------------------------------------------
diff --git a/storage/AggregationHashTable.hpp b/storage/AggregationHashTable.hpp
new file mode 100644
index 0000000..fca6d4c
--- /dev/null
+++ b/storage/AggregationHashTable.hpp
@@ -0,0 +1,330 @@
+/**
+ * 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 QUICKSTEP_STORAGE_AGGREGATION_HASH_TABLE_HPP_
+#define QUICKSTEP_STORAGE_AGGREGATION_HASH_TABLE_HPP_
+
+#include <algorithm>
+#include <atomic>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <limits>
+#include <memory>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include "expressions/aggregation/AggregationHandle.hpp"
+#include "storage/HashTableBase.hpp"
+#include "storage/HashTableUntypedKeyManager.hpp"
+#include "storage/StorageBlob.hpp"
+#include "storage/StorageBlockInfo.hpp"
+#include "storage/StorageConstants.hpp"
+#include "storage/StorageManager.hpp"
+#include "storage/ValueAccessor.hpp"
+#include "storage/ValueAccessorUtil.hpp"
+#include "threading/SpinMutex.hpp"
+#include "threading/SpinSharedMutex.hpp"
+#include "types/Type.hpp"
+#include "types/TypeFunctors.hpp"
+#include "utility/Alignment.hpp"
+#include "utility/InlineMemcpy.hpp"
+#include "utility/Macros.hpp"
+#include "utility/PrimeNumber.hpp"
+
+namespace quickstep {
+
+/** \addtogroup Storage
+ *  @{
+ */
+
+template <bool use_mutex>
+class AggregationHashTablePayloadManager {
+ public:
+  AggregationHashTablePayloadManager(const std::vector<AggregationHandle *> 
&handles)
+      : handles_(handles),
+        payload_size_in_bytes_(0) {
+    if (use_mutex) {
+      payload_size_in_bytes_ += sizeof(SpinMutex);
+    }
+    for (const AggregationHandle *handle : handles) {
+      const std::size_t state_size = handle->getStateSize();
+      agg_state_sizes_.emplace_back(state_size);
+      agg_state_offsets_.emplace_back(payload_size_in_bytes_);
+      payload_size_in_bytes_ += state_size;
+    }
+
+    initial_payload_ = std::malloc(payload_size_in_bytes_);
+    if (use_mutex) {
+      new(initial_payload_) Mutex;
+    }
+//    for (std::size_t i = 0; i < handles_.size(); ++i) {
+//      handles_[i]->initPayload(
+//          static_cast<std::uint8_t *>(initial_payload_) + 
agg_state_offsets_[i]);
+//    }
+  }
+
+  ~AggregationHashTablePayloadManager() {
+    std::free(initial_payload_);
+  }
+
+  inline std::size_t getPayloadSizeInBytes() const {
+    return payload_size_in_bytes_;
+  }
+
+  inline void updatePayload(void *payload) const {
+  }
+
+  inline void initPayload(void *payload) const {
+  }
+
+ private:
+  std::vector<AggregationHandle *> handles_;
+
+  std::vector<std::size_t> agg_state_sizes_;
+  std::vector<std::size_t> agg_state_offsets_;
+  std::size_t payload_size_in_bytes_;
+
+  void *initial_payload_;
+
+  DISALLOW_COPY_AND_ASSIGN(AggregationHashTablePayloadManager);
+};
+
+class ThreadPrivateAggregationHashTable : public AggregationHashTableBase {
+ public:
+  ThreadPrivateAggregationHashTable(const std::vector<const Type *> &key_types,
+                                    const std::size_t num_entries,
+                                    const std::vector<AggregationHandle *> 
&handles,
+                                    StorageManager *storage_manager)
+    : payload_manager_(handles),
+      key_types_(key_types),
+      key_manager_(this->key_types_, payload_manager_.getPayloadSizeInBytes()),
+      slots_(num_entries * kHashTableLoadFactor,
+             key_manager_.getUntypedKeyHashFunctor(),
+             key_manager_.getUntypedKeyEqualityFunctor()),
+      bucket_size_(ComputeBucketSize(key_manager_.getFixedKeySize(),
+                                     
payload_manager_.getPayloadSizeInBytes())),
+      buckets_allocated_(0),
+      storage_manager_(storage_manager) {
+    std::size_t num_storage_slots =
+        this->storage_manager_->SlotsNeededForBytes(num_entries);
+
+    // Get a StorageBlob to hold the hash table.
+    const block_id blob_id = 
this->storage_manager_->createBlob(num_storage_slots);
+    this->blob_ = this->storage_manager_->getBlobMutable(blob_id);
+
+    buckets_ = this->blob_->getMemoryMutable();
+    num_buckets_ = num_storage_slots * kSlotSizeBytes / bucket_size_;
+  }
+
+  void resize() {
+    const std::size_t resized_memory_required = num_buckets_ * bucket_size_ * 
2;
+    const std::size_t resized_storage_slots =
+        this->storage_manager_->SlotsNeededForBytes(resized_memory_required);
+    const block_id resized_blob_id =
+        this->storage_manager_->createBlob(resized_storage_slots);
+    MutableBlobReference resized_blob =
+        this->storage_manager_->getBlobMutable(resized_blob_id);
+
+    void *resized_buckets = resized_blob->getMemoryMutable();
+    std::memcpy(resized_buckets, buckets_, buckets_allocated_ * bucket_size_);
+
+    for (auto &pair : slots_) {
+      pair.second =
+           (static_cast<const char *>(pair.first) - static_cast<char 
*>(buckets_))
+           + static_cast<char *>(resized_buckets);
+    }
+
+    buckets_ = resized_buckets;
+    num_buckets_ = resized_storage_slots * kSlotSizeBytes / bucket_size_;
+    std::swap(this->blob_, resized_blob);
+  }
+
+  bool upsertValueAccessor(ValueAccessor *accessor,
+                           const attribute_id key_attr_id,
+                           const std::vector<attribute_id> &argument_ids,
+                           const bool check_for_null_keys) override {
+    if (check_for_null_keys) {
+      return upsertValueAccessorInternal<true>(
+          accessor, key_attr_id, argument_ids);
+    } else {
+      return upsertValueAccessorInternal<false>(
+          accessor, key_attr_id, argument_ids);
+    }
+  }
+
+  template <bool check_for_null_keys>
+  bool upsertValueAccessorInternal(ValueAccessor *accessor,
+                                   const attribute_id key_attr_id,
+                                   const std::vector<attribute_id> 
&argument_ids) {
+    return InvokeOnAnyValueAccessor(
+        accessor,
+        [&](auto *accessor) -> bool {  // NOLINT(build/c++11)
+      accessor->beginIteration();
+      while (accessor->next()) {
+        const void *key = accessor->template 
getUntypedValue<check_for_null_keys>(key_attr_id);
+        if (check_for_null_keys && key == nullptr) {
+          continue;
+        }
+        bool is_empty;
+        void *bucket = locateBucket(key, &is_empty);
+        if (is_empty) {
+          payload_manager_.initPayload(bucket);
+        } else {
+          payload_manager_.updatePayload(bucket);
+        }
+      }
+      return true;
+    });
+  }
+
+  bool upsertValueAccessorCompositeKey(ValueAccessor *accessor,
+                                       const std::vector<attribute_id> 
&key_attr_ids,
+                                       const std::vector<attribute_id> 
&argument_ids,
+                                       const bool check_for_null_keys) 
override {
+    if (check_for_null_keys) {
+      return upsertValueAccessorCompositeKeyInternal<true>(
+          accessor, key_attr_ids, argument_ids);
+    } else {
+      return upsertValueAccessorCompositeKeyInternal<false>(
+          accessor, key_attr_ids, argument_ids);
+    }
+  }
+
+  template <bool check_for_null_keys>
+  bool upsertValueAccessorCompositeKeyInternal(ValueAccessor *accessor,
+                                               const std::vector<attribute_id> 
&key_attr_ids,
+                                               const std::vector<attribute_id> 
&argument_ids) {
+    return InvokeOnAnyValueAccessor(
+        accessor,
+        [&](auto *accessor) -> bool {  // NOLINT(build/c++11)
+      accessor->beginIteration();
+      void *prealloc_bucket = allocateBucket();
+      while (accessor->next()) {
+        if (check_for_null_keys) {
+          const bool is_null =
+              key_manager_.writeNullableUntypedKeyFromValueAccessorToBucket(
+                  accessor,
+                  key_attr_ids,
+                  prealloc_bucket);
+          if (is_null) {
+            continue;
+          }
+        } else {
+          key_manager_.writeUntypedKeyFromValueAccessorToBucket(
+              accessor,
+              key_attr_ids,
+              prealloc_bucket);
+        }
+        void *bucket = locateBucketWithPrealloc(prealloc_bucket);
+        if (bucket != prealloc_bucket) {
+          payload_manager_.initPayload(bucket);
+          prealloc_bucket = allocateBucket();
+        } else {
+          payload_manager_.updatePayload(bucket);
+        }
+      }
+      // Reclaim the last unused bucket
+      --buckets_allocated_;
+      return true;
+    });
+  }
+
+  inline void* locateBucket(const void *key, bool *is_empty) {
+    auto slot_it = slots_.find(key);
+    if (slot_it == slots_.end()) {
+      void *bucket = allocateBucket();
+      key_manager_.writeUntypedKeyToBucket(key, bucket);
+      slots_.emplace(key_manager_.getUntypedKeyComponent(bucket), bucket);
+      *is_empty = true;
+      return bucket;
+    } else {
+      *is_empty = false;
+      return slot_it->second;
+    }
+  }
+
+  inline void* locateBucketWithPrealloc(void *prealloc_bucket) {
+    const void *key = key_manager_.getUntypedKeyComponent(prealloc_bucket);
+    auto slot_it = slots_.find(key);
+    if (slot_it == slots_.end()) {
+      slots_.emplace(key, prealloc_bucket);
+      return prealloc_bucket;
+    } else {
+      return slot_it->second;
+    }
+  }
+
+  inline void* allocateBucket() {
+    if (buckets_allocated_ >= num_buckets_) {
+      resize();
+    }
+    void *bucket = static_cast<char *>(buckets_) + buckets_allocated_ * 
bucket_size_;
+    ++buckets_allocated_;
+    return bucket;
+  }
+
+  void print() const override {
+    std::cerr << "Bucket size = " << bucket_size_ << "\n";
+    std::cerr << "Buckets: \n";
+    for (const auto &pair : slots_) {
+      std::cerr << pair.first << " -- " << pair.second << "\n";
+      std::cerr << *static_cast<const int *>(pair.second) << "\n";
+    }
+  }
+
+ private:
+  // Helper object to manage hash table payloads (i.e. aggregation states).
+  AggregationHashTablePayloadManager<false> payload_manager_;
+
+  // Type(s) of keys.
+  const std::vector<const Type*> key_types_;
+
+  // Helper object to manage key storage.
+  HashTableUntypedKeyManager key_manager_;
+
+  // Round bucket size up to a multiple of kBucketAlignment.
+  static std::size_t ComputeBucketSize(const std::size_t fixed_key_size,
+                                       const std::size_t total_payload_size) {
+    constexpr std::size_t kBucketAlignment = 4;
+    return (((fixed_key_size + total_payload_size - 1)
+               / kBucketAlignment) + 1) * kBucketAlignment;
+  }
+
+  std::unordered_map<const void *, void *,
+                     UntypedKeyHashFunctor,
+                     UntypedKeyEqualityFunctor> slots_;
+
+  void *buckets_;
+  const std::size_t bucket_size_;
+  std::size_t num_buckets_;
+  std::size_t buckets_allocated_;
+
+  StorageManager *storage_manager_;
+  MutableBlobReference blob_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadPrivateAggregationHashTable);
+};
+
+
+}  // namespace quickstep
+
+#endif  // QUICKSTEP_STORAGE_AGGREGATION_HASH_TABLE_HPP_
+

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/storage/AggregationOperationState.cpp
----------------------------------------------------------------------
diff --git a/storage/AggregationOperationState.cpp 
b/storage/AggregationOperationState.cpp
index 7908db1..fe16fc4 100644
--- a/storage/AggregationOperationState.cpp
+++ b/storage/AggregationOperationState.cpp
@@ -38,6 +38,7 @@
 #include "expressions/aggregation/AggregationID.hpp"
 #include "expressions/predicate/Predicate.hpp"
 #include "expressions/scalar/Scalar.hpp"
+#include "storage/AggregationHashTable.hpp"
 #include "storage/AggregationOperationState.pb.h"
 #include "storage/HashTable.hpp"
 #include "storage/HashTableBase.hpp"
@@ -46,6 +47,7 @@
 #include "storage/StorageBlock.hpp"
 #include "storage/StorageBlockInfo.hpp"
 #include "storage/StorageManager.hpp"
+#include "types/TypeFunctors.hpp"
 #include "types/TypedValue.hpp"
 #include "types/containers/ColumnVector.hpp"
 #include "types/containers/ColumnVectorsValueAccessor.hpp"
@@ -446,10 +448,13 @@ void AggregationOperationState::aggregateBlockHashTable(
   AggregationStateHashTableBase *agg_hash_table =
       group_by_hashtable_pool_->getHashTableFast();
   DCHECK(agg_hash_table != nullptr);
+
   block->aggregateGroupBy(arguments_,
                           group_by_list_,
                           predicate_.get(),
                           agg_hash_table,
+                          
group_by_hashtable_pool_->createNewThreadPrivateHashTable(),
+//                          nullptr,
                           &reuse_matches,
                           &reuse_group_by_vectors);
   group_by_hashtable_pool_->returnHashTable(agg_hash_table);

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/storage/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/storage/CMakeLists.txt b/storage/CMakeLists.txt
index f05cc46..bdc7596 100644
--- a/storage/CMakeLists.txt
+++ b/storage/CMakeLists.txt
@@ -145,6 +145,7 @@ if (ENABLE_DISTRIBUTED)
 endif()
 
 # Declare micro-libs:
+add_library(quickstep_storage_AggregationHashTable ../empty_src.cpp 
AggregationHashTable.hpp)
 add_library(quickstep_storage_AggregationOperationState
             AggregationOperationState.cpp
             AggregationOperationState.hpp)
@@ -217,6 +218,7 @@ add_library(quickstep_storage_HashTableBase 
../empty_src.cpp HashTableBase.hpp)
 add_library(quickstep_storage_HashTableFactory HashTableFactory.cpp 
HashTableFactory.hpp)
 add_library(quickstep_storage_HashTableKeyManager ../empty_src.cpp 
HashTableKeyManager.hpp)
 add_library(quickstep_storage_HashTablePool ../empty_src.cpp HashTablePool.hpp)
+add_library(quickstep_storage_HashTableUntypedKeyManager ../empty_src.cpp 
HashTableUntypedKeyManager.hpp)
 add_library(quickstep_storage_IndexSubBlock ../empty_src.cpp IndexSubBlock.hpp)
 add_library(quickstep_storage_IndexSubBlockDescriptionFactory ../empty_src.cpp 
IndexSubBlockDescriptionFactory.hpp)
 add_library(quickstep_storage_InsertDestination InsertDestination.cpp 
InsertDestination.hpp)
@@ -269,6 +271,27 @@ 
add_library(quickstep_storage_WindowAggregationOperationState_proto ${storage_Wi
 
 
 # Link dependencies:
+target_link_libraries(quickstep_storage_AggregationHashTable
+                      quickstep_catalog_CatalogTypedefs
+                      quickstep_expressions_aggregation_AggregationHandle
+                      quickstep_storage_HashTableBase
+                      quickstep_storage_HashTableUntypedKeyManager
+                      quickstep_storage_StorageBlob
+                      quickstep_storage_StorageBlockInfo
+                      quickstep_storage_StorageConstants
+                      quickstep_storage_StorageManager
+                      quickstep_storage_TupleReference
+                      quickstep_storage_ValueAccessor
+                      quickstep_storage_ValueAccessorUtil
+                      quickstep_threading_SpinMutex
+                      quickstep_threading_SpinSharedMutex
+                      quickstep_types_Type
+                      quickstep_types_TypeFunctors
+                      quickstep_types_TypedValue
+                      quickstep_utility_Alignment
+                      quickstep_utility_HashPair
+                      quickstep_utility_Macros
+                      quickstep_utility_PrimeNumber)
 target_link_libraries(quickstep_storage_AggregationOperationState
                       glog
                       quickstep_catalog_CatalogDatabaseLite
@@ -283,6 +306,7 @@ 
target_link_libraries(quickstep_storage_AggregationOperationState
                       quickstep_expressions_aggregation_AggregationID
                       quickstep_expressions_predicate_Predicate
                       quickstep_expressions_scalar_Scalar
+                      quickstep_storage_AggregationHashTable
                       quickstep_storage_AggregationOperationState_proto
                       quickstep_storage_HashTable
                       quickstep_storage_HashTableBase
@@ -292,6 +316,7 @@ 
target_link_libraries(quickstep_storage_AggregationOperationState
                       quickstep_storage_StorageBlock
                       quickstep_storage_StorageBlockInfo
                       quickstep_storage_StorageManager
+                      quickstep_types_TypeFunctors
                       quickstep_types_TypedValue
                       quickstep_types_containers_ColumnVector
                       quickstep_types_containers_ColumnVectorsValueAccessor
@@ -761,12 +786,20 @@ 
target_link_libraries(quickstep_storage_HashTableKeyManager
 target_link_libraries(quickstep_storage_HashTablePool
                       glog
                       quickstep_expressions_aggregation_AggregationHandle
+                      quickstep_storage_AggregationHashTable
                       quickstep_storage_FastHashTable
                       quickstep_storage_FastHashTableFactory
                       quickstep_storage_HashTableBase
                       quickstep_threading_SpinMutex
                       quickstep_utility_Macros
                       quickstep_utility_StringUtil)
+target_link_libraries(quickstep_storage_HashTableUntypedKeyManager
+                      glog
+                      quickstep_storage_StorageConstants
+                      quickstep_types_Type
+                      quickstep_types_TypeFunctors
+                      quickstep_types_TypedValue
+                      quickstep_utility_Macros)
 target_link_libraries(quickstep_storage_IndexSubBlock
                       quickstep_catalog_CatalogTypedefs
                       quickstep_expressions_predicate_PredicateCost
@@ -1132,6 +1165,7 @@ 
target_link_libraries(quickstep_storage_WindowAggregationOperationState_proto
 # Module all-in-one library:
 add_library(quickstep_storage ../empty_src.cpp StorageModule.hpp)
 target_link_libraries(quickstep_storage
+                      quickstep_storage_AggregationHashTable
                       quickstep_storage_AggregationOperationState
                       quickstep_storage_AggregationOperationState_proto
                       quickstep_storage_BasicColumnStoreTupleStorageSubBlock
@@ -1159,6 +1193,7 @@ target_link_libraries(quickstep_storage
                       quickstep_storage_HashTableFactory
                       quickstep_storage_HashTableKeyManager
                       quickstep_storage_HashTablePool
+                      quickstep_storage_HashTableUntypedKeyManager
                       quickstep_storage_IndexSubBlock
                       quickstep_storage_IndexSubBlockDescriptionFactory
                       quickstep_storage_InsertDestination

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/storage/HashTableBase.hpp
----------------------------------------------------------------------
diff --git a/storage/HashTableBase.hpp b/storage/HashTableBase.hpp
index cd0a141..f98c645 100644
--- a/storage/HashTableBase.hpp
+++ b/storage/HashTableBase.hpp
@@ -108,6 +108,25 @@ class HashTableBase {
 
 typedef HashTableBase<true, false, true, false> AggregationStateHashTableBase;
 
+class AggregationHashTableBase {
+ public:
+  virtual bool upsertValueAccessor(ValueAccessor *accessor,
+                                   const attribute_id key_attr_id,
+                                   const std::vector<attribute_id> 
&argument_ids,
+                                   const bool check_for_null_keys) = 0;
+
+  virtual bool upsertValueAccessorCompositeKey(ValueAccessor *accessor,
+                                               const std::vector<attribute_id> 
&key_attr_ids,
+                                               const std::vector<attribute_id> 
&argument_ids,
+                                               const bool check_for_null_keys) 
= 0;
+
+  virtual void print() const = 0;
+
+ protected:
+  AggregationHashTableBase() {}
+};
+
+
 /** @} */
 
 }  // namespace quickstep

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/storage/HashTablePool.hpp
----------------------------------------------------------------------
diff --git a/storage/HashTablePool.hpp b/storage/HashTablePool.hpp
index 3cdfcb3..faa0abc 100644
--- a/storage/HashTablePool.hpp
+++ b/storage/HashTablePool.hpp
@@ -27,6 +27,7 @@
 
 #include "expressions/aggregation/AggregationHandle.hpp"
 #include "storage/HashTableBase.hpp"
+#include "storage/AggregationHashTable.hpp"
 #include "storage/FastHashTable.hpp"
 #include "storage/FastHashTableFactory.hpp"
 #include "threading/SpinMutex.hpp"
@@ -178,6 +179,17 @@ class HashTablePool {
     return &hash_tables_;
   }
 
+  AggregationHashTableBase* createNewThreadPrivateHashTable() {
+    agg_hash_tables_.emplace_back(
+        std::unique_ptr<AggregationHashTableBase>(
+            new ThreadPrivateAggregationHashTable(
+               group_by_types_,
+               estimated_num_entries_,
+               handles_,
+               storage_manager_)));
+    return agg_hash_tables_.back().get();
+  }
+
  private:
   AggregationStateHashTableBase* createNewHashTable() {
     return agg_handle_->createGroupByHashTable(hash_table_impl_type_,
@@ -209,6 +221,7 @@ class HashTablePool {
   static constexpr std::size_t kEstimateReductionFactor = 100;
 
   std::vector<std::unique_ptr<AggregationStateHashTableBase>> hash_tables_;
+  std::vector<std::unique_ptr<AggregationHashTableBase>> agg_hash_tables_;
 
   const std::size_t estimated_num_entries_;
   const HashTableImplType hash_table_impl_type_;

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/storage/HashTableUntypedKeyManager.hpp
----------------------------------------------------------------------
diff --git a/storage/HashTableUntypedKeyManager.hpp 
b/storage/HashTableUntypedKeyManager.hpp
new file mode 100644
index 0000000..dffb116
--- /dev/null
+++ b/storage/HashTableUntypedKeyManager.hpp
@@ -0,0 +1,154 @@
+/**
+ * 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 QUICKSTEP_STORAGE_HASH_TABLE_UNTYPED_KEY_MANAGER_HPP_
+#define QUICKSTEP_STORAGE_HASH_TABLE_UNTYPED_KEY_MANAGER_HPP_
+
+#include <atomic>
+#include <functional>
+#include <cstddef>
+#include <cstring>
+#include <vector>
+
+#include "storage/StorageConstants.hpp"
+#include "types/Type.hpp"
+#include "types/TypeFunctors.hpp"
+#include "types/TypedValue.hpp"
+#include "utility/InlineMemcpy.hpp"
+#include "utility/Macros.hpp"
+
+#include "glog/logging.h"
+
+namespace quickstep {
+
+/** \addtogroup Storage
+ *  @{
+ */
+
+class HashTableUntypedKeyManager {
+ public:
+  HashTableUntypedKeyManager(const std::vector<const Type *> &key_types,
+                             const std::size_t key_start_in_bucket)
+      : key_types_(key_types),
+        key_hasher_(MakeUntypedKeyHashFunctor(key_types)),
+        key_equality_checker_(MakeUntypedKeyEqualityFunctor(key_types)),
+        key_start_in_bucket_(key_start_in_bucket),
+        fixed_key_size_(0) {
+    for (const Type *key_type : key_types) {
+      key_sizes_.emplace_back(key_type->maximumByteLength());
+      key_offsets_.emplace_back(fixed_key_size_);
+      key_offsets_in_bucket_.emplace_back(key_start_in_bucket + 
fixed_key_size_);
+
+      DCHECK(!key_type->isVariableLength());
+      fixed_key_size_ += key_type->maximumByteLength();
+    }
+  }
+
+  inline std::size_t getNumKeyComponents() const {
+    return key_types_.size();
+  }
+
+  inline std::size_t getFixedKeySize() const  {
+    return fixed_key_size_;
+  }
+
+  inline std::size_t hashUntypedKey(const void *key) const {
+    return key_hasher_(key);
+  }
+
+  inline bool checkUntypedKeyCollision(const void *key,
+                                       const void *bucket) const {
+    return key_equality_checker_(key, getUntypedKeyComponent(bucket));
+  }
+
+  inline void writeUntypedKeyToBucket(const void *key, void *bucket) {
+    InlineMemcpy(getUntypedKeyComponent(bucket), key, fixed_key_size_);
+  }
+
+  template <typename ValueAccessorT>
+  inline bool writeNullableUntypedKeyFromValueAccessorToBucket(
+      ValueAccessorT *accessor,
+      const std::vector<attribute_id> &key_attr_ids,
+      void *bucket) {
+    for (std::size_t i = 0; i < key_attr_ids.size(); ++i) {
+      const void *key_component = accessor->getUntypedValue(key_attr_ids[i]);
+      if (key_component == nullptr) {
+        return true;
+      }
+      InlineMemcpy(getUntypedKeyComponent(bucket, i), key_component, 
key_sizes_[i]);
+    }
+    return false;
+  }
+
+  template <typename ValueAccessorT>
+  inline void writeUntypedKeyFromValueAccessorToBucket(
+      ValueAccessorT *accessor,
+      const std::vector<attribute_id> &key_attr_ids,
+      void *bucket) {
+    for (std::size_t i = 0; i < key_attr_ids.size(); ++i) {
+      const void *key_component = accessor->template 
getUntypedValue<false>(key_attr_ids[i]);
+      InlineMemcpy(getUntypedKeyComponent(bucket, i), key_component, 
key_sizes_[i]);
+    }
+  }
+
+  inline const void* getUntypedKeyComponent(const void *bucket) const {
+    return static_cast<const char *>(bucket) + key_start_in_bucket_;
+  }
+
+  inline void* getUntypedKeyComponent(void *bucket) const {
+    return static_cast<char *>(bucket) + key_start_in_bucket_;
+  }
+
+  inline const void* getUntypedKeyComponent(const void *bucket,
+                                            const std::size_t component_id) 
const {
+    return static_cast<const char *>(bucket) + 
key_offsets_in_bucket_[component_id];
+  }
+
+  inline void* getUntypedKeyComponent(void *bucket,
+                                      const std::size_t component_id) const {
+    return static_cast<char *>(bucket) + key_offsets_in_bucket_[component_id];
+  }
+
+  inline const UntypedKeyHashFunctor& getUntypedKeyHashFunctor() const {
+    return key_hasher_;
+  }
+
+  inline const UntypedKeyEqualityFunctor& getUntypedKeyEqualityFunctor() const 
{
+    return key_equality_checker_;
+  }
+
+ private:
+  const std::vector<const Type*> &key_types_;
+  const UntypedKeyHashFunctor key_hasher_;
+  const UntypedKeyEqualityFunctor key_equality_checker_;
+
+  std::size_t key_start_in_bucket_;
+  std::size_t fixed_key_size_;
+  std::vector<std::size_t> key_sizes_;
+  std::vector<std::size_t> key_offsets_;
+  std::vector<std::size_t> key_offsets_in_bucket_;
+
+  DISALLOW_COPY_AND_ASSIGN(HashTableUntypedKeyManager);
+};
+
+/** @} */
+
+}  // namespace quickstep
+
+#endif  // QUICKSTEP_STORAGE_HASH_TABLE_UNTYPED_KEY_MANAGER_HPP_

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/storage/StorageBlock.cpp
----------------------------------------------------------------------
diff --git a/storage/StorageBlock.cpp b/storage/StorageBlock.cpp
index ec5990f..4fce131 100644
--- a/storage/StorageBlock.cpp
+++ b/storage/StorageBlock.cpp
@@ -419,6 +419,7 @@ void StorageBlock::aggregateGroupBy(
     const std::vector<std::unique_ptr<const Scalar>> &group_by,
     const Predicate *predicate,
     AggregationStateHashTableBase *hash_table,
+    AggregationHashTableBase *tp_hash_table,
     std::unique_ptr<TupleIdSequence> *reuse_matches,
     std::vector<std::unique_ptr<ColumnVector>> *reuse_group_by_vectors) const {
   DCHECK_GT(group_by.size(), 0u)
@@ -495,6 +496,22 @@ void StorageBlock::aggregateGroupBy(
                                                   &temp_result,
                                                   key_ids,
                                                   true);
+
+  // NOTE: experiments here
+  if (tp_hash_table != nullptr) {
+    if (key_ids.size() == 1) {
+      tp_hash_table->upsertValueAccessor(&temp_result,
+                                         key_ids.front(),
+                                         argument_ids,
+                                         true);
+    } else {
+      tp_hash_table->upsertValueAccessorCompositeKey(&temp_result,
+                                                     key_ids,
+                                                     argument_ids,
+                                                     true);
+    }
+    tp_hash_table->print();
+  }
 }
 
 

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/storage/StorageBlock.hpp
----------------------------------------------------------------------
diff --git a/storage/StorageBlock.hpp b/storage/StorageBlock.hpp
index bab5bab..567af33 100644
--- a/storage/StorageBlock.hpp
+++ b/storage/StorageBlock.hpp
@@ -463,6 +463,7 @@ class StorageBlock : public StorageBlockBase {
       const std::vector<std::unique_ptr<const Scalar>> &group_by,
       const Predicate *predicate,
       AggregationStateHashTableBase *hash_table,
+      AggregationHashTableBase *tp_hash_table,
       std::unique_ptr<TupleIdSequence> *reuse_matches,
       std::vector<std::unique_ptr<ColumnVector>> *reuse_group_by_vectors) 
const;
 

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/types/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/types/CMakeLists.txt b/types/CMakeLists.txt
index 769187b..8f003d7 100644
--- a/types/CMakeLists.txt
+++ b/types/CMakeLists.txt
@@ -52,6 +52,7 @@ add_library(quickstep_types_Type Type.cpp Type.hpp)
 add_library(quickstep_types_TypeErrors ../empty_src.cpp TypeErrors.hpp)
 add_library(quickstep_types_TypeFactory TypeFactory.cpp TypeFactory.hpp)
 add_library(quickstep_types_TypeID TypeID.cpp TypeID.hpp)
+add_library(quickstep_types_TypeFunctors TypeFunctors.cpp TypeFunctors.hpp)
 add_library(quickstep_types_Type_proto ${types_Type_proto_srcs})
 add_library(quickstep_types_TypedValue TypedValue.cpp TypedValue.hpp)
 add_library(quickstep_types_TypedValue_proto ${types_TypedValue_proto_srcs})
@@ -164,6 +165,8 @@ target_link_libraries(quickstep_types_Type
                       quickstep_types_Type_proto
                       quickstep_types_TypeID
                       quickstep_types_TypedValue
+                      quickstep_types_port_strnlen
+                      quickstep_utility_HashPair
                       quickstep_utility_Macros)
 target_link_libraries(quickstep_types_TypeFactory
                       glog
@@ -182,6 +185,28 @@ target_link_libraries(quickstep_types_TypeFactory
                       quickstep_types_VarCharType
                       quickstep_types_YearMonthIntervalType
                       quickstep_utility_Macros)
+target_link_libraries(quickstep_types_TypeFunctors
+                      quickstep_types_CharType
+                      quickstep_types_DateType
+                      quickstep_types_DatetimeIntervalType
+                      quickstep_types_DatetimeLit
+                      quickstep_types_DatetimeType
+                      quickstep_types_DoubleType
+                      quickstep_types_FloatType
+                      quickstep_types_IntType
+                      quickstep_types_IntervalLit
+                      quickstep_types_LongType
+                      quickstep_types_NullType
+                      quickstep_types_NumericSuperType
+                      quickstep_types_NumericTypeUnifier
+                      quickstep_types_Type
+                      quickstep_types_TypeID
+                      quickstep_types_VarCharType
+                      quickstep_types_YearMonthIntervalType
+                      quickstep_types_operations_comparisons_ComparisonUtil
+                      quickstep_types_port_strnlen
+                      quickstep_utility_HashPair
+                      quickstep_utility_Macros)
 target_link_libraries(quickstep_types_TypedValue
                       farmhash
                       glog
@@ -241,6 +266,7 @@ target_link_libraries(quickstep_types
                       quickstep_types_Type_proto
                       quickstep_types_TypeErrors
                       quickstep_types_TypeFactory
+                      quickstep_types_TypeFunctors
                       quickstep_types_TypeID
                       quickstep_types_TypedValue
                       quickstep_types_TypedValue_proto

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/types/DateType.hpp
----------------------------------------------------------------------
diff --git a/types/DateType.hpp b/types/DateType.hpp
index 07225d5..b83848e 100644
--- a/types/DateType.hpp
+++ b/types/DateType.hpp
@@ -122,6 +122,14 @@ class DateType : public Type {
   bool parseValueFromString(const std::string &value_string,
                             TypedValue *value) const override;
 
+  bool canCheckEqualityWithMemcmp() const override {
+    return true;
+  }
+
+  inline std::size_t getHash(const void *value_ptr) const {
+    return DateLit::getHash(reinterpret_cast<const DateLit *>(value_ptr));
+  }
+
  private:
   explicit DateType(const bool nullable)
       : Type(Type::kOther, kDate, nullable, sizeof(DateLit), sizeof(DateLit)) {

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/types/DatetimeIntervalType.hpp
----------------------------------------------------------------------
diff --git a/types/DatetimeIntervalType.hpp b/types/DatetimeIntervalType.hpp
index 005cb31..71e2842 100644
--- a/types/DatetimeIntervalType.hpp
+++ b/types/DatetimeIntervalType.hpp
@@ -114,6 +114,14 @@ class DatetimeIntervalType : public Type {
   bool parseValueFromString(const std::string &value_string,
                             TypedValue *value) const override;
 
+  bool canCheckEqualityWithMemcmp() const override {
+    return true;
+  }
+
+  inline std::size_t getHash(const void *value_ptr) const {
+    return *reinterpret_cast<const DatetimeIntervalLit::cpptype *>(value_ptr);
+  }
+
  private:
   explicit DatetimeIntervalType(const bool nullable)
       : Type(Type::kOther, kDatetimeInterval, nullable, 
sizeof(DatetimeIntervalLit), sizeof(DatetimeIntervalLit)) {

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/types/DatetimeLit.hpp
----------------------------------------------------------------------
diff --git a/types/DatetimeLit.hpp b/types/DatetimeLit.hpp
index 58c852f..c528b1f 100644
--- a/types/DatetimeLit.hpp
+++ b/types/DatetimeLit.hpp
@@ -99,12 +99,20 @@ struct DateLit {
   inline std::int32_t monthField() const {
     return static_cast<std::int32_t>(month);
   }
+
+  static inline std::size_t getHash(const DateLit *date_lit) {
+    return static_cast<std::uint64_t>(date_lit->year) << 16
+        | static_cast<std::uint64_t>(date_lit->month) << 8
+        | static_cast<std::uint64_t>(date_lit->day);
+  }
 };
 
 /**
  * @brief A literal representing the datetime.
  **/
 struct DatetimeLit {
+  typedef std::int64_t cpptype;
+
   std::int64_t ticks;  // Ticks in GMT.
 
   static constexpr std::int64_t kTicksPerSecond = INT64_C(1000000);

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/types/DatetimeType.hpp
----------------------------------------------------------------------
diff --git a/types/DatetimeType.hpp b/types/DatetimeType.hpp
index aad536a..974a277 100644
--- a/types/DatetimeType.hpp
+++ b/types/DatetimeType.hpp
@@ -130,6 +130,14 @@ class DatetimeType : public Type {
   bool parseValueFromString(const std::string &value_string,
                             TypedValue *value) const override;
 
+  bool canCheckEqualityWithMemcmp() const override {
+    return true;
+  }
+
+  inline std::size_t getHash(const void *value_ptr) const {
+    return *reinterpret_cast<const DatetimeLit::cpptype *>(value_ptr);
+  }
+
  private:
   explicit DatetimeType(const bool nullable)
       : Type(Type::kOther, kDatetime, nullable, sizeof(DatetimeLit), 
sizeof(DatetimeLit)) {

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/types/IntervalLit.hpp
----------------------------------------------------------------------
diff --git a/types/IntervalLit.hpp b/types/IntervalLit.hpp
index 8b1ae28..42861ee 100644
--- a/types/IntervalLit.hpp
+++ b/types/IntervalLit.hpp
@@ -37,6 +37,8 @@ namespace quickstep {
  * @brief A literal representing the datetime interval.
  **/
 struct DatetimeIntervalLit {
+  typedef std::int64_t cpptype;
+
   std::int64_t interval_ticks;
 
   static constexpr std::int64_t kTicksPerSecond = INT64_C(1000000);
@@ -121,6 +123,8 @@ struct DatetimeIntervalLit {
  * @brief A literal representing the year-month interval.
  **/
 struct YearMonthIntervalLit {
+  typedef std::int64_t cpptype;
+
   std::int64_t months;
 
   // The maximum number of characters needed to print out a DatetimeInterval in

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/types/NullType.hpp
----------------------------------------------------------------------
diff --git a/types/NullType.hpp b/types/NullType.hpp
index c27a584..309c826 100644
--- a/types/NullType.hpp
+++ b/types/NullType.hpp
@@ -103,6 +103,10 @@ class NullType : public Type {
     return false;
   }
 
+  bool canCheckEqualityWithMemcmp() const override {
+    return true;
+  }
+
  private:
   // NOTE(chasseur): NullType requires 0 bytes of inherent storage. It does,
   // however, require a bit in NULL bitmaps.

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/types/NumericSuperType.hpp
----------------------------------------------------------------------
diff --git a/types/NumericSuperType.hpp b/types/NumericSuperType.hpp
index 0cc1546..76dfe33 100644
--- a/types/NumericSuperType.hpp
+++ b/types/NumericSuperType.hpp
@@ -56,6 +56,14 @@ class NumericSuperType : public Type {
     return TypedValue(static_cast<CppType>(0));
   }
 
+  bool canCheckEqualityWithMemcmp() const override {
+    return true;
+  }
+
+  inline std::size_t getHash(const void *value_ptr) const {
+    return *reinterpret_cast<const CppType *>(value_ptr);
+  }
+
  protected:
   NumericSuperType(const TypeID type_id, const bool nullable)
       : Type(Type::kNumeric, type_id, nullable, sizeof(CppType), 
sizeof(CppType)) {

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/types/Type.hpp
----------------------------------------------------------------------
diff --git a/types/Type.hpp b/types/Type.hpp
index 0e8c4e5..041b6b8 100644
--- a/types/Type.hpp
+++ b/types/Type.hpp
@@ -28,6 +28,8 @@
 #include "types/Type.pb.h"
 #include "types/TypeID.hpp"
 #include "types/TypedValue.hpp"
+#include "types/port/strnlen.hpp"
+#include "utility/HashPair.hpp"
 #include "utility/Macros.hpp"
 
 #include "glog/logging.h"
@@ -448,6 +450,8 @@ class Type {
   virtual TypedValue coerceValue(const TypedValue &original_value,
                                  const Type &original_type) const;
 
+  virtual bool canCheckEqualityWithMemcmp() const = 0;
+
  protected:
   Type(const SuperTypeID super_type_id,
        const TypeID type_id,
@@ -487,6 +491,15 @@ class AsciiStringSuperType : public Type {
     return length_;
   }
 
+  bool canCheckEqualityWithMemcmp() const override {
+    return false;
+  }
+
+  inline std::size_t getHash(const void *value_ptr) const {
+    const char *char_ptr = reinterpret_cast<const char *>(value_ptr);
+    return util::Hash(char_ptr, strnlen(char_ptr, length_));
+  }
+
  protected:
   AsciiStringSuperType(const TypeID type_id,
                        const bool nullable,

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/types/TypeFunctors.cpp
----------------------------------------------------------------------
diff --git a/types/TypeFunctors.cpp b/types/TypeFunctors.cpp
new file mode 100644
index 0000000..84fcad2
--- /dev/null
+++ b/types/TypeFunctors.cpp
@@ -0,0 +1,179 @@
+/**
+ * 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.
+ **/
+
+#include "types/TypeFunctors.hpp"
+
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <vector>
+
+#include "types/CharType.hpp"
+#include "types/DateType.hpp"
+#include "types/DatetimeIntervalType.hpp"
+#include "types/DatetimeType.hpp"
+#include "types/DoubleType.hpp"
+#include "types/FloatType.hpp"
+#include "types/IntType.hpp"
+#include "types/LongType.hpp"
+#include "types/NullType.hpp"
+#include "types/Type.hpp"
+#include "types/TypeID.hpp"
+#include "types/VarCharType.hpp"
+#include "types/YearMonthIntervalType.hpp"
+#include "types/operations/comparisons/ComparisonUtil.hpp"
+#include "types/port/strnlen.hpp"
+#include "utility/HashPair.hpp"
+
+#include "glog/logging.h"
+
+namespace quickstep {
+
+template <typename Maker>
+typename Maker::FunctorType MakeHelper(const Type *type) {
+  switch (type->getTypeID()) {
+    case kInt:
+      return Maker::MakeFunctor(static_cast<const IntType *>(type));
+    case kLong:
+      return Maker::MakeFunctor(static_cast<const LongType *>(type));
+    case kFloat:
+      return Maker::MakeFunctor(static_cast<const FloatType *>(type));
+    case kDouble:
+      return Maker::MakeFunctor(static_cast<const DoubleType *>(type));
+    case kDate:
+      return Maker::MakeFunctor(static_cast<const DateType *>(type));
+    case kDatetime:
+      return Maker::MakeFunctor(static_cast<const DatetimeType *>(type));
+    case kDatetimeInterval:
+      return Maker::MakeFunctor(static_cast<const DatetimeIntervalType 
*>(type));
+    case kYearMonthInterval:
+      return Maker::MakeFunctor(static_cast<const YearMonthIntervalType 
*>(type));
+    case kChar:
+      return Maker::MakeFunctor(static_cast<const CharType *>(type));
+    case kVarChar:
+      return Maker::MakeFunctor(static_cast<const VarCharType *>(type));
+    default:
+      LOG(FATAL) << "Unrecognized type: " << type->getName();
+  }
+}
+
+struct UntypedKeyHashFunctorMaker {
+  typedef UntypedKeyHashFunctor FunctorType;
+
+  template <typename TypeName>
+  static FunctorType MakeFunctor(const TypeName *type) {
+    return [type](const void *value_ptr) -> std::size_t {
+      return type->getHash(value_ptr);
+    };
+  }
+};
+
+UntypedKeyHashFunctor MakeUntypedKeyHashFunctor(const Type *type) {
+  return MakeHelper<UntypedKeyHashFunctorMaker>(type);
+}
+
+UntypedKeyHashFunctor MakeUntypedKeyHashFunctor(const std::vector<const Type 
*> &types) {
+  DCHECK_GE(types.size(), 1u);
+
+  if (types.size() == 1u) {
+    return MakeUntypedKeyHashFunctor(types.front());
+  }
+
+  std::vector<UntypedKeyHashFunctor> hashers;
+  std::vector<std::size_t> offsets;
+  std::size_t accum_offset = 0;
+  for (const Type *type : types) {
+    hashers.emplace_back(MakeUntypedKeyHashFunctor(type));
+    offsets.emplace_back(accum_offset);
+    accum_offset += type->isVariableLength() ? sizeof(void *)
+                                             : type->maximumByteLength();
+  }
+  return [offsets, hashers](const void *value_ptr) -> std::size_t {
+    std::size_t hash = hashers[0](value_ptr);
+    for (std::size_t i = 1; i < hashers.size(); ++i) {
+      hash = CombineHashes(
+          hash,
+          hashers[i](static_cast<const char *>(value_ptr) + offsets[i]));
+    }
+    return hash;
+  };
+}
+
+struct UntypedKeyEqualityFunctorMaker {
+  typedef UntypedKeyEqualityFunctor FunctorType;
+
+  template <typename TypeName>
+  static UntypedKeyEqualityFunctor MakeFunctor(const TypeName *type) {
+    return STLLiteralEqual<typename TypeName::cpptype>();
+  }
+};
+
+template <>
+UntypedKeyEqualityFunctor UntypedKeyEqualityFunctorMaker::MakeFunctor(
+    const CharType *type) {
+  return STLCharEqual(type->getStringLength());
+}
+
+template <>
+UntypedKeyEqualityFunctor UntypedKeyEqualityFunctorMaker::MakeFunctor(
+    const VarCharType *type) {
+  return STLVarCharEqual();
+}
+
+UntypedKeyEqualityFunctor MakeUntypedKeyEqualityFunctor(const Type *type) {
+  return MakeHelper<UntypedKeyEqualityFunctorMaker>(type);
+}
+
+UntypedKeyEqualityFunctor MakeUntypedKeyEqualityFunctor(const 
std::vector<const Type *> &types) {
+  DCHECK_GE(types.size(), 1u);
+
+  if (types.size() == 1u) {
+    return MakeUntypedKeyEqualityFunctor(types.front());
+  }
+
+  std::vector<UntypedKeyEqualityFunctor> equality_checkers;
+  std::vector<std::size_t> offsets;
+  std::size_t accum_offset = 0;
+  bool can_check_equality_with_memcmp = true;
+  for (const Type *type : types) {
+    equality_checkers.emplace_back(MakeUntypedKeyEqualityFunctor(type));
+    offsets.emplace_back(accum_offset);
+    accum_offset += type->isVariableLength() ? sizeof(void *)
+                                             : type->maximumByteLength();
+    can_check_equality_with_memcmp &= type->canCheckEqualityWithMemcmp();
+  }
+  if (can_check_equality_with_memcmp) {
+    return [accum_offset](const void *left, const void *right) -> bool {
+      return memcmp(left, right, accum_offset);
+    };
+  } else {
+    return [offsets, equality_checkers](const void *left, const void *right) 
-> bool {
+      for (std::size_t i = 0; i < equality_checkers.size(); ++i) {
+        if (!equality_checkers[i](static_cast<const char *>(left) + offsets[i],
+                                  static_cast<const char *>(right) + 
offsets[i])) {
+          return false;
+        }
+      }
+      return true;
+    };
+  }
+}
+
+
+}  // namespace quickstep

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/types/TypeFunctors.hpp
----------------------------------------------------------------------
diff --git a/types/TypeFunctors.hpp b/types/TypeFunctors.hpp
new file mode 100644
index 0000000..a8466c5
--- /dev/null
+++ b/types/TypeFunctors.hpp
@@ -0,0 +1,47 @@
+/**
+ * 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 QUICKSTEP_TYPES_TYPE_FUNCTORS_HPP_
+#define QUICKSTEP_TYPES_TYPE_FUNCTORS_HPP_
+
+#include <cstddef>
+#include <functional>
+#include <vector>
+
+namespace quickstep {
+
+class Type;
+
+/** \addtogroup Types
+ *  @{
+ */
+
+typedef std::function<std::size_t (const void *)> UntypedKeyHashFunctor;
+UntypedKeyHashFunctor MakeUntypedKeyHashFunctor(const Type *type);
+UntypedKeyHashFunctor MakeUntypedKeyHashFunctor(const std::vector<const Type 
*> &types);
+
+typedef std::function<bool (const void *, const void *)> 
UntypedKeyEqualityFunctor;
+UntypedKeyEqualityFunctor MakeUntypedKeyEqualityFunctor(const Type *type);
+UntypedKeyEqualityFunctor MakeUntypedKeyEqualityFunctor(const 
std::vector<const Type *> &types);
+
+/** @} */
+
+}  // namespace quickstep
+
+#endif  // QUICKSTEP_TYPES_TYPE_FUNCTORS_HPP_

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/types/YearMonthIntervalType.hpp
----------------------------------------------------------------------
diff --git a/types/YearMonthIntervalType.hpp b/types/YearMonthIntervalType.hpp
index a2ba175..6c54b10 100644
--- a/types/YearMonthIntervalType.hpp
+++ b/types/YearMonthIntervalType.hpp
@@ -113,6 +113,14 @@ class YearMonthIntervalType : public Type {
   bool parseValueFromString(const std::string &value_string,
                             TypedValue *value) const override;
 
+  bool canCheckEqualityWithMemcmp() const override {
+    return true;
+  }
+
+  inline std::size_t getHash(const void *value_ptr) const {
+    return *reinterpret_cast<const YearMonthIntervalLit::cpptype *>(value_ptr);
+  }
+
  private:
   explicit YearMonthIntervalType(const bool nullable)
       : Type(Type::kOther, kYearMonthInterval, nullable, 
sizeof(YearMonthIntervalLit), sizeof(YearMonthIntervalLit)) {

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/utility/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/utility/CMakeLists.txt b/utility/CMakeLists.txt
index ddaae45..8765a57 100644
--- a/utility/CMakeLists.txt
+++ b/utility/CMakeLists.txt
@@ -174,6 +174,7 @@ add_library(quickstep_utility_ExecutionDAGVisualizer
             ExecutionDAGVisualizer.hpp)
 add_library(quickstep_utility_Glob Glob.cpp Glob.hpp)
 add_library(quickstep_utility_HashPair ../empty_src.cpp HashPair.hpp)
+add_library(quickstep_utility_InlineMemcpy ../empty_src.cpp InlineMemcpy.hpp)
 add_library(quickstep_utility_Macros ../empty_src.cpp Macros.hpp)
 add_library(quickstep_utility_MemStream ../empty_src.cpp MemStream.hpp)
 add_library(quickstep_utility_PlanVisualizer PlanVisualizer.cpp 
PlanVisualizer.hpp)
@@ -323,6 +324,7 @@ target_link_libraries(quickstep_utility
                       quickstep_utility_ExecutionDAGVisualizer
                       quickstep_utility_Glob
                       quickstep_utility_HashPair
+                      quickstep_utility_InlineMemcpy
                       quickstep_utility_Macros
                       quickstep_utility_MemStream
                       quickstep_utility_PlanVisualizer

http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/140069b9/utility/InlineMemcpy.hpp
----------------------------------------------------------------------
diff --git a/utility/InlineMemcpy.hpp b/utility/InlineMemcpy.hpp
new file mode 100644
index 0000000..ff7ae83
--- /dev/null
+++ b/utility/InlineMemcpy.hpp
@@ -0,0 +1,80 @@
+/**
+ * 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 QUICKSTEP_UTILITY_INLINE_MEMCPY_HPP_
+#define QUICKSTEP_UTILITY_INLINE_MEMCPY_HPP_
+
+#include <cstring>
+
+namespace quickstep {
+
+/** \addtogroup Utility
+ *  @{
+ */
+
+inline void InlineMemcpy(void *dst, const void *src, const std::size_t size) {
+#define INLINE_ENTRY_(len) \
+  case len: std::memcpy(dst, src, len); break
+
+  switch (size) {
+    INLINE_ENTRY_(1);
+    INLINE_ENTRY_(2);
+    INLINE_ENTRY_(3);
+    INLINE_ENTRY_(4);
+    INLINE_ENTRY_(5);
+    INLINE_ENTRY_(6);
+    INLINE_ENTRY_(7);
+    INLINE_ENTRY_(8);
+    INLINE_ENTRY_(9);
+    INLINE_ENTRY_(10);
+    INLINE_ENTRY_(11);
+    INLINE_ENTRY_(12);
+    INLINE_ENTRY_(13);
+    INLINE_ENTRY_(14);
+    INLINE_ENTRY_(15);
+    INLINE_ENTRY_(16);
+    INLINE_ENTRY_(17);
+    INLINE_ENTRY_(18);
+    INLINE_ENTRY_(19);
+    INLINE_ENTRY_(20);
+    INLINE_ENTRY_(21);
+    INLINE_ENTRY_(22);
+    INLINE_ENTRY_(23);
+    INLINE_ENTRY_(24);
+    INLINE_ENTRY_(25);
+    INLINE_ENTRY_(26);
+    INLINE_ENTRY_(27);
+    INLINE_ENTRY_(28);
+    INLINE_ENTRY_(29);
+    INLINE_ENTRY_(30);
+    INLINE_ENTRY_(31);
+    INLINE_ENTRY_(32);
+
+    default:
+      std::memcpy(dst, src, size);
+  }
+
+#undef INLINE_ENTRY_
+}
+
+/** @} */
+
+}  // namespace quickstep
+
+#endif  // QUICKSTEP_UTILITY_INLINE_MEMCPY_HPP_

Reply via email to