This commit is contained in:
Michael Kolupaev 2014-04-18 15:05:30 +04:00
parent 2ff0b62529
commit 88644b2377
2 changed files with 72 additions and 64 deletions

View File

@ -303,6 +303,52 @@ public:
assertEOF(file);
return true;
}
void checkNotBroken()
{
String path = storage.full_path + name;
if (!checksums.empty())
{
checksums.checkSizes(path + "/");
}
else
{
/// Проверяем, что первичный ключ непуст.
Poco::File index_file(path + "/primary.idx");
if (!index_file.exists() || index_file.getSize() == 0)
throw Exception("Part " + path + " is broken: primary key is empty.", ErrorCodes::BAD_SIZE_OF_FILE_IN_DATA_PART);
/// Проверяем, что все засечки непусты и имеют одинаковый размер.
ssize_t marks_size = -1;
for (NamesAndTypesList::const_iterator it = storage.columns->begin(); it != storage.columns->end(); ++it)
{
Poco::File marks_file(path + "/" + escapeForFileName(it->first) + ".mrk");
/// При добавлении нового столбца в таблицу файлы .mrk не создаются. Не будем ничего удалять.
if (!marks_file.exists())
continue;
if (marks_size == -1)
{
marks_size = marks_file.getSize();
if (0 == marks_size)
throw Exception("Part " + path + " is broken: " + marks_file.path() + " is empty.",
ErrorCodes::BAD_SIZE_OF_FILE_IN_DATA_PART);
}
else
{
if (static_cast<ssize_t>(marks_file.getSize()) != marks_size)
throw Exception("Part " + path + " is broken: marks have different sizes.",
ErrorCodes::BAD_SIZE_OF_FILE_IN_DATA_PART);
}
}
}
}
};
typedef std::shared_ptr<DataPart> MutableDataPartPtr;

View File

@ -177,6 +177,8 @@ void MergeTreeData::loadDataParts()
}
}
DataPartsVector broken_parts_to_remove;
Poco::RegularExpression::MatchVec matches;
for (const String & file_name : part_file_names)
{
@ -187,14 +189,28 @@ void MergeTreeData::loadDataParts()
parsePartName(file_name, *part, &matches);
part->name = file_name;
bool broken = false;
try
{
part->loadIndex();
part->loadChecksums();
part->checkNotBroken();
}
catch (...)
{
broken = true;
tryLogCurrentException(__PRETTY_FUNCTION__);
}
/// Игнорируем и, возможно, удаляем битые куски, которые могут образовываться после грубого перезапуска сервера.
if (isBrokenPart(full_path + file_name))
if (broken)
{
if (part->level == 0)
{
/// Восстановить куски нулевого уровня невозможно.
LOG_ERROR(log, "Removing broken part " << full_path + file_name << " because is't impossible to repair.");
part->remove();
broken_parts_to_remove.push_back(part);
}
else
{
@ -222,7 +238,7 @@ void MergeTreeData::loadDataParts()
if (contained_parts >= 2)
{
LOG_ERROR(log, "Removing broken part " << full_path + file_name << " because it covers at least 2 other parts");
Poco::File(full_path + file_name).remove(true);
broken_parts_to_remove.push_back(part);
}
else
{
@ -236,21 +252,16 @@ void MergeTreeData::loadDataParts()
part->modification_time = Poco::File(full_path + file_name).getLastModified().epochTime();
try
{
part->loadIndex();
part->loadChecksums();
}
catch (...)
{
/// Не будем вставлять в набор кусок с битым индексом. Пропустим кусок и позволим серверу запуститься.
tryLogCurrentException(__PRETTY_FUNCTION__);
continue;
}
data_parts.insert(part);
}
if (broken_parts_to_remove.size() > 2)
throw Exception("Suspiciously many (" + toString(broken_parts_to_remove.size()) + ") broken parts to remove.",
ErrorCodes::TOO_MANY_UNEXPECTED_DATA_PARTS);
for (const auto & part : broken_parts_to_remove)
part->remove();
all_data_parts = data_parts;
/** Удаляем из набора актуальных кусков куски, которые содержатся в другом куске (которые были склеены),
@ -627,55 +638,6 @@ bool MergeTreeData::isPartDirectory(const String & dir_name, Poco::RegularExpres
}
bool MergeTreeData::isBrokenPart(const String & path)
{
/// Проверяем, что первичный ключ непуст.
Poco::File index_file(path + "/primary.idx");
if (!index_file.exists() || index_file.getSize() == 0)
{
LOG_ERROR(log, "Part " << path << " is broken: primary key is empty.");
return true;
}
/// Проверяем, что все засечки непусты и имеют одинаковый размер.
ssize_t marks_size = -1;
for (NamesAndTypesList::const_iterator it = columns->begin(); it != columns->end(); ++it)
{
Poco::File marks_file(path + "/" + escapeForFileName(it->first) + ".mrk");
/// при добавлении нового столбца в таблицу файлы .mrk не создаются. Не будем ничего удалять.
if (!marks_file.exists())
continue;
if (marks_size == -1)
{
marks_size = marks_file.getSize();
if (0 == marks_size)
{
LOG_ERROR(log, "Part " << path << " is broken: " << marks_file.path() << " is empty.");
return true;
}
}
else
{
if (static_cast<ssize_t>(marks_file.getSize()) != marks_size)
{
LOG_ERROR(log, "Part " << path << " is broken: marks have different sizes.");
return true;
}
}
}
return false;
}
void MergeTreeData::renameTempPartAndAdd(MutableDataPartPtr part, Increment * increment)
{
auto removed = renameTempPartAndReplace(part, increment);