599 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			599 lines
		
	
	
		
			16 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 <gtest/gtest.h>
 | |
| #include <vector>
 | |
| #include <algorithm>
 | |
| 
 | |
| //#include "lib/oblog/ob_log_module.h"
 | |
| #include "share/ob_define.h"
 | |
| #include "storage/ob_storage_log_type.h"
 | |
| #include "storage/transaction/ob_trans_log.h"
 | |
| 
 | |
| #include "obcdc/src/ob_log_instance.h"
 | |
| #include "ob_log_stream_worker.h"
 | |
| #define private public
 | |
| #include "ob_log_rpc.h"
 | |
| #include "ob_log_utils.h"
 | |
| #include "ob_log_systable_helper.h"
 | |
| 
 | |
| //#include "ob_log_part_fetch_ctx.h"
 | |
| //#include "ob_log_fetcher_stream.h"
 | |
| 
 | |
| using namespace oceanbase;
 | |
| using namespace common;
 | |
| using namespace liboblog;
 | |
| using namespace transaction;
 | |
| using namespace storage;
 | |
| //using namespace clog;
 | |
| //using namespace fetcher;
 | |
| 
 | |
| namespace oceanbase
 | |
| {
 | |
| namespace unittest
 | |
| {
 | |
| 
 | |
| /*
 | |
|  * Utils.
 | |
|  */
 | |
| typedef std::vector<ObAddr> Svrs;
 | |
| typedef std::vector<ObPartitionKey> PKeys;
 | |
| typedef std::vector<uint64_t> LogIds;
 | |
| typedef std::vector<int64_t> Tstamps;
 | |
| 
 | |
| class MockFetcherErrHandler1 : public IObLogErrHandler
 | |
| {
 | |
| public:
 | |
|   virtual ~MockFetcherErrHandler1() { }
 | |
| public:
 | |
|   virtual void handle_error(const int err_no, const char *fmt, ...)
 | |
|   {
 | |
|     UNUSED(err_no);
 | |
|     va_list ap;
 | |
|     va_start(ap, fmt);
 | |
|     //__E__(fmt, ap);
 | |
| 		//LOG_ERROR("test", fmt, ap);
 | |
|     va_end(ap);
 | |
|     abort();
 | |
|   }
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * SvrFinder
 | |
|  *
 | |
|  */
 | |
| static const int64_t ALL_SERVER_COUNT   = 100;
 | |
| 
 | |
| static const int64_t QUERY_CLOG_HISTORY_VALID_COUNT   = 10;
 | |
| static const int64_t QUERY_CLOG_HISTORY_INVALID_COUNT = 5;
 | |
| static const int64_t QUERY_META_INFO_ADD_COUNT        = 6;
 | |
| 
 | |
| static const int64_t SVR_FINDER_REQ_NUM    = 10 * 1000;
 | |
| static const int64_t LEADER_FINDER_REQ_NUM = 10 * 1000;
 | |
| 
 | |
| // Construct a request server to initiate asynchronous requests
 | |
| // request server: query clog/query meta
 | |
| // Request leader:
 | |
| class MockSysTableHelperBase: public IObLogSysTableHelper
 | |
| {
 | |
| public:
 | |
| 	MockSysTableHelperBase() {}
 | |
| 	virtual ~MockSysTableHelperBase() {}
 | |
| 
 | |
| public:
 | |
|   /// Query __all_clog_history_info_v2 based on log_id to get all servers with service log IDs greater than or equal to log_id logs
 | |
| 	/// Returns two types of logs: one for servers in the _all_server table, and one for servers not in the _all_server table
 | |
|   virtual int query_clog_history_by_log_id(
 | |
|     const common::ObPartitionKey &pkey,
 | |
|     const uint64_t log_id,
 | |
|     ClogHistoryRecordArray &records)
 | |
| 	{
 | |
|     // Generate random results.
 | |
|     int ret = OB_SUCCESS;
 | |
| 
 | |
| 		UNUSED(pkey);
 | |
|     records.reset();
 | |
|     ClogHistoryRecord rec;
 | |
| 
 | |
|     int64_t valid_seed = static_cast<int64_t>(pkey.table_id_);
 | |
|     int64_t invalid_seed = ALL_SERVER_COUNT;
 | |
| 		int64_t cnt = QUERY_CLOG_HISTORY_VALID_COUNT + QUERY_CLOG_HISTORY_INVALID_COUNT;
 | |
| 
 | |
| 		for (int64_t idx = 0; idx < cnt; idx++) {
 | |
|       rec.reset();
 | |
|       rec.start_log_id_ = log_id;
 | |
|       rec.end_log_id_ = log_id + 10000;
 | |
| 			if (idx < QUERY_CLOG_HISTORY_VALID_COUNT) {
 | |
| 				// Insert QUERY_CLOG_HISTORY_VALID_COUNT a valid record
 | |
| 	snprintf(rec.svr_ip_, common::MAX_IP_ADDR_LENGTH + 1,
 | |
| 						     "127.0.0.%ld", valid_seed % ALL_SERVER_COUNT);
 | |
| 				valid_seed++;
 | |
| 			} else {
 | |
| 				// Insert QUERY_CLOG_HISTORY_INVALID_COUNT an invalid record
 | |
| 	snprintf(rec.svr_ip_, common::MAX_IP_ADDR_LENGTH + 1, "127.0.0.%ld", invalid_seed);
 | |
| 				invalid_seed++;
 | |
| 			}
 | |
|       rec.svr_port_ = 8888;
 | |
| 
 | |
|       records.push_back(rec);
 | |
| 		}
 | |
| 
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
|   /// Query __all_clog_history_info_v2 for all servers with timestamp greater than or equal to timestamp log based on timestamp
 | |
|   virtual int query_clog_history_by_tstamp(
 | |
|     const common::ObPartitionKey &pkey,
 | |
|     const int64_t timestamp,
 | |
|     ClogHistoryRecordArray &records)
 | |
| 	{
 | |
|     // Generate random results.
 | |
|     int ret = OB_SUCCESS;
 | |
| 
 | |
| 		UNUSED(timestamp);
 | |
| 
 | |
|     records.reset();
 | |
|     ClogHistoryRecord rec;
 | |
| 
 | |
|     int64_t valid_seed = static_cast<int64_t>(pkey.table_id_);
 | |
|     int64_t invalid_seed = ALL_SERVER_COUNT;
 | |
| 		int64_t cnt = QUERY_CLOG_HISTORY_VALID_COUNT + QUERY_CLOG_HISTORY_INVALID_COUNT;
 | |
| 
 | |
| 		for (int64_t idx = 0; idx < cnt; idx++) {
 | |
|       rec.reset();
 | |
|       rec.start_log_id_ = 0;
 | |
|       rec.end_log_id_ = 65536;
 | |
| 			if (idx < QUERY_CLOG_HISTORY_VALID_COUNT) {
 | |
| 				// Insert QUERY_CLOG_HISTORY_VALID_COUNT a valid record
 | |
| 	snprintf(rec.svr_ip_, common::MAX_IP_ADDR_LENGTH + 1,
 | |
| 						     "127.0.0.%ld", valid_seed % ALL_SERVER_COUNT);
 | |
| 				valid_seed++;
 | |
| 			} else {
 | |
| 				// Insert QUERY_CLOG_HISTORY_INVALID_COUNT an invalid record
 | |
| 	snprintf(rec.svr_ip_, common::MAX_IP_ADDR_LENGTH + 1, "127.0.0.%ld", invalid_seed);
 | |
| 				invalid_seed++;
 | |
| 			}
 | |
|       rec.svr_port_ = 8888;
 | |
| 
 | |
|       records.push_back(rec);
 | |
| 		}
 | |
| 
 | |
|     return ret;
 | |
| 	}
 | |
| 
 | |
|   /// Query __all_meta_table / __all_root_table to get information about the servers that are serving the partition
 | |
| 	// Add records: return a batch of servers to add to query_clog_history, add only those servers for which clog history does not exist
 | |
|   virtual int query_meta_info(
 | |
|     const common::ObPartitionKey &pkey,
 | |
|     MetaRecordArray &records)
 | |
| 	{
 | |
|     // Generate random results.
 | |
|     int ret = OB_SUCCESS;
 | |
| 
 | |
| 		UNUSED(pkey);
 | |
|     records.reset();
 | |
| 		MetaRecord rec;
 | |
| 
 | |
|     int64_t seed = static_cast<int64_t>(pkey.table_id_);
 | |
| 		int64_t cnt = QUERY_CLOG_HISTORY_VALID_COUNT + QUERY_META_INFO_ADD_COUNT;
 | |
| 
 | |
| 		for (int64_t idx = 0; idx < cnt; idx++) {
 | |
|       rec.reset();
 | |
| 			if (idx < QUERY_CLOG_HISTORY_VALID_COUNT) {
 | |
| 				// Returns the same server as query_clog_history
 | |
| 	snprintf(rec.svr_ip_, common::MAX_IP_ADDR_LENGTH + 1,
 | |
| 						     "127.0.0.%ld", seed % ALL_SERVER_COUNT);
 | |
| 			} else {
 | |
| 				// Return QUERY_META_INFO_ADD_COUNT additional records
 | |
| 	snprintf(rec.svr_ip_, common::MAX_IP_ADDR_LENGTH + 1,
 | |
| 						     "127.0.0.%ld", seed % ALL_SERVER_COUNT);
 | |
| 			}
 | |
|       rec.svr_port_ = 8888;
 | |
|       rec.replica_type_ = REPLICA_TYPE_FULL;
 | |
| 			seed++;
 | |
| 
 | |
|       records.push_back(rec);
 | |
| 		}
 | |
| 
 | |
|     return ret;
 | |
| 	}
 | |
| 
 | |
|   // Query __all_meta_table / __all_root_table for leader information
 | |
|   virtual int query_leader_info(
 | |
|     const common::ObPartitionKey &pkey,
 | |
|     bool &has_leader,
 | |
|     common::ObAddr &leader)
 | |
| 	{
 | |
| 		int ret = OB_SUCCESS;
 | |
| 
 | |
| 		UNUSED(pkey);
 | |
|     has_leader = true;
 | |
|     leader.set_ip_addr("127.0.0.1", 8888);
 | |
| 
 | |
|     return ret;
 | |
| 	}
 | |
| 
 | |
|   /// Query __all_server table for all active server information
 | |
|   virtual int query_all_server_info(AllServerRecordArray &records)
 | |
| 	{
 | |
| 	  int ret = OB_SUCCESS;
 | |
| 
 | |
| 		UNUSED(records);
 | |
| 
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
|   virtual int query_all_zone_info(AllZoneRecordArray &records)
 | |
|   {
 | |
| 		UNUSED(records);
 | |
| 
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   virtual int query_cluster_info(ClusterInfo &cluster_info)
 | |
|   {
 | |
| 		UNUSED(cluster_info);
 | |
| 
 | |
|     return 0;
 | |
|   }
 | |
| };
 | |
| 
 | |
| class MockSysTableHelperDerive1 : public MockSysTableHelperBase
 | |
| {
 | |
| public:
 | |
| 	MockSysTableHelperDerive1() {}
 | |
| 	virtual ~MockSysTableHelperDerive1() {}
 | |
| 
 | |
| public:
 | |
|   /// Query the __all_server table to get all active server information
 | |
|   /// The _all_server table has 100 servers in the range 127.0.0.1:8888 ~ 127.0.0.99:8888
 | |
|   virtual int query_all_server_info(AllServerRecordArray &records)
 | |
| 	{
 | |
| 	  int ret = OB_SUCCESS;
 | |
| 
 | |
| 		int64_t seed = 0;
 | |
| 		AllServerRecord rec;
 | |
| 		for(int64_t idx = 0; idx < ALL_SERVER_COUNT; idx++) {
 | |
|       rec.reset();
 | |
|       snprintf(rec.svr_ip_, common::MAX_IP_ADDR_LENGTH + 1, "127.0.0.%ld", seed);
 | |
|       rec.svr_port_ = 8888;
 | |
| 			rec.status_ = share::ObServerStatus::DisplayStatus::OB_SERVER_ACTIVE;
 | |
|       records.push_back(rec);
 | |
| 			seed++;
 | |
| 		}
 | |
| 
 | |
| 		return ret;
 | |
| 	}
 | |
| };
 | |
| 
 | |
| class MockSysTableHelperDerive2 : public MockSysTableHelperBase
 | |
| {
 | |
| public:
 | |
| 	MockSysTableHelperDerive2() {}
 | |
| 	virtual ~MockSysTableHelperDerive2() {}
 | |
| 
 | |
| public:
 | |
|   /// Query the __all_server table to get all active server information
 | |
|   /// The _all_server table has 100 servers in the range of 127.0.0.1:8888 ~ 127.0.0.20:8888
 | |
| 	// 1. 50 of them are ACTIVE
 | |
| 	// 2. 50 of them are INACTIVE
 | |
|   virtual int query_all_server_info(AllServerRecordArray &records)
 | |
| 	{
 | |
| 	  int ret = OB_SUCCESS;
 | |
| 
 | |
| 		int64_t seed = 0;
 | |
| 		AllServerRecord rec;
 | |
| 		for(int64_t idx = 0; idx < ALL_SERVER_COUNT; idx++) {
 | |
|       rec.reset();
 | |
|       snprintf(rec.svr_ip_, common::MAX_IP_ADDR_LENGTH + 1, "127.0.0.%ld", seed);
 | |
|       rec.svr_port_ = 8888;
 | |
| 			if (0 == (idx & 0x01)) {
 | |
| 				rec.status_ = share::ObServerStatus::DisplayStatus::OB_SERVER_ACTIVE;
 | |
| 			} else {
 | |
| 				rec.status_ = share::ObServerStatus::DisplayStatus::OB_SERVER_INACTIVE;
 | |
| 			}
 | |
| 
 | |
|       records.push_back(rec);
 | |
| 			seed++;
 | |
| 		}
 | |
| 
 | |
| 		return ret;
 | |
| 	}
 | |
| };
 | |
| 
 | |
| class MockObLogRpcBase : public IObLogRpc
 | |
| {
 | |
| public:
 | |
| 	MockObLogRpcBase() {}
 | |
|   virtual ~MockObLogRpcBase() { }
 | |
| 
 | |
|   // Request start log id based on timestamp
 | |
|   virtual int req_start_log_id_by_tstamp(const common::ObAddr &svr,
 | |
|       const obrpc::ObLogReqStartLogIdByTsRequestWithBreakpoint& req,
 | |
|       obrpc::ObLogReqStartLogIdByTsResponseWithBreakpoint& res,
 | |
|       const int64_t timeout)
 | |
|   {
 | |
| 	  int ret = OB_SUCCESS;
 | |
| 		UNUSED(svr);
 | |
| 		UNUSED(req);
 | |
| 		UNUSED(res);
 | |
| 		UNUSED(timeout);
 | |
| 
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
|   // Request Leader Heartbeat
 | |
|   virtual int req_leader_heartbeat(const common::ObAddr &svr,
 | |
|       const obrpc::ObLogLeaderHeartbeatReq &req,
 | |
|       obrpc::ObLogLeaderHeartbeatResp &res,
 | |
|       const int64_t timeout)
 | |
|   {
 | |
| 	  int ret = OB_SUCCESS;
 | |
| 		UNUSED(svr);
 | |
| 		UNUSED(req);
 | |
| 		UNUSED(res);
 | |
| 		UNUSED(timeout);
 | |
| 
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
|   // Open a new stream
 | |
|   // Synchronous RPC
 | |
|   virtual int open_stream(const common::ObAddr &svr,
 | |
|       const obrpc::ObLogOpenStreamReq &req,
 | |
|       obrpc::ObLogOpenStreamResp &resp,
 | |
|       const int64_t timeout)
 | |
|   {
 | |
| 	  int ret = OB_SUCCESS;
 | |
| 		UNUSED(svr);
 | |
| 		UNUSED(req);
 | |
| 		UNUSED(resp);
 | |
| 		UNUSED(timeout);
 | |
| 
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
|   // Stream based, get logs
 | |
|   // Asynchronous RPC
 | |
|   virtual int async_stream_fetch_log(const common::ObAddr &svr,
 | |
|       const obrpc::ObLogStreamFetchLogReq &req,
 | |
|       obrpc::ObLogExternalProxy::AsyncCB<obrpc::OB_LOG_STREAM_FETCH_LOG> &cb,
 | |
|       const int64_t timeout)
 | |
|   {
 | |
| 	  int ret = OB_SUCCESS;
 | |
| 		UNUSED(svr);
 | |
| 		UNUSED(req);
 | |
| 		UNUSED(cb);
 | |
| 		UNUSED(timeout);
 | |
| 
 | |
| 		return ret;
 | |
| 	}
 | |
| };
 | |
| 
 | |
| class MockObLogStartLogIdRpc : public MockObLogRpcBase
 | |
| {
 | |
|   typedef const obrpc::ObLogReqStartLogIdByTsRequestWithBreakpoint::Param Param;
 | |
|   typedef const obrpc::ObLogReqStartLogIdByTsRequestWithBreakpoint::ParamArray ParamArray;
 | |
| public:
 | |
| 	MockObLogStartLogIdRpc() :
 | |
|       spec_err_(false),
 | |
|       svr_err_(OB_SUCCESS),
 | |
|       part_err_(OB_SUCCESS)
 | |
|   {}
 | |
|   virtual ~MockObLogStartLogIdRpc() { }
 | |
| 
 | |
|   void set_err(const int svr_err, const int part_err)
 | |
|   {
 | |
|     svr_err_ = svr_err;
 | |
|     part_err_ = part_err;
 | |
|     spec_err_ = true;
 | |
|   }
 | |
| 
 | |
|   // Request start log id based on timestamp
 | |
| 	// 1. rpc always assumes success
 | |
| 	// 2. 10% chance of server internal error
 | |
| 	// 3. 30% probability that partition returns success (30%) when server succeeds,
 | |
| 	// 30% probability that start_log_id returns pkey-table_id with breakpoint information
 | |
|   // 4. Support for external error codes
 | |
|   virtual int req_start_log_id_by_tstamp(const common::ObAddr &svr,
 | |
|       const obrpc::ObLogReqStartLogIdByTsRequestWithBreakpoint& req,
 | |
|       obrpc::ObLogReqStartLogIdByTsResponseWithBreakpoint& res,
 | |
|       const int64_t timeout)
 | |
|   {
 | |
| 	  int ret = OB_SUCCESS;
 | |
| 		UNUSED(svr);
 | |
| 		UNUSED(timeout);
 | |
| 
 | |
| 		res.reset();
 | |
|     // Seed.
 | |
|     int64_t seed = (get_timestamp());
 | |
| 		int64_t rand = (seed) % 100;
 | |
|     bool svr_internal_err = (rand < 10);
 | |
| 
 | |
|     // Preferred use of the specified error code
 | |
|     if (spec_err_) {
 | |
|       res.set_err(svr_err_);
 | |
|     } else if (svr_internal_err) {
 | |
| 		  res.set_err(OB_ERR_UNEXPECTED);
 | |
|     }
 | |
| 
 | |
|     if (OB_SUCCESS == res.get_err()) {
 | |
|       ParamArray ¶m_array = req.get_params();
 | |
| 	for (int64_t idx = 0, cnt = param_array.count(); idx < cnt; ++idx) {
 | |
|         Param ¶m = param_array[idx];
 | |
| 	obrpc::ObLogReqStartLogIdByTsResponseWithBreakpoint::Result result;
 | |
| 	result.reset();
 | |
| 	result.start_log_id_ = param.pkey_.table_id_;
 | |
| 
 | |
|         if (spec_err_) {
 | |
|           result.err_ = part_err_;
 | |
|         } else {
 | |
|           // 30% success, 30% break.
 | |
|           rand = (idx + seed) % 100;
 | |
|           bool succeed = (rand < 30);
 | |
|           bool breakrpc = (30 <= rand) && (rand < 60);
 | |
|           result.err_ = (succeed) ? OB_SUCCESS : ((breakrpc) ? OB_EXT_HANDLE_UNFINISH : OB_NEED_RETRY);
 | |
|         }
 | |
| 
 | |
| 	// Break info is actually not returned.
 | |
| 	EXPECT_EQ(OB_SUCCESS, res.append_result(result));
 | |
| 	}
 | |
| 		}
 | |
| 
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| private:
 | |
|   bool spec_err_;
 | |
|   int svr_err_;
 | |
|   int part_err_;
 | |
| };
 | |
| 
 | |
| class MockObLogRpcDerived2 : public MockObLogRpcBase
 | |
| {
 | |
|   typedef obrpc::ObLogReqStartLogIdByTsRequestWithBreakpoint Req;
 | |
|   typedef Req::Param Param;
 | |
|   typedef Req::ParamArray ParamArray;
 | |
| public:
 | |
| 	MockObLogRpcDerived2() : request_(NULL),
 | |
| 	                         start_pos_(0),
 | |
|                            end_pos_(0),
 | |
| 	                         query_time_(0) {}
 | |
| 
 | |
|   virtual ~MockObLogRpcDerived2() {}
 | |
| 
 | |
| 	int init(int64_t req_cnt)
 | |
| 	{
 | |
| 		int ret = OB_SUCCESS;
 | |
| 
 | |
| 		if (OB_UNLIKELY(req_cnt <= 0)) {
 | |
| 			//LOG_ERROR("invalid_argument");
 | |
| 			ret = OB_INVALID_ARGUMENT;
 | |
| 		} else {
 | |
| 			request_ = new Req;
 | |
| 			request_->reset();
 | |
| 			start_pos_ = 0;
 | |
| 			end_pos_ = req_cnt - 1;
 | |
| 			query_time_ = 1;
 | |
| 		}
 | |
| 
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	void destroy()
 | |
| 	{
 | |
| 		delete request_;
 | |
| 		start_pos_ = 0;
 | |
| 		end_pos_ = 0;
 | |
| 		query_time_ = 1;
 | |
| 	}
 | |
| 
 | |
|   // Request start log id based on timestamp
 | |
| 	// 1. rpc always assumes success, and no server internal error
 | |
| 	// 2. Each time the second half returns succ and the first half returns break info
 | |
|   virtual int req_start_log_id_by_tstamp(const common::ObAddr &svr,
 | |
|       const obrpc::ObLogReqStartLogIdByTsRequestWithBreakpoint& req,
 | |
|       obrpc::ObLogReqStartLogIdByTsResponseWithBreakpoint& res,
 | |
|       const int64_t timeout)
 | |
|   {
 | |
| 	  int ret = OB_SUCCESS;
 | |
| 		UNUSED(svr);
 | |
| 		UNUSED(timeout);
 | |
| 
 | |
| 		res.reset();
 | |
| 		int64_t mid_index = (end_pos_ - start_pos_ + 1) / 2;
 | |
| 		const ParamArray ¶m_array = req.get_params();
 | |
| 
 | |
| 		if (1 == query_time_) {
 | |
|             // No validation is required for the first query
 | |
|             // Save the request parameters
 | |
| 			for (int64_t idx = 0, cnt = param_array.count(); idx < cnt; ++idx) {
 | |
| 				const Param ¶m = param_array[idx];
 | |
| 	Param add_param;
 | |
| 	add_param.reset(param.pkey_, param.start_tstamp_, param.break_info_);
 | |
| 
 | |
| 	if (OB_FAIL(request_->append_param(add_param))) {
 | |
|           //LOG_ERROR("append param fail", K(ret), K(idx), K(add_param));
 | |
| 				}
 | |
| 			}
 | |
| 		} else {
 | |
| 			// Verify that it is the original request
 | |
| 			is_original_req(&req, start_pos_, end_pos_);
 | |
| 		}
 | |
| 
 | |
| 		for (int64_t idx = 0, cnt = param_array.count(); idx < cnt; ++idx) {
 | |
| 			const Param ¶m = param_array[idx];
 | |
| 			obrpc::ObLogReqStartLogIdByTsResponseWithBreakpoint::Result result;
 | |
| 
 | |
| 			if (idx < mid_index) {
 | |
| 				// First half returns break info
 | |
| 				result.reset();
 | |
| 				result.err_ = OB_EXT_HANDLE_UNFINISH;;
 | |
| 			  reset_break_info(result.break_info_, static_cast<uint32_t>(idx), idx + 100);
 | |
| 				result.start_log_id_ = OB_INVALID_ID;
 | |
| 
 | |
| 				// dynamically update the break info of the corresponding parameter of the saved requeset, for subsequent verification
 | |
|         Param &all_param = const_cast<Param &>(request_->params_[idx]);
 | |
| 			  reset_break_info(all_param.break_info_, static_cast<uint32_t>(idx), idx + 100);
 | |
| 			} else {
 | |
| 				// The second half returns success
 | |
| 				result.reset();
 | |
| 				result.err_ = OB_SUCCESS;
 | |
| 				result.start_log_id_ = param.pkey_.table_id_;
 | |
| 			}
 | |
| 		  EXPECT_EQ(OB_SUCCESS, res.append_result(result));
 | |
| 		}
 | |
| 		if (end_pos_ != 0) {
 | |
| 			end_pos_ = mid_index - 1;
 | |
| 		}
 | |
| 		query_time_++;
 | |
| 
 | |
| 		return ret;
 | |
| 	}
 | |
| private:
 | |
|   void is_original_req(const Req *cur_req, int64_t start_pos, int64_t end_pos)
 | |
| 	{
 | |
| 		ParamArray all_param_array = request_->get_params();
 | |
| 		ParamArray cur_param_array = cur_req->get_params();
 | |
| 
 | |
| 		for (int64_t idx = start_pos; idx <= end_pos; idx++) {
 | |
| 			Param all_param = all_param_array[idx];
 | |
| 			Param cur_param = cur_param_array[idx];
 | |
| 			// verify pkey, start_tstamp
 | |
| 			EXPECT_EQ(all_param.pkey_, cur_param.pkey_);
 | |
| 			EXPECT_EQ(all_param.start_tstamp_, cur_param.start_tstamp_);
 | |
| 			// verify BreakInfo
 | |
|       const obrpc::BreakInfo all_breakinfo = all_param.break_info_;
 | |
|       const obrpc::BreakInfo cur_breakinfo = cur_param.break_info_;
 | |
| 			EXPECT_EQ(all_breakinfo.break_file_id_, cur_breakinfo.break_file_id_);
 | |
| 			EXPECT_EQ(all_breakinfo.min_greater_log_id_, cur_breakinfo.min_greater_log_id_);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	void reset_break_info(obrpc::BreakInfo &break_info,
 | |
| 			                  uint32_t break_file_id,
 | |
| 												uint64_t min_greater_log_id)
 | |
| 	{
 | |
| 		break_info.break_file_id_ = break_file_id;
 | |
| 		break_info.min_greater_log_id_ = min_greater_log_id;
 | |
| 	}
 | |
| private:
 | |
|   Req *request_;
 | |
| 	int64_t start_pos_;
 | |
| 	int64_t end_pos_;
 | |
| 	int64_t query_time_;
 | |
| };
 | |
| 
 | |
| 
 | |
| }
 | |
| }
 | 
