967 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			967 lines
		
	
	
		
			32 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 "storage/tx/ob_time_wheel.h"
 | |
| #include <gtest/gtest.h>
 | |
| #include "common/ob_clock_generator.h"
 | |
| #include "share/ob_errno.h"
 | |
| #include "lib/oblog/ob_log.h"
 | |
| #include "lib/random/ob_random.h"
 | |
| 
 | |
| #define BASE_TEST
 | |
| #define CURRENTCY_TEST
 | |
| #define EDGE_TEST
 | |
| 
 | |
| #define TEST_TW_CREATE_INIT_DES
 | |
| #define TEST_TASK_CREATE_INIT_DES
 | |
| #define TEST_TW_SCHEDULE_RUN
 | |
| #define TEST_TW_SCHEDULE_RUN_CANCEL
 | |
| #define TEST_TW_TASK_RUN_PRECISION
 | |
| 
 | |
| #define TEST_TW_HIGHCURRENCY_SCHEDULE
 | |
| #define TEST_TW_HIGHCURRENCY_SCHEDULE_RUN
 | |
| #define TEST_TW_HIGHCURRENCY_SCHEDULE_CANCEL
 | |
| //#define TEST_TW_HIGHCURRENCY_SCHEDULE_CANCEL_RANDOM
 | |
| #define TEST_TW_LOCK_AVAILABLITY
 | |
| 
 | |
| #define TEST_TIMEWHEELBASE_NO_INIT
 | |
| #define TEST_TIMEWHEEL_NO_INIT
 | |
| #define TEST_TIMEWHEEL_RUNNING
 | |
| #define TEST_TIMEWHEEL_INVALID_INIT
 | |
| #define TEST_TIMEWHEEL_REPEAT_INIT
 | |
| #define TEST_TIMEWHEEL_REPEAT_DES
 | |
| #define TEST_TIMEWHEEL_SCHEDULE_AFTER_DES
 | |
| #define TEST_TIMEWHEEL_INVALID_TASK_SCHEDULE
 | |
| #define TEST_TIMEWHEEL_REPEAT_SCHEDULE
 | |
| #define TEST_TIMEWHEEL_REPEAT_CANCEL
 | |
| #define TEST_TIMEWHEEL_REPEAT_SCHEDULE_CANCEL
 | |
| #define TEST_TIMEWHEEL_SCHEDULE_SELF
 | |
| #define TEST_TIMEWHEEL_CANCEL_RUNOVER_TASK
 | |
| 
 | |
| namespace oceanbase
 | |
| {
 | |
| using namespace common;
 | |
| 
 | |
| namespace unittest
 | |
| {
 | |
| 
 | |
| struct NumTask{
 | |
|   // thread count
 | |
|   static const int64_t THREAD_NUM = 15;
 | |
| 
 | |
|   // high concurrency test task count
 | |
|   static const int64_t MAX_NUM_TASK = 1000000;
 | |
|   // static const int64_t HIGH_CURRENCY_NUM_TASK = 100000;
 | |
|   static const int64_t HIGH_CURRENCY_NUM_TASK = 100000;
 | |
| 
 | |
|   // lock availablity test paras
 | |
|   static const int64_t HIGH_CURRENCY_LOCK_NUM_TASK = 1000;
 | |
|   static const int64_t HIGH_CURRENCY_LOCK_TEST_COUNT = 10;
 | |
| 
 | |
|   // inc_num for task hash value
 | |
|   static int64_t inc_num_;
 | |
| 
 | |
|   // time wheel thread num
 | |
|   static const int64_t TW_THREAD_NUM = 6;
 | |
| };
 | |
| int64_t NumTask::inc_num_ = 0;
 | |
| 
 | |
| class TestObTimeWheel : public ::testing::Test
 | |
| {
 | |
| public :
 | |
|   virtual void SetUP(){}
 | |
|   virtual  void TearDown(){}
 | |
| };
 | |
| 
 | |
| class ObSampleTimer : public ObTimeWheel{};
 | |
| 
 | |
| class ObSampleTask : public ObTimeWheelTask
 | |
| {
 | |
| public :
 | |
|   ObSampleTask() : run_over_(false), inc_num_(++NumTask::inc_num_) {}
 | |
|   ~ObSampleTask(){}
 | |
|   void runTimerTask();
 | |
|   bool is_run_over() const;
 | |
|   void reset();
 | |
|   static int64_t get_total_run_count();
 | |
|   static void clear_total_run_count();
 | |
|   uint64_t hash() const { return inc_num_; }
 | |
| public :
 | |
|   static int64_t task_run_count_num_;
 | |
| private :
 | |
|   bool run_over_;
 | |
|   int64_t inc_num_;
 | |
| };
 | |
| 
 | |
| int64_t ObSampleTask::task_run_count_num_ = 0;
 | |
| 
 | |
| void ObSampleTask::runTimerTask()
 | |
| {
 | |
|   ATOMIC_FAA(&task_run_count_num_, 1);
 | |
|   run_over_ = true;
 | |
| }
 | |
| 
 | |
| bool ObSampleTask::is_run_over() const
 | |
| {
 | |
|   return run_over_;
 | |
| }
 | |
| 
 | |
| void ObSampleTask::reset()
 | |
| {
 | |
|   run_over_ = false;
 | |
| }
 | |
| 
 | |
| void ObSampleTask::clear_total_run_count()
 | |
| {
 | |
|   task_run_count_num_ = 0;
 | |
| }
 | |
| 
 | |
| int64_t ObSampleTask::get_total_run_count()
 | |
| {
 | |
|   return task_run_count_num_;
 | |
| }
 | |
| 
 | |
| class ObSampleTask2 : public ObTimeWheelTask
 | |
| {
 | |
| public :
 | |
|   ObSampleTask2() : time_wheel_(NULL), retry_time_(0), inc_num_(++NumTask::inc_num_) { }
 | |
|   ~ObSampleTask2(){};
 | |
|   void set_time_wheel(ObTimeWheel *time_wheel);
 | |
|   void runTimerTask();
 | |
|   int64_t get_retry_time() const;
 | |
|   uint64_t hash() const { return inc_num_; }
 | |
| private :
 | |
|   ObTimeWheel *time_wheel_;
 | |
|   int64_t retry_time_;
 | |
|   int64_t inc_num_;
 | |
| };
 | |
| 
 | |
| void ObSampleTask2::set_time_wheel(ObTimeWheel *time_wheel)
 | |
| {
 | |
|   if (NULL != time_wheel) {
 | |
|     time_wheel_ = time_wheel;
 | |
|   } else {
 | |
|     TRANS_LOG(INFO, "",  "input paras time_wheel = NULL", time_wheel);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void ObSampleTask2::runTimerTask()
 | |
| {
 | |
|   if (retry_time_ < 100) {
 | |
|     retry_time_++;
 | |
|     EXPECT_EQ(OB_SUCCESS, time_wheel_->schedule(this, 100000));
 | |
|   }
 | |
| }
 | |
| 
 | |
| int64_t ObSampleTask2::get_retry_time() const
 | |
| {
 | |
|   return retry_time_;
 | |
| }
 | |
| 
 | |
| class ObSampleTask3 : public ObTimeWheelTask
 | |
| {
 | |
| public :
 | |
|   ObSampleTask3() : tw_precision_(0), run_time_(0), inc_num_(++NumTask::inc_num_) { }
 | |
|   ~ObSampleTask3() {};
 | |
|   void set_run_time(const int64_t run_time) { run_time_ = run_time; }
 | |
|   int64_t get_run_time() const { return run_time_; }
 | |
|   void runTimerTask();
 | |
|   void set_precision(const int64_t precision) { tw_precision_ = precision; }
 | |
|   int64_t get_precision() const  { return tw_precision_;}
 | |
|   uint64_t hash() const { return inc_num_; }
 | |
| private :
 | |
|   int64_t tw_precision_;
 | |
|   int64_t run_time_;
 | |
|   int64_t inc_num_;
 | |
| };
 | |
| 
 | |
| void ObSampleTask3::runTimerTask()
 | |
| {
 | |
|   int64_t max = ((get_run_time() + get_precision() - 1) / get_precision() ) * get_precision() + 5000;
 | |
|   int64_t min = (get_run_time() / get_precision()) * get_precision();
 | |
|   int64_t current = ObClockGenerator::getClock();
 | |
| 
 | |
|   if (current < min || current > max) {
 | |
|     TRANS_LOG(INFO, "run task", K(min), K(max), K(current), "run_time", get_run_time());
 | |
|   }
 | |
|   EXPECT_TRUE(current >= min && current <= max);
 | |
| }
 | |
| 
 | |
| struct InputParas{
 | |
|   InputParas() : tw_(NULL), task_(NULL), task_num_(0), task_delay_(0) {}
 | |
|   ~InputParas() {}
 | |
|   ObSampleTimer *tw_;
 | |
|   ObSampleTask *task_;
 | |
|   int64_t task_num_;
 | |
|   int64_t task_delay_;
 | |
| };
 | |
| 
 | |
| struct OutputParas
 | |
| {
 | |
|   explicit OutputParas(const int64_t count);
 | |
|   ~OutputParas();
 | |
|   ObSampleTask *task_arr_[NumTask::MAX_NUM_TASK];
 | |
|   int64_t valid_task_count_;
 | |
| };
 | |
| 
 | |
| OutputParas::OutputParas(const int64_t count) : valid_task_count_(0)
 | |
| {
 | |
|   for (int64_t i = 0; i < NumTask::MAX_NUM_TASK; i++) {
 | |
|     task_arr_[i] = NULL;
 | |
|   }
 | |
|   valid_task_count_ = count;
 | |
| }
 | |
| 
 | |
| OutputParas::~OutputParas()
 | |
| {
 | |
|   for (int64_t i = 0; i < valid_task_count_; ++i) {
 | |
|     task_arr_[i] = NULL;
 | |
|   }
 | |
| }
 | |
| 
 | |
| class MyThread
 | |
| {
 | |
| public :
 | |
|   static void *create_task(void *args);
 | |
|   static void *schedule_task(void *args);
 | |
|   static void *cancel_task(void *args);
 | |
|   static void schedule_run(const int64_t thread_num, const int64_t task_num, const int64_t sleep_time);
 | |
| };
 | |
| 
 | |
| // according to the schedule's task, cancel the task randomly
 | |
| void MyThread::schedule_run(const int64_t thread_num, const int64_t task_num, const int64_t sleep_time)
 | |
| {
 | |
|   ObSampleTimer *ob_sample_timer = new ObSampleTimer();
 | |
|   ASSERT_TRUE(NULL != ob_sample_timer);
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->init(1000, NumTask::TW_THREAD_NUM, "test"));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->start());
 | |
| 
 | |
|   pthread_attr_t attr;
 | |
|   pthread_attr_init(&attr);
 | |
|   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
 | |
| 
 | |
|   // create and init the paras
 | |
|   const int64_t NUM = thread_num;
 | |
|   const int64_t TASK_NUM_FOR_THREAD = task_num;
 | |
|   const int64_t SLEEP_TIME = sleep_time;
 | |
|   InputParas *params = new InputParas[NUM];
 | |
|   EXPECT_TRUE(NULL != params);
 | |
| 
 | |
|   for (int64_t i = 0; i < NUM; ++i) {
 | |
|     params[i].tw_ = ob_sample_timer;
 | |
|     params[i].task_ = new ObSampleTask[TASK_NUM_FOR_THREAD];
 | |
|     EXPECT_TRUE(NULL != params[i].task_);
 | |
|     params[i].task_num_ = NumTask::HIGH_CURRENCY_LOCK_NUM_TASK;
 | |
|     params[i].task_delay_ = SLEEP_TIME * 1000 +  ObRandom::rand(0, 200) % (int64_t) ((i +1) * 1000); // delay = 5s + rand()
 | |
|   }
 | |
|   // create five schedule threads, and schedule above tasks respectively
 | |
|   pthread_t tids[NUM * 2];
 | |
|   for (int64_t i = 0; i < NUM; ++i) {
 | |
|     tids[i] = i;
 | |
|     EXPECT_TRUE(0 == pthread_create(&tids[i], &attr, MyThread::schedule_task, static_cast<void *>(&(params[i]))));
 | |
|   }
 | |
|   // sleep 5s
 | |
|   ObClockGenerator::msleep(SLEEP_TIME);
 | |
|   // create five cancel threads, and cancel above taask accordingly
 | |
|   for (int64_t i = 0; i < NUM; ++i) {
 | |
|     tids[NUM + i] = i;
 | |
|     EXPECT_TRUE(0 == pthread_create(&tids[NUM + i], &attr, MyThread::cancel_task, static_cast<void *>(&(params[i]))));
 | |
|   }
 | |
|   // collect resources of threads
 | |
|   for (int64_t i = 0; i < NUM * 2; ++i) {
 | |
|     pthread_join(tids[i], NULL);
 | |
|   }
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->stop());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->wait());
 | |
| 
 | |
|   delete ob_sample_timer;
 | |
|   ob_sample_timer = NULL;
 | |
| 
 | |
|   if (NULL != params) {
 | |
|     for (int64_t i = 0; i < NUM; ++i) {
 | |
|       if (NULL != params[i].task_) {
 | |
|         delete [] params[i].task_;
 | |
|         params[i].task_ = NULL;
 | |
|       }
 | |
|     }
 | |
|     delete [] params;
 | |
|     params = NULL;
 | |
|   }
 | |
| }
 | |
| // schedule tasks in thread functions
 | |
| void *MyThread::schedule_task(void *args)
 | |
| {
 | |
|   InputParas *in_paras = static_cast<InputParas *>(args);
 | |
|   EXPECT_TRUE(NULL != in_paras);
 | |
|   for (int64_t i = 0; i < in_paras->task_num_; ++i) {
 | |
|     EXPECT_TRUE(OB_SUCCESS == in_paras->tw_->schedule(&(in_paras->task_[i]), in_paras->task_delay_));
 | |
|     TRANS_LOG(INFO, "schedule task", "task", &(in_paras->task_[i]), "delay", in_paras->task_delay_);
 | |
|   }
 | |
|   pthread_exit(NULL);
 | |
| }
 | |
| // cancel tasks in thread functions
 | |
| void *MyThread::cancel_task(void *args)
 | |
| {
 | |
|   InputParas *in_paras = static_cast<InputParas *>(args);
 | |
|   EXPECT_TRUE(NULL != in_paras);
 | |
|   for (int64_t i = 0; i < in_paras->task_num_; ++i) {
 | |
|     EXPECT_EQ(OB_SUCCESS, in_paras->tw_->cancel(&(in_paras->task_[i])));
 | |
|     TRANS_LOG(INFO, "cancel task", "task", &(in_paras->task_[i]), "delay", in_paras->task_delay_);
 | |
|   }
 | |
|   pthread_exit(NULL);
 | |
| }
 | |
| // register tasks in thread functions
 | |
| void *MyThread::create_task(void *args)
 | |
| {
 | |
|   int64_t start = 0;
 | |
|   int64_t end = 0;
 | |
|   InputParas *in_para = static_cast<InputParas *>(args);
 | |
|   EXPECT_TRUE(in_para != NULL);
 | |
|   OutputParas *out_para = new OutputParas(in_para->task_num_);
 | |
|   EXPECT_TRUE(NULL != out_para);
 | |
| 
 | |
|   start = ObClockGenerator::getClock();
 | |
|   for (int64_t i = 0; i < in_para->task_num_; i++) {
 | |
|     out_para->task_arr_[i] = new ObSampleTask();
 | |
|     EXPECT_TRUE(NULL != out_para->task_arr_[i]);
 | |
|   }
 | |
|   end = ObClockGenerator::getClock();
 | |
|   TRANS_LOG(INFO, "", "alloc used", end - start);
 | |
| 
 | |
|   start = ObClockGenerator::getClock();
 | |
|   for (int64_t i = 0; i < in_para->task_num_; i++) {
 | |
|     EXPECT_TRUE(OB_SUCCESS == in_para->tw_->schedule(out_para->task_arr_[i], in_para->task_delay_));
 | |
|   }
 | |
|   end = ObClockGenerator::getClock();
 | |
|   TRANS_LOG(INFO, "", "schedule used", end - start);
 | |
| 
 | |
|   pthread_exit(static_cast<void *>(out_para));
 | |
| }
 | |
| 
 | |
| //------------------------------basic funtions test--------------------------
 | |
| // basic functions test are as follows
 | |
| // test the time wheel work flows which contain create,init and destroy operations
 | |
| 
 | |
| #ifdef BASE_TEST
 | |
| #ifdef TEST_TW_CREATE_INIT_DES
 | |
| TEST_F(TestObTimeWheel, test_tw_create_init_des)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   int64_t precision = 1;
 | |
|   for (int64_t i = 0; i < 4; i++) {
 | |
|     if( i!= 0) {
 | |
|       precision *= 10;
 | |
|     }
 | |
|     ObSampleTimer ob_sample_timer;
 | |
|     EXPECT_EQ(OB_SUCCESS, ob_sample_timer.init(precision, NumTask::TW_THREAD_NUM, "test"));
 | |
|     EXPECT_EQ(OB_SUCCESS, ob_sample_timer.start());
 | |
|     EXPECT_EQ(OB_SUCCESS, ob_sample_timer.stop());
 | |
|     EXPECT_EQ(OB_SUCCESS, ob_sample_timer.wait());
 | |
|     ob_sample_timer.destroy();
 | |
|   }
 | |
| }
 | |
| #endif
 | |
| // test the task token work flows which contain create,init and destroy operations
 | |
| #ifdef TEST_TASK_CREATE_INIT_DES
 | |
| TEST_F(TestObTimeWheel, test_task_create_init_des)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTask *ob_sample_task = new ObSampleTask();
 | |
|   ASSERT_TRUE(NULL != ob_sample_task);
 | |
|   EXPECT_TRUE(!ob_sample_task->is_run_over());
 | |
| 
 | |
|   delete ob_sample_task;
 | |
|   ob_sample_task = NULL;
 | |
| }
 | |
| #endif
 | |
| // test the task which delay time is too long.
 | |
| #ifdef TEST_TW_SCHEDULE_RUN
 | |
| TEST_F(TestObTimeWheel, test_tw_schedule_run)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTimer ob_sample_timer;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.init(1000, NumTask::TW_THREAD_NUM, "test"));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.start());
 | |
| 
 | |
|   ObSampleTask ob_sample_task1;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.schedule(&ob_sample_task1, 100000));
 | |
| 
 | |
|   ObSampleTask ob_sample_task2;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.schedule(&ob_sample_task2, 15000000));
 | |
| 
 | |
|   ObClockGenerator::msleep(110);
 | |
|   EXPECT_TRUE(ob_sample_task1.is_run_over());
 | |
|   ObClockGenerator::msleep(15010);
 | |
|   EXPECT_TRUE(ob_sample_task2.is_run_over());
 | |
| 
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.stop());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.wait());
 | |
| }
 | |
| #endif
 | |
| // test the run process of task
 | |
| #ifdef TEST_TW_SCHEDULE_RUN_CANCEL
 | |
| TEST_F(TestObTimeWheel, test_tw_schedule_run_cancel)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTimer ob_sample_timer;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.init(1000, NumTask::TW_THREAD_NUM, "test"));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.start());
 | |
| 
 | |
|   ObSampleTask ob_sample_task;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.schedule(&ob_sample_task, 1000000));
 | |
|   ObClockGenerator::msleep(1010);
 | |
|   EXPECT_TRUE(ob_sample_task.is_run_over());
 | |
| 
 | |
|   ob_sample_task.reset();
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.schedule(&ob_sample_task, 1000000));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.cancel(&ob_sample_task));
 | |
|   ObClockGenerator::msleep(1010);
 | |
|   EXPECT_TRUE(!ob_sample_task.is_run_over());
 | |
| 
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.stop());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.wait());
 | |
| }
 | |
| #endif
 | |
| 
 | |
| // test the precision of task
 | |
| #ifdef TEST_TW_TASK_RUN_PRECISION
 | |
| TEST_F(TestObTimeWheel, test_tw_task_run_precision)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTimer ob_sample_timer;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.init(1000, NumTask::TW_THREAD_NUM, "test"));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.start());
 | |
| 
 | |
|   const int64_t count = 100;
 | |
|   const int64_t delay = 1000000;
 | |
| 
 | |
|   ObSampleTask3 *tmp[count];
 | |
|   for (int64_t i = 0; i < count; i++) {
 | |
|     tmp[i] = new ObSampleTask3();
 | |
|     ASSERT_TRUE(NULL != tmp[i]);
 | |
|     tmp[i]->set_precision(1000);
 | |
|     tmp[i]->set_run_time(ObClockGenerator::getClock() + delay);
 | |
|     EXPECT_EQ(OB_SUCCESS, ob_sample_timer.schedule(tmp[i], delay));
 | |
|   }
 | |
| 
 | |
|   ObClockGenerator::msleep(1000);
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.stop());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.wait());
 | |
| 
 | |
|   for (int64_t i = 0; i < count; i++) {
 | |
|     EXPECT_TRUE(NULL != tmp[i]);
 | |
|     delete tmp[i];
 | |
|     tmp[i] = NULL;
 | |
|   }
 | |
| }
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| //--------------------- high concurrency schedule and run ------------------
 | |
| // high concurrency test are as follows
 | |
| // schedule the task in high concurrency way.
 | |
| //
 | |
| 
 | |
| #ifdef CURRENTCY_TEST
 | |
| 
 | |
| #ifdef TEST_TW_HIGHCURRENCY_SCHEDULE
 | |
| TEST_F(TestObTimeWheel, test_tw_highcurrency_schedule)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTimer *ob_sample_timer = new ObSampleTimer();
 | |
|   ASSERT_TRUE(NULL != ob_sample_timer);
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->init(1000, NumTask::TW_THREAD_NUM, "test"));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->start());
 | |
| 
 | |
|   pthread_attr_t attr;
 | |
|   pthread_attr_init(&attr);
 | |
|   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
 | |
|   pthread_t tids[NumTask::THREAD_NUM];
 | |
| 
 | |
|   //create para and init
 | |
|   InputParas *in_para = new InputParas();
 | |
|   in_para->tw_ = ob_sample_timer;
 | |
|   in_para->task_num_ = NumTask::HIGH_CURRENCY_NUM_TASK;
 | |
|   in_para->task_delay_ = 1000000;
 | |
| 
 | |
|   for (int64_t i = 0; i < NumTask::THREAD_NUM; i++) {
 | |
|     EXPECT_TRUE(pthread_create(&tids[i], &attr, MyThread::create_task, static_cast<void *>(in_para)) == 0);
 | |
|   }
 | |
| 
 | |
|   void *tmp[NumTask::THREAD_NUM];
 | |
|   pthread_attr_destroy(&attr);
 | |
|   for (int64_t i = 0; i < NumTask::THREAD_NUM; i++) {
 | |
|     EXPECT_EQ(0, pthread_join(tids[i], &tmp[i]));
 | |
|   }
 | |
| 
 | |
|   delete in_para;
 | |
|   in_para = NULL;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->stop());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->wait());
 | |
| 
 | |
|   for (int64_t i = 0; i < NumTask::THREAD_NUM; i++) {
 | |
|     OutputParas *out_pars = static_cast<OutputParas *>(tmp[i]);
 | |
|     EXPECT_TRUE(NULL != out_pars);
 | |
|     delete out_pars;
 | |
|     out_pars = NULL;
 | |
|   }
 | |
|   delete ob_sample_timer;
 | |
|   ob_sample_timer = NULL;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| // run the task in high concurrency way.
 | |
| #ifdef TEST_TW_HIGHCURRENCY_SCHEDULE_RUN
 | |
| TEST_F(TestObTimeWheel, test_tw_highcurrency_schedule_run)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTask::clear_total_run_count();
 | |
|   ObSampleTimer *ob_sample_timer = new ObSampleTimer();
 | |
|   ASSERT_TRUE(NULL != ob_sample_timer);
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->init(1000, NumTask::TW_THREAD_NUM, "test"));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->start());
 | |
| 
 | |
|   pthread_attr_t attr;
 | |
|   pthread_attr_init(&attr);
 | |
|   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
 | |
|   pthread_t tids[NumTask::THREAD_NUM];
 | |
| 
 | |
|   // create para and init
 | |
|   InputParas *in_para = new InputParas();
 | |
|   in_para->tw_ = ob_sample_timer;
 | |
|   in_para->task_num_ = NumTask::HIGH_CURRENCY_NUM_TASK;
 | |
|   in_para->task_delay_ = 100000;
 | |
| 
 | |
|   for (int64_t i = 0; i < NumTask::THREAD_NUM; i++){
 | |
|     EXPECT_TRUE(pthread_create(&tids[i], &attr, MyThread::create_task, static_cast<void *>(in_para)) == 0);
 | |
|   }
 | |
| 
 | |
|   void *tmp[NumTask::THREAD_NUM];
 | |
|   for (int64_t i = 0; i < NumTask::THREAD_NUM; i++) {
 | |
|     EXPECT_EQ(0, pthread_join(tids[i], &tmp[i]));
 | |
|   }
 | |
|   // Error:there are several tasks which have not been executed.
 | |
|   // success: all tasks have been executed.
 | |
|   ObClockGenerator::msleep(10000);
 | |
|   EXPECT_EQ(NumTask::THREAD_NUM * NumTask::HIGH_CURRENCY_NUM_TASK, ObSampleTask::get_total_run_count());
 | |
| 
 | |
|   delete in_para;
 | |
|   in_para = NULL;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->stop());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->wait());
 | |
| 
 | |
|   for (int64_t i = 0; i < NumTask::THREAD_NUM; i++) {
 | |
|     OutputParas *out_pars = static_cast<OutputParas *>(tmp[i]);
 | |
|     EXPECT_TRUE(NULL != out_pars);
 | |
|     delete out_pars;
 | |
|     out_pars = NULL;
 | |
|   }
 | |
|   delete ob_sample_timer;
 | |
|   ob_sample_timer = NULL;
 | |
|   ObSampleTask::clear_total_run_count();
 | |
| }
 | |
| #endif
 | |
| 
 | |
| // run the task and cancel in high concurrency way.
 | |
| #ifdef TEST_TW_HIGHCURRENCY_SCHEDULE_CANCEL
 | |
| TEST_F(TestObTimeWheel, test_tw_highcurrency_schedule_cancel)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTask::clear_total_run_count();
 | |
|   ObSampleTimer *ob_sample_timer = new ObSampleTimer();
 | |
|   ASSERT_TRUE(NULL != ob_sample_timer);
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->init(1000, NumTask::TW_THREAD_NUM, "test"));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->start());
 | |
| 
 | |
|   pthread_attr_t attr;
 | |
|   pthread_attr_init(&attr);
 | |
|   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
 | |
|   pthread_t tids[NumTask::THREAD_NUM];
 | |
| 
 | |
|   // create para and init
 | |
|   InputParas *in_para = new InputParas();
 | |
|   in_para->tw_ = ob_sample_timer;
 | |
|   in_para->task_num_ = NumTask::HIGH_CURRENCY_NUM_TASK;
 | |
|   in_para->task_delay_ = 12000000;
 | |
| 
 | |
|   for (int64_t i = 0; i < NumTask::THREAD_NUM; i++) {
 | |
|     EXPECT_TRUE(pthread_create(&tids[i], &attr, MyThread::create_task, static_cast<void *>(in_para)) == 0);
 | |
|   }
 | |
|   void *tmp[NumTask::THREAD_NUM];
 | |
|   for (int64_t i = 0; i < NumTask::THREAD_NUM; i++) {
 | |
|     EXPECT_EQ(0, pthread_join(tids[i], &tmp[i]));
 | |
|   }
 | |
|   int64_t start = 0;
 | |
|   int64_t end = 0;
 | |
|   start = ObClockGenerator::getClock();
 | |
|   for (int64_t i = 0; i < NumTask::THREAD_NUM; i++) {
 | |
|     OutputParas *out_para = static_cast<OutputParas *>(tmp[i]);
 | |
|     ASSERT_TRUE(NULL != out_para);
 | |
|     for (int64_t j = 0; j < in_para->task_num_; j++) {
 | |
|       ASSERT_TRUE(NULL != out_para->task_arr_[j]);
 | |
|       ob_sample_timer->cancel(out_para->task_arr_[j]);
 | |
|     }
 | |
|     delete out_para;
 | |
|     out_para = NULL;
 | |
|   }
 | |
|   end = ObClockGenerator::getClock();
 | |
|   TRANS_LOG(WARN, "", "used", end - start);
 | |
|   EXPECT_EQ(0, ObSampleTask::get_total_run_count());
 | |
| 
 | |
|   delete in_para;
 | |
|   in_para = NULL;
 | |
|   ObSampleTask::clear_total_run_count();
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->stop());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->wait());
 | |
|   delete ob_sample_timer;
 | |
|   ob_sample_timer = NULL;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| // purpose: test whether there are bugs after/before executing tasks
 | |
| // steps: (a special case is as follows)
 | |
| // (1) Create 100,000 tasks in main thread, and use the same timer to schedule these tasks in threads A, B, C, D and E,
 | |
| //     where A is responsible for the first 20,000 tasks, B the next 20,000 tasks, ....
 | |
| //     All tasks' delay is set to [5s, 6s]
 | |
| // (2) Threads F, G, H, I and J start to cancel the corresponding tasks after main thread sleeps 5s
 | |
| #ifdef TEST_TW_HIGHCURRENCY_SCHEDULE_CANCEL_RANDOM
 | |
| TEST_F(TestObTimeWheel, test_tw_high_concurrency_run_cancel)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   // 1 schedule thread and 1 cancel thread, each thread schedules 1,000 tasks
 | |
|   // sleep time is set to 1s
 | |
|   MyThread::schedule_run(1, 1000, 1000);
 | |
|   // 2 schedule thread and 2 cancel thread, each thread schedules 10,000 tasks
 | |
|   // sleep time is set to 2s
 | |
|   MyThread::schedule_run(2, 10000, 2000);
 | |
|   // 4 schedule thread and 4 cancel thread, each thread schedules 100,000 tasks
 | |
|   // sleep time is set to 3s
 | |
|   MyThread::schedule_run(4, 100 * 1000, 3000);
 | |
|   // 6 schedule thread and 6 cancel thread, each thread schedules 1,000,000 tasks
 | |
|   // sleep time is set to 4s
 | |
|   MyThread::schedule_run(6, 1000 * 1000, 4000 );
 | |
|   // 8 schedule thread and 8 cancel thread, each thread schedules 10,000,000 tasks
 | |
|   // sleep time is set to 4s
 | |
|   MyThread::schedule_run(8, 10 * 1000 * 1000, 4000);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| // when the task will run, cancel it.
 | |
| // this case is to test the availablity of lock between run and cancel thread.
 | |
| #ifdef TEST_TW_LOCK_AVAILABLITY
 | |
| TEST_F(TestObTimeWheel, test_tw_lock_availablity)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTimer *ob_sample_timer = new ObSampleTimer();
 | |
|   ASSERT_TRUE(NULL != ob_sample_timer);
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->init(1000, NumTask::TW_THREAD_NUM, "test"));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->start());
 | |
| 
 | |
|   pthread_attr_t attr;
 | |
|   pthread_attr_init(&attr);
 | |
|   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
 | |
| 
 | |
|   // create and init the paras
 | |
|   InputParas *in_para = new InputParas();
 | |
|   in_para->tw_ = ob_sample_timer;
 | |
|   in_para->task_num_ = NumTask::HIGH_CURRENCY_LOCK_NUM_TASK;
 | |
|   in_para->task_delay_ = 1500000;
 | |
| 
 | |
|   for (int64_t i = 0; i < NumTask::HIGH_CURRENCY_LOCK_TEST_COUNT; i++) {
 | |
|     // create a pthread
 | |
|     pthread_t tid = 0;
 | |
|     EXPECT_TRUE(pthread_create(&tid, &attr, MyThread::create_task, static_cast<void *>(in_para)) == 0);
 | |
| 
 | |
|     ObClockGenerator::msleep(1450);
 | |
|     void *tmp = NULL;
 | |
|     EXPECT_EQ(0, pthread_join(tid, &tmp));
 | |
|     OutputParas *out_para = static_cast<OutputParas *>(tmp);
 | |
|     ASSERT_TRUE(NULL != out_para);
 | |
| 
 | |
|     for (int i = 0; i < out_para->valid_task_count_; i++) {
 | |
|       ASSERT_TRUE(NULL != out_para->task_arr_[i]);
 | |
|       ob_sample_timer->cancel(out_para->task_arr_[i]);
 | |
|       EXPECT_TRUE(false == (out_para->task_arr_[i])->is_run_over());
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   delete in_para;
 | |
|   in_para = NULL;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->stop());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->wait());
 | |
|   delete ob_sample_timer;
 | |
|   ob_sample_timer = NULL;
 | |
| }
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| //-------------------------------boundary test-----------------------------------------
 | |
| // boundary test are as follows
 | |
| // test the time wheel which wasn't inited before used.
 | |
| 
 | |
| #ifdef EDGE_TEST
 | |
| 
 | |
| #ifdef TEST_TIMEWHEELBASE_NO_INIT
 | |
| TEST_F(TestObTimeWheel, test_timewheel_base_init)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   TimeWheelBase tw_base;
 | |
|   // not init tw_base
 | |
|   EXPECT_EQ(OB_NOT_INIT, tw_base.start());
 | |
|   EXPECT_EQ(OB_NOT_INIT, tw_base.stop());
 | |
|   EXPECT_EQ(OB_NOT_INIT, tw_base.wait());
 | |
|   EXPECT_EQ(OB_NOT_INIT, tw_base.schedule(NULL, 1000));
 | |
|   EXPECT_EQ(OB_NOT_INIT, tw_base.cancel(NULL));
 | |
|   // after init, no start
 | |
|   EXPECT_EQ(OB_SUCCESS, tw_base.init(1000));
 | |
|   EXPECT_EQ(OB_ERR_UNEXPECTED, tw_base.stop());
 | |
|   EXPECT_EQ(OB_SUCCESS, tw_base.wait());
 | |
|   EXPECT_EQ(OB_ERR_UNEXPECTED, tw_base.schedule(NULL, 1000));
 | |
|   EXPECT_EQ(OB_INVALID_ARGUMENT, tw_base.cancel(NULL));
 | |
| 
 | |
|   EXPECT_EQ(OB_SUCCESS, tw_base.start());
 | |
|   EXPECT_EQ(OB_INVALID_ARGUMENT, tw_base.schedule(NULL, 1000));
 | |
|   EXPECT_EQ(OB_INVALID_ARGUMENT, tw_base.cancel(NULL));
 | |
| 
 | |
|   tw_base.destroy();
 | |
| }
 | |
| #endif
 | |
| // test the fucntions of time wheel
 | |
| #ifdef TEST_TIMEWHEEL_NO_INIT
 | |
| TEST_F(TestObTimeWheel, test_timewheel_no_init)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTimer ob_sample_timer;
 | |
|   ObSampleTask ob_sample_task;
 | |
|   const static int64_t precision= 1000;
 | |
|   const static int64_t delay = 100000;
 | |
|   EXPECT_EQ(OB_NOT_INIT, ob_sample_timer.schedule(&ob_sample_task, precision));
 | |
|   EXPECT_EQ(OB_NOT_INIT, ob_sample_timer.start());
 | |
|   EXPECT_EQ(OB_NOT_INIT, ob_sample_timer.stop());
 | |
|   EXPECT_EQ(OB_NOT_INIT, ob_sample_timer.wait());
 | |
| 
 | |
|   EXPECT_EQ(OB_NOT_INIT, ob_sample_timer.schedule(&ob_sample_task, delay));
 | |
|   EXPECT_EQ(OB_NOT_INIT, ob_sample_timer.cancel(&ob_sample_task));
 | |
| }
 | |
| #endif
 | |
| // test the order of calling start, stop and wait
 | |
| #ifdef TEST_TIMEWHEEL_RUNNING
 | |
| TEST_F(TestObTimeWheel, test_timewheel_start_stop_wait)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTimer ob_sample_timer;
 | |
|   ObSampleTask ob_sample_task;
 | |
|   const static int64_t precision= 1000;
 | |
|   const static int64_t delay = 100000;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.init(precision, NumTask::TW_THREAD_NUM, "test"));
 | |
|   // call the functions schedule and cancle without calling start
 | |
|   EXPECT_EQ(OB_ERR_UNEXPECTED, ob_sample_timer.schedule(&ob_sample_task, delay));
 | |
|   EXPECT_EQ(OB_TIMER_TASK_HAS_NOT_SCHEDULED, ob_sample_timer.cancel(&ob_sample_task));
 | |
|   // call the functions stop/wait directly without calling start
 | |
|   EXPECT_EQ(OB_ERR_UNEXPECTED, ob_sample_timer.stop());
 | |
|   // call the function start repeatedly
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.start());
 | |
|   EXPECT_EQ(OB_ERR_UNEXPECTED, ob_sample_timer.start());
 | |
|   // call the fucntion wait without calling stop
 | |
|   EXPECT_EQ(OB_ERR_UNEXPECTED, ob_sample_timer.wait());
 | |
|   ob_sample_timer.destroy();
 | |
| }
 | |
| #endif
 | |
| // init the timewheel with invalid argument
 | |
| #ifdef TEST_TIMEWHEEL_INVALID_INIT
 | |
| TEST_F(TestObTimeWheel, test_timewheel_invalid_init)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTimer ob_sample_timer;
 | |
|   EXPECT_EQ(OB_INVALID_ARGUMENT, ob_sample_timer.init(-1, NumTask::TW_THREAD_NUM, "test"));
 | |
| }
 | |
| #endif
 | |
| // test the time wheel which was inited twice.
 | |
| #ifdef TEST_TIMEWHEEL_REPEAT_INIT
 | |
| TEST_F(TestObTimeWheel, test_timewheel_repeat_init)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTimer ob_sample_timer;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.init(1000, NumTask::TW_THREAD_NUM, "test"));
 | |
|   EXPECT_EQ(OB_INIT_TWICE, ob_sample_timer.init(1000, NumTask::TW_THREAD_NUM, "test"));
 | |
| }
 | |
| #endif
 | |
| // destroy the time wheel twice
 | |
| #ifdef TEST_TIMEWHEEL_REPEAT_DES
 | |
| TEST_F(TestObTimeWheel, test_timewheel_repeat_des)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTimer ob_sample_timer;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.init(1000, NumTask::TW_THREAD_NUM, "test"));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.start());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.stop());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.wait());
 | |
|   ob_sample_timer.destroy();
 | |
|   ob_sample_timer.destroy();
 | |
| }
 | |
| #endif
 | |
| // schedule the task after having destroy time wheel
 | |
| #ifdef TEST_TIMEWHEEL_SCHEDULE_AFTER_DES
 | |
| TEST_F(TestObTimeWheel, test_timewheel_schedule_after_des)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTimer ob_sample_timer;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.init(1000, NumTask::TW_THREAD_NUM, "test"));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.start());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.stop());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.wait());
 | |
|   ob_sample_timer.destroy();
 | |
| 
 | |
|   ObSampleTask ob_sample_task;
 | |
|   EXPECT_EQ(OB_NOT_INIT, ob_sample_timer.schedule(&ob_sample_task, 1000));
 | |
| }
 | |
| #endif
 | |
| // schedule the task which has invalid argument
 | |
| #ifdef TEST_TIMEWHEEL_INVALID_TASK_SCHEDULE
 | |
| TEST_F(TestObTimeWheel, test_timewheel_invalid_task_schedule)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTimer ob_sample_timer;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.init(1000, NumTask::TW_THREAD_NUM, "test"));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.start());
 | |
| 
 | |
|   ObSampleTask *ob_sample_task = NULL;
 | |
|   EXPECT_EQ(OB_INVALID_ARGUMENT, ob_sample_timer.schedule(ob_sample_task, 1000));
 | |
|   ob_sample_task = new ObSampleTask();
 | |
|   EXPECT_EQ(OB_INVALID_ARGUMENT, ob_sample_timer.schedule(ob_sample_task, -1));
 | |
| 
 | |
|   delete ob_sample_task;
 | |
|   ob_sample_task = NULL;
 | |
| }
 | |
| #endif
 | |
| // schedule the task twice
 | |
| #ifdef TEST_TIMEWHEEL_REPEAT_SCHEDULE
 | |
| TEST_F(TestObTimeWheel, test_timewheel_repeat_schedule)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTimer ob_sample_timer;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.init(1000, NumTask::TW_THREAD_NUM, "test"));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.start());
 | |
| 
 | |
|   ObSampleTask ob_sample_task;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.schedule(&ob_sample_task, 100000));
 | |
|   EXPECT_EQ(OB_TIMER_TASK_HAS_SCHEDULED, ob_sample_timer.schedule(&ob_sample_task, 1000));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.stop());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.wait());
 | |
| }
 | |
| #endif
 | |
| 
 | |
| // cancel the same task for several times
 | |
| #ifdef TEST_TIMEWHEEL_REPEAT_CANCEL
 | |
| TEST_F(TestObTimeWheel, test_timewheel_repeat_cancel)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTimer ob_sample_timer;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.init(1000, NumTask::TW_THREAD_NUM, "test"));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.start());
 | |
| 
 | |
|   ObSampleTask ob_sample_task;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.schedule(&ob_sample_task, 1000));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.cancel(&ob_sample_task));
 | |
|   EXPECT_EQ(OB_TIMER_TASK_HAS_NOT_SCHEDULED, ob_sample_timer.cancel(&ob_sample_task));
 | |
|   ObSampleTask *task = NULL;
 | |
|   EXPECT_EQ(OB_INVALID_ARGUMENT, ob_sample_timer.cancel(task));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.stop());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.wait());
 | |
| }
 | |
| #endif
 | |
| 
 | |
| // repeat the process "schedule->cancel" for several times
 | |
| #ifdef TEST_TIMEWHEEL_REPEAT_SCHEDULE_CANCEL
 | |
| TEST_F(TestObTimeWheel, test_timewheel_repeat_schedule_cancel)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTimer *ob_sample_timer = new ObSampleTimer();
 | |
|   ASSERT_TRUE(NULL != ob_sample_timer);
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->init(1000, NumTask::TW_THREAD_NUM, "test"));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->start());
 | |
|   ObSampleTask ob_sample_task;
 | |
|   for (int64_t i = 0; i < 1000000; i++) {
 | |
|     // the delay time should great and equal to 1000us.
 | |
|     EXPECT_EQ(OB_SUCCESS, ob_sample_timer->schedule(&ob_sample_task, 100000));
 | |
|     EXPECT_TRUE(!ob_sample_task.is_run_over());
 | |
|     EXPECT_EQ(OB_SUCCESS, ob_sample_timer->cancel(&ob_sample_task));
 | |
|   }
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->stop());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer->wait());
 | |
|   delete ob_sample_timer;
 | |
|   ob_sample_timer = NULL;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| // schedule self for 100 times
 | |
| #ifdef TEST_TIMEWHEEL_SCHEDULE_SELF
 | |
| TEST_F(TestObTimeWheel, test_timewheel_schedule_self)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTimer ob_sample_timer;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.init(1000, NumTask::TW_THREAD_NUM, "test"));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.start());
 | |
| 
 | |
|   ObSampleTask2 ob_sample_task;
 | |
|   ob_sample_task.set_time_wheel(&ob_sample_timer);
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.schedule(&ob_sample_task, 100000));
 | |
| 
 | |
|   ObClockGenerator::msleep(15000);
 | |
|   EXPECT_EQ(100, ob_sample_task.get_retry_time());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.stop());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.wait());
 | |
| }
 | |
| #endif
 | |
| 
 | |
| // cancel the task which has been executed.
 | |
| #ifdef TEST_TIMEWHEEL_CANCEL_RUNOVER_TASK
 | |
| TEST_F(TestObTimeWheel, test_timewheel_cancel_runover_task)
 | |
| {
 | |
|   TRANS_LOG(INFO, "called", "func", test_info_->name());
 | |
|   ObSampleTimer ob_sample_timer;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.init(1000, NumTask::TW_THREAD_NUM, "test"));
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.start());
 | |
| 
 | |
|   ObSampleTask ob_sample_task;
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.schedule(&ob_sample_task, 100000));
 | |
| 
 | |
|   ObClockGenerator::msleep(1000);
 | |
|   EXPECT_TRUE(true ==  ob_sample_task.is_run_over());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.stop());
 | |
|   EXPECT_EQ(OB_SUCCESS, ob_sample_timer.wait());
 | |
| }
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| }//end of unittest
 | |
| }//end of oceanbase
 | |
| 
 | |
| using namespace oceanbase;
 | |
| using namespace oceanbase::common;
 | |
| 
 | |
| int main(int argc, char **argv)
 | |
| {
 | |
|   int ret = 1;
 | |
|   ObLogger &logger = ObLogger::get_logger();
 | |
|   logger.set_file_name("test_ob_time_wheel.log", true);
 | |
|   logger.set_log_level(OB_LOG_LEVEL_INFO);
 | |
|     TRANS_LOG(WARN, "init memory pool error!");
 | |
|   } else if (OB_SUCCESS != (ret = ObClockGenerator::init())) {
 | |
|     TRANS_LOG(WARN, "init ObClockGenerator error!");
 | |
|   } else {
 | |
|     testing::InitGoogleTest(&argc, argv);
 | |
|     ret = RUN_ALL_TESTS();
 | |
|   }
 | |
|   return ret;
 | |
| }
 | 
