2014-04-02 07:59:43 +00:00
|
|
|
#pragma once
|
|
|
|
|
2020-11-10 10:23:46 +00:00
|
|
|
#include "ReplicatedMergeTreeMutationEntry.h"
|
|
|
|
|
2017-06-19 20:06:35 +00:00
|
|
|
#include <Common/ZooKeeper/ZooKeeper.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Common/Exception.h>
|
|
|
|
#include <IO/ReadHelpers.h>
|
2014-04-02 07:59:43 +00:00
|
|
|
|
2020-11-10 10:23:46 +00:00
|
|
|
#include <map>
|
|
|
|
#include <optional>
|
|
|
|
|
2014-04-02 07:59:43 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2016-01-24 05:00:24 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
extern const int LOGICAL_ERROR;
|
2016-01-24 05:00:24 +00:00
|
|
|
}
|
|
|
|
|
2018-07-04 16:31:21 +00:00
|
|
|
/// A class that is used for locking a block number in a partition.
|
|
|
|
/// It creates a secondary ephemeral node in `temp_path` and a main ephemeral node with `path_prefix`
|
|
|
|
/// that references the secondary node. The reasons for this two-level scheme are historical (of course
|
|
|
|
/// it would be simpler to allocate block numbers for all partitions in one ZK directory).
|
|
|
|
class EphemeralLockInZooKeeper : public boost::noncopyable
|
2014-04-02 07:59:43 +00:00
|
|
|
{
|
|
|
|
public:
|
2018-07-04 16:31:21 +00:00
|
|
|
EphemeralLockInZooKeeper(
|
2018-08-25 01:58:14 +00:00
|
|
|
const String & path_prefix_, const String & temp_path, zkutil::ZooKeeper & zookeeper_, Coordination::Requests * precheck_ops = nullptr);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-07-04 16:31:21 +00:00
|
|
|
EphemeralLockInZooKeeper() = default;
|
2018-03-13 20:36:22 +00:00
|
|
|
|
2018-07-04 16:31:21 +00:00
|
|
|
EphemeralLockInZooKeeper(EphemeralLockInZooKeeper && rhs) noexcept
|
2018-03-13 20:36:22 +00:00
|
|
|
{
|
|
|
|
*this = std::move(rhs);
|
|
|
|
}
|
|
|
|
|
2018-07-04 16:31:21 +00:00
|
|
|
EphemeralLockInZooKeeper & operator=(EphemeralLockInZooKeeper && rhs) noexcept
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2018-03-13 20:36:22 +00:00
|
|
|
zookeeper = rhs.zookeeper;
|
|
|
|
rhs.zookeeper = nullptr;
|
|
|
|
path_prefix = std::move(rhs.path_prefix);
|
|
|
|
path = std::move(rhs.path);
|
|
|
|
holder_path = std::move(rhs.holder_path);
|
|
|
|
return *this;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
2018-01-19 22:37:50 +00:00
|
|
|
bool isCreated() const
|
|
|
|
{
|
2018-03-13 20:36:22 +00:00
|
|
|
return zookeeper && !holder_path.empty() && !path.empty();
|
2018-01-19 22:37:50 +00:00
|
|
|
}
|
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
String getPath() const
|
|
|
|
{
|
2018-01-19 22:37:50 +00:00
|
|
|
checkCreated();
|
2017-04-01 07:20:54 +00:00
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
2017-04-16 15:00:33 +00:00
|
|
|
/// Parse the number at the end of the path.
|
2017-04-01 07:20:54 +00:00
|
|
|
UInt64 getNumber() const
|
|
|
|
{
|
2018-01-19 22:37:50 +00:00
|
|
|
checkCreated();
|
2017-04-01 07:20:54 +00:00
|
|
|
return parse<UInt64>(path.c_str() + path_prefix.size(), path.size() - path_prefix.size());
|
|
|
|
}
|
|
|
|
|
2018-04-04 12:39:48 +00:00
|
|
|
void unlock();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-04-16 15:00:33 +00:00
|
|
|
/// Adds actions equivalent to `unlock()` to the list.
|
2018-08-25 01:58:14 +00:00
|
|
|
void getUnlockOps(Coordination::Requests & ops);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-03-15 19:05:58 +00:00
|
|
|
/// Do not delete nodes in destructor. You may call this method after 'getUnlockOps' and successful execution of these ops,
|
|
|
|
/// because the nodes will be already deleted.
|
|
|
|
void assumeUnlocked()
|
2018-03-15 17:04:47 +00:00
|
|
|
{
|
2018-03-15 19:06:53 +00:00
|
|
|
holder_path.clear();
|
2018-03-15 17:04:47 +00:00
|
|
|
}
|
|
|
|
|
2018-01-19 22:37:50 +00:00
|
|
|
void checkCreated() const
|
|
|
|
{
|
|
|
|
if (!isCreated())
|
2018-07-04 16:31:21 +00:00
|
|
|
throw Exception("EphemeralLock is not created", ErrorCodes::LOGICAL_ERROR);
|
2018-01-19 22:37:50 +00:00
|
|
|
}
|
|
|
|
|
2018-07-04 16:31:21 +00:00
|
|
|
~EphemeralLockInZooKeeper();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-04-04 12:39:48 +00:00
|
|
|
private:
|
|
|
|
zkutil::ZooKeeper * zookeeper = nullptr;
|
|
|
|
String path_prefix;
|
|
|
|
String path;
|
|
|
|
String holder_path;
|
|
|
|
};
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
|
2018-07-04 16:31:21 +00:00
|
|
|
/// Acquires block number locks in all partitions.
|
2020-11-10 10:23:46 +00:00
|
|
|
class EphemeralLocksInAllPartitions : public boost::noncopyable
|
2018-04-04 12:39:48 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
EphemeralLocksInAllPartitions(
|
|
|
|
const String & block_numbers_path, const String & path_prefix, const String & temp_path,
|
|
|
|
zkutil::ZooKeeper & zookeeper_);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2020-11-10 10:23:46 +00:00
|
|
|
EphemeralLocksInAllPartitions() = default;
|
|
|
|
|
|
|
|
EphemeralLocksInAllPartitions(EphemeralLocksInAllPartitions && rhs) noexcept
|
|
|
|
: zookeeper(rhs.zookeeper)
|
|
|
|
, locks(std::move(rhs.locks))
|
|
|
|
{
|
|
|
|
rhs.zookeeper = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
EphemeralLocksInAllPartitions & operator=(EphemeralLocksInAllPartitions && rhs) noexcept
|
|
|
|
{
|
|
|
|
zookeeper = rhs.zookeeper;
|
|
|
|
rhs.zookeeper = nullptr;
|
|
|
|
locks = std::move(rhs.locks);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2018-04-04 12:39:48 +00:00
|
|
|
struct LockInfo
|
|
|
|
{
|
|
|
|
String path;
|
|
|
|
String holder_path;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-04-04 12:39:48 +00:00
|
|
|
String partition_id;
|
|
|
|
UInt64 number = 0;
|
|
|
|
};
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-04-04 12:39:48 +00:00
|
|
|
const std::vector<LockInfo> & getLocks() const { return locks; }
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2018-04-04 12:39:48 +00:00
|
|
|
void unlock();
|
|
|
|
|
|
|
|
~EphemeralLocksInAllPartitions();
|
2014-07-25 16:32:02 +00:00
|
|
|
|
2014-04-02 07:59:43 +00:00
|
|
|
private:
|
2020-11-10 10:23:46 +00:00
|
|
|
zkutil::ZooKeeper * zookeeper = nullptr;
|
2018-04-04 12:39:48 +00:00
|
|
|
std::vector<LockInfo> locks;
|
2014-04-02 07:59:43 +00:00
|
|
|
};
|
|
|
|
|
2020-11-10 10:23:46 +00:00
|
|
|
|
|
|
|
/// This class allows scoped manipulations with block numbers locked in certain partitions
|
|
|
|
/// See StorageReplicatedMergeTree::allocateBlockNumbersInAffectedPartitions and alter()/mutate() methods
|
|
|
|
class PartitionBlockNumbersHolder
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
PartitionBlockNumbersHolder(const PartitionBlockNumbersHolder &) = delete;
|
|
|
|
PartitionBlockNumbersHolder & operator=(const PartitionBlockNumbersHolder &) = delete;
|
|
|
|
|
|
|
|
using BlockNumbersType = ReplicatedMergeTreeMutationEntry::BlockNumbersType;
|
|
|
|
|
|
|
|
PartitionBlockNumbersHolder() = default;
|
|
|
|
PartitionBlockNumbersHolder(
|
|
|
|
BlockNumbersType block_numbers_, std::optional<EphemeralLocksInAllPartitions> locked_block_numbers_holder)
|
|
|
|
: block_numbers(std::move(block_numbers_))
|
|
|
|
, multiple_partitions_holder(std::move(locked_block_numbers_holder))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
PartitionBlockNumbersHolder(
|
|
|
|
BlockNumbersType block_numbers_, std::optional<EphemeralLockInZooKeeper> locked_block_numbers_holder)
|
|
|
|
: block_numbers(std::move(block_numbers_))
|
|
|
|
, single_partition_holder(std::move(locked_block_numbers_holder))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
PartitionBlockNumbersHolder & operator=(PartitionBlockNumbersHolder &&) = default;
|
|
|
|
|
|
|
|
const BlockNumbersType & getBlockNumbers() const { return block_numbers; }
|
|
|
|
|
|
|
|
void reset()
|
|
|
|
{
|
|
|
|
multiple_partitions_holder.reset();
|
|
|
|
single_partition_holder.reset();
|
|
|
|
block_numbers.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
BlockNumbersType block_numbers;
|
|
|
|
|
|
|
|
std::optional<EphemeralLocksInAllPartitions> multiple_partitions_holder;
|
|
|
|
std::optional<EphemeralLockInZooKeeper> single_partition_holder;
|
|
|
|
};
|
|
|
|
|
2014-04-02 07:59:43 +00:00
|
|
|
}
|