ClickHouse/src/Storages/MergeTree/MergeTreePartInfo.cpp

243 lines
6.7 KiB
C++
Raw Normal View History

#include <Storages/MergeTree/MergeTreePartInfo.h>
#include <IO/ReadBufferFromString.h>
#include <IO/ReadHelpers.h>
#include <IO/WriteHelpers.h>
namespace DB
{
namespace ErrorCodes
{
extern const int BAD_DATA_PART_NAME;
}
2020-03-09 02:31:05 +00:00
MergeTreePartInfo MergeTreePartInfo::fromPartName(const String & part_name, MergeTreeDataFormatVersion format_version)
{
MergeTreePartInfo part_info;
2020-03-09 02:31:05 +00:00
if (!tryParsePartName(part_name, &part_info, format_version))
throw Exception("Unexpected part name: " + part_name, ErrorCodes::BAD_DATA_PART_NAME);
return part_info;
}
2020-03-09 02:31:05 +00:00
bool MergeTreePartInfo::tryParsePartName(const String & part_name, MergeTreePartInfo * part_info, MergeTreeDataFormatVersion format_version)
{
2020-03-09 02:31:05 +00:00
ReadBufferFromString in(part_name);
String partition_id;
if (format_version < MERGE_TREE_DATA_MIN_FORMAT_VERSION_WITH_CUSTOM_PARTITIONING)
{
UInt32 min_yyyymmdd = 0;
UInt32 max_yyyymmdd = 0;
if (!tryReadIntText(min_yyyymmdd, in)
|| !checkChar('_', in)
|| !tryReadIntText(max_yyyymmdd, in)
|| !checkChar('_', in))
{
return false;
}
partition_id = toString(min_yyyymmdd / 100);
}
else
{
while (!in.eof())
{
char c;
readChar(c, in);
if (c == '_')
break;
partition_id.push_back(c);
}
}
/// Sanity check
if (partition_id.empty())
{
return false;
}
Int64 min_block_num = 0;
Int64 max_block_num = 0;
UInt32 level = 0;
2018-05-13 00:24:23 +00:00
UInt32 mutation = 0;
if (!tryReadIntText(min_block_num, in)
|| !checkChar('_', in)
|| !tryReadIntText(max_block_num, in)
|| !checkChar('_', in)
2018-05-13 00:24:23 +00:00
|| !tryReadIntText(level, in))
{
return false;
}
/// Sanity check
if (min_block_num > max_block_num)
{
return false;
}
2018-05-13 00:24:23 +00:00
if (!in.eof())
{
if (!checkChar('_', in)
|| !tryReadIntText(mutation, in)
|| !in.eof())
{
return false;
}
}
if (part_info)
{
part_info->partition_id = std::move(partition_id);
part_info->min_block = min_block_num;
part_info->max_block = max_block_num;
2021-05-14 12:55:30 +00:00
if (level == LEGACY_MAX_LEVEL)
{
/// We (accidentally) had two different max levels until 21.6 and it might cause logical errors like
/// "Part 20170601_20170630_0_2_999999999 intersects 201706_0_1_4294967295".
/// So we replace unexpected max level to make contains(...) method and comparison operators work
/// correctly with such virtual parts. On part name serialization we will use legacy max level to keep the name unchanged.
part_info->use_leagcy_max_level = true;
level = MAX_LEVEL;
}
part_info->level = level;
2018-05-13 00:24:23 +00:00
part_info->mutation = mutation;
}
return true;
}
2020-03-09 02:31:05 +00:00
void MergeTreePartInfo::parseMinMaxDatesFromPartName(const String & part_name, DayNum & min_date, DayNum & max_date)
{
UInt32 min_yyyymmdd = 0;
UInt32 max_yyyymmdd = 0;
2020-03-09 02:31:05 +00:00
ReadBufferFromString in(part_name);
if (!tryReadIntText(min_yyyymmdd, in)
|| !checkChar('_', in)
|| !tryReadIntText(max_yyyymmdd, in))
{
2020-03-09 02:31:05 +00:00
throw Exception("Unexpected part name: " + part_name, ErrorCodes::BAD_DATA_PART_NAME);
}
const auto & date_lut = DateLUT::instance();
min_date = date_lut.YYYYMMDDToDayNum(min_yyyymmdd);
max_date = date_lut.YYYYMMDDToDayNum(max_yyyymmdd);
auto min_month = date_lut.toNumYYYYMM(min_date);
auto max_month = date_lut.toNumYYYYMM(max_date);
if (min_month != max_month)
2020-03-09 02:31:05 +00:00
throw Exception("Part name " + part_name + " contains different months", ErrorCodes::BAD_DATA_PART_NAME);
}
bool MergeTreePartInfo::contains(const String & outer_part_name, const String & inner_part_name, MergeTreeDataFormatVersion format_version)
{
MergeTreePartInfo outer = fromPartName(outer_part_name, format_version);
MergeTreePartInfo inner = fromPartName(inner_part_name, format_version);
return outer.contains(inner);
}
String MergeTreePartInfo::getPartName() const
{
WriteBufferFromOwnString wb;
writeString(partition_id, wb);
writeChar('_', wb);
writeIntText(min_block, wb);
writeChar('_', wb);
writeIntText(max_block, wb);
writeChar('_', wb);
2021-05-14 12:55:30 +00:00
if (use_leagcy_max_level)
{
assert(level == MAX_LEVEL);
writeIntText(LEGACY_MAX_LEVEL, wb);
}
else
{
writeIntText(level, wb);
}
2018-05-13 00:24:23 +00:00
if (mutation)
{
writeChar('_', wb);
writeIntText(mutation, wb);
}
return wb.str();
}
String MergeTreePartInfo::getPartNameV0(DayNum left_date, DayNum right_date) const
{
const auto & date_lut = DateLUT::instance();
/// Directory name for the part has form: `YYYYMMDD_YYYYMMDD_N_N_L`.
unsigned left_date_id = date_lut.toNumYYYYMMDD(left_date);
unsigned right_date_id = date_lut.toNumYYYYMMDD(right_date);
WriteBufferFromOwnString wb;
writeIntText(left_date_id, wb);
writeChar('_', wb);
writeIntText(right_date_id, wb);
writeChar('_', wb);
writeIntText(min_block, wb);
writeChar('_', wb);
writeIntText(max_block, wb);
writeChar('_', wb);
2021-05-14 12:55:30 +00:00
if (use_leagcy_max_level)
{
assert(level == MAX_LEVEL);
writeIntText(LEGACY_MAX_LEVEL, wb);
}
else
{
writeIntText(level, wb);
}
2018-05-13 00:24:23 +00:00
if (mutation)
{
writeChar('_', wb);
writeIntText(mutation, wb);
}
return wb.str();
}
2019-07-26 20:04:45 +00:00
bool DetachedPartInfo::tryParseDetachedPartName(const String & dir_name, DetachedPartInfo & part_info,
2019-07-23 19:43:33 +00:00
MergeTreeDataFormatVersion format_version)
{
2019-07-26 20:04:45 +00:00
part_info.dir_name = dir_name;
2019-07-23 19:43:33 +00:00
/// First, try to parse as <part_name>.
2019-07-31 14:44:55 +00:00
// TODO what if tryParsePartName will parse prefix as partition_id? It can happen if dir_name doesn't contain mutation number at the end
2019-07-26 20:04:45 +00:00
if (MergeTreePartInfo::tryParsePartName(dir_name, &part_info, format_version))
return part_info.valid_name = true;
2019-07-23 19:43:33 +00:00
/// Next, as <prefix>_<partname>. Use entire name as prefix if it fails.
2019-07-26 20:04:45 +00:00
part_info.prefix = dir_name;
2019-07-23 19:43:33 +00:00
const auto first_separator = dir_name.find_first_of('_');
if (first_separator == String::npos)
2019-07-26 20:04:45 +00:00
return part_info.valid_name = false;
2019-07-23 19:43:33 +00:00
// TODO what if <prefix> contains '_'?
const auto part_name = dir_name.substr(first_separator + 1,
dir_name.size() - first_separator - 1);
2019-07-26 20:04:45 +00:00
if (!MergeTreePartInfo::tryParsePartName(part_name, &part_info, format_version))
return part_info.valid_name = false;
2019-07-23 19:43:33 +00:00
2019-07-26 20:04:45 +00:00
part_info.prefix = dir_name.substr(0, first_separator);
return part_info.valid_name = true;
2019-07-23 19:43:33 +00:00
}
2019-07-25 10:46:07 +00:00
}