delete unused code & sys parameters
This commit is contained in:
15
deps/oblib/src/lib/hash/ob_array_hash_map.h
vendored
15
deps/oblib/src/lib/hash/ob_array_hash_map.h
vendored
@ -119,21 +119,6 @@ public:
|
|||||||
size_ = 0;
|
size_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int shrink_size(int64_t size)
|
|
||||||
{
|
|
||||||
LockGuard guard(lock_);
|
|
||||||
int ret = OB_SUCCESS;
|
|
||||||
if (size <= 0 || size > capacity_) {
|
|
||||||
ret = OB_INVALID_ARGUMENT;
|
|
||||||
COMMON_LOG(WARN, "invalid argument", K(size), K_(capacity));
|
|
||||||
} else if (size * 2 <= capacity_) {
|
|
||||||
capacity_ = size * 2;
|
|
||||||
} else {
|
|
||||||
capacity_ = size;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void print() const
|
void print() const
|
||||||
{
|
{
|
||||||
COMMON_LOG(INFO, "array_hash dump begin:", K(this));
|
COMMON_LOG(INFO, "array_hash dump begin:", K(this));
|
||||||
|
|||||||
307
deps/oblib/src/lib/hash/ob_ext_iter_hashset.h
vendored
307
deps/oblib/src/lib/hash/ob_ext_iter_hashset.h
vendored
@ -1,307 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2021 OceanBase
|
|
||||||
* OceanBase CE is licensed under Mulan PubL v2.
|
|
||||||
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
||||||
* You may obtain a copy of Mulan PubL v2 at:
|
|
||||||
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
||||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the Mulan PubL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef OCEANBASE_LIB_HASH_OB_EXT_ITER_HASHSET_H__
|
|
||||||
#define OCEANBASE_LIB_HASH_OB_EXT_ITER_HASHSET_H__
|
|
||||||
|
|
||||||
#include "lib/hash/ob_iteratable_hashset.h" // ObIteratableHashSet
|
|
||||||
#include "lib/utility/ob_print_utils.h"
|
|
||||||
|
|
||||||
namespace oceanbase
|
|
||||||
{
|
|
||||||
namespace common
|
|
||||||
{
|
|
||||||
namespace hash
|
|
||||||
{
|
|
||||||
template <class K, uint64_t N, class Allocator> class ObExtIterHashSet;
|
|
||||||
|
|
||||||
///////////////////////////////////// ObExtIterHashSet Iterator /////////////////////////////////////
|
|
||||||
template <class HashSet>
|
|
||||||
class ObExtIterHashSetConstIterator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef typename HashSet::const_key_ref_t const_key_ref_t;
|
|
||||||
typedef ObExtIterHashSetConstIterator<HashSet> SelfType;
|
|
||||||
typedef typename HashSet::HashSetBucket BucketType;
|
|
||||||
typedef typename HashSet::InnerHashSetIter InnerIter;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ObExtIterHashSetConstIterator(const HashSet *set, const BucketType *bucket, const InnerIter &iter)
|
|
||||||
: hash_set_(set), bucket_(bucket), iter_(iter)
|
|
||||||
{}
|
|
||||||
|
|
||||||
ObExtIterHashSetConstIterator(const SelfType &other)
|
|
||||||
: hash_set_(other.hash_set_), bucket_(other.bucket_), iter_(other.iter_)
|
|
||||||
{}
|
|
||||||
|
|
||||||
~ObExtIterHashSetConstIterator()
|
|
||||||
{}
|
|
||||||
|
|
||||||
public:
|
|
||||||
ObExtIterHashSetConstIterator &operator=(const SelfType &other)
|
|
||||||
{
|
|
||||||
if (this != &other) {
|
|
||||||
hash_set_ = other.hash_set_;
|
|
||||||
bucket_ = other.bucket_;
|
|
||||||
iter_ = other.iter_;
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
ObExtIterHashSetConstIterator &operator=(SelfType &&other) = default;
|
|
||||||
|
|
||||||
bool operator==(const SelfType &other) const
|
|
||||||
{
|
|
||||||
return other.hash_set_ == hash_set_ && other.bucket_ == bucket_ && other.iter_ == iter_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const SelfType &other) const
|
|
||||||
{
|
|
||||||
return other.hash_set_ != hash_set_ || other.bucket_ != bucket_ || other.iter_ != iter_;
|
|
||||||
}
|
|
||||||
|
|
||||||
SelfType &operator++()
|
|
||||||
{
|
|
||||||
if (NULL == hash_set_ || NULL == bucket_) {
|
|
||||||
LIB_LOG(ERROR, "err hash set, iter or bucket", K(hash_set_), K(bucket_));
|
|
||||||
} else {
|
|
||||||
// if current bucket is not null, fetch next one.
|
|
||||||
if (iter_ != bucket_->hash_set_.end()) {
|
|
||||||
++iter_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if reach end of current bucket, step to the next bucket.
|
|
||||||
if (iter_ == bucket_->hash_set_.end() && NULL != bucket_->next_) {
|
|
||||||
bucket_ = bucket_->next_;
|
|
||||||
iter_ = bucket_->hash_set_.begin();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
const_key_ref_t operator*() const
|
|
||||||
{
|
|
||||||
if (NULL == hash_set_ || NULL == bucket_) {
|
|
||||||
LIB_LOG(ERROR, "err hash set, iter or bucket", K(hash_set_), K(bucket_));
|
|
||||||
}
|
|
||||||
return *iter_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const HashSet *hash_set_;
|
|
||||||
const BucketType *bucket_;
|
|
||||||
InnerIter iter_;
|
|
||||||
};
|
|
||||||
|
|
||||||
///////////////////////////////////// ObExtIterHashSet /////////////////////////////////////
|
|
||||||
|
|
||||||
template <class K, uint64_t N = 1031, class Allocator = ObIAllocator>
|
|
||||||
class ObExtIterHashSet
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef const K &const_key_ref_t;
|
|
||||||
typedef ObIteratableHashSet<K, N> BaseHashSet;
|
|
||||||
typedef ObExtIterHashSet<K, N, Allocator> SelfType;
|
|
||||||
typedef ObExtIterHashSetConstIterator<SelfType> const_iterator_t;
|
|
||||||
typedef typename BaseHashSet::const_iterator_t InnerHashSetIter;
|
|
||||||
|
|
||||||
struct HashSetBucket
|
|
||||||
{
|
|
||||||
BaseHashSet hash_set_;
|
|
||||||
HashSetBucket *next_;
|
|
||||||
|
|
||||||
HashSetBucket() : hash_set_(), next_(NULL) {}
|
|
||||||
~HashSetBucket() {}
|
|
||||||
void reset()
|
|
||||||
{
|
|
||||||
hash_set_.reset();
|
|
||||||
next_ = NULL;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ObExtIterHashSet(Allocator &allocator);
|
|
||||||
virtual ~ObExtIterHashSet();
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @retval OB_SUCCESS insert successfully
|
|
||||||
* @retval OB_HASH_EXIST key exists
|
|
||||||
* @retval other ret failed
|
|
||||||
*/
|
|
||||||
int set_refactored(const K &key);
|
|
||||||
/**
|
|
||||||
* @retval OB_HASH_EXIST key exists
|
|
||||||
* @retval OB_HASH_NOT_EXIST key not exists
|
|
||||||
*/
|
|
||||||
int exist_refactored(const K &key) const { return is_exist_(key) ? OB_HASH_EXIST : OB_HASH_NOT_EXIST; }
|
|
||||||
|
|
||||||
void reset();
|
|
||||||
void clear() { reset(); }
|
|
||||||
|
|
||||||
const_iterator_t begin() const
|
|
||||||
{
|
|
||||||
return const_iterator_t(this, &buckets_, buckets_.hash_set_.begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator_t end() const
|
|
||||||
{
|
|
||||||
return const_iterator_t(this, buckets_tail_, buckets_tail_->hash_set_.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t count() const { return count_; }
|
|
||||||
|
|
||||||
public:
|
|
||||||
DECLARE_TO_STRING;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool is_exist_(const K &key) const;
|
|
||||||
bool is_full_() const { return count_ >= bucket_num_ * static_cast<int64_t>(N); }
|
|
||||||
int add_bucket_();
|
|
||||||
|
|
||||||
private:
|
|
||||||
int64_t count_; // count of object
|
|
||||||
int64_t bucket_num_; // count of bucket
|
|
||||||
Allocator &allocator_; // allocator
|
|
||||||
HashSetBucket buckets_; // bucket lists
|
|
||||||
HashSetBucket *buckets_tail_; // bucket lists tail
|
|
||||||
|
|
||||||
private:
|
|
||||||
template <class HashSet>
|
|
||||||
friend class ObExtIterHashSetConstIterator;
|
|
||||||
|
|
||||||
private:
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(ObExtIterHashSet);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class K, uint64_t N, class Allocator>
|
|
||||||
ObExtIterHashSet<K, N, Allocator>::ObExtIterHashSet(Allocator &allocator) :
|
|
||||||
count_(0),
|
|
||||||
bucket_num_(1),
|
|
||||||
allocator_(allocator),
|
|
||||||
buckets_(),
|
|
||||||
buckets_tail_(&buckets_)
|
|
||||||
{}
|
|
||||||
|
|
||||||
template <class K, uint64_t N, class Allocator>
|
|
||||||
ObExtIterHashSet<K, N, Allocator>::~ObExtIterHashSet()
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class K, uint64_t N, class Allocator>
|
|
||||||
int ObExtIterHashSet<K, N, Allocator>::set_refactored(const K &key)
|
|
||||||
{
|
|
||||||
int ret = OB_SUCCESS;
|
|
||||||
bool exist = is_exist_(key);
|
|
||||||
|
|
||||||
if (exist) {
|
|
||||||
ret = OB_HASH_EXIST;
|
|
||||||
} else if (is_full_() && OB_FAIL(add_bucket_())) {
|
|
||||||
LIB_LOG(WARN, "add_bucket_ fail", K(ret));
|
|
||||||
} else {
|
|
||||||
// keep inserting successful
|
|
||||||
if (NULL == buckets_tail_) {
|
|
||||||
ret = OB_ERR_UNEXPECTED;
|
|
||||||
LIB_LOG(WARN, "err bucket tail", K(ret));
|
|
||||||
} else if (OB_FAIL(buckets_tail_->hash_set_.set_refactored(key))) {
|
|
||||||
LIB_LOG(WARN, "set key into hash set fail", K(ret));
|
|
||||||
} else {
|
|
||||||
count_++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class K, uint64_t N, class Allocator>
|
|
||||||
bool ObExtIterHashSet<K, N, Allocator>::is_exist_(const K &key) const
|
|
||||||
{
|
|
||||||
bool exist = false;
|
|
||||||
const HashSetBucket *item = &buckets_;
|
|
||||||
|
|
||||||
while (! exist && NULL != item) {
|
|
||||||
if (OB_HASH_EXIST == item->hash_set_.exist_refactored(key)) {
|
|
||||||
exist = true;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
item = item->next_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return exist;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class K, uint64_t N, class Allocator>
|
|
||||||
int ObExtIterHashSet<K, N, Allocator>::add_bucket_()
|
|
||||||
{
|
|
||||||
int ret = OB_SUCCESS;
|
|
||||||
HashSetBucket *bucket = (HashSetBucket *)allocator_.alloc(sizeof(HashSetBucket));
|
|
||||||
if (NULL == bucket) {
|
|
||||||
LIB_LOG(WARN, "allocate memory for bucket fail", "bucket_size", sizeof(HashSetBucket));
|
|
||||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
||||||
} else {
|
|
||||||
new(bucket) HashSetBucket();
|
|
||||||
|
|
||||||
bucket->next_ = NULL;
|
|
||||||
buckets_tail_->next_ = bucket;
|
|
||||||
buckets_tail_ = bucket;
|
|
||||||
|
|
||||||
bucket_num_++;
|
|
||||||
|
|
||||||
LIB_LOG(DEBUG, "add bucket", K(bucket_num_), K(count_), K(bucket));
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class K, uint64_t N, class Allocator>
|
|
||||||
void ObExtIterHashSet<K, N, Allocator>::reset()
|
|
||||||
{
|
|
||||||
HashSetBucket *bucket = buckets_.next_;
|
|
||||||
|
|
||||||
while (NULL != bucket) {
|
|
||||||
HashSetBucket *next = bucket->next_;
|
|
||||||
bucket->~HashSetBucket();
|
|
||||||
allocator_.free((void*)bucket);
|
|
||||||
|
|
||||||
bucket = next;
|
|
||||||
}
|
|
||||||
bucket = NULL;
|
|
||||||
|
|
||||||
buckets_.reset();
|
|
||||||
buckets_tail_ = &buckets_;
|
|
||||||
bucket_num_ = 1;
|
|
||||||
count_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class K, uint64_t N, class Allocator>
|
|
||||||
int64_t ObExtIterHashSet<K, N, Allocator>::to_string(char *buf, const int64_t buf_len) const
|
|
||||||
{
|
|
||||||
int64_t pos = 0;
|
|
||||||
J_ARRAY_START();
|
|
||||||
const_iterator_t beg = begin();
|
|
||||||
for (const_iterator_t it = beg;
|
|
||||||
it != end();
|
|
||||||
++it) {
|
|
||||||
if (it != beg) {
|
|
||||||
J_COMMA();
|
|
||||||
}
|
|
||||||
BUF_PRINTO(*it);
|
|
||||||
}
|
|
||||||
J_ARRAY_END();
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
} // namespace hash
|
|
||||||
} // namespace common
|
|
||||||
} // namespace oceanbase
|
|
||||||
#endif
|
|
||||||
164
deps/oblib/src/lib/hash/ob_fixed_hash.h
vendored
164
deps/oblib/src/lib/hash/ob_fixed_hash.h
vendored
@ -1,164 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2021 OceanBase
|
|
||||||
* OceanBase CE is licensed under Mulan PubL v2.
|
|
||||||
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
||||||
* You may obtain a copy of Mulan PubL v2 at:
|
|
||||||
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
||||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the Mulan PubL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef OCEANBASE_HASH_OB_FIXED_HASH_H_
|
|
||||||
#define OCEANBASE_HASH_OB_FIXED_HASH_H_
|
|
||||||
|
|
||||||
#include "lib/ob_define.h"
|
|
||||||
#include "lib/queue/ob_link.h"
|
|
||||||
#include "lib/hash/ob_hash.h"
|
|
||||||
|
|
||||||
namespace oceanbase
|
|
||||||
{
|
|
||||||
namespace common
|
|
||||||
{
|
|
||||||
template<typename key_t>
|
|
||||||
class FixedHash
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef ObLink Link;
|
|
||||||
struct node_t: public Link
|
|
||||||
{
|
|
||||||
node_t(): hash_(0), key_() {}
|
|
||||||
explicit node_t(key_t key): key_(key) {
|
|
||||||
hash_ = hash_map_calc_hash(key_);
|
|
||||||
}
|
|
||||||
~node_t() {}
|
|
||||||
static uint64_t hash_map_calc_hash(key_t key)
|
|
||||||
{
|
|
||||||
return calc_hash(key) | 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
node_t* set(key_t key)
|
|
||||||
{
|
|
||||||
hash_ = hash_map_calc_hash(key);
|
|
||||||
key_ = key;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_dummy_node() {
|
|
||||||
return 0 == (hash_ & 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int compare(node_t* that)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
if (this->hash_ > that->hash_) {
|
|
||||||
ret = 1;
|
|
||||||
} else if (this->hash_ < that->hash_) {
|
|
||||||
ret = -1;
|
|
||||||
} else if (this->is_dummy_node()) {
|
|
||||||
ret = 0;
|
|
||||||
} else {
|
|
||||||
ret = common::compare(this->key_, that->key_);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
node_t* set_as_bucket(uint64_t idx)
|
|
||||||
{
|
|
||||||
hash_ = bitrev(idx);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t get_spk() { return bitrev(hash_); }
|
|
||||||
uint64_t hash_;
|
|
||||||
key_t key_;
|
|
||||||
};
|
|
||||||
|
|
||||||
FixedHash(void* buf, int64_t size):
|
|
||||||
nodes_((node_t*)buf), limit_(last2n(size/sizeof(node_t))) {
|
|
||||||
init_buckets(nodes_, limit_);
|
|
||||||
}
|
|
||||||
~FixedHash() {}
|
|
||||||
|
|
||||||
int insert(key_t key, node_t* node) {
|
|
||||||
node_t key_node(key);
|
|
||||||
return ol_insert(get_pre(&key_node), node->set(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
int del(key_t key, node_t*& node) {
|
|
||||||
node_t key_node(key);
|
|
||||||
return ol_del(get_pre(&key_node), &key_node, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
int get(key_t key, node_t*& node) {
|
|
||||||
node_t key_node(key);
|
|
||||||
return ol_get(get_pre(&key_node), &key_node, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
node_t* next(node_t* node) {
|
|
||||||
while(NULL != (node = next_node(node))
|
|
||||||
&& node->is_dummy_node())
|
|
||||||
;
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
node_t* next_node(node_t* node) {
|
|
||||||
node_t* next = NULL;
|
|
||||||
if (NULL == node) {
|
|
||||||
next = nodes_;
|
|
||||||
} else if (is_last_bit_set((uint64_t)(next = (node_t*)ATOMIC_LOAD(&node->next_)))) {
|
|
||||||
next = get_pre(node);
|
|
||||||
}
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t last2n(const uint64_t x)
|
|
||||||
{
|
|
||||||
return x == 0? 0 : (1UL << 63) >> (__builtin_clzll(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t bitrev(uint64_t x)
|
|
||||||
{
|
|
||||||
x = (((x & 0xaaaaaaaaaaaaaaaaUL) >> 1) | ((x & 0x5555555555555555UL) << 1));
|
|
||||||
x = (((x & 0xccccccccccccccccUL) >> 2) | ((x & 0x3333333333333333UL) << 2));
|
|
||||||
x = (((x & 0xf0f0f0f0f0f0f0f0UL) >> 4) | ((x & 0x0f0f0f0f0f0f0f0fUL) << 4));
|
|
||||||
x = (((x & 0xff00ff00ff00ff00UL) >> 8) | ((x & 0x00ff00ff00ff00ffUL) << 8));
|
|
||||||
x = (((x & 0xffff0000ffff0000UL) >> 16) | ((x & 0x0000ffff0000ffff) << 16));
|
|
||||||
return((x >> 32) | (x << 32));
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t get_idx(uint64_t spk, uint64_t bcnt)
|
|
||||||
{
|
|
||||||
return bcnt == 0? 0 : (spk & (bcnt - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
node_t* get_pre(node_t* key_node)
|
|
||||||
{
|
|
||||||
return nodes_ + get_idx(key_node->get_spk(), limit_);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t get_bucket_pre_idx(uint64_t idx) {
|
|
||||||
return idx & ~last2n(idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int init_buckets(node_t* nodes, int64_t limit) {
|
|
||||||
int err = 0;
|
|
||||||
new(nodes)node_t[limit];
|
|
||||||
nodes[0].set_as_bucket(0);
|
|
||||||
for(int64_t i = 1; 0 == err && i < limit; i++) {
|
|
||||||
node_t* node = nodes + i;
|
|
||||||
node->set_as_bucket(i);
|
|
||||||
err = ol_insert(nodes + get_bucket_pre_idx(i), node);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
node_t* nodes_;
|
|
||||||
int64_t limit_;
|
|
||||||
};
|
|
||||||
|
|
||||||
}; // end namespace common
|
|
||||||
}; // end namespace oceanbase
|
|
||||||
#endif /* OCEANBASE_HASH_OB_FIXED_HASH_H_ */
|
|
||||||
379
deps/oblib/src/lib/hash/ob_pre_alloc_link_hashmap.h
vendored
379
deps/oblib/src/lib/hash/ob_pre_alloc_link_hashmap.h
vendored
@ -1,379 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2021 OceanBase
|
|
||||||
* OceanBase CE is licensed under Mulan PubL v2.
|
|
||||||
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
||||||
* You may obtain a copy of Mulan PubL v2 at:
|
|
||||||
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
||||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the Mulan PubL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SRC_LIBRARY_SRC_LIB_HASH_OB_MEMLESS_LINK_HASHMAP_H_
|
|
||||||
#define SRC_LIBRARY_SRC_LIB_HASH_OB_MEMLESS_LINK_HASHMAP_H_
|
|
||||||
|
|
||||||
#include "lib/ob_define.h"
|
|
||||||
#include "lib/hash/ob_hashutils.h"
|
|
||||||
#include "lib/atomic/ob_atomic.h"
|
|
||||||
#include "lib/utility/ob_print_utils.h"
|
|
||||||
#include "lib/container/ob_array.h"
|
|
||||||
#include "lib/lock/ob_bucket_lock.h"
|
|
||||||
|
|
||||||
namespace oceanbase
|
|
||||||
{
|
|
||||||
namespace common
|
|
||||||
{
|
|
||||||
namespace hash
|
|
||||||
{
|
|
||||||
|
|
||||||
// ObMemLessLinkHashMap is convenient for reuse of node.
|
|
||||||
// there is a simple allocator in the map.
|
|
||||||
// memory of node should be pre-allocated.
|
|
||||||
// use of storage of table and meta block.
|
|
||||||
template <class KEY, class ITEM>
|
|
||||||
struct ObPreAllocLinkHashNode
|
|
||||||
{
|
|
||||||
explicit ObPreAllocLinkHashNode(ITEM &item): item_(item) {}
|
|
||||||
virtual ~ObPreAllocLinkHashNode() { }
|
|
||||||
virtual OB_INLINE bool equals(const ObPreAllocLinkHashNode &node) { return equals(node.get_key()); }
|
|
||||||
virtual OB_INLINE bool equals(const KEY &key) { return get_key() == key; }
|
|
||||||
//derived class should override static uint64_t hash(const uint64_t &key);
|
|
||||||
|
|
||||||
virtual const KEY &get_key() const = 0;
|
|
||||||
VIRTUAL_TO_STRING_KV(KP(this), K_(item));
|
|
||||||
|
|
||||||
ITEM &item_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class KEY, class ITEM, class NODE, class ITEM_PROTECTOR>
|
|
||||||
class ObPreAllocLinkHashMap
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
class ForeachFunctor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual int operator()(ITEM &item, bool &is_full) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class EraseChecker
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual int operator()(ITEM &item) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class GetFunctor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual int operator()(ITEM &item) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Iterator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Iterator(ObPreAllocLinkHashMap &map)
|
|
||||||
: items_(),
|
|
||||||
item_idx_(0),
|
|
||||||
bucket_pos_(0),
|
|
||||||
map_(map)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
virtual ~Iterator() { release_items(); }
|
|
||||||
int get_next(ITEM *&item)
|
|
||||||
{
|
|
||||||
int ret = OB_SUCCESS;
|
|
||||||
item = NULL;
|
|
||||||
|
|
||||||
while (OB_SUCC(ret)) {
|
|
||||||
if (item_idx_ < items_.count()) {
|
|
||||||
item = items_.at(item_idx_);
|
|
||||||
++item_idx_;
|
|
||||||
break;
|
|
||||||
} else if (bucket_pos_ >= map_.buckets_count_) {
|
|
||||||
ret = OB_ITER_END;
|
|
||||||
} else {
|
|
||||||
item_idx_ = 0;
|
|
||||||
release_items();
|
|
||||||
ObBucketRLockGuard guard(map_.buckets_lock_, bucket_pos_);
|
|
||||||
if (NULL != map_.buckets_[bucket_pos_]) {
|
|
||||||
NODE *node = map_.buckets_[bucket_pos_];
|
|
||||||
while (OB_SUCC(ret) && NULL != node) {
|
|
||||||
ITEM_PROTECTOR::hold(node->item_);
|
|
||||||
if (OB_FAIL(items_.push_back(&node->item_))) {
|
|
||||||
COMMON_LOG(WARN, "Failed to add item", K(ret));
|
|
||||||
ITEM_PROTECTOR::release(node->item_);
|
|
||||||
} else {
|
|
||||||
node = node->next_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++bucket_pos_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
void release_items()
|
|
||||||
{
|
|
||||||
for (int64_t i = 0; i < items_.count(); ++i) {
|
|
||||||
ITEM_PROTECTOR::release(*items_.at(i));
|
|
||||||
}
|
|
||||||
items_.reuse();
|
|
||||||
}
|
|
||||||
common::ObArray<ITEM *> items_;
|
|
||||||
int64_t item_idx_;
|
|
||||||
int64_t bucket_pos_;
|
|
||||||
ObPreAllocLinkHashMap &map_;
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Iterator);
|
|
||||||
};
|
|
||||||
|
|
||||||
ObPreAllocLinkHashMap()
|
|
||||||
: is_inited_(false),
|
|
||||||
buckets_lock_(),
|
|
||||||
count_(),
|
|
||||||
buckets_(NULL),
|
|
||||||
buckets_count_(1),
|
|
||||||
allocator_()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
virtual ~ObPreAllocLinkHashMap()
|
|
||||||
{
|
|
||||||
destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy()
|
|
||||||
{
|
|
||||||
for (uint64_t bucket_pos = 0; NULL != buckets_ && bucket_pos < buckets_count_; ++bucket_pos) {
|
|
||||||
ObBucketRLockGuard bucket_guard(buckets_lock_, bucket_pos);
|
|
||||||
NODE *cur = buckets_[bucket_pos];
|
|
||||||
NODE *next = NULL;
|
|
||||||
while (NULL != cur) {
|
|
||||||
next = cur->next_;
|
|
||||||
free_node(cur);
|
|
||||||
cur = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is_inited_ = false;
|
|
||||||
buckets_lock_.destroy();
|
|
||||||
count_ = 0;
|
|
||||||
ob_free(buckets_);
|
|
||||||
buckets_ = NULL;
|
|
||||||
buckets_count_ = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int init(const int64_t buckets_count, const uint32_t latch_id, const lib::ObLabel &label)
|
|
||||||
{
|
|
||||||
int ret = OB_SUCCESS;
|
|
||||||
ObMemAttr mem_attr(OB_SERVER_TENANT_ID, label);
|
|
||||||
const int64_t real_buckets_count = hash::cal_next_prime(buckets_count);
|
|
||||||
|
|
||||||
if (is_inited_) {
|
|
||||||
ret = OB_INIT_TWICE;
|
|
||||||
COMMON_LOG(WARN, "cannot init twice", K(ret));
|
|
||||||
} else if (real_buckets_count <= 0 || buckets_count <= 0) {
|
|
||||||
ret = OB_INVALID_ARGUMENT;
|
|
||||||
COMMON_LOG(WARN, "invalid bucket count", K(ret), K(real_buckets_count), K(buckets_count));
|
|
||||||
} else if (OB_FAIL(buckets_lock_.init(real_buckets_count, latch_id, label))) {
|
|
||||||
COMMON_LOG(WARN, "failed to init buckets lock", K(ret));
|
|
||||||
} else if (OB_ISNULL(buckets_ = reinterpret_cast<NODE**>(
|
|
||||||
ob_malloc(sizeof(NODE*) * real_buckets_count, mem_attr)))) {
|
|
||||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
||||||
COMMON_LOG(WARN, "failed to alloc buckets", K(ret), K(real_buckets_count));
|
|
||||||
} else {
|
|
||||||
allocator_.set_label(label);
|
|
||||||
MEMSET(buckets_, 0, sizeof(NODE*) * real_buckets_count);
|
|
||||||
COMMON_LOG(INFO, "init hashmap", K(buckets_count), K(real_buckets_count),
|
|
||||||
"buf_size", sizeof(NODE*) * real_buckets_count, K(latch_id), K(label));
|
|
||||||
count_ = 0;
|
|
||||||
buckets_count_ = real_buckets_count;
|
|
||||||
is_inited_ = true;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t get_count() const { return ATOMIC_LOAD(&count_); }
|
|
||||||
uint64_t get_buckets_count() const { return buckets_count_; }
|
|
||||||
|
|
||||||
NODE *alloc_node(ITEM &item)
|
|
||||||
{
|
|
||||||
return allocator_.alloc(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_node(NODE *&node)
|
|
||||||
{
|
|
||||||
allocator_.free(node);
|
|
||||||
node = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int put(NODE &node)
|
|
||||||
{
|
|
||||||
int ret = OB_SUCCESS;
|
|
||||||
|
|
||||||
if (!is_inited_) {
|
|
||||||
ret = OB_NOT_INIT;
|
|
||||||
COMMON_LOG(WARN, "not inited", K(ret));
|
|
||||||
} else {
|
|
||||||
const uint64_t bucket_pos = NODE::hash(node.get_key()) % buckets_count_;
|
|
||||||
ObBucketWLockGuard bucket_guard(buckets_lock_, bucket_pos);
|
|
||||||
NODE *cur = buckets_[bucket_pos];
|
|
||||||
while (NULL != cur) {
|
|
||||||
if (cur->equals(node)) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
cur = cur->next_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NULL != cur) {
|
|
||||||
ret = OB_HASH_EXIST;
|
|
||||||
} else {
|
|
||||||
node.next_ = buckets_[bucket_pos];
|
|
||||||
buckets_[bucket_pos] = &node;
|
|
||||||
ATOMIC_INC(&count_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete node which has common key
|
|
||||||
int erase(const KEY &key, ITEM *&del_item, EraseChecker *checker = NULL)
|
|
||||||
{
|
|
||||||
int ret = OB_SUCCESS;
|
|
||||||
del_item = NULL;
|
|
||||||
|
|
||||||
if (!is_inited_) {
|
|
||||||
ret = OB_NOT_INIT;
|
|
||||||
COMMON_LOG(WARN, "not inited", K(ret));
|
|
||||||
} else {
|
|
||||||
const uint64_t bucket_pos = NODE::hash(key) % buckets_count_;
|
|
||||||
ObBucketWLockGuard bucket_guard(buckets_lock_, bucket_pos);
|
|
||||||
NODE *cur = buckets_[bucket_pos];
|
|
||||||
NODE *prev = NULL;
|
|
||||||
while (NULL != cur) {
|
|
||||||
if (cur->equals(key)) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
prev = cur;
|
|
||||||
cur = cur->next_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NULL == cur) {
|
|
||||||
ret = OB_HASH_NOT_EXIST;
|
|
||||||
} else if (NULL != checker && OB_FAIL((*checker)(cur->item_))) {
|
|
||||||
// cannot erase now
|
|
||||||
} else {
|
|
||||||
if (NULL != prev) {
|
|
||||||
prev->next_ = cur->next_;
|
|
||||||
} else {
|
|
||||||
buckets_[bucket_pos] = cur->next_;
|
|
||||||
}
|
|
||||||
cur->next_ = NULL;
|
|
||||||
del_item = &cur->item_;
|
|
||||||
free_node(cur);
|
|
||||||
ATOMIC_DEC(&count_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete node which has common key
|
|
||||||
int erase(const KEY &key)
|
|
||||||
{
|
|
||||||
int ret = OB_SUCCESS;
|
|
||||||
ITEM *del_item = NULL;
|
|
||||||
if (OB_FAIL(erase(key, del_item))) {
|
|
||||||
COMMON_LOG(WARN, "failed to erase ndoe", K(ret), K(key));
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int exist(const KEY &key)
|
|
||||||
{
|
|
||||||
ITEM *item = NULL;
|
|
||||||
int ret = get(key, item);
|
|
||||||
if (OB_SUCCESS == ret) {
|
|
||||||
ret = OB_HASH_EXIST;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int get(const KEY &key, GetFunctor &functor)
|
|
||||||
{
|
|
||||||
ITEM *item = NULL;
|
|
||||||
return get(key, item, &functor);
|
|
||||||
}
|
|
||||||
|
|
||||||
int get(const KEY &key, ITEM *&item, GetFunctor *functor = NULL)
|
|
||||||
{
|
|
||||||
int ret = OB_SUCCESS;
|
|
||||||
item = NULL;
|
|
||||||
|
|
||||||
if (!is_inited_) {
|
|
||||||
ret = OB_NOT_INIT;
|
|
||||||
COMMON_LOG(WARN, "not inited", K(ret));
|
|
||||||
} else {
|
|
||||||
const uint64_t bucket_pos = NODE::hash(key) % buckets_count_;
|
|
||||||
ObBucketRLockGuard bucket_guard(buckets_lock_, bucket_pos);
|
|
||||||
NODE *cur = buckets_[bucket_pos];
|
|
||||||
while (NULL != cur) {
|
|
||||||
if (cur->equals(key)) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
cur = cur->next_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NULL == cur) {
|
|
||||||
ret = OB_HASH_NOT_EXIST;
|
|
||||||
} else if (NULL != functor && OB_FAIL((*functor)(cur->item_))) {
|
|
||||||
COMMON_LOG(WARN, "failed to do get functor", K(ret), K(*cur));
|
|
||||||
} else {
|
|
||||||
item = &cur->item_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int foreach(ForeachFunctor &functor)
|
|
||||||
{
|
|
||||||
int ret = OB_SUCCESS;
|
|
||||||
bool is_full = false;
|
|
||||||
|
|
||||||
if (!is_inited_) {
|
|
||||||
ret = OB_NOT_INIT;
|
|
||||||
COMMON_LOG(WARN, "not inited", K(ret));
|
|
||||||
} else {
|
|
||||||
for (uint64_t bucket_pos = 0; OB_SUCC(ret) && !is_full && bucket_pos < buckets_count_; ++bucket_pos) {
|
|
||||||
ObBucketRLockGuard bucket_guard(buckets_lock_, bucket_pos);
|
|
||||||
NODE *cur = buckets_[bucket_pos];
|
|
||||||
while (OB_SUCC(ret) && NULL != cur && !is_full) {
|
|
||||||
if (OB_FAIL(functor(cur->item_, is_full))) {
|
|
||||||
COMMON_LOG(WARN, "failed to do foreach functor", K(ret));
|
|
||||||
} else {
|
|
||||||
cur = cur->next_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool is_inited_;
|
|
||||||
mutable common::ObBucketLock buckets_lock_;
|
|
||||||
uint64_t count_;
|
|
||||||
NODE **buckets_;
|
|
||||||
uint64_t buckets_count_;
|
|
||||||
SimpleAllocer<NODE> allocator_;
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(ObPreAllocLinkHashMap);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} // hash
|
|
||||||
} // common
|
|
||||||
} // oceanbase
|
|
||||||
#endif /* SRC_LIBRARY_SRC_LIB_HASH_OB_MEMLESS_LINK_HASHMAP_H_ */
|
|
||||||
2
deps/oblib/unittest/lib/CMakeLists.txt
vendored
2
deps/oblib/unittest/lib/CMakeLists.txt
vendored
@ -47,7 +47,6 @@ oblib_addtest(hash/test_array_index_hash_set.cpp)
|
|||||||
oblib_addtest(hash/test_build_in_hashmap.cpp)
|
oblib_addtest(hash/test_build_in_hashmap.cpp)
|
||||||
oblib_addtest(hash/test_concurrent_hash_map.cpp)
|
oblib_addtest(hash/test_concurrent_hash_map.cpp)
|
||||||
oblib_addtest(hash/test_cuckoo_hashmap.cpp)
|
oblib_addtest(hash/test_cuckoo_hashmap.cpp)
|
||||||
oblib_addtest(hash/test_ext_iter_hashset.cpp)
|
|
||||||
oblib_addtest(hash/test_hashmap.cpp)
|
oblib_addtest(hash/test_hashmap.cpp)
|
||||||
oblib_addtest(hash/test_fnv_hash.cpp)
|
oblib_addtest(hash/test_fnv_hash.cpp)
|
||||||
oblib_addtest(hash/test_hashset.cpp)
|
oblib_addtest(hash/test_hashset.cpp)
|
||||||
@ -57,7 +56,6 @@ oblib_addtest(hash/test_link_hashmap.cpp)
|
|||||||
oblib_addtest(hash/test_linear_hash_map.cpp)
|
oblib_addtest(hash/test_linear_hash_map.cpp)
|
||||||
oblib_addtest(hash/test_placement_hashset.cpp)
|
oblib_addtest(hash/test_placement_hashset.cpp)
|
||||||
oblib_addtest(hash/test_pointer_hashmap.cpp)
|
oblib_addtest(hash/test_pointer_hashmap.cpp)
|
||||||
oblib_addtest(hash/test_pre_alloc_link_hashmap.cpp)
|
|
||||||
oblib_addtest(hash/test_simpleallocer.cpp)
|
oblib_addtest(hash/test_simpleallocer.cpp)
|
||||||
oblib_addtest(json/test_json_print_utils.cpp)
|
oblib_addtest(json/test_json_print_utils.cpp)
|
||||||
oblib_addtest(json/test_yson.cpp)
|
oblib_addtest(json/test_yson.cpp)
|
||||||
|
|||||||
@ -1,360 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2021 OceanBase
|
|
||||||
* OceanBase CE is licensed under Mulan PubL v2.
|
|
||||||
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
||||||
* You may obtain a copy of Mulan PubL v2 at:
|
|
||||||
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
||||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the Mulan PubL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lib/hash/ob_ext_iter_hashset.h"
|
|
||||||
#include "lib/allocator/ob_malloc.h"
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
|
|
||||||
using namespace oceanbase::common;
|
|
||||||
using namespace oceanbase::common::hash;
|
|
||||||
class ObExtIterHashSetTest: public ::testing::Test
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ObExtIterHashSetTest();
|
|
||||||
virtual ~ObExtIterHashSetTest();
|
|
||||||
virtual void SetUp();
|
|
||||||
virtual void TearDown();
|
|
||||||
|
|
||||||
public:
|
|
||||||
ObArenaAllocator allocator_;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// disallow copy
|
|
||||||
ObExtIterHashSetTest(const ObExtIterHashSetTest &other);
|
|
||||||
ObExtIterHashSetTest& operator=(const ObExtIterHashSetTest &other);
|
|
||||||
protected:
|
|
||||||
// data members
|
|
||||||
};
|
|
||||||
|
|
||||||
ObExtIterHashSetTest::ObExtIterHashSetTest() : allocator_(ObModIds::TEST)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ObExtIterHashSetTest::~ObExtIterHashSetTest()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObExtIterHashSetTest::SetUp()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObExtIterHashSetTest::TearDown()
|
|
||||||
{
|
|
||||||
allocator_.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ObExtIterHashSetTest, basic_test)
|
|
||||||
{
|
|
||||||
static const int64_t N = 256;
|
|
||||||
static const int64_t BUCKET_NUM = 8;
|
|
||||||
ObExtIterHashSet<int64_t, N> set(allocator_);
|
|
||||||
for (int round = 0; round < 5; ++round) {
|
|
||||||
ASSERT_EQ(0, set.count());
|
|
||||||
ASSERT_EQ(set.begin(), set.end());
|
|
||||||
ASSERT_EQ(++(set.begin()), set.end());
|
|
||||||
|
|
||||||
// insert data
|
|
||||||
for (int64_t index = 0; index < N * BUCKET_NUM; index++) {
|
|
||||||
int64_t value = index + 1;
|
|
||||||
ASSERT_EQ(OB_HASH_NOT_EXIST, set.exist_refactored(value));
|
|
||||||
ASSERT_EQ(OB_SUCCESS, set.set_refactored(value));
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, set.exist_refactored(value));
|
|
||||||
ASSERT_EQ(index + 1, set.count());
|
|
||||||
}
|
|
||||||
|
|
||||||
// verify data
|
|
||||||
ObExtIterHashSet<int64_t, N>::const_iterator_t it = set.begin();
|
|
||||||
for(int64_t value = 1; it != set.end(); ++it, value++) {
|
|
||||||
ASSERT_EQ(value, *it);
|
|
||||||
}
|
|
||||||
set.clear();
|
|
||||||
ASSERT_EQ(0, set.count());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ObExtIterHashSetTest, single_N)
|
|
||||||
{
|
|
||||||
ObExtIterHashSet<int64_t, 1> hashset(allocator_);
|
|
||||||
ObExtIterHashSet<int64_t, 1>::const_iterator_t iter = hashset.begin();
|
|
||||||
ASSERT_EQ(iter, hashset.end());
|
|
||||||
ASSERT_EQ(++iter, hashset.end());
|
|
||||||
|
|
||||||
ASSERT_EQ(0, hashset.count());
|
|
||||||
ASSERT_EQ(OB_SUCCESS, hashset.set_refactored(1));
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.set_refactored(1));
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.exist_refactored(1));
|
|
||||||
ASSERT_EQ(1, hashset.count());
|
|
||||||
ASSERT_EQ(OB_SUCCESS, hashset.set_refactored(2));
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.exist_refactored(2));
|
|
||||||
ASSERT_EQ(2, hashset.count());
|
|
||||||
|
|
||||||
iter = hashset.begin();
|
|
||||||
ASSERT_NE(iter, hashset.end());
|
|
||||||
ASSERT_EQ(1, *iter);
|
|
||||||
ASSERT_NE(++iter, hashset.end());
|
|
||||||
ASSERT_EQ(2, *iter);
|
|
||||||
ASSERT_EQ(++iter, hashset.end());
|
|
||||||
ASSERT_EQ(++iter, hashset.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ObExtIterHashSetTest, many_N_single_bucket)
|
|
||||||
{
|
|
||||||
const uint64_t N = 10345;
|
|
||||||
int64_t value = 0;
|
|
||||||
ObExtIterHashSet<int64_t, N> hashset(allocator_);
|
|
||||||
ObExtIterHashSet<int64_t, N>::const_iterator_t iter = hashset.begin();
|
|
||||||
ASSERT_EQ(iter, hashset.end());
|
|
||||||
ASSERT_EQ(++iter, hashset.end());
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < N; i++) {
|
|
||||||
ASSERT_EQ(OB_HASH_NOT_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = 0; i < N; i++) {
|
|
||||||
ASSERT_EQ(OB_SUCCESS, hashset.set_refactored(i));
|
|
||||||
}
|
|
||||||
ASSERT_EQ(OB_SUCCESS, hashset.set_refactored(N));
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < N; i++) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = 0; i < N; i++) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.set_refactored(i));
|
|
||||||
}
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.set_refactored(N));
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < N; i++) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_EQ(N + 1, hashset.count());
|
|
||||||
for (value = 0, iter = hashset.begin(); iter != hashset.end(); ++iter, value++) {
|
|
||||||
ASSERT_EQ(value, *iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
hashset.clear();
|
|
||||||
|
|
||||||
iter = hashset.begin();
|
|
||||||
ASSERT_EQ(iter, hashset.end());
|
|
||||||
ASSERT_EQ(++iter, hashset.end());
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < N; i++) {
|
|
||||||
ASSERT_EQ(OB_HASH_NOT_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = 0; i < N; i++) {
|
|
||||||
ASSERT_EQ(OB_SUCCESS, hashset.set_refactored(i));
|
|
||||||
}
|
|
||||||
ASSERT_EQ(OB_SUCCESS, hashset.set_refactored(N));
|
|
||||||
for (uint64_t i = 0; i < N; i++) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = 0; i < N; i++) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.set_refactored(i));
|
|
||||||
}
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.set_refactored(N));
|
|
||||||
for (uint64_t i = 0; i < N; i++) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_EQ(N + 1, hashset.count());
|
|
||||||
for (value = 0, iter = hashset.begin(); iter != hashset.end(); ++iter, value++) {
|
|
||||||
ASSERT_EQ(value, *iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ObExtIterHashSetTest, many_N_single_buckets2)
|
|
||||||
{
|
|
||||||
const uint64_t N = 10345;
|
|
||||||
int64_t value = 0;
|
|
||||||
ObExtIterHashSet<int64_t, N> hashset(allocator_);
|
|
||||||
ObExtIterHashSet<int64_t, N>::const_iterator_t iter = hashset.begin();
|
|
||||||
ASSERT_EQ(iter, hashset.end());
|
|
||||||
ASSERT_EQ(++iter, hashset.end());
|
|
||||||
|
|
||||||
for (uint64_t i = N; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_HASH_NOT_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = N; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_SUCCESS, hashset.set_refactored(i));
|
|
||||||
}
|
|
||||||
ASSERT_EQ(OB_SUCCESS, hashset.set_refactored(0));
|
|
||||||
for (uint64_t i = N; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = N; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.set_refactored(i));
|
|
||||||
}
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.set_refactored(0));
|
|
||||||
for (uint64_t i = N; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_EQ(N + 1, hashset.count());
|
|
||||||
for (value = N, iter = hashset.begin(); iter != hashset.end(); ++iter, value--) {
|
|
||||||
ASSERT_EQ(value, *iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
hashset.clear();
|
|
||||||
|
|
||||||
iter = hashset.begin();
|
|
||||||
ASSERT_EQ(iter, hashset.end());
|
|
||||||
ASSERT_EQ(++iter, hashset.end());
|
|
||||||
|
|
||||||
for (uint64_t i = N; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_HASH_NOT_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = N; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_SUCCESS, hashset.set_refactored(i));
|
|
||||||
}
|
|
||||||
ASSERT_EQ(OB_SUCCESS, hashset.set_refactored(0));
|
|
||||||
for (uint64_t i = N; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = N; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.set_refactored(i));
|
|
||||||
}
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.set_refactored(0));
|
|
||||||
for (uint64_t i = N; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_EQ(N + 1, hashset.count());
|
|
||||||
for (value = N, iter = hashset.begin(); iter != hashset.end(); ++iter, value--) {
|
|
||||||
ASSERT_EQ(value, *iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ObExtIterHashSetTest, many_N_many_buckets)
|
|
||||||
{
|
|
||||||
static const uint64_t N = 16;
|
|
||||||
static const uint64_t BUCKET_NUM = 100;
|
|
||||||
static const uint64_t ELEMENT_NUM = N * BUCKET_NUM;
|
|
||||||
int64_t value = 0;
|
|
||||||
ObExtIterHashSet<int64_t, N> hashset(allocator_);
|
|
||||||
ObExtIterHashSet<int64_t, N>::const_iterator_t iter = hashset.begin();
|
|
||||||
ASSERT_EQ(iter, hashset.end());
|
|
||||||
ASSERT_EQ(++iter, hashset.end());
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < ELEMENT_NUM; i++) {
|
|
||||||
ASSERT_EQ(OB_HASH_NOT_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = 0; i < ELEMENT_NUM; i++) {
|
|
||||||
ASSERT_EQ(OB_SUCCESS, hashset.set_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = 0; i < ELEMENT_NUM; i++) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = 0; i < ELEMENT_NUM; i++) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.set_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = 0; i < ELEMENT_NUM; i++) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_EQ(ELEMENT_NUM, hashset.count());
|
|
||||||
for (value = 0, iter = hashset.begin(); iter != hashset.end(); ++iter, value++) {
|
|
||||||
ASSERT_EQ(value, *iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
hashset.clear();
|
|
||||||
|
|
||||||
iter = hashset.begin();
|
|
||||||
ASSERT_EQ(iter, hashset.end());
|
|
||||||
ASSERT_EQ(++iter, hashset.end());
|
|
||||||
|
|
||||||
for (uint64_t i = 0; i < ELEMENT_NUM; i++) {
|
|
||||||
ASSERT_EQ(OB_HASH_NOT_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = 0; i < ELEMENT_NUM; i++) {
|
|
||||||
ASSERT_EQ(OB_SUCCESS, hashset.set_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = 0; i < ELEMENT_NUM; i++) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = 0; i < ELEMENT_NUM; i++) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.set_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = 0; i < ELEMENT_NUM; i++) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_EQ(ELEMENT_NUM, hashset.count());
|
|
||||||
for (value = 0, iter = hashset.begin(); iter != hashset.end(); ++iter, value++) {
|
|
||||||
ASSERT_EQ(value, *iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ObExtIterHashSetTest, many_N_many_buckets2)
|
|
||||||
{
|
|
||||||
static const uint64_t N = 128;
|
|
||||||
static const uint64_t BUCKET_NUM = 10;
|
|
||||||
static const uint64_t ELEMENT_NUM = N * BUCKET_NUM;
|
|
||||||
int64_t value = 0;
|
|
||||||
ObExtIterHashSet<int64_t, N> hashset(allocator_);
|
|
||||||
ObExtIterHashSet<int64_t, N>::const_iterator_t iter = hashset.begin();
|
|
||||||
ASSERT_EQ(iter, hashset.end());
|
|
||||||
ASSERT_EQ(++iter, hashset.end());
|
|
||||||
|
|
||||||
for (uint64_t i = ELEMENT_NUM; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_HASH_NOT_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = ELEMENT_NUM; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_SUCCESS, hashset.set_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = ELEMENT_NUM; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = ELEMENT_NUM; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.set_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = ELEMENT_NUM; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_EQ(ELEMENT_NUM, hashset.count());
|
|
||||||
for (value = ELEMENT_NUM, iter = hashset.begin(); iter != hashset.end(); ++iter, value--) {
|
|
||||||
ASSERT_EQ(value, *iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
hashset.clear();
|
|
||||||
|
|
||||||
iter = hashset.begin();
|
|
||||||
ASSERT_EQ(iter, hashset.end());
|
|
||||||
ASSERT_EQ(++iter, hashset.end());
|
|
||||||
|
|
||||||
for (uint64_t i = ELEMENT_NUM; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_HASH_NOT_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = ELEMENT_NUM; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_SUCCESS, hashset.set_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = ELEMENT_NUM; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = ELEMENT_NUM; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.set_refactored(i));
|
|
||||||
}
|
|
||||||
for (uint64_t i = ELEMENT_NUM; i > 0; i--) {
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, hashset.exist_refactored(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_EQ(ELEMENT_NUM, hashset.count());
|
|
||||||
for (value = ELEMENT_NUM, iter = hashset.begin(); iter != hashset.end(); ++iter, value--) {
|
|
||||||
ASSERT_EQ(value, *iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
OB_LOGGER.set_log_level("INFO");
|
|
||||||
::testing::InitGoogleTest(&argc,argv);
|
|
||||||
return RUN_ALL_TESTS();
|
|
||||||
}
|
|
||||||
@ -1,373 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2021 OceanBase
|
|
||||||
* OceanBase CE is licensed under Mulan PubL v2.
|
|
||||||
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
||||||
* You may obtain a copy of Mulan PubL v2 at:
|
|
||||||
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
||||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the Mulan PubL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include "lib/hash/ob_pre_alloc_link_hashmap.h"
|
|
||||||
#include "lib/allocator/ob_malloc.h"
|
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
|
||||||
|
|
||||||
using namespace oceanbase;
|
|
||||||
using namespace oceanbase::common;
|
|
||||||
using namespace oceanbase::common::hash;
|
|
||||||
|
|
||||||
struct Item
|
|
||||||
{
|
|
||||||
int64_t key_;
|
|
||||||
int64_t value_;
|
|
||||||
int64_t ref_;
|
|
||||||
|
|
||||||
Item(): key_(0), value_(0), ref_(0) {}
|
|
||||||
Item(const int64_t key, const int64_t value, const int64_t ref):
|
|
||||||
key_(key), value_(value), ref_(ref) {}
|
|
||||||
TO_STRING_KV(K_(key), K_(value));
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Node: public ObPreAllocLinkHashNode<int64_t, Item>
|
|
||||||
{
|
|
||||||
explicit Node(Item &item): ObPreAllocLinkHashNode(item), next_(NULL) {}
|
|
||||||
virtual ~Node() { }
|
|
||||||
static uint64_t hash(int64_t key) { return key; }
|
|
||||||
virtual uint64_t hash() const { return hash(item_.key_); }
|
|
||||||
virtual const int64_t &get_key() const { return item_.key_; }
|
|
||||||
Node *next_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ItemProtector
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static void hold(Item &item)
|
|
||||||
{
|
|
||||||
++item.ref_;
|
|
||||||
}
|
|
||||||
static void release(Item &item)
|
|
||||||
{
|
|
||||||
--item.ref_;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef common::hash::ObPreAllocLinkHashMap<int64_t, Item, Node, ItemProtector> TestMap;
|
|
||||||
struct TestForeachFinder: public TestMap::ForeachFunctor
|
|
||||||
{
|
|
||||||
TestForeachFinder(): count_(0) {}
|
|
||||||
virtual ~TestForeachFinder() {}
|
|
||||||
virtual int operator()(Item &item, bool &is_full)
|
|
||||||
{
|
|
||||||
int ret = OB_SUCCESS;
|
|
||||||
if (count_ >= MAX_COUNT) {
|
|
||||||
is_full = true;
|
|
||||||
} else if (item.value_ == 0) {
|
|
||||||
items_[count_++] = &item;
|
|
||||||
} else if (item.value_ == 2) {
|
|
||||||
ret = OB_ERR_SYS;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const int64_t MAX_COUNT = 3;
|
|
||||||
Item *items_[MAX_COUNT];
|
|
||||||
int64_t count_;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TestForeachCheckRef: public TestMap::ForeachFunctor
|
|
||||||
{
|
|
||||||
TestForeachCheckRef(): count_(0) {}
|
|
||||||
virtual ~TestForeachCheckRef() {}
|
|
||||||
virtual int operator()(Item &item, bool &is_full)
|
|
||||||
{
|
|
||||||
int ret = OB_SUCCESS;
|
|
||||||
is_full = false;
|
|
||||||
++count_;
|
|
||||||
if (item.ref_ != 0) {
|
|
||||||
COMMON_LOG(ERROR, "ref not zero", K(item.ref_), K(item.key_));
|
|
||||||
ret = OB_ERR_SYS;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t count_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TestEraseChecker: public TestMap::EraseChecker
|
|
||||||
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~TestEraseChecker() {}
|
|
||||||
virtual int operator()(Item &item)
|
|
||||||
{
|
|
||||||
int ret = OB_SUCCESS;
|
|
||||||
if (item.value_ != 0) {
|
|
||||||
ret = OB_EAGAIN;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class TestGetFunctor: public TestMap::GetFunctor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TestGetFunctor(): item_(NULL) {}
|
|
||||||
virtual ~TestGetFunctor() {}
|
|
||||||
virtual int operator()(Item &item) override
|
|
||||||
{
|
|
||||||
int ret = OB_SUCCESS;
|
|
||||||
item_ = NULL;
|
|
||||||
if (item.value_ == 3) {
|
|
||||||
ret = OB_ERR_SYS;
|
|
||||||
} else {
|
|
||||||
item_ = &item;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
Item *item_;
|
|
||||||
private:
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(TestGetFunctor);
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(TestObMemLessLinkHashMap, basic)
|
|
||||||
{
|
|
||||||
TestMap map;
|
|
||||||
int64_t buckets_count = 0;
|
|
||||||
uint32_t latch_id = 1;
|
|
||||||
const lib::ObLabel &label = "1";
|
|
||||||
Item item1 = {1,0,0};
|
|
||||||
Node *node1 = map.alloc_node(item1);
|
|
||||||
COMMON_LOG(INFO, "dump", K(item1), K(node1->item_), KP(&item1), KP(&node1->item_));
|
|
||||||
TestForeachFinder finder;
|
|
||||||
|
|
||||||
ASSERT_EQ(OB_NOT_INIT, map.put(*node1));
|
|
||||||
ASSERT_EQ(OB_INVALID_ARGUMENT, map.init(buckets_count, latch_id, label));
|
|
||||||
ASSERT_EQ(OB_INVALID_ARGUMENT, map.init(buckets_count, latch_id, label));
|
|
||||||
buckets_count = 100;
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.init(buckets_count, latch_id, label));
|
|
||||||
ASSERT_EQ(OB_INIT_TWICE, map.init(buckets_count, latch_id, label));
|
|
||||||
ASSERT_EQ(0, map.get_count());
|
|
||||||
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.put(*node1));
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, map.put(*node1));
|
|
||||||
ASSERT_EQ(1, map.get_count());
|
|
||||||
|
|
||||||
Item item2 = {1,0,0};
|
|
||||||
Node node2(item2);
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, map.put(node2));
|
|
||||||
ASSERT_EQ(1, map.get_count());
|
|
||||||
|
|
||||||
Item *get_item = NULL;
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.get(1, get_item));
|
|
||||||
ASSERT_EQ(&item1, get_item);
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.foreach(finder));
|
|
||||||
ASSERT_EQ(1, finder.count_);
|
|
||||||
COMMON_LOG(INFO, "dump", K(node1), K(finder.items_[0]));
|
|
||||||
ASSERT_EQ(&item1, finder.items_[0]);
|
|
||||||
|
|
||||||
Item *del_item = NULL;
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.erase(1, del_item));
|
|
||||||
ASSERT_EQ(&item1, del_item);
|
|
||||||
ASSERT_EQ(OB_HASH_NOT_EXIST, map.erase(1, del_item));
|
|
||||||
ASSERT_EQ(OB_HASH_NOT_EXIST, map.get(1, del_item));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TestObMemLessLinkHashMap, same_hash)
|
|
||||||
{
|
|
||||||
TestMap map;
|
|
||||||
int64_t buckets_count = 1;
|
|
||||||
uint32_t latch_id = 1;
|
|
||||||
const lib::ObLabel &label = "1";
|
|
||||||
Item item1 = {1,0,0};
|
|
||||||
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.init(buckets_count, latch_id, label));
|
|
||||||
buckets_count = map.get_buckets_count();
|
|
||||||
Node *node1 = map.alloc_node(item1);
|
|
||||||
Item item2 = {1 + buckets_count,0,0};
|
|
||||||
Node *node2 = map.alloc_node(item2);
|
|
||||||
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.put(*node1));
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.put(*node2));
|
|
||||||
ASSERT_EQ(2, map.get_count());
|
|
||||||
|
|
||||||
Item *got_item = NULL;
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.get(1, got_item));
|
|
||||||
ASSERT_EQ(&item1, got_item);
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.get(item2.key_, got_item));
|
|
||||||
ASSERT_EQ(&item2, got_item);
|
|
||||||
|
|
||||||
Item *del_item = NULL;
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.erase(item2.key_, del_item));
|
|
||||||
ASSERT_EQ(&item2, del_item);
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.erase(item1.key_, del_item));
|
|
||||||
ASSERT_EQ(&item1, del_item);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TestObMemLessLinkHashMap, erase)
|
|
||||||
{
|
|
||||||
TestMap map;
|
|
||||||
int64_t buckets_count = 100;
|
|
||||||
uint32_t latch_id = 1;
|
|
||||||
const lib::ObLabel &label = "1";
|
|
||||||
TestEraseChecker checker;
|
|
||||||
Item *del_item = NULL;
|
|
||||||
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.init(buckets_count, latch_id, label));
|
|
||||||
Item item1 = {1,0,0};
|
|
||||||
Node *node1 = map.alloc_node(item1);
|
|
||||||
Item item2 = {2,1, 0};
|
|
||||||
Node *node2 = map.alloc_node(item2);
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.put(*node1));
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.put(*node2));
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.erase(1, del_item, &checker));
|
|
||||||
ASSERT_EQ(del_item, &item1);
|
|
||||||
ASSERT_EQ(OB_EAGAIN, map.erase(2, del_item, &checker));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TestObMemLessLinkHashMap, get_functor)
|
|
||||||
{
|
|
||||||
TestMap map;
|
|
||||||
int64_t buckets_count = 100;
|
|
||||||
uint32_t latch_id = 1;
|
|
||||||
const lib::ObLabel &label = "1";
|
|
||||||
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.init(buckets_count, latch_id, label));
|
|
||||||
|
|
||||||
Item item1 = {1,0,0};
|
|
||||||
Node *node1 = map.alloc_node(item1);
|
|
||||||
Item item2 = {2,3, 0};
|
|
||||||
Node *node2 = map.alloc_node(item2);
|
|
||||||
TestGetFunctor get_functor;
|
|
||||||
Item *got_item = NULL;
|
|
||||||
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.put(*node1));
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.put(*node2));
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.get(1, got_item, &get_functor));
|
|
||||||
ASSERT_EQ(got_item, &item1);
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.get(1, get_functor));
|
|
||||||
ASSERT_EQ(get_functor.item_, &item1);
|
|
||||||
ASSERT_EQ(OB_ERR_SYS, map.get(2, got_item, &get_functor));
|
|
||||||
ASSERT_TRUE(got_item == NULL);
|
|
||||||
ASSERT_TRUE(get_functor.item_ == NULL);
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, map.exist(1));
|
|
||||||
ASSERT_EQ(OB_HASH_EXIST, map.exist(2));
|
|
||||||
ASSERT_EQ(OB_HASH_NOT_EXIST, map.exist(3));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TEST(TestObMemLessLinkHashMap, foreach)
|
|
||||||
{
|
|
||||||
TestMap map;
|
|
||||||
int64_t buckets_count = 100;
|
|
||||||
uint32_t latch_id = 1;
|
|
||||||
const lib::ObLabel &label = "1";
|
|
||||||
const int64_t count = 10000;
|
|
||||||
Item *items[count];
|
|
||||||
TestForeachFinder finder;
|
|
||||||
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.init(buckets_count, latch_id, label));
|
|
||||||
|
|
||||||
for (int64_t i = 0; i < count; ++i) {
|
|
||||||
Item *item = new Item();
|
|
||||||
item->key_ = i;
|
|
||||||
item->value_ = i % 2;
|
|
||||||
Node *node = map.alloc_node(*item);
|
|
||||||
items[i] = item;
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.put(*node));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int64_t i = 0; i < count; ++i) {
|
|
||||||
Item *got_item = NULL;
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.get(i, got_item));
|
|
||||||
ASSERT_EQ(items[i], got_item);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.foreach(finder));
|
|
||||||
ASSERT_EQ(3, finder.count_);
|
|
||||||
for (int64_t i = 0; i < 3; ++i) {
|
|
||||||
COMMON_LOG(INFO, "dump", K(items[2 * i]), K(*finder.items_[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for (int64_t i = 0; i < count; ++i) {
|
|
||||||
delete items[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TestObMemLessLinkHashMap, iterator)
|
|
||||||
{
|
|
||||||
TestMap map;
|
|
||||||
TestMap::Iterator iter(map);
|
|
||||||
int64_t buckets_count = 100000;
|
|
||||||
uint32_t latch_id = 1;
|
|
||||||
const lib::ObLabel &label = "1";
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.init(buckets_count, latch_id, label));
|
|
||||||
Item item1 = {1,0,0};
|
|
||||||
Node *node1 = map.alloc_node(item1);
|
|
||||||
Item item2 = {2,3, 0};
|
|
||||||
Node *node2 = map.alloc_node(item2);
|
|
||||||
TestGetFunctor get_functor;
|
|
||||||
Item *got_item = NULL;
|
|
||||||
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.put(*node1));
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.put(*node2));
|
|
||||||
ASSERT_EQ(OB_SUCCESS, iter.get_next(got_item));
|
|
||||||
ASSERT_EQ(&item1, got_item);
|
|
||||||
ASSERT_EQ(OB_SUCCESS, iter.get_next(got_item));
|
|
||||||
ASSERT_EQ(&item2, got_item);
|
|
||||||
ASSERT_EQ(OB_ITER_END, iter.get_next(got_item));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TestObMemLessLinkHashMap, iterator2)
|
|
||||||
{
|
|
||||||
int ret = OB_SUCCESS;
|
|
||||||
TestMap map;
|
|
||||||
int64_t buckets_count = 100;
|
|
||||||
uint32_t latch_id = 1;
|
|
||||||
const lib::ObLabel &label = "1";
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.init(buckets_count, latch_id, label));
|
|
||||||
|
|
||||||
const int64_t count = 8061;
|
|
||||||
for (int64_t i = 0; i < count; ++i) {
|
|
||||||
Item *item = new Item();
|
|
||||||
item->key_ = i;
|
|
||||||
item->value_ = i;
|
|
||||||
item->ref_ = 0;
|
|
||||||
Node *node = map.alloc_node(*item);
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.put(*node));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
TestMap::Iterator iter(map);
|
|
||||||
Item *got_item = NULL;
|
|
||||||
int64_t num = 0;
|
|
||||||
while (OB_SUCC(ret)) {
|
|
||||||
if (OB_FAIL(iter.get_next(got_item))) {
|
|
||||||
COMMON_LOG(WARN, "rend", K(ret), K(num));
|
|
||||||
} else {
|
|
||||||
++num;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ASSERT_EQ(OB_ITER_END, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
TestForeachCheckRef checker;
|
|
||||||
ASSERT_EQ(OB_SUCCESS, map.foreach(checker));
|
|
||||||
ASSERT_EQ(count, checker.count_);
|
|
||||||
|
|
||||||
}
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
OB_LOGGER.set_log_level("INFO");
|
|
||||||
testing::InitGoogleTest(&argc,argv);
|
|
||||||
return RUN_ALL_TESTS();
|
|
||||||
}
|
|
||||||
@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
#include "share/ob_define.h" // OB_*
|
#include "share/ob_define.h" // OB_*
|
||||||
#include "lib/allocator/ob_allocator.h" // ObIAllocator
|
#include "lib/allocator/ob_allocator.h" // ObIAllocator
|
||||||
#include "lib/hash/ob_ext_iter_hashset.h" // ObExtIterHashSet
|
|
||||||
#include "lib/container/ob_se_array.h" // ObSEArray
|
#include "lib/container/ob_se_array.h" // ObSEArray
|
||||||
#include "lib/allocator/page_arena.h" // ObArenaAllocator
|
#include "lib/allocator/page_arena.h" // ObArenaAllocator
|
||||||
#include "lib/lock/ob_spin_lock.h" // ObSpinLock
|
#include "lib/lock/ob_spin_lock.h" // ObSpinLock
|
||||||
|
|||||||
Reference in New Issue
Block a user