oceanbase/deps/oblib/unittest/lib/container/test_ext_ring_buffer.cpp
wangzelin.wzl 93a1074b0c patch 4.0
2022-10-24 17:57:12 +08:00

420 lines
9.8 KiB
C++

/**
* 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 = ObTimeUtility::current_time();
while (++cnt < lmt) {
TypeA *ptr = hazptr.acquire(target, 0);
EXPECT_EQ(target, ptr);
hazptr.revert(0);
}
int64_t end = ObTimeUtility::current_time();
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_)) { ::usleep(1000000); }
hazptr_->acquire(data_, 0);
while (ATOMIC_LOAD(&acquire_)) { ::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_))) { ::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);
}
}
}
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;
}