init push
This commit is contained in:
444
deps/oblib/unittest/lib/container/test_ext_ring_buffer.cpp
vendored
Normal file
444
deps/oblib/unittest/lib/container/test_ext_ring_buffer.cpp
vendored
Normal file
@ -0,0 +1,444 @@
|
||||
/**
|
||||
* 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 <cstdlib>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "lib/allocator/ob_malloc.h"
|
||||
#include "lib/stat/ob_diagnose_info.h"
|
||||
#include "lib/container/ob_ext_ring_buffer.h"
|
||||
#include "lib/container/ob_ext_ring_buffer_impl.h"
|
||||
#include "lib/coro/testing.h"
|
||||
|
||||
using namespace oceanbase;
|
||||
using namespace common;
|
||||
using namespace erb;
|
||||
|
||||
namespace oceanbase {
|
||||
namespace unittest {
|
||||
|
||||
struct PopCondA {
|
||||
bool operator()(int64_t val)
|
||||
{
|
||||
UNUSED(val);
|
||||
return true;
|
||||
}
|
||||
bool operator()(int64_t oldptr, int* newptr)
|
||||
{
|
||||
UNUSED(oldptr);
|
||||
UNUSED(newptr);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
struct SetCondA {
|
||||
bool operator()(int* oldptr, int* newptr)
|
||||
{
|
||||
UNUSED(oldptr);
|
||||
UNUSED(newptr);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
TEST(RINGBUFFER_BASE, debug)
|
||||
{
|
||||
typedef PtrSlot<int> SlotT;
|
||||
ObExtendibleRingBufferBase<int*, SlotT> rb_base;
|
||||
|
||||
RingBufferAlloc alloc;
|
||||
int64_t begin_sn = 7000;
|
||||
int ret = rb_base.init(begin_sn, &alloc);
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
|
||||
// set and get
|
||||
int* ptr = reinterpret_cast<int*>(8);
|
||||
int64_t cnt = 200000;
|
||||
for (int64_t idx = begin_sn; idx < cnt; ++idx) {
|
||||
bool set = false;
|
||||
SetCondA setcond;
|
||||
ret = rb_base.set(idx, ptr, setcond, set);
|
||||
EXPECT_TRUE(set);
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
int* ptr_val = NULL;
|
||||
ret = rb_base.get(idx, ptr_val);
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
EXPECT_EQ(ptr, ptr_val);
|
||||
}
|
||||
|
||||
// pop
|
||||
PopCondA cond;
|
||||
bool popped = false;
|
||||
int* ptr_val = NULL;
|
||||
for (int64_t idx = begin_sn; idx < cnt; ++idx) {
|
||||
ret = rb_base.pop(cond, ptr_val, popped);
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
EXPECT_EQ(true, popped);
|
||||
EXPECT_EQ(ptr, ptr_val) << "current idx:" << idx;
|
||||
}
|
||||
|
||||
ret = rb_base.destroy();
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
}
|
||||
|
||||
struct PopCondB {
|
||||
bool operator()(int64_t val)
|
||||
{
|
||||
UNUSED(val);
|
||||
return true;
|
||||
}
|
||||
bool operator()(int64_t oldptr, int64_t newptr)
|
||||
{
|
||||
UNUSED(oldptr);
|
||||
UNUSED(newptr);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
struct SetCondB {
|
||||
bool operator()(int64_t oldval, int64_t newval)
|
||||
{
|
||||
UNUSED(oldval);
|
||||
UNUSED(newval);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
TEST(RINGBUFFER_BASE, debug2)
|
||||
{
|
||||
|
||||
typedef ValSlot<int64_t> SlotT;
|
||||
ObExtendibleRingBufferBase<int64_t, SlotT> rb_base;
|
||||
|
||||
RingBufferAlloc alloc;
|
||||
int64_t begin_sn = 10000;
|
||||
int ret = rb_base.init(begin_sn, &alloc);
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
|
||||
// set and get
|
||||
int64_t cnt = 1000000;
|
||||
for (int64_t idx = begin_sn; idx < cnt; ++idx) {
|
||||
SetCondB setcond;
|
||||
bool set = false;
|
||||
ret = rb_base.set(idx, idx, setcond, set);
|
||||
EXPECT_TRUE(set);
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
int64_t val = 0;
|
||||
ret = rb_base.get(idx, val);
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
EXPECT_EQ(val, idx);
|
||||
}
|
||||
|
||||
// pop
|
||||
PopCondB cond;
|
||||
bool popped = false;
|
||||
int64_t val = 0;
|
||||
for (int64_t idx = begin_sn; idx < cnt; ++idx) {
|
||||
ret = rb_base.pop(cond, val, popped);
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
EXPECT_EQ(true, popped);
|
||||
EXPECT_EQ(val, idx);
|
||||
}
|
||||
|
||||
ret = rb_base.destroy();
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
}
|
||||
|
||||
typedef ValSlot<int64_t> SlotT;
|
||||
typedef ObExtendibleRingBufferBase<int64_t, SlotT> I64RBBASE;
|
||||
class SetRunnable : public cotesting::DefaultRunnable {
|
||||
public:
|
||||
void run1() final
|
||||
{
|
||||
for (int64_t idx = 0; idx < cnt_; ++idx) {
|
||||
int64_t sn = s_ + idx;
|
||||
EXPECT_EQ(OB_SUCCESS, rb_->set(sn, sn));
|
||||
}
|
||||
}
|
||||
I64RBBASE* rb_;
|
||||
int64_t s_;
|
||||
int64_t cnt_;
|
||||
};
|
||||
class PopRunnable : public cotesting::DefaultRunnable {
|
||||
public:
|
||||
struct PopCond {
|
||||
int64_t expect_;
|
||||
/*
|
||||
bool operator()(const int64_t &val)
|
||||
{
|
||||
return (expect_ == val);
|
||||
}
|
||||
*/
|
||||
bool operator()(const int64_t begin_sn, const int64_t val)
|
||||
{
|
||||
UNUSED(begin_sn);
|
||||
return (expect_ == val);
|
||||
}
|
||||
};
|
||||
void run1() final
|
||||
{
|
||||
PopCond cond;
|
||||
int64_t begin_sn = -1;
|
||||
while ((begin_sn = rb_->begin_sn()) < (s_ + cnt_)) {
|
||||
cond.expect_ = begin_sn;
|
||||
int64_t val = 0;
|
||||
bool popped = false;
|
||||
int ret = rb_->pop(cond, val, popped);
|
||||
if (OB_SUCCESS != ret && OB_ENTRY_NOT_EXIST != ret) {
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
} else if (!popped) {
|
||||
// Pass.
|
||||
} else {
|
||||
EXPECT_EQ(begin_sn, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
I64RBBASE* rb_;
|
||||
int64_t s_;
|
||||
int64_t cnt_;
|
||||
};
|
||||
TEST(RINGBUFFER_BASE, debug3)
|
||||
{
|
||||
const int64_t s = 10000;
|
||||
const int64_t setthcnt = 1;
|
||||
const int64_t popthcnt = 100;
|
||||
const int64_t th_size = 100;
|
||||
|
||||
I64RBBASE rb;
|
||||
RingBufferAlloc alloc;
|
||||
int ret = rb.init(s, &alloc);
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
|
||||
SetRunnable set_runnable[setthcnt];
|
||||
PopRunnable pop_runnable[popthcnt];
|
||||
for (int64_t idx = 0; idx < setthcnt; ++idx) {
|
||||
SetRunnable& r = set_runnable[idx];
|
||||
r.rb_ = &rb;
|
||||
r.s_ = s + idx * th_size;
|
||||
r.cnt_ = th_size;
|
||||
}
|
||||
for (int64_t idx = 0; idx < popthcnt; ++idx) {
|
||||
PopRunnable& r = pop_runnable[idx];
|
||||
r.rb_ = &rb;
|
||||
r.s_ = s;
|
||||
r.cnt_ = th_size * setthcnt;
|
||||
}
|
||||
|
||||
// Run.
|
||||
for (int64_t idx = 0; idx < popthcnt; ++idx) {
|
||||
PopRunnable& r = pop_runnable[idx];
|
||||
r.start();
|
||||
}
|
||||
for (int64_t idx = 0; idx < setthcnt; ++idx) {
|
||||
SetRunnable& r = set_runnable[idx];
|
||||
r.start();
|
||||
}
|
||||
|
||||
// Join.
|
||||
for (int64_t idx = 0; idx < popthcnt; ++idx) {
|
||||
PopRunnable& r = pop_runnable[idx];
|
||||
r.wait();
|
||||
}
|
||||
for (int64_t idx = 0; idx < setthcnt; ++idx) {
|
||||
SetRunnable& r = set_runnable[idx];
|
||||
r.wait();
|
||||
}
|
||||
|
||||
ret = rb.destroy();
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
}
|
||||
|
||||
struct CondC {
|
||||
bool operator()(const int* ptr)
|
||||
{
|
||||
UNUSED(ptr);
|
||||
return true;
|
||||
}
|
||||
bool operator()(int64_t oldptr, int* newptr)
|
||||
{
|
||||
UNUSED(oldptr);
|
||||
UNUSED(newptr);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
TEST(RingBuffer, debug)
|
||||
{
|
||||
typedef ObExtendibleRingBuffer<int> RBT;
|
||||
RBT rb;
|
||||
rb.init(100);
|
||||
|
||||
int* ptr = reinterpret_cast<int*>(2);
|
||||
rb.set(101, ptr);
|
||||
rb.set(10100, ptr);
|
||||
rb.get(101, ptr);
|
||||
rb.get(10100, ptr);
|
||||
CondC cond;
|
||||
bool popped;
|
||||
for (int64_t idx = 100; idx < 10100; ++idx) {
|
||||
rb.pop(cond, ptr, popped);
|
||||
}
|
||||
|
||||
int64_t b = rb.begin_sn();
|
||||
int64_t e = rb.end_sn();
|
||||
e = b;
|
||||
UNUSED(e);
|
||||
rb.destroy();
|
||||
}
|
||||
|
||||
// Hazrd Ptr Tests.
|
||||
struct TypeA : public erb::HazardBase {
|
||||
public:
|
||||
virtual int purge()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
TEST(HazPtr, Basic0)
|
||||
{
|
||||
// Acquire & release.
|
||||
erb::HazardPtr<2> hazptr;
|
||||
int err = hazptr.init();
|
||||
EXPECT_EQ(common::OB_SUCCESS, err);
|
||||
|
||||
TypeA ta;
|
||||
TypeA* target = &ta;
|
||||
|
||||
const int64_t lmt = 10000000;
|
||||
int64_t cnt = 0;
|
||||
int64_t start = obsys::CTimeUtil::getTime();
|
||||
while (++cnt < lmt) {
|
||||
TypeA* ptr = hazptr.acquire(target, 0);
|
||||
EXPECT_EQ(target, ptr);
|
||||
hazptr.revert(0);
|
||||
}
|
||||
int64_t end = obsys::CTimeUtil::getTime();
|
||||
LIB_LOG(ERROR, ">>>", K(cnt), K(end - start), K((double)cnt / ((double)(end - start) / 1000000)));
|
||||
|
||||
err = hazptr.destroy();
|
||||
EXPECT_EQ(common::OB_SUCCESS, err);
|
||||
}
|
||||
|
||||
struct TypeB : public erb::HazardBase {
|
||||
public:
|
||||
virtual int purge()
|
||||
{
|
||||
if (!alloc_) {
|
||||
LIB_LOG(ERROR, "err alloc state");
|
||||
}
|
||||
alloc_ = false;
|
||||
return 0;
|
||||
}
|
||||
bool alloc_;
|
||||
};
|
||||
class PurgeTestA : public cotesting::DefaultRunnable {
|
||||
public:
|
||||
void run1() final
|
||||
{
|
||||
while (!ATOMIC_LOAD(&acquire_)) {
|
||||
this_routine::usleep(1000000);
|
||||
}
|
||||
hazptr_->acquire(data_, 0);
|
||||
while (ATOMIC_LOAD(&acquire_)) {
|
||||
this_routine::usleep(1000000);
|
||||
}
|
||||
hazptr_->revert(0);
|
||||
}
|
||||
bool acquire_;
|
||||
TypeB* data_;
|
||||
erb::HazardPtr<1>* hazptr_;
|
||||
};
|
||||
|
||||
#include <vector>
|
||||
TEST(HazPtr, Basic1)
|
||||
{
|
||||
// Purge test.
|
||||
|
||||
erb::HazardPtr<1> hazptr;
|
||||
int err = hazptr.init();
|
||||
EXPECT_EQ(common::OB_SUCCESS, err);
|
||||
|
||||
// Alloc all.
|
||||
const int64_t obj_cnt = 1000;
|
||||
TypeB objects[obj_cnt];
|
||||
for (int64_t idx = 0, cnt = obj_cnt; idx < cnt; ++idx) {
|
||||
objects[idx].alloc_ = true;
|
||||
}
|
||||
// Acquire half, odd ones.
|
||||
std::vector<PurgeTestA*> purge_runnable;
|
||||
for (int64_t idx = 0, cnt = obj_cnt; idx < cnt; ++idx) {
|
||||
if (0 != idx % 2) {
|
||||
PurgeTestA* r = new PurgeTestA();
|
||||
ATOMIC_STORE(&(r->acquire_), true);
|
||||
r->data_ = objects + idx;
|
||||
r->hazptr_ = &hazptr;
|
||||
purge_runnable.push_back(r);
|
||||
r->start();
|
||||
}
|
||||
}
|
||||
for (int64_t idx = 0, cnt = purge_runnable.size(); idx < cnt; ++idx) {
|
||||
while (!ATOMIC_LOAD(&(purge_runnable[idx]->acquire_))) {
|
||||
this_routine::usleep(100000);
|
||||
}
|
||||
}
|
||||
// Retire half, even ones.
|
||||
for (int64_t idx = 0, cnt = obj_cnt; idx < cnt; ++idx) {
|
||||
if (0 == idx % 2) {
|
||||
err = hazptr.retire(&objects[idx]);
|
||||
EXPECT_EQ(common::OB_SUCCESS, err);
|
||||
}
|
||||
}
|
||||
// Purge.
|
||||
err = hazptr.purge();
|
||||
EXPECT_EQ(common::OB_SUCCESS, err);
|
||||
// Check them.
|
||||
for (int64_t idx = 0, cnt = obj_cnt; idx < cnt; ++idx) {
|
||||
if (0 != idx % 2) {
|
||||
EXPECT_TRUE(objects[idx].alloc_) << idx;
|
||||
} else {
|
||||
EXPECT_FALSE(objects[idx].alloc_) << idx;
|
||||
}
|
||||
}
|
||||
// Release protection.
|
||||
for (int64_t idx = 0, cnt = purge_runnable.size(); idx < cnt; ++idx) {
|
||||
ATOMIC_STORE(&(purge_runnable[idx]->acquire_), false);
|
||||
}
|
||||
// Retire half, odd ones.
|
||||
for (int64_t idx = 0, cnt = obj_cnt; idx < cnt; ++idx) {
|
||||
if (0 != idx % 2) {
|
||||
err = hazptr.retire(&objects[idx]);
|
||||
EXPECT_EQ(common::OB_SUCCESS, err);
|
||||
}
|
||||
}
|
||||
// Join.
|
||||
for (int64_t idx = 0, cnt = purge_runnable.size(); idx < cnt; ++idx) {
|
||||
purge_runnable[idx]->wait();
|
||||
delete purge_runnable[idx];
|
||||
}
|
||||
// Purge.
|
||||
err = hazptr.purge();
|
||||
EXPECT_EQ(common::OB_SUCCESS, err);
|
||||
// Check them.
|
||||
for (int64_t idx = 0, cnt = obj_cnt; idx < cnt; ++idx) {
|
||||
EXPECT_FALSE(objects[idx].alloc_) << idx;
|
||||
}
|
||||
|
||||
err = hazptr.destroy();
|
||||
EXPECT_EQ(common::OB_SUCCESS, err);
|
||||
}
|
||||
|
||||
} // namespace unittest
|
||||
} // namespace oceanbase
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
oceanbase::common::ObLogger::get_logger().set_log_level("info");
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
// testing::FLAGS_gtest_filter = "DO_NOT_RUN";
|
||||
return RUN_ALL_TESTS();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user