736 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			736 lines
		
	
	
		
			19 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.
 | |
|  */
 | |
| 
 | |
| #ifndef OCEANBASE_SHARE_OB_CACHE_TEST_UTILS_H_
 | |
| #define OCEANBASE_SHARE_OB_CACHE_TEST_UTILS_H_
 | |
| 
 | |
| #include "share/ob_define.h"
 | |
| #include "lib/atomic/ob_atomic.h"
 | |
| #include "lib/queue/ob_lighty_queue.h"
 | |
| #include "lib/alloc/ob_malloc_allocator.h"
 | |
| namespace oceanbase {
 | |
| using namespace lib;
 | |
| namespace common {
 | |
| 
 | |
| template <int64_t SIZE>
 | |
| struct TestKVCacheKey : public ObIKVCacheKey {
 | |
|   TestKVCacheKey(void) : v_(0), tenant_id_(0)
 | |
|   {
 | |
|     memset(buf_, 0, sizeof(buf_));
 | |
|   }
 | |
|   virtual bool operator==(const ObIKVCacheKey& other) const;
 | |
|   virtual uint64_t get_tenant_id() const
 | |
|   {
 | |
|     return tenant_id_;
 | |
|   }
 | |
|   virtual uint64_t hash() const
 | |
|   {
 | |
|     return v_;
 | |
|   }
 | |
|   virtual int64_t size() const
 | |
|   {
 | |
|     return sizeof(*this);
 | |
|   }
 | |
|   virtual int deep_copy(char* buf, const int64_t buf_len, ObIKVCacheKey*& key) const;
 | |
|   uint64_t v_;
 | |
|   uint64_t tenant_id_;
 | |
|   char buf_[SIZE > sizeof(v_) ? SIZE - sizeof(v_) : 0];
 | |
| };
 | |
| 
 | |
| template <int64_t SIZE>
 | |
| struct TestKVCacheValue : public ObIKVCacheValue {
 | |
|   TestKVCacheValue(void) : v_(0)
 | |
|   {
 | |
|     memset(buf_, 0, sizeof(buf_));
 | |
|   }
 | |
|   virtual int64_t size() const
 | |
|   {
 | |
|     return sizeof(*this);
 | |
|   }
 | |
|   virtual int deep_copy(char* buf, const int64_t buf_len, ObIKVCacheValue*& value) const;
 | |
|   uint64_t v_;
 | |
|   char buf_[SIZE > sizeof(v_) ? SIZE - sizeof(v_) : 0];
 | |
| };
 | |
| 
 | |
| template <int64_t SIZE>
 | |
| bool TestKVCacheKey<SIZE>::operator==(const ObIKVCacheKey& other) const
 | |
| {
 | |
|   const TestKVCacheKey& other_key = reinterpret_cast<const TestKVCacheKey&>(other);
 | |
|   return v_ == other_key.v_ && tenant_id_ == other_key.tenant_id_;
 | |
| }
 | |
| 
 | |
| template <int64_t SIZE>
 | |
| int TestKVCacheKey<SIZE>::deep_copy(char* buf, const int64_t buf_len, ObIKVCacheKey*& key) const
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
|   TestKVCacheKey<SIZE>* pkey = NULL;
 | |
|   if (NULL == buf || buf_len < size()) {
 | |
|     ret = OB_INVALID_ARGUMENT;
 | |
|   } else {
 | |
|     pkey = new (buf) TestKVCacheKey<SIZE>();
 | |
|     pkey->v_ = v_;
 | |
|     pkey->tenant_id_ = tenant_id_;
 | |
|     key = pkey;
 | |
|   }
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| template <int64_t SIZE>
 | |
| int TestKVCacheValue<SIZE>::deep_copy(char* buf, const int64_t buf_len, ObIKVCacheValue*& value) const
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
|   TestKVCacheValue<SIZE>* pvalue = NULL;
 | |
|   if (NULL == buf || buf_len < size()) {
 | |
|     ret = OB_INVALID_ARGUMENT;
 | |
|   } else {
 | |
|     pvalue = new (buf) TestKVCacheValue<SIZE>();
 | |
|     pvalue->v_ = v_;
 | |
|     value = pvalue;
 | |
|   }
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| struct AllocBuf {
 | |
|   void* ptr_;
 | |
|   AllocBuf* next_;
 | |
| };
 | |
| 
 | |
| class ObCacheTestTask;
 | |
| class ObICacheTestStat {
 | |
| public:
 | |
|   virtual void add_task(ObCacheTestTask* task) = 0;
 | |
|   virtual ObCacheTestTask* pop_oppo_task(ObCacheTestTask* task) = 0;
 | |
|   virtual void inc_fail_count() = 0;
 | |
| };
 | |
| 
 | |
| class ObCacheTestTask {
 | |
| public:
 | |
|   ObCacheTestTask(const int64_t tenant_id, const bool is_alloc, const int64_t alloc_size, const int64_t alloc_count,
 | |
|       ObICacheTestStat* stat)
 | |
|       : tenant_id_(tenant_id),
 | |
|         is_alloc_(is_alloc),
 | |
|         alloc_size_(alloc_size),
 | |
|         alloc_count_(alloc_count),
 | |
|         next_(NULL),
 | |
|         stat_(stat),
 | |
|         alloc_list_(NULL)
 | |
|   {}
 | |
| 
 | |
|   virtual ~ObCacheTestTask()
 | |
|   {}
 | |
| 
 | |
|   virtual int process()
 | |
|   {
 | |
|     int ret = OB_SUCCESS;
 | |
|     if (is_alloc_) {
 | |
|       ObMemAttr attr;
 | |
|       attr.tenant_id_ = tenant_id_;
 | |
|       attr.label_ = 1;  // xxx
 | |
|       for (int64_t i = 0; i < alloc_count_; ++i) {
 | |
|         void* ptr = ob_malloc(alloc_size_, attr);
 | |
|         if (NULL == ptr) {
 | |
|           ret = OB_ALLOCATE_MEMORY_FAILED;
 | |
|           COMMON_LOG(WARN, "ob_malloc failed", K(ret), K_(alloc_size));
 | |
|           ObMallocAllocator::get_instance()->print_tenant_memory_usage(tenant_id_);
 | |
|           ObMallocAllocator::get_instance()->print_tenant_ctx_memory_usage(tenant_id_);
 | |
|           break;
 | |
|         } else {
 | |
|           append_alloc_list(ptr);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (OB_SUCC(ret)) {
 | |
|         stat_->add_task(this);
 | |
|       }
 | |
|     } else {
 | |
|       ObCacheTestTask* oppo_task = stat_->pop_oppo_task(this);
 | |
|       if (NULL == oppo_task) {
 | |
|         ret = OB_ERR_UNEXPECTED;
 | |
|         COMMON_LOG(WARN, "oppo_task not exist", K(ret), "this", *this);
 | |
|       } else {
 | |
|         int64_t free_count = 0;
 | |
|         AllocBuf* buf = oppo_task->alloc_list_;
 | |
|         AllocBuf* next = NULL;
 | |
|         while (NULL != buf) {
 | |
|           next = buf->next_;
 | |
|           ob_free(buf->ptr_);
 | |
|           buf = next;
 | |
|           ++free_count;
 | |
|         }
 | |
| 
 | |
|         if (free_count != alloc_count_) {
 | |
|           ret = OB_ERR_UNEXPECTED;
 | |
|           COMMON_LOG(WARN, "free_count != alloc_count_", K(ret), K(free_count), K_(alloc_count));
 | |
|         }
 | |
| 
 | |
|         ob_free(oppo_task);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (OB_FAIL(ret)) {
 | |
|       COMMON_LOG(WARN, "task process failed", K(ret));
 | |
|       ObMallocAllocator::get_instance()->print_tenant_memory_usage(tenant_id_);
 | |
|       ObMallocAllocator::get_instance()->print_tenant_ctx_memory_usage(tenant_id_);
 | |
|       stat_->inc_fail_count();
 | |
|     }
 | |
| 
 | |
|     return ret;
 | |
|   }
 | |
|   void set_next(ObCacheTestTask* task)
 | |
|   {
 | |
|     next_ = task;
 | |
|   }
 | |
|   void append_alloc_list(void* ptr)
 | |
|   {
 | |
|     AllocBuf* buf = new (ptr) AllocBuf();
 | |
|     buf->ptr_ = ptr;
 | |
|     buf->next_ = alloc_list_;
 | |
|     alloc_list_ = buf;
 | |
|   }
 | |
|   TO_STRING_KV(K_(tenant_id), K_(is_alloc), K_(alloc_size), K_(alloc_count));
 | |
| 
 | |
| public:
 | |
|   uint64_t tenant_id_;
 | |
|   bool is_alloc_;  // alloc or free
 | |
|   int64_t alloc_size_;
 | |
|   int64_t alloc_count_;
 | |
|   ObCacheTestTask* next_;
 | |
|   ObICacheTestStat* stat_;
 | |
|   AllocBuf* alloc_list_;
 | |
| };
 | |
| 
 | |
| class CacheTestStat : public ObICacheTestStat {
 | |
| public:
 | |
|   CacheTestStat() : fail_count_(0), task_list_(NULL)
 | |
|   {}
 | |
|   virtual ~CacheTestStat()
 | |
|   {}
 | |
| 
 | |
|   virtual void inc_fail_count()
 | |
|   {
 | |
|     ATOMIC_AAF(&fail_count_, 1);
 | |
|   }
 | |
|   virtual int64_t get_fail_count() const
 | |
|   {
 | |
|     return ATOMIC_LOAD(&fail_count_);
 | |
|   }
 | |
|   virtual void add_task(ObCacheTestTask* task)
 | |
|   {
 | |
|     if (NULL != task) {
 | |
|       task->next_ = task_list_;
 | |
|       task_list_ = task;
 | |
|     }
 | |
|   }
 | |
|   virtual ObCacheTestTask* pop_oppo_task(ObCacheTestTask* task)
 | |
|   {
 | |
|     ObCacheTestTask* oppo_task = NULL;
 | |
|     ObCacheTestTask* prev_task = NULL;
 | |
|     ObCacheTestTask* cur_task = NULL;
 | |
|     if (NULL != task && !task->is_alloc_) {
 | |
|       cur_task = task_list_;
 | |
|       while (NULL != cur_task) {
 | |
|         if (cur_task->is_alloc_ && cur_task->tenant_id_ == task->tenant_id_ &&
 | |
|             cur_task->alloc_size_ == task->alloc_size_ && cur_task->alloc_count_ == task->alloc_count_) {
 | |
|           oppo_task = cur_task;
 | |
|           // delete it from list
 | |
|           if (NULL != prev_task) {
 | |
|             prev_task->next_ = cur_task->next_;
 | |
|             cur_task->next_ = NULL;
 | |
|           } else {
 | |
|             task_list_ = cur_task->next_;
 | |
|             cur_task->next_ = NULL;
 | |
|           }
 | |
|           break;
 | |
|         }
 | |
|         cur_task = cur_task->next_;
 | |
|         prev_task = cur_task;
 | |
|       }
 | |
|     }
 | |
|     return oppo_task;
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   int64_t fail_count_;
 | |
|   ObCacheTestTask* task_list_;
 | |
| };
 | |
| 
 | |
| class ObAllocatorStress : public share::ObThreadPool {
 | |
| public:
 | |
|   ObAllocatorStress() : inited_(false), stat_(), queue_()
 | |
|   {}
 | |
|   virtual ~ObAllocatorStress()
 | |
|   {}
 | |
| 
 | |
|   int init()
 | |
|   {
 | |
|     int ret = OB_SUCCESS;
 | |
|     if (inited_) {
 | |
|       ret = OB_INIT_TWICE;
 | |
|       COMMON_LOG(WARN, "init twice", K(ret));
 | |
|     } else if (OB_FAIL(queue_.init(1024))) {
 | |
|       COMMON_LOG(WARN, "queue init failed", K(ret));
 | |
|     } else {
 | |
|       inited_ = true;
 | |
|     }
 | |
|     return ret;
 | |
|   }
 | |
| 
 | |
|   virtual void run1()
 | |
|   {
 | |
| 
 | |
|     UNUSED(arg);
 | |
|     int ret = OB_SUCCESS;
 | |
|     COMMON_LOG(INFO, "allocator stress thread start");
 | |
|     if (!inited_) {
 | |
|       ret = OB_NOT_INIT;
 | |
|       COMMON_LOG(WARN, "not init", K(ret));
 | |
|     } else {
 | |
|       // will process all task before exit
 | |
|       while (!has_set_stop() || OB_ENTRY_NOT_EXIST != ret) {
 | |
|         ObCacheTestTask* task = NULL;
 | |
|         if (OB_FAIL(pop(task))) {
 | |
|           if (OB_ENTRY_NOT_EXIST != ret) {
 | |
|             COMMON_LOG(WARN, "pop task failed", K(ret));
 | |
|           }
 | |
|         } else {
 | |
|           if (OB_FAIL(task->process())) {
 | |
|             COMMON_LOG(WARN, "task process failed", K(ret));
 | |
|           } else {
 | |
|             COMMON_LOG(INFO, "task process succeed", "task", *task);
 | |
|           }
 | |
|           ObMallocAllocator::get_instance()->print_tenant_memory_usage(500);
 | |
|           ObMallocAllocator::get_instance()->print_tenant_ctx_memory_usage(500);
 | |
| 
 | |
|           ObMallocAllocator::get_instance()->print_tenant_memory_usage(task->tenant_id_);
 | |
|           ObMallocAllocator::get_instance()->print_tenant_ctx_memory_usage(task->tenant_id_);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     COMMON_LOG(INFO, "allocator stress thread end");
 | |
|   }
 | |
| 
 | |
|   int add_task(const ObCacheTestTask& task)
 | |
|   {
 | |
|     int ret = OB_SUCCESS;
 | |
|     const int64_t buf_size = sizeof(task);
 | |
|     void* ptr = NULL;
 | |
|     if (NULL == (ptr = ob_malloc(buf_size))) {
 | |
|       ret = OB_ALLOCATE_MEMORY_FAILED;
 | |
|       COMMON_LOG(WARN, "ob_malloc failed", K(ret), K(buf_size));
 | |
|     } else {
 | |
|       ObCacheTestTask* copy_task =
 | |
|           new (ptr) ObCacheTestTask(task.tenant_id_, task.is_alloc_, task.alloc_size_, task.alloc_count_, task.stat_);
 | |
|       if (OB_FAIL(queue_.push(copy_task))) {
 | |
|         COMMON_LOG(WARN, "push task failed", K(ret));
 | |
|       }
 | |
|     }
 | |
|     return ret;
 | |
|   }
 | |
| 
 | |
|   int pop(ObCacheTestTask*& task)
 | |
|   {
 | |
|     int ret = OB_SUCCESS;
 | |
|     void* vp = NULL;
 | |
|     const int64_t timeout = 1000 * 1000;
 | |
|     if (!inited_) {
 | |
|       ret = OB_NOT_INIT;
 | |
|       COMMON_LOG(WARN, "not init", K(ret));
 | |
|     } else {
 | |
|       ret = queue_.pop(vp, timeout);
 | |
|       if (OB_FAIL(ret)) {
 | |
|         if (OB_ENTRY_NOT_EXIST != ret) {
 | |
|           COMMON_LOG(WARN, "queue pop failed", K(ret));
 | |
|         }
 | |
|       } else {
 | |
|         task = static_cast<ObCacheTestTask*>(vp);
 | |
|       }
 | |
|     }
 | |
|     return ret;
 | |
|   }
 | |
| 
 | |
|   int64_t get_fail_count()
 | |
|   {
 | |
|     return stat_.get_fail_count();
 | |
|   }
 | |
|   CacheTestStat* get_stat()
 | |
|   {
 | |
|     return &stat_;
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   bool inited_;
 | |
|   CacheTestStat stat_;
 | |
|   common::LightyQueue queue_;
 | |
| };
 | |
| 
 | |
| template <int64_t K_SIZE, int64_t V_SIZE>
 | |
| class ObCacheStress : public share::ObThreadPool {
 | |
| public:
 | |
|   typedef TestKVCacheKey<K_SIZE> TestKey;
 | |
|   typedef TestKVCacheValue<V_SIZE> TestValue;
 | |
| 
 | |
|   ObCacheStress() : inited_(false), tenant_id_(OB_INVALID_ID), put_count_(0), fail_count_(0), cache_()
 | |
|   {}
 | |
|   virtual ~ObCacheStress()
 | |
|   {}
 | |
| 
 | |
|   int init(const uint64_t tenant_id, int64_t index)
 | |
|   {
 | |
|     int ret = OB_SUCCESS;
 | |
|     char cache_name[1024];
 | |
|     snprintf(cache_name, 1024, "%s_%ld", "test", index);
 | |
|     if (inited_) {
 | |
|       ret = OB_INIT_TWICE;
 | |
|       COMMON_LOG(WARN, "init twice", K(ret));
 | |
|     } else if (OB_FAIL(cache_.init(cache_name))) {
 | |
|       COMMON_LOG(WARN, "cache init failed", K(ret));
 | |
|     } else {
 | |
|       tenant_id_ = tenant_id;
 | |
|       inited_ = true;
 | |
|     }
 | |
|     return ret;
 | |
|   }
 | |
|   virtual void run1()
 | |
|   {
 | |
| 
 | |
|     UNUSED(arg);
 | |
|     int ret = OB_SUCCESS;
 | |
|     COMMON_LOG(INFO, "cache stress thread start");
 | |
|     TestKey key;
 | |
|     TestValue value;
 | |
|     if (!inited_) {
 | |
|       ret = OB_NOT_INIT;
 | |
|       COMMON_LOG(WARN, "not init", K(ret));
 | |
|     } else {
 | |
|       while (!has_set_stop()) {
 | |
|         key.tenant_id_ = tenant_id_;
 | |
|         key.v_ = put_count_;
 | |
|         if (OB_FAIL(cache_.put(key, value))) {
 | |
|           COMMON_LOG(WARN, "cache put failed", K(ret));
 | |
|         } else {
 | |
|           const TestValue* get_value = NULL;
 | |
|           ObKVCacheHandle handle;
 | |
|           if (OB_FAIL(cache_.get(key, get_value, handle))) {
 | |
|             COMMON_LOG(WARN, "cache get failed", K(ret));
 | |
|           }
 | |
|         }
 | |
|         ++put_count_;
 | |
|         if (OB_FAIL(ret)) {
 | |
|           ++fail_count_;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     COMMON_LOG(INFO, "cache stress thread exit");
 | |
|   }
 | |
| 
 | |
|   uint64_t get_tenant_id() const
 | |
|   {
 | |
|     return tenant_id_;
 | |
|   }
 | |
|   int64_t get_put_count() const
 | |
|   {
 | |
|     return put_count_;
 | |
|   }
 | |
|   int64_t get_fail_count() const
 | |
|   {
 | |
|     return fail_count_;
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   bool inited_;
 | |
|   uint64_t tenant_id_;
 | |
|   int64_t put_count_;
 | |
|   int64_t fail_count_;
 | |
|   ObKVCache<TestKey, TestValue> cache_;
 | |
| };
 | |
| 
 | |
| template <int64_t K_SIZE, int64_t V_SIZE>
 | |
| class ObCacheGetStress : public share::ObThreadPool {
 | |
| public:
 | |
|   typedef TestKVCacheKey<K_SIZE> TestKey;
 | |
|   typedef TestKVCacheValue<V_SIZE> TestValue;
 | |
| 
 | |
|   ObCacheGetStress()
 | |
|       : inited_(false), tenant_id_(OB_INVALID_ID), kv_cnt_(0), hit_cnt_(0), total_cnt_(0), fail_cnt_(0), cache_()
 | |
|   {}
 | |
| 
 | |
|   int init(const uint64_t tenant_id, const int64_t kv_cnt)
 | |
|   {
 | |
|     int ret = OB_SUCCESS;
 | |
|     if (inited_) {
 | |
|       ret = OB_INIT_TWICE;
 | |
|       COMMON_LOG(WARN, "init twice", K(ret));
 | |
|     } else if (OB_INVALID_ID == tenant_id || kv_cnt <= 0) {
 | |
|       ret = OB_INVALID_ARGUMENT;
 | |
|       COMMON_LOG(WARN, "invalid arguments", K(ret), K(tenant_id), K(kv_cnt));
 | |
|     } else if (OB_FAIL(cache_.init("test_cache"))) {
 | |
|       COMMON_LOG(WARN, "cache init failed", K(ret));
 | |
|     } else {
 | |
|       // put kv pairs to cache
 | |
|       TestKey key;
 | |
|       TestValue value;
 | |
|       for (int64_t i = 0; OB_SUCC(ret) && i < kv_cnt; ++i) {
 | |
|         key.tenant_id_ = tenant_id;
 | |
|         ;
 | |
|         key.v_ = i;
 | |
|         if (OB_FAIL(cache_.put(key, value))) {
 | |
|           COMMON_LOG(WARN, "put failed", K(ret));
 | |
|         }
 | |
|       }
 | |
|       tenant_id_ = tenant_id;
 | |
|       kv_cnt_ = kv_cnt;
 | |
|       hit_cnt_ = 0;
 | |
|       total_cnt_ = 0;
 | |
|       fail_cnt_ = 0;
 | |
|       inited_ = true;
 | |
|     }
 | |
|     return ret;
 | |
|   }
 | |
| 
 | |
|   // will create monitor thread print hit ratio per second
 | |
|   virtual void set_thread_count(const int64_t thread_count)
 | |
|   {
 | |
|     // extra thread for monitor thread
 | |
|     share::ObThreadPool::set_thread_count(static_cast<int32_t>(thread_count + 1));
 | |
|   }
 | |
| 
 | |
|   virtual void run1()
 | |
|   {
 | |
| 
 | |
|     int64_t thread_id = (int64_t)(arg);
 | |
|     if (0 == thread_id) {
 | |
|       do_monitor();
 | |
|     } else {
 | |
|       do_work();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   ObKVCache<TestKey, TestValue>& get_cache()
 | |
|   {
 | |
|     return cache_;
 | |
|   }
 | |
|   double get_hit_ratio()
 | |
|   {
 | |
|     int ret = OB_SUCCESS;
 | |
|     int64_t hit_cnt = 0;
 | |
|     TestKey key;
 | |
|     const TestValue* pvalue = NULL;
 | |
|     ObKVCacheHandle handle;
 | |
|     for (int64_t i = 0; i < kv_cnt_; ++i) {
 | |
|       key.tenant_id_ = tenant_id_;
 | |
|       key.v_ = i;
 | |
|       if (OB_FAIL(cache_.get(key, pvalue, handle))) {
 | |
|         if (OB_ENTRY_NOT_EXIST != ret) {
 | |
|           COMMON_LOG(ERROR, "get failed", K(ret));
 | |
|         }
 | |
|       } else {
 | |
|         ++hit_cnt;
 | |
|       }
 | |
|     }
 | |
|     return (double)hit_cnt / (double)kv_cnt_;
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   void do_monitor()
 | |
|   {
 | |
|     while (!has_set_stop()) {
 | |
|       double hit_ratio = 0;
 | |
|       const int64_t hit_cnt = ATOMIC_LOAD(&hit_cnt_);
 | |
|       const int64_t total_cnt = ATOMIC_LOAD(&total_cnt_);
 | |
|       ATOMIC_STORE(&hit_cnt_, 0);
 | |
|       ATOMIC_STORE(&total_cnt_, 0);
 | |
|       if (total_cnt > 0) {
 | |
|         hit_ratio = (double)hit_cnt / (double)total_cnt;
 | |
|       }
 | |
|       COMMON_LOG(INFO, "get stress stat", K(hit_ratio));
 | |
|       sleep(1);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   void do_work()
 | |
|   {
 | |
|     int ret = OB_SUCCESS;
 | |
|     TestKey key;
 | |
|     const TestValue* pvalue = NULL;
 | |
|     ObKVCacheHandle handle;
 | |
|     while (!has_set_stop()) {
 | |
|       for (int64_t i = 0; i < kv_cnt_ && !has_set_stop(); ++i) {
 | |
|         const int64_t get_cnt = i < (int64_t)((double)kv_cnt_ * 0.8) ? 1 : 4;
 | |
|         key.tenant_id_ = tenant_id_;
 | |
|         key.v_ = i;
 | |
|         for (int64_t i = 0; i < get_cnt; ++i) {
 | |
|           ATOMIC_INC(&total_cnt_);
 | |
|           if (OB_FAIL(cache_.get(key, pvalue, handle))) {
 | |
|             if (OB_ENTRY_NOT_EXIST != ret) {
 | |
|               COMMON_LOG(ERROR, "get failed", K(ret));
 | |
|             } else {
 | |
|               ATOMIC_INC(&fail_cnt_);
 | |
|             }
 | |
|           } else {
 | |
|             ATOMIC_INC(&hit_cnt_);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   bool inited_;
 | |
|   uint64_t tenant_id_;
 | |
|   int64_t kv_cnt_;
 | |
|   int64_t hit_cnt_;
 | |
|   int64_t total_cnt_;
 | |
|   int64_t fail_cnt_;
 | |
|   ObKVCache<TestKey, TestValue> cache_;
 | |
| };
 | |
| 
 | |
| template <int64_t K_SIZE, int64_t V_SIZE>
 | |
| class ObWorkingSetStress : public share::ObThreadPool {
 | |
| public:
 | |
|   typedef TestKVCacheKey<K_SIZE> TestKey;
 | |
|   typedef TestKVCacheValue<V_SIZE> TestValue;
 | |
| 
 | |
|   ObWorkingSetStress() : inited_(false), tenant_id_(OB_INVALID_ID), put_count_(0), fail_count_(0)
 | |
|   {}
 | |
|   virtual ~ObWorkingSetStress()
 | |
|   {}
 | |
| 
 | |
|   int init(const uint64_t tenant_id, const bool only_put)
 | |
|   {
 | |
|     int ret = OB_SUCCESS;
 | |
|     if (inited_) {
 | |
|       ret = OB_INIT_TWICE;
 | |
|       COMMON_LOG(WARN, "init twice", K(ret));
 | |
|     } else if (OB_FAIL(cache_.init("test_cache"))) {
 | |
|       COMMON_LOG(WARN, "cache init failed", K(ret));
 | |
|     } else if (OB_FAIL(ws_.init(tenant_id, cache_))) {
 | |
|       COMMON_LOG(WARN, "init ws failed", K(ret), K(tenant_id));
 | |
|     } else {
 | |
|       tenant_id_ = tenant_id;
 | |
|       put_count_ = 0;
 | |
|       fail_count_ = 0;
 | |
|       only_put_ = only_put;
 | |
|       pcache_ = &ws_;
 | |
|       inited_ = true;
 | |
|     }
 | |
|     return ret;
 | |
|   }
 | |
| 
 | |
|   int init(
 | |
|       const uint64_t tenant_id, ObKVCache<TestKey, TestValue>& cache, const bool use_ws, const int64_t start_key = 0)
 | |
|   {
 | |
|     int ret = OB_SUCCESS;
 | |
|     if (inited_) {
 | |
|       ret = OB_INIT_TWICE;
 | |
|       COMMON_LOG(WARN, "init twice", K(ret));
 | |
|     } else {
 | |
|       tenant_id_ = tenant_id;
 | |
|       put_count_ = 0;
 | |
|       fail_count_ = 0;
 | |
|       only_put_ = false;
 | |
|       pcache_ = &cache;
 | |
|       start_key_ = start_key;
 | |
|       if (use_ws) {
 | |
|         if (OB_FAIL(ws_.init(tenant_id, cache))) {
 | |
|           COMMON_LOG(WARN, "init ws failed", K(ret), K(tenant_id));
 | |
|         } else {
 | |
|           pcache_ = &ws_;
 | |
|         }
 | |
|       }
 | |
|       if (OB_SUCC(ret)) {
 | |
|         inited_ = true;
 | |
|       }
 | |
|     }
 | |
|     return ret;
 | |
|   }
 | |
| 
 | |
|   virtual void run1()
 | |
|   {
 | |
| 
 | |
|     const int64_t thread_id = (int64_t)(arg);
 | |
|     const int64_t count = _threadCount;
 | |
|     int64_t put_count = 0;
 | |
|     int64_t fail_count = 0;
 | |
|     int ret = OB_SUCCESS;
 | |
|     COMMON_LOG(INFO, "working set stress thread start");
 | |
|     TestKey key;
 | |
|     TestValue value;
 | |
|     if (!inited_) {
 | |
|       ret = OB_NOT_INIT;
 | |
|       COMMON_LOG(WARN, "not init", K(ret));
 | |
|     } else {
 | |
|       while (!has_set_stop()) {
 | |
|         key.tenant_id_ = tenant_id_;
 | |
|         key.v_ = start_key_ + thread_id + put_count * count;
 | |
|         if (OB_FAIL(pcache_->put(key, value))) {
 | |
|           COMMON_LOG(WARN, "cache put failed", K(ret));
 | |
|         } else if (!only_put_) {
 | |
|           const TestValue* get_value = NULL;
 | |
|           ObKVCacheHandle handle;
 | |
|           if (OB_FAIL(pcache_->get(key, get_value, handle))) {
 | |
|             if (OB_ENTRY_NOT_EXIST == ret) {
 | |
|               ret = OB_SUCCESS;
 | |
|             } else {
 | |
|               COMMON_LOG(WARN, "cache get failed", K(ret));
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|         ++put_count;
 | |
|         if (OB_FAIL(ret)) {
 | |
|           ++fail_count;
 | |
|           ObMallocAllocator::get_instance()->print_tenant_memory_usage(tenant_id_);
 | |
|           ObMallocAllocator::get_instance()->print_tenant_ctx_memory_usage(tenant_id_);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     ATOMIC_AAF(&put_count_, put_count);
 | |
|     ATOMIC_AAF(&fail_count_, fail_count);
 | |
|     COMMON_LOG(INFO, "working set stress thread exit");
 | |
|   }
 | |
| 
 | |
|   uint64_t get_tenant_id() const
 | |
|   {
 | |
|     return tenant_id_;
 | |
|   }
 | |
|   int64_t get_put_count() const
 | |
|   {
 | |
|     return put_count_;
 | |
|   }
 | |
|   int64_t get_fail_count() const
 | |
|   {
 | |
|     return fail_count_;
 | |
|   }
 | |
|   int64_t get_used() const
 | |
|   {
 | |
|     return ws_.working_set_->get_used();
 | |
|   }
 | |
|   int64_t get_limit() const
 | |
|   {
 | |
|     return ws_.working_set_->get_limit();
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   bool inited_;
 | |
|   uint64_t tenant_id_;
 | |
|   int64_t put_count_;
 | |
|   int64_t fail_count_;
 | |
|   bool only_put_;
 | |
|   ObIKVCache<TestKey, TestValue>* pcache_;
 | |
|   ObKVCache<TestKey, TestValue> cache_;
 | |
|   ObCacheWorkingSet<TestKey, TestValue> ws_;
 | |
|   int64_t start_key_;
 | |
| };
 | |
| 
 | |
| }  // end namespace common
 | |
| }  // end namespace oceanbase
 | |
| 
 | |
| #endif  // OCEANBASE_SHARE_OB_CACHE_TEST_UTILS_H_
 | 
