mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-02 12:32:04 +00:00
Merge
This commit is contained in:
parent
1be80d3410
commit
776f11a256
@ -158,6 +158,7 @@ private:
|
|||||||
typedef std::list<LogEntry> LogEntries;
|
typedef std::list<LogEntry> LogEntries;
|
||||||
|
|
||||||
typedef std::set<String> StringSet;
|
typedef std::set<String> StringSet;
|
||||||
|
typedef std::list<String> StringList;
|
||||||
|
|
||||||
Context & context;
|
Context & context;
|
||||||
zkutil::ZooKeeperPtr zookeeper;
|
zkutil::ZooKeeperPtr zookeeper;
|
||||||
@ -179,6 +180,15 @@ private:
|
|||||||
*/
|
*/
|
||||||
StringSet future_parts;
|
StringSet future_parts;
|
||||||
|
|
||||||
|
/** Куски, для которых нужно проверить одно из двух:
|
||||||
|
* - Если кусок у нас есть, сверить, его данные с его контрольными суммами, а их с ZooKeeper.
|
||||||
|
* - Если куска у нас нет, проверить, есть ли он (или покрывающий его кусок) хоть у кого-то.
|
||||||
|
*/
|
||||||
|
StringSet parts_to_check_set;
|
||||||
|
StringList parts_to_check_queue;
|
||||||
|
Poco::FastMuterx parts_to_check_mutex;
|
||||||
|
Poco::Event parts_to_check_event;
|
||||||
|
|
||||||
String database_name;
|
String database_name;
|
||||||
String table_name;
|
String table_name;
|
||||||
String full_path;
|
String full_path;
|
||||||
@ -218,7 +228,7 @@ private:
|
|||||||
std::unique_ptr<MergeTreeDataSelectExecutor> unreplicated_reader;
|
std::unique_ptr<MergeTreeDataSelectExecutor> unreplicated_reader;
|
||||||
std::unique_ptr<MergeTreeDataMerger> unreplicated_merger;
|
std::unique_ptr<MergeTreeDataMerger> unreplicated_merger;
|
||||||
|
|
||||||
/// Потоки.
|
/// Потоки:
|
||||||
|
|
||||||
/// Поток, следящий за обновлениями в логах всех реплик и загружающий их в очередь.
|
/// Поток, следящий за обновлениями в логах всех реплик и загружающий их в очередь.
|
||||||
std::thread queue_updating_thread;
|
std::thread queue_updating_thread;
|
||||||
@ -241,6 +251,8 @@ private:
|
|||||||
std::thread alter_thread;
|
std::thread alter_thread;
|
||||||
zkutil::EventPtr alter_thread_event = zkutil::EventPtr(new Poco::Event);
|
zkutil::EventPtr alter_thread_event = zkutil::EventPtr(new Poco::Event);
|
||||||
|
|
||||||
|
/// Поток, проверяющий данные кусков.
|
||||||
|
std::thread part_check_thread;
|
||||||
|
|
||||||
/// Событие, пробуждающее метод alter от ожидания завершения запроса ALTER.
|
/// Событие, пробуждающее метод alter от ожидания завершения запроса ALTER.
|
||||||
zkutil::EventPtr alter_query_event = zkutil::EventPtr(new Poco::Event);
|
zkutil::EventPtr alter_query_event = zkutil::EventPtr(new Poco::Event);
|
||||||
@ -314,6 +326,9 @@ private:
|
|||||||
*/
|
*/
|
||||||
void checkPartAndAddToZooKeeper(MergeTreeData::DataPartPtr part, zkutil::Ops & ops);
|
void checkPartAndAddToZooKeeper(MergeTreeData::DataPartPtr part, zkutil::Ops & ops);
|
||||||
|
|
||||||
|
/// Добавить кусок в очередь кусков, чьи данные нужно проверить в фоновом потоке.
|
||||||
|
void enqueuePartForCheck(const String & name);
|
||||||
|
|
||||||
void clearOldParts();
|
void clearOldParts();
|
||||||
|
|
||||||
/// Удалить из ZooKeeper старые записи в логе.
|
/// Удалить из ZooKeeper старые записи в логе.
|
||||||
@ -343,7 +358,7 @@ private:
|
|||||||
*/
|
*/
|
||||||
bool executeLogEntry(const LogEntry & entry, BackgroundProcessingPool::Context & pool_context);
|
bool executeLogEntry(const LogEntry & entry, BackgroundProcessingPool::Context & pool_context);
|
||||||
|
|
||||||
/** В бесконечном цикле обновляет очередь.
|
/** Обновляет очередь.
|
||||||
*/
|
*/
|
||||||
void queueUpdatingThread();
|
void queueUpdatingThread();
|
||||||
|
|
||||||
@ -355,19 +370,23 @@ private:
|
|||||||
|
|
||||||
void becomeLeader();
|
void becomeLeader();
|
||||||
|
|
||||||
/** В бесконечном цикле выбирает куски для слияния и записывает в лог.
|
/** Выбирает куски для слияния и записывает в лог.
|
||||||
*/
|
*/
|
||||||
void mergeSelectingThread();
|
void mergeSelectingThread();
|
||||||
|
|
||||||
/** В бесконечном цикле вызывает clearOldBlocks.
|
/** Удаляет устаревшие данные.
|
||||||
*/
|
*/
|
||||||
void cleanupThread();
|
void cleanupThread();
|
||||||
|
|
||||||
/** В бесконечном цикле проверяет, не нужно ли сделать локальный ALTER, и делает его.
|
/** Делает локальный ALTER, когда список столбцов в ZooKeeper меняется.
|
||||||
*/
|
*/
|
||||||
void alterThread();
|
void alterThread();
|
||||||
|
|
||||||
/** В бесконечном цикле проверяет, не протухла ли сессия в ZooKeeper.
|
/** Проверяет целостность кусков.
|
||||||
|
*/
|
||||||
|
void partCheckThread();
|
||||||
|
|
||||||
|
/** Когда сессия в ZooKeeper протухает, переходит на новую.
|
||||||
*/
|
*/
|
||||||
void restartingThread();
|
void restartingThread();
|
||||||
|
|
||||||
|
@ -515,6 +515,15 @@ void StorageReplicatedMergeTree::checkPartAndAddToZooKeeper(MergeTreeData::DataP
|
|||||||
zkutil::CreateMode::Persistent));
|
zkutil::CreateMode::Persistent));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StorageReplicatedMergeTree::enqueuePartForCheck(const String & name)
|
||||||
|
{
|
||||||
|
Poco::ScopedLock<Poco::FastMutex> lock(parts_to_check_mutex);
|
||||||
|
if (parts_to_check_set.count(name))
|
||||||
|
return;
|
||||||
|
parts_to_check_queue.push_back(name);
|
||||||
|
parts_to_check_set.insert(name);
|
||||||
|
}
|
||||||
|
|
||||||
void StorageReplicatedMergeTree::clearOldParts()
|
void StorageReplicatedMergeTree::clearOldParts()
|
||||||
{
|
{
|
||||||
Strings parts = data.clearOldParts();
|
Strings parts = data.clearOldParts();
|
||||||
@ -1248,6 +1257,139 @@ void StorageReplicatedMergeTree::alterThread()
|
|||||||
LOG_DEBUG(log, "alter thread finished");
|
LOG_DEBUG(log, "alter thread finished");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StorageReplicatedMergeTree::partCheckThread()
|
||||||
|
{
|
||||||
|
while (!shutdown_called)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
/// Достанем из очереди кусок для проверки.
|
||||||
|
String part_name;
|
||||||
|
{
|
||||||
|
Poco::ScopedLock<Poco::FastMutex> lock(parts_to_check_mutex);
|
||||||
|
if (parts_to_check_queue.empty())
|
||||||
|
{
|
||||||
|
if (!parts_to_check_set.empty())
|
||||||
|
{
|
||||||
|
LOG_ERROR(log, "Non-empty parts_to_check_set with empty parts_to_check_queue. This is a bug.");
|
||||||
|
parts_to_check_set.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
part_name = parts_to_check_queue.front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (part_name.empty())
|
||||||
|
{
|
||||||
|
parts_to_check_event.wait();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_WARNING(log, "Checking part " << part_name);
|
||||||
|
|
||||||
|
auto part = data.getContainingPart(part_name);
|
||||||
|
String part_path = replica_path + "/parts/" + part_name;
|
||||||
|
|
||||||
|
/// Этого или покрывающего куска у нас нет.
|
||||||
|
if (!part)
|
||||||
|
{
|
||||||
|
/// Если кусок есть в ZooKeeper, удалим его оттуда и добавим в очередь задание скачать его.
|
||||||
|
if (zookeeper->exists(part_path))
|
||||||
|
{
|
||||||
|
LOG_WARNING(log, "Part " << part_name << " exists in ZooKeeper but not locally. "
|
||||||
|
"Removing from ZooKeeper and queueing a fetch.");
|
||||||
|
|
||||||
|
LogEntry log_entry;
|
||||||
|
log_entry.type = LogEntry::GET_PART;
|
||||||
|
log_entry.source_replica = "";
|
||||||
|
log_entry.new_part_name = part_name;
|
||||||
|
|
||||||
|
zkutil::Ops ops;
|
||||||
|
ops.push_back(new zkutil::Op::Create(
|
||||||
|
replica_path + "/queue/queue-", log_entry.toString(), zookeeper->getDefaultACL(),
|
||||||
|
zkutil::CreateMode::PersistentSequential));
|
||||||
|
ops.push_back(new zkutil::Op::Remove(part_path + "/checksums", -1));
|
||||||
|
ops.push_back(new zkutil::Op::Remove(part_path + "/columns", -1));
|
||||||
|
ops.push_back(new zkutil::Op::Remove(part_path, -1));
|
||||||
|
auto results = zookeeper->multi(ops);
|
||||||
|
|
||||||
|
{
|
||||||
|
Poco::ScopedLock<Poco::FastMutex> lock(queue_mutex);
|
||||||
|
|
||||||
|
String path_created = dynamic_cast<zkutil::Op::Create &>(ops[0]).getPathCreated();
|
||||||
|
log_entry.znode_name = path_created.substr(path_created.find_last_of('/') + 1);
|
||||||
|
log_entry.addResultToVirtualParts(*this);
|
||||||
|
queue.push_back(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Если куска нет в ZooKeeper, проверим есть ли он хоть у кого-то.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_WARNING(log, "Checking if anyone has part covering " << part_name << ".");
|
||||||
|
asdqwe;
|
||||||
|
|
||||||
|
/// Если ни у кого нет такого куска, удалим его из нашей очереди и добавим его в block_numbers.
|
||||||
|
//не получится надежно удалить из очереди :( Можно попробовать полагаться на block_numbers, но их могут удалить
|
||||||
|
LOG_ERROR(log,
|
||||||
|
//asdqwe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// У нас есть этот кусок, и он активен.
|
||||||
|
else if (part->name == part_name)
|
||||||
|
{
|
||||||
|
/// Если кусок есть в ZooKeeper, сверим его данные с его чексуммами, а их с ZooKeeper.
|
||||||
|
if (zookeeper->exists(replica_path + "/parts/" + part_name))
|
||||||
|
{
|
||||||
|
asdqwe;
|
||||||
|
|
||||||
|
/// Если кусок сломан, одновременно удалим его из ZK и добавим в очередь задание забрать этот кусок у другой реплики.
|
||||||
|
/// И удалим кусок локально.
|
||||||
|
asdqwe;
|
||||||
|
}
|
||||||
|
/// Если куска нет в ZooKeeper, удалим его локально.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/// Если этот кусок еще и получен в результате слияния, это уже чересчур странно.
|
||||||
|
if (part->left != part->right)
|
||||||
|
{
|
||||||
|
LOG_ERROR(log, );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
asdqwe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/// Если у нас есть покрывающий кусок, игнорируем все проблемы с этим куском.
|
||||||
|
/// В худшем случае в лог еще old_parts_lifetime секунд будут валиться ошибки, пока кусок не удалится как старый.
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Удалим кусок из очереди.
|
||||||
|
{
|
||||||
|
Poco::ScopedLock<Poco::FastMutex> lock(parts_to_check_mutex);
|
||||||
|
if (parts_to_check_queue.empty() || parts_to_check_queue.front() != part_name)
|
||||||
|
{
|
||||||
|
LOG_ERROR(log, "Someone changed parts_to_check_queue.front(). This is a bug.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parts_to_check_queue.pop_front();
|
||||||
|
parts_to_check_set.erase(part_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
tryLogCurrentException(__PRETTY_FUNCTION__);
|
||||||
|
parts_to_check_event.tryWait(ERROR_SLEEP_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool StorageReplicatedMergeTree::canMergeParts(const MergeTreeData::DataPartPtr & left, const MergeTreeData::DataPartPtr & right)
|
bool StorageReplicatedMergeTree::canMergeParts(const MergeTreeData::DataPartPtr & left, const MergeTreeData::DataPartPtr & right)
|
||||||
{
|
{
|
||||||
/// Если какой-то из кусков уже собираются слить в больший, не соглашаемся его сливать.
|
/// Если какой-то из кусков уже собираются слить в больший, не соглашаемся его сливать.
|
||||||
|
Loading…
Reference in New Issue
Block a user