blob: 210075cc3038e2270ac091928a93f9d5aeb89ad3 [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 <dsn/utils/time_utils.h>
#include "pegasus_server_test_base.h"
#include "server/pegasus_manual_compact_service.h"
namespace pegasus {
namespace server {
class manual_compact_service_test : public pegasus_server_test_base
{
public:
std::unique_ptr<pegasus_manual_compact_service> manual_compact_svc;
static const uint64_t compacted_ts = 1500000000; // 2017.07.14 10:40:00 CST
public:
manual_compact_service_test()
{
start();
manual_compact_svc = dsn::make_unique<pegasus_manual_compact_service>(_server.get());
}
void set_compact_time(int64_t ts)
{
manual_compact_svc->_manual_compact_last_finish_time_ms.store(
static_cast<uint64_t>(ts * 1000));
}
void set_mock_now(uint64_t mock_now_sec)
{
manual_compact_svc->_mock_now_timestamp = mock_now_sec * 1000;
}
void check_compact_disabled(const std::map<std::string, std::string> &envs, bool ok)
{
ASSERT_EQ(ok, manual_compact_svc->check_compact_disabled(envs))
<< dsn::utils::kv_map_to_string(envs, ';', '=');
}
void check_once_compact(const std::map<std::string, std::string> &envs, bool ok)
{
ASSERT_EQ(ok, manual_compact_svc->check_once_compact(envs))
<< dsn::utils::kv_map_to_string(envs, ';', '=');
}
void check_periodic_compact(const std::map<std::string, std::string> &envs, bool ok)
{
ASSERT_EQ(ok, manual_compact_svc->check_periodic_compact(envs))
<< dsn::utils::kv_map_to_string(envs, ';', '=');
}
void extract_manual_compact_opts(const std::map<std::string, std::string> &envs,
const std::string &key_prefix,
rocksdb::CompactRangeOptions &options)
{
manual_compact_svc->extract_manual_compact_opts(envs, key_prefix, options);
}
void set_num_level(int level) { _server->_data_cf_opts.num_levels = level; }
void check_manual_compact_state(bool ok, const std::string &msg = "")
{
ASSERT_EQ(ok, manual_compact_svc->check_manual_compact_state()) << msg;
}
void manual_compact(uint64_t mock_now_sec, uint64_t time_cost_sec)
{
set_mock_now(mock_now_sec);
uint64_t start = manual_compact_svc->now_timestamp();
manual_compact_svc->_manual_compact_start_running_time_ms.store(start);
// do compacting...
set_mock_now(mock_now_sec + time_cost_sec);
uint64_t finish = manual_compact_svc->now_timestamp();
manual_compact_svc->_manual_compact_last_finish_time_ms.store(finish);
manual_compact_svc->_manual_compact_last_time_used_ms.store(finish - start);
manual_compact_svc->_manual_compact_enqueue_time_ms.store(0);
}
void set_manual_compact_interval(int sec)
{
manual_compact_svc->_manual_compact_min_interval_seconds = sec;
}
};
TEST_F(manual_compact_service_test, check_compact_disabled)
{
std::map<std::string, std::string> envs;
check_compact_disabled(envs, false);
envs[MANUAL_COMPACT_DISABLED_KEY] = "";
check_compact_disabled(envs, false);
envs[MANUAL_COMPACT_DISABLED_KEY] = "true";
check_compact_disabled(envs, true);
envs[MANUAL_COMPACT_DISABLED_KEY] = "false";
check_compact_disabled(envs, false);
envs[MANUAL_COMPACT_DISABLED_KEY] = "1";
check_compact_disabled(envs, false);
envs[MANUAL_COMPACT_DISABLED_KEY] = "0";
check_compact_disabled(envs, false);
envs[MANUAL_COMPACT_DISABLED_KEY] = "abc";
check_compact_disabled(envs, false);
}
TEST_F(manual_compact_service_test, check_once_compact)
{
// suppose compacted at 1500000000
set_compact_time(compacted_ts);
// invalid trigger time
std::map<std::string, std::string> envs;
check_once_compact(envs, false);
envs[MANUAL_COMPACT_ONCE_TRIGGER_TIME_KEY] = "";
check_once_compact(envs, false);
envs[MANUAL_COMPACT_ONCE_TRIGGER_TIME_KEY] = "abc";
check_once_compact(envs, false);
envs[MANUAL_COMPACT_ONCE_TRIGGER_TIME_KEY] = "-1";
check_once_compact(envs, false);
// has been compacted
envs[MANUAL_COMPACT_ONCE_TRIGGER_TIME_KEY] = std::to_string(compacted_ts - 1);
check_once_compact(envs, false);
envs[MANUAL_COMPACT_ONCE_TRIGGER_TIME_KEY] = std::to_string(compacted_ts);
check_once_compact(envs, false);
// has not been compacted
envs[MANUAL_COMPACT_ONCE_TRIGGER_TIME_KEY] = std::to_string(compacted_ts + 1);
check_once_compact(envs, true);
envs[MANUAL_COMPACT_ONCE_TRIGGER_TIME_KEY] = std::to_string(dsn_now_ms() / 1000);
check_once_compact(envs, true);
}
TEST_F(manual_compact_service_test, check_periodic_compact)
{
std::map<std::string, std::string> envs;
// invalid trigger time format
check_periodic_compact(envs, false);
envs[MANUAL_COMPACT_PERIODIC_TRIGGER_TIME_KEY] = "";
check_periodic_compact(envs, false);
envs[MANUAL_COMPACT_PERIODIC_TRIGGER_TIME_KEY] = ",";
check_periodic_compact(envs, false);
envs[MANUAL_COMPACT_PERIODIC_TRIGGER_TIME_KEY] = "12:oo";
check_periodic_compact(envs, false);
envs[MANUAL_COMPACT_PERIODIC_TRIGGER_TIME_KEY] = std::to_string(compacted_ts);
check_periodic_compact(envs, false);
// suppose compacted at 10:00
set_compact_time(dsn::utils::hh_mm_today_to_unix_sec("10:00"));
// has been compacted
envs[MANUAL_COMPACT_PERIODIC_TRIGGER_TIME_KEY] = "9:00";
check_periodic_compact(envs, false);
envs[MANUAL_COMPACT_PERIODIC_TRIGGER_TIME_KEY] = "3:00,9:00";
check_periodic_compact(envs, false);
envs[MANUAL_COMPACT_PERIODIC_TRIGGER_TIME_KEY] = "10:00";
check_periodic_compact(envs, false);
// suppose compacted at 09:00
set_compact_time(dsn::utils::hh_mm_today_to_unix_sec("09:00"));
// single compact time
envs[MANUAL_COMPACT_PERIODIC_TRIGGER_TIME_KEY] = "10:00";
set_mock_now((uint64_t)dsn::utils::hh_mm_today_to_unix_sec("08:00"));
check_periodic_compact(envs, false);
set_mock_now((uint64_t)dsn::utils::hh_mm_today_to_unix_sec("09:30"));
check_periodic_compact(envs, false);
set_mock_now((uint64_t)dsn::utils::hh_mm_today_to_unix_sec("10:30"));
check_periodic_compact(envs, true);
// multiple compact time
envs[MANUAL_COMPACT_PERIODIC_TRIGGER_TIME_KEY] = "10:00,21:00";
set_mock_now((uint64_t)dsn::utils::hh_mm_today_to_unix_sec("08:00"));
check_periodic_compact(envs, false);
set_mock_now((uint64_t)dsn::utils::hh_mm_today_to_unix_sec("09:30"));
check_periodic_compact(envs, false);
set_mock_now((uint64_t)dsn::utils::hh_mm_today_to_unix_sec("10:30"));
check_periodic_compact(envs, true);
// suppose compacted at 11:00
set_compact_time(dsn::utils::hh_mm_today_to_unix_sec("11:00"));
set_mock_now((uint64_t)dsn::utils::hh_mm_today_to_unix_sec("11:01"));
check_periodic_compact(envs, false);
set_mock_now((uint64_t)dsn::utils::hh_mm_today_to_unix_sec("20:30"));
check_periodic_compact(envs, false);
set_mock_now((uint64_t)dsn::utils::hh_mm_today_to_unix_sec("21:01"));
check_periodic_compact(envs, true);
// suppose compacted at 21:50
set_compact_time(dsn::utils::hh_mm_today_to_unix_sec("21:50"));
set_mock_now((uint64_t)dsn::utils::hh_mm_today_to_unix_sec("22:00"));
check_periodic_compact(envs, false);
}
TEST_F(manual_compact_service_test, extract_manual_compact_opts)
{
// init _db max level
set_num_level(7);
std::map<std::string, std::string> envs;
rocksdb::CompactRangeOptions out;
extract_manual_compact_opts(envs, MANUAL_COMPACT_ONCE_KEY_PREFIX, out);
ASSERT_EQ(out.target_level, -1);
ASSERT_EQ(out.bottommost_level_compaction, rocksdb::BottommostLevelCompaction::kSkip);
envs[MANUAL_COMPACT_ONCE_KEY_PREFIX + MANUAL_COMPACT_TARGET_LEVEL_KEY] = "2";
envs[MANUAL_COMPACT_ONCE_KEY_PREFIX + MANUAL_COMPACT_BOTTOMMOST_LEVEL_COMPACTION_KEY] =
MANUAL_COMPACT_BOTTOMMOST_LEVEL_COMPACTION_FORCE;
extract_manual_compact_opts(envs, MANUAL_COMPACT_ONCE_KEY_PREFIX, out);
ASSERT_EQ(out.target_level, 2);
ASSERT_EQ(out.bottommost_level_compaction, rocksdb::BottommostLevelCompaction::kForce);
envs[MANUAL_COMPACT_ONCE_KEY_PREFIX + MANUAL_COMPACT_TARGET_LEVEL_KEY] = "-1";
envs[MANUAL_COMPACT_ONCE_KEY_PREFIX + MANUAL_COMPACT_BOTTOMMOST_LEVEL_COMPACTION_KEY] =
MANUAL_COMPACT_BOTTOMMOST_LEVEL_COMPACTION_SKIP;
extract_manual_compact_opts(envs, MANUAL_COMPACT_ONCE_KEY_PREFIX, out);
ASSERT_EQ(out.target_level, -1);
ASSERT_EQ(out.bottommost_level_compaction, rocksdb::BottommostLevelCompaction::kSkip);
envs[MANUAL_COMPACT_ONCE_KEY_PREFIX + MANUAL_COMPACT_TARGET_LEVEL_KEY] = "-2";
envs[MANUAL_COMPACT_ONCE_KEY_PREFIX + MANUAL_COMPACT_BOTTOMMOST_LEVEL_COMPACTION_KEY] =
"nonono";
extract_manual_compact_opts(envs, MANUAL_COMPACT_ONCE_KEY_PREFIX, out);
ASSERT_EQ(out.target_level, -1);
ASSERT_EQ(out.bottommost_level_compaction, rocksdb::BottommostLevelCompaction::kSkip);
envs[MANUAL_COMPACT_ONCE_KEY_PREFIX + MANUAL_COMPACT_TARGET_LEVEL_KEY] = "8";
extract_manual_compact_opts(envs, MANUAL_COMPACT_ONCE_KEY_PREFIX, out);
ASSERT_EQ(out.target_level, -1);
}
TEST_F(manual_compact_service_test, check_manual_compact_state_0_interval)
{
set_manual_compact_interval(0);
uint64_t first_time = 1500000000;
set_mock_now(first_time);
check_manual_compact_state(true, "1st start ok");
check_manual_compact_state(false, "1st start not ok");
manual_compact(first_time, 1);
check_manual_compact_state(true, "2nd start ok");
check_manual_compact_state(false, "2nd start not ok");
}
TEST_F(manual_compact_service_test, check_manual_compact_state_1h_interval)
{
set_manual_compact_interval(3600);
uint64_t first_time = 1500000000;
set_mock_now(first_time);
check_manual_compact_state(true, "1st start ok");
check_manual_compact_state(false, "1st start not ok");
manual_compact(first_time, 10); // cost 10 seconds
set_mock_now(first_time + 1800);
check_manual_compact_state(false, "1800s past");
set_mock_now(first_time + 3609);
check_manual_compact_state(false, "3609s past");
set_mock_now(first_time + 3610);
check_manual_compact_state(false, "3610s past");
set_mock_now(first_time + 3611);
check_manual_compact_state(true, "3611s past, start ok");
check_manual_compact_state(false, "3611s past, start not ok");
}
} // namespace server
} // namespace pegasus