blob: 7bcb0f90a42bd5255920d43fcfb516704a42ac62 [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include "cloud/cloud_internal_service.h"
#include <chrono>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <unordered_map>
#include "cloud/cloud_storage_engine.h"
#include "cloud/cloud_tablet_mgr.h"
#include "cpp/sync_point.h"
#include "gen_cpp/Status_types.h"
#include "storage/tablet/tablet_meta.h"
#include "util/uid_util.h"
#include "util/work_thread_pool.hpp"
namespace doris {
namespace {
class TestClosure final : public google::protobuf::Closure {
public:
explicit TestClosure(std::function<void()> callback) : _callback(std::move(callback)) {}
void Run() override {
if (_callback) {
_callback();
}
}
private:
std::function<void()> _callback;
};
} // namespace
class CloudInternalServiceTest : public testing::Test {
public:
CloudInternalServiceTest() : _engine(CloudStorageEngine(EngineOptions())) {}
protected:
static constexpr int64_t kSyncedTabletId = 90001;
static constexpr int64_t kFailedTabletId = 90002;
static constexpr int64_t kUncachedTabletId = 90003;
void SetUp() override {
auto sp = SyncPoint::get_instance();
sp->clear_all_call_backs();
sp->enable_processing();
sp->set_call_back("CloudMetaMgr::sync_tablet_rowsets",
[](auto&& args) { try_any_cast_ret<Status>(args)->second = true; });
sp->set_call_back("CloudMetaMgr::get_tablet_meta", [this](auto&& args) {
const auto tablet_id = try_any_cast<int64_t>(args[0]);
auto* tablet_meta_ptr = try_any_cast<TabletMetaSharedPtr*>(args[1]);
auto* ret = try_any_cast_ret<Status>(args);
auto& call_count = _tablet_meta_call_count[tablet_id];
++call_count;
if (tablet_id == kFailedTabletId && call_count >= 2) {
ret->first = Status::InternalError<false>("injected sync_meta failure");
ret->second = true;
return;
}
*tablet_meta_ptr =
create_tablet_meta(tablet_id, call_count >= 2 ? "time_series" : "size_based");
ret->second = true;
});
}
void TearDown() override {
auto sp = SyncPoint::get_instance();
sp->disable_processing();
sp->clear_all_call_backs();
}
TabletMetaSharedPtr create_tablet_meta(int64_t tablet_id, std::string compaction_policy) {
TTabletSchema tablet_schema;
TColumn column;
column.__set_column_name("c1");
column.__set_column_type(TColumnType());
column.column_type.__set_type(TPrimitiveType::INT);
column.__set_is_key(true);
column.__set_aggregation_type(TAggregationType::NONE);
column.__set_col_unique_id(0);
tablet_schema.__set_columns({column});
tablet_schema.__set_keys_type(TKeysType::DUP_KEYS);
std::unordered_map<uint32_t, uint32_t> col_ordinal_to_unique_id = {{0, 0}};
auto tablet_meta = std::make_shared<TabletMeta>(
1, 2, tablet_id, 15674, 4, 5, tablet_schema, 1, col_ordinal_to_unique_id,
UniqueId(9, 10), TTabletType::TABLET_TYPE_DISK, TCompressionType::LZ4F);
tablet_meta->set_compaction_policy(std::move(compaction_policy));
return tablet_meta;
}
CloudStorageEngine _engine;
std::unordered_map<int64_t, int> _tablet_meta_call_count;
};
TEST_F(CloudInternalServiceTest, TestSyncTabletMetaCountsSyncedSkippedAndFailedTablets) {
auto synced_res = _engine.tablet_mgr().get_tablet(kSyncedTabletId);
ASSERT_TRUE(synced_res.has_value()) << synced_res.error();
auto failed_res = _engine.tablet_mgr().get_tablet(kFailedTabletId);
ASSERT_TRUE(failed_res.has_value()) << failed_res.error();
auto cached_synced_tablet = synced_res.value();
auto cached_failed_tablet = failed_res.value();
ASSERT_EQ("size_based", cached_synced_tablet->tablet_meta()->compaction_policy());
ASSERT_EQ("size_based", cached_failed_tablet->tablet_meta()->compaction_policy());
FifoThreadPool work_pool(1, 1, "sync_tablet_meta_test");
PSyncTabletMetaRequest request;
request.add_tablet_ids(kSyncedTabletId);
request.add_tablet_ids(kUncachedTabletId);
request.add_tablet_ids(kFailedTabletId);
PSyncTabletMetaResponse response;
std::mutex mutex;
std::condition_variable cv;
bool done = false;
TestClosure closure([&]() {
std::lock_guard lock(mutex);
done = true;
cv.notify_all();
});
test_submit_sync_tablet_meta(_engine, work_pool, &request, &response, &closure);
std::unique_lock lock(mutex);
ASSERT_TRUE(cv.wait_for(lock, std::chrono::seconds(5), [&] { return done; }));
ASSERT_TRUE(response.has_status());
EXPECT_EQ(TStatusCode::OK, response.status().status_code()) << response.status().DebugString();
EXPECT_EQ(1, response.synced_tablets());
EXPECT_EQ(1, response.skipped_tablets());
EXPECT_EQ(1, response.failed_tablets());
EXPECT_EQ("time_series", cached_synced_tablet->tablet_meta()->compaction_policy());
EXPECT_EQ("size_based", cached_failed_tablet->tablet_meta()->compaction_policy());
EXPECT_EQ(nullptr, _engine.tablet_mgr().get_tablet_if_cached(kUncachedTabletId));
}
TEST_F(CloudInternalServiceTest, TestSyncTabletMetaOfferFailure) {
FifoThreadPool work_pool(1, 0, "sync_tablet_meta_offer_failure_test");
PSyncTabletMetaRequest request;
request.add_tablet_ids(kSyncedTabletId);
PSyncTabletMetaResponse response;
bool done = false;
TestClosure closure([&]() { done = true; });
test_submit_sync_tablet_meta(_engine, work_pool, &request, &response, &closure);
EXPECT_TRUE(done);
ASSERT_TRUE(response.has_status());
EXPECT_EQ(TStatusCode::INTERNAL_ERROR, response.status().status_code());
EXPECT_TRUE(response.status().error_msgs(0).find(
"failed to offer sync_tablet_meta request to work pool") !=
std::string::npos);
}
} // namespace doris