mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-25 17:12:03 +00:00
Add option to disable ttl move on data part insert
This commit is contained in:
parent
0052bbdd84
commit
0da19ab46d
@ -36,10 +36,11 @@ using Volumes = std::vector<VolumePtr>;
|
|||||||
class IVolume : public Space
|
class IVolume : public Space
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
IVolume(String name_, Disks disks_, size_t max_data_part_size_ = 0)
|
IVolume(String name_, Disks disks_, size_t max_data_part_size_ = 0, bool perform_ttl_move_on_insert_ = true)
|
||||||
: disks(std::move(disks_))
|
: disks(std::move(disks_))
|
||||||
, name(name_)
|
, name(name_)
|
||||||
, max_data_part_size(max_data_part_size_)
|
, max_data_part_size(max_data_part_size_)
|
||||||
|
, perform_ttl_move_on_insert(perform_ttl_move_on_insert_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,6 +71,9 @@ protected:
|
|||||||
public:
|
public:
|
||||||
/// Max size of reservation, zero means unlimited size
|
/// Max size of reservation, zero means unlimited size
|
||||||
UInt64 max_data_part_size = 0;
|
UInt64 max_data_part_size = 0;
|
||||||
|
/// Should a new data part be synchronously moved to a volume according to ttl on insert
|
||||||
|
/// or move this part in background task asynchronously after insert.
|
||||||
|
bool perform_ttl_move_on_insert;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Reservation for multiple disks at once. Can be used in RAID1 implementation.
|
/// Reservation for multiple disks at once. Can be used in RAID1 implementation.
|
||||||
|
@ -53,6 +53,9 @@ VolumeJBOD::VolumeJBOD(
|
|||||||
static constexpr UInt64 MIN_PART_SIZE = 8u * 1024u * 1024u;
|
static constexpr UInt64 MIN_PART_SIZE = 8u * 1024u * 1024u;
|
||||||
if (max_data_part_size != 0 && max_data_part_size < MIN_PART_SIZE)
|
if (max_data_part_size != 0 && max_data_part_size < MIN_PART_SIZE)
|
||||||
LOG_WARNING(logger, "Volume {} max_data_part_size is too low ({} < {})", backQuote(name), ReadableSize(max_data_part_size), ReadableSize(MIN_PART_SIZE));
|
LOG_WARNING(logger, "Volume {} max_data_part_size is too low ({} < {})", backQuote(name), ReadableSize(max_data_part_size), ReadableSize(MIN_PART_SIZE));
|
||||||
|
|
||||||
|
/// Default value is 'true' due to backward compatibility.
|
||||||
|
perform_ttl_move_on_insert = config.getBool(config_prefix + ".perform_ttl_move_on_insert", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
DiskPtr VolumeJBOD::getDisk(size_t /* index */) const
|
DiskPtr VolumeJBOD::getDisk(size_t /* index */) const
|
||||||
|
@ -2961,11 +2961,12 @@ ReservationPtr MergeTreeData::tryReserveSpace(UInt64 expected_size, SpacePtr spa
|
|||||||
ReservationPtr MergeTreeData::reserveSpacePreferringTTLRules(UInt64 expected_size,
|
ReservationPtr MergeTreeData::reserveSpacePreferringTTLRules(UInt64 expected_size,
|
||||||
const IMergeTreeDataPart::TTLInfos & ttl_infos,
|
const IMergeTreeDataPart::TTLInfos & ttl_infos,
|
||||||
time_t time_of_move,
|
time_t time_of_move,
|
||||||
size_t min_volume_index) const
|
size_t min_volume_index,
|
||||||
|
bool is_insert) const
|
||||||
{
|
{
|
||||||
expected_size = std::max(RESERVATION_MIN_ESTIMATION_SIZE, expected_size);
|
expected_size = std::max(RESERVATION_MIN_ESTIMATION_SIZE, expected_size);
|
||||||
|
|
||||||
ReservationPtr reservation = tryReserveSpacePreferringTTLRules(expected_size, ttl_infos, time_of_move, min_volume_index);
|
ReservationPtr reservation = tryReserveSpacePreferringTTLRules(expected_size, ttl_infos, time_of_move, min_volume_index, is_insert);
|
||||||
|
|
||||||
return checkAndReturnReservation(expected_size, std::move(reservation));
|
return checkAndReturnReservation(expected_size, std::move(reservation));
|
||||||
}
|
}
|
||||||
@ -2973,7 +2974,8 @@ ReservationPtr MergeTreeData::reserveSpacePreferringTTLRules(UInt64 expected_siz
|
|||||||
ReservationPtr MergeTreeData::tryReserveSpacePreferringTTLRules(UInt64 expected_size,
|
ReservationPtr MergeTreeData::tryReserveSpacePreferringTTLRules(UInt64 expected_size,
|
||||||
const IMergeTreeDataPart::TTLInfos & ttl_infos,
|
const IMergeTreeDataPart::TTLInfos & ttl_infos,
|
||||||
time_t time_of_move,
|
time_t time_of_move,
|
||||||
size_t min_volume_index) const
|
size_t min_volume_index,
|
||||||
|
bool is_insert) const
|
||||||
{
|
{
|
||||||
expected_size = std::max(RESERVATION_MIN_ESTIMATION_SIZE, expected_size);
|
expected_size = std::max(RESERVATION_MIN_ESTIMATION_SIZE, expected_size);
|
||||||
|
|
||||||
@ -2984,13 +2986,13 @@ ReservationPtr MergeTreeData::tryReserveSpacePreferringTTLRules(UInt64 expected_
|
|||||||
|
|
||||||
if (ttl_entry)
|
if (ttl_entry)
|
||||||
{
|
{
|
||||||
SpacePtr destination_ptr = getDestinationForTTL(*ttl_entry);
|
SpacePtr destination_ptr = getDestinationForTTL(*ttl_entry, is_insert);
|
||||||
if (!destination_ptr)
|
if (!destination_ptr)
|
||||||
{
|
{
|
||||||
if (ttl_entry->destination_type == DataDestinationType::VOLUME)
|
if (ttl_entry->destination_type == DataDestinationType::VOLUME)
|
||||||
LOG_WARNING(log, "Would like to reserve space on volume '{}' by TTL rule of table '{}' but volume was not found", ttl_entry->destination_name, log_name);
|
LOG_WARNING(log, "Would like to reserve space on volume '{}' by TTL rule of table '{}' but volume was not found or rule is not applicable at the moment", ttl_entry->destination_name, log_name);
|
||||||
else if (ttl_entry->destination_type == DataDestinationType::DISK)
|
else if (ttl_entry->destination_type == DataDestinationType::DISK)
|
||||||
LOG_WARNING(log, "Would like to reserve space on disk '{}' by TTL rule of table '{}' but disk was not found", ttl_entry->destination_name, log_name);
|
LOG_WARNING(log, "Would like to reserve space on disk '{}' by TTL rule of table '{}' but disk was not found or rule is not applicable at the moment", ttl_entry->destination_name, log_name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -3010,13 +3012,36 @@ ReservationPtr MergeTreeData::tryReserveSpacePreferringTTLRules(UInt64 expected_
|
|||||||
return reservation;
|
return reservation;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpacePtr MergeTreeData::getDestinationForTTL(const TTLDescription & ttl) const
|
SpacePtr MergeTreeData::getDestinationForTTL(const TTLDescription & ttl, bool is_insert) const
|
||||||
{
|
{
|
||||||
auto policy = getStoragePolicy();
|
auto policy = getStoragePolicy();
|
||||||
if (ttl.destination_type == DataDestinationType::VOLUME)
|
if (ttl.destination_type == DataDestinationType::VOLUME)
|
||||||
return policy->getVolumeByName(ttl.destination_name);
|
{
|
||||||
|
auto volume = policy->getVolumeByName(ttl.destination_name);
|
||||||
|
|
||||||
|
if (!volume)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (is_insert && !volume->perform_ttl_move_on_insert)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
else if (ttl.destination_type == DataDestinationType::DISK)
|
else if (ttl.destination_type == DataDestinationType::DISK)
|
||||||
return policy->getDiskByName(ttl.destination_name);
|
{
|
||||||
|
auto disk = policy->getDiskByName(ttl.destination_name);
|
||||||
|
if (!disk)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto volume = policy->getVolume(policy->getVolumeIndexByDisk(disk));
|
||||||
|
if (!volume)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (is_insert && !volume->perform_ttl_move_on_insert)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return disk;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -624,13 +624,15 @@ public:
|
|||||||
UInt64 expected_size,
|
UInt64 expected_size,
|
||||||
const IMergeTreeDataPart::TTLInfos & ttl_infos,
|
const IMergeTreeDataPart::TTLInfos & ttl_infos,
|
||||||
time_t time_of_move,
|
time_t time_of_move,
|
||||||
size_t min_volume_index = 0) const;
|
size_t min_volume_index = 0,
|
||||||
|
bool is_insert = false) const;
|
||||||
|
|
||||||
ReservationPtr tryReserveSpacePreferringTTLRules(
|
ReservationPtr tryReserveSpacePreferringTTLRules(
|
||||||
UInt64 expected_size,
|
UInt64 expected_size,
|
||||||
const IMergeTreeDataPart::TTLInfos & ttl_infos,
|
const IMergeTreeDataPart::TTLInfos & ttl_infos,
|
||||||
time_t time_of_move,
|
time_t time_of_move,
|
||||||
size_t min_volume_index = 0) const;
|
size_t min_volume_index = 0,
|
||||||
|
bool is_insert = false) const;
|
||||||
|
|
||||||
/// Choose disk with max available free space
|
/// Choose disk with max available free space
|
||||||
/// Reserves 0 bytes
|
/// Reserves 0 bytes
|
||||||
@ -638,9 +640,9 @@ public:
|
|||||||
|
|
||||||
/// Return alter conversions for part which must be applied on fly.
|
/// Return alter conversions for part which must be applied on fly.
|
||||||
AlterConversions getAlterConversionsForPart(const MergeTreeDataPartPtr part) const;
|
AlterConversions getAlterConversionsForPart(const MergeTreeDataPartPtr part) const;
|
||||||
/// Returns destination disk or volume for the TTL rule according to current
|
/// Returns destination disk or volume for the TTL rule according to current storage policy
|
||||||
/// storage policy
|
/// 'is_insert' - is TTL move performed on new data part insert.
|
||||||
SpacePtr getDestinationForTTL(const TTLDescription & ttl) const;
|
SpacePtr getDestinationForTTL(const TTLDescription & ttl, bool is_insert = false) const;
|
||||||
|
|
||||||
/// Checks if given part already belongs destination disk or volume for the
|
/// Checks if given part already belongs destination disk or volume for the
|
||||||
/// TTL rule.
|
/// TTL rule.
|
||||||
|
@ -237,7 +237,7 @@ MergeTreeData::MutableDataPartPtr MergeTreeDataWriter::writeTempPart(BlockWithPa
|
|||||||
updateTTL(ttl_entry, move_ttl_infos, move_ttl_infos.moves_ttl[ttl_entry.result_column], block, false);
|
updateTTL(ttl_entry, move_ttl_infos, move_ttl_infos.moves_ttl[ttl_entry.result_column], block, false);
|
||||||
|
|
||||||
NamesAndTypesList columns = metadata_snapshot->getColumns().getAllPhysical().filter(block.getNames());
|
NamesAndTypesList columns = metadata_snapshot->getColumns().getAllPhysical().filter(block.getNames());
|
||||||
ReservationPtr reservation = data.reserveSpacePreferringTTLRules(expected_size, move_ttl_infos, time(nullptr));
|
ReservationPtr reservation = data.reserveSpacePreferringTTLRules(expected_size, move_ttl_infos, time(nullptr), true);
|
||||||
VolumePtr volume = data.getStoragePolicy()->getVolume(0);
|
VolumePtr volume = data.getStoragePolicy()->getVolume(0);
|
||||||
|
|
||||||
auto new_data_part = data.createPart(
|
auto new_data_part = data.createPart(
|
||||||
|
@ -83,6 +83,18 @@
|
|||||||
</main>
|
</main>
|
||||||
</volumes>
|
</volumes>
|
||||||
</only_jbod2>
|
</only_jbod2>
|
||||||
|
|
||||||
|
<jbod_without_instant_ttl_move>
|
||||||
|
<volumes>
|
||||||
|
<main>
|
||||||
|
<disk>jbod1</disk>
|
||||||
|
</main>
|
||||||
|
<external>
|
||||||
|
<disk>external</disk>
|
||||||
|
<perform_ttl_move_on_insert>false</perform_ttl_move_on_insert>
|
||||||
|
</external>
|
||||||
|
</volumes>
|
||||||
|
</jbod_without_instant_ttl_move>
|
||||||
</policies>
|
</policies>
|
||||||
|
|
||||||
</storage_configuration>
|
</storage_configuration>
|
||||||
|
@ -1102,3 +1102,48 @@ limitations under the License."""
|
|||||||
|
|
||||||
finally:
|
finally:
|
||||||
node1.query("DROP TABLE IF EXISTS {name} NO DELAY".format(name=name))
|
node1.query("DROP TABLE IF EXISTS {name} NO DELAY".format(name=name))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("name,dest_type,engine", [
|
||||||
|
("mt_test_disabled_ttl_move_on_insert_work", "DISK", "MergeTree()"),
|
||||||
|
("mt_test_disabled_ttl_move_on_insert_work", "VOLUME", "MergeTree()"),
|
||||||
|
("replicated_mt_test_disabled_ttl_move_on_insert_work", "DISK", "ReplicatedMergeTree('/clickhouse/replicated_test_disabled_ttl_move_on_insert_work', '1')"),
|
||||||
|
("replicated_mt_test_disabled_ttl_move_on_insert_work", "VOLUME", "ReplicatedMergeTree('/clickhouse/replicated_test_disabled_ttl_move_on_insert_work', '1')"),
|
||||||
|
])
|
||||||
|
def test_disabled_ttl_move_on_insert(started_cluster, name, dest_type, engine):
|
||||||
|
try:
|
||||||
|
node1.query("SYSTEM STOP MOVES")
|
||||||
|
|
||||||
|
node1.query("""
|
||||||
|
CREATE TABLE {name} (
|
||||||
|
s1 String,
|
||||||
|
d1 DateTime
|
||||||
|
) ENGINE = {engine}
|
||||||
|
ORDER BY tuple()
|
||||||
|
TTL d1 TO {dest_type} 'external'
|
||||||
|
SETTINGS storage_policy='jbod_without_instant_ttl_move'
|
||||||
|
""".format(name=name, dest_type=dest_type, engine=engine))
|
||||||
|
|
||||||
|
data = [] # 10MB in total
|
||||||
|
for i in range(10):
|
||||||
|
data.append(("'{}'".format(get_random_string(1024 * 1024)), "toDateTime({})".format(
|
||||||
|
time.time() - 1))) # 1MB row
|
||||||
|
|
||||||
|
node1.query("INSERT INTO {} (s1, d1) VALUES {}".format(name, ",".join(["(" + ",".join(x) + ")" for x in data])))
|
||||||
|
|
||||||
|
used_disks = get_used_disks_for_table(node1, name)
|
||||||
|
assert set(used_disks) == "jbod1"
|
||||||
|
assert node1.query("SELECT count() FROM {name}".format(name=name)).strip() == "10"
|
||||||
|
|
||||||
|
node1.query("SYSTEM START MOVES")
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
used_disks = get_used_disks_for_table(node1, name)
|
||||||
|
assert set(used_disks) == "external"
|
||||||
|
assert node1.query("SELECT count() FROM {name}".format(name=name)).strip() == "10"
|
||||||
|
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
node1.query("DROP TABLE IF EXISTS {} NO DELAY".format(name))
|
||||||
|
except:
|
||||||
|
pass
|
Loading…
Reference in New Issue
Block a user