ClickHouse/dbms/src/Storages/MergeTree/AbandonableLockInZooKeeper.h

128 lines
3.1 KiB
C++
Raw Normal View History

2014-04-02 07:59:43 +00:00
#pragma once
#include <Common/ZooKeeper/ZooKeeper.h>
#include <Common/Exception.h>
#include <IO/ReadHelpers.h>
2014-04-02 07:59:43 +00:00
namespace DB
{
namespace ErrorCodes
{
extern const int LOGICAL_ERROR;
}
2017-04-16 15:00:33 +00:00
/** The synchronization is primitive. Works as follows:
* Creates a non-ephemeral incremental node and marks it as locked (LOCKED).
* `unlock()` unlocks it (UNLOCKED).
* When the destructor is called or the session ends in ZooKeeper, it goes into the ABANDONED state.
* (Including when the program is halted).
2014-04-02 07:59:43 +00:00
*/
class AbandonableLockInZooKeeper : public boost::noncopyable
2014-04-02 07:59:43 +00:00
{
public:
enum State
{
UNLOCKED,
LOCKED,
ABANDONED,
};
AbandonableLockInZooKeeper(
const String & path_prefix_, const String & temp_path, zkutil::ZooKeeper & zookeeper_, zkutil::Requests * precheck_ops = nullptr);
AbandonableLockInZooKeeper() = default;
AbandonableLockInZooKeeper(AbandonableLockInZooKeeper && rhs) noexcept
{
*this = std::move(rhs);
}
AbandonableLockInZooKeeper & operator=(AbandonableLockInZooKeeper && rhs) noexcept
{
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;
}
bool isCreated() const
{
return zookeeper && !holder_path.empty() && !path.empty();
}
String getPath() const
{
checkCreated();
return path;
}
2017-04-16 15:00:33 +00:00
/// Parse the number at the end of the path.
UInt64 getNumber() const
{
checkCreated();
return parse<UInt64>(path.c_str() + path_prefix.size(), path.size() - path_prefix.size());
}
void unlock();
2017-04-16 15:00:33 +00:00
/// Adds actions equivalent to `unlock()` to the list.
void getUnlockOps(zkutil::Requests & ops);
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 19:06:53 +00:00
holder_path.clear();
}
void checkCreated() const
{
if (!isCreated())
throw Exception("AbandonableLock is not created", ErrorCodes::LOGICAL_ERROR);
}
~AbandonableLockInZooKeeper();
private:
zkutil::ZooKeeper * zookeeper = nullptr;
String path_prefix;
String path;
String holder_path;
};
/// Acquires block number locks in all partitions. The class is called Ephemeral- instead of Abandonable-
/// because it creates ephemeral block nodes (there is no need to leave abandoned tombstones).
class EphemeralLocksInAllPartitions
{
public:
EphemeralLocksInAllPartitions(
const String & block_numbers_path, const String & path_prefix, const String & temp_path,
zkutil::ZooKeeper & zookeeper_);
struct LockInfo
{
String path;
String holder_path;
String partition_id;
UInt64 number = 0;
};
const std::vector<LockInfo> & getLocks() const { return locks; }
void unlock();
~EphemeralLocksInAllPartitions();
2014-07-25 16:32:02 +00:00
2014-04-02 07:59:43 +00:00
private:
zkutil::ZooKeeper & zookeeper;
std::vector<LockInfo> locks;
2014-04-02 07:59:43 +00:00
};
}