fork of https://github.com/rust-rocksdb/rust-rocksdb for nextgraph
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
4.5 KiB
146 lines
4.5 KiB
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
|
// This source code is licensed under both the GPLv2 (found in the
|
|
// COPYING file in the root directory) and Apache 2.0 License
|
|
// (found in the LICENSE.Apache file in the root directory).
|
|
|
|
#pragma once
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
|
|
#include "util/mutexlock.h"
|
|
#include "utilities/transactions/lock/lock_tracker.h"
|
|
#include "utilities/transactions/pessimistic_transaction.h"
|
|
|
|
// Range Locking:
|
|
#include "lib/locktree/lock_request.h"
|
|
#include "lib/locktree/locktree.h"
|
|
|
|
namespace ROCKSDB_NAMESPACE {
|
|
|
|
class RangeTreeLockManager;
|
|
|
|
// Storage for locks that are currently held by a transaction.
|
|
//
|
|
// Locks are kept in toku::range_buffer because toku::locktree::release_locks()
|
|
// accepts that as an argument.
|
|
//
|
|
// Note: the list of locks may differ slighly from the contents of the lock
|
|
// tree, due to concurrency between lock acquisition, lock release, and lock
|
|
// escalation. See MDEV-18227 and RangeTreeLockManager::UnLock for details.
|
|
// This property is currently harmless.
|
|
//
|
|
// Append() and ReleaseLocks() are not thread-safe, as they are expected to be
|
|
// called only by the owner transaction. ReplaceLocks() is safe to call from
|
|
// other threads.
|
|
class RangeLockList {
|
|
public:
|
|
~RangeLockList() { Clear(); }
|
|
|
|
RangeLockList() : releasing_locks_(false) {}
|
|
|
|
void Append(ColumnFamilyId cf_id, const DBT* left_key, const DBT* right_key);
|
|
void ReleaseLocks(RangeTreeLockManager* mgr, PessimisticTransaction* txn,
|
|
bool all_trx_locks);
|
|
void ReplaceLocks(const toku::locktree* lt, const toku::range_buffer& buffer);
|
|
|
|
private:
|
|
void Clear() {
|
|
for (auto it : buffers_) {
|
|
it.second->destroy();
|
|
}
|
|
buffers_.clear();
|
|
}
|
|
|
|
std::unordered_map<ColumnFamilyId, std::shared_ptr<toku::range_buffer>>
|
|
buffers_;
|
|
port::Mutex mutex_;
|
|
std::atomic<bool> releasing_locks_;
|
|
};
|
|
|
|
// A LockTracker-based object that is used together with RangeTreeLockManager.
|
|
class RangeTreeLockTracker : public LockTracker {
|
|
public:
|
|
RangeTreeLockTracker() : range_list_(nullptr) {}
|
|
|
|
RangeTreeLockTracker(const RangeTreeLockTracker&) = delete;
|
|
RangeTreeLockTracker& operator=(const RangeTreeLockTracker&) = delete;
|
|
|
|
void Track(const PointLockRequest&) override;
|
|
void Track(const RangeLockRequest&) override;
|
|
|
|
bool IsPointLockSupported() const override {
|
|
// This indicates that we don't implement GetPointLockStatus()
|
|
return false;
|
|
}
|
|
bool IsRangeLockSupported() const override { return true; }
|
|
|
|
// a Not-supported dummy implementation.
|
|
UntrackStatus Untrack(const RangeLockRequest& /*lock_request*/) override {
|
|
return UntrackStatus::NOT_TRACKED;
|
|
}
|
|
|
|
UntrackStatus Untrack(const PointLockRequest& /*lock_request*/) override {
|
|
return UntrackStatus::NOT_TRACKED;
|
|
}
|
|
|
|
// "If this method is not supported, leave it as a no-op."
|
|
void Merge(const LockTracker&) override {}
|
|
|
|
// "If this method is not supported, leave it as a no-op."
|
|
void Subtract(const LockTracker&) override {}
|
|
|
|
void Clear() override;
|
|
|
|
// "If this method is not supported, returns nullptr."
|
|
virtual LockTracker* GetTrackedLocksSinceSavePoint(
|
|
const LockTracker&) const override {
|
|
return nullptr;
|
|
}
|
|
|
|
PointLockStatus GetPointLockStatus(ColumnFamilyId column_family_id,
|
|
const std::string& key) const override;
|
|
|
|
// The return value is only used for tests
|
|
uint64_t GetNumPointLocks() const override { return 0; }
|
|
|
|
ColumnFamilyIterator* GetColumnFamilyIterator() const override {
|
|
return nullptr;
|
|
}
|
|
|
|
KeyIterator* GetKeyIterator(
|
|
ColumnFamilyId /*column_family_id*/) const override {
|
|
return nullptr;
|
|
}
|
|
|
|
void ReleaseLocks(RangeTreeLockManager* mgr, PessimisticTransaction* txn,
|
|
bool all_trx_locks) {
|
|
if (range_list_) range_list_->ReleaseLocks(mgr, txn, all_trx_locks);
|
|
}
|
|
|
|
void ReplaceLocks(const toku::locktree* lt,
|
|
const toku::range_buffer& buffer) {
|
|
// range_list_ cannot be NULL here
|
|
range_list_->ReplaceLocks(lt, buffer);
|
|
}
|
|
|
|
private:
|
|
RangeLockList* getOrCreateList();
|
|
std::unique_ptr<RangeLockList> range_list_;
|
|
};
|
|
|
|
class RangeTreeLockTrackerFactory : public LockTrackerFactory {
|
|
public:
|
|
static const RangeTreeLockTrackerFactory& Get() {
|
|
static const RangeTreeLockTrackerFactory instance;
|
|
return instance;
|
|
}
|
|
|
|
LockTracker* Create() const override { return new RangeTreeLockTracker(); }
|
|
|
|
private:
|
|
RangeTreeLockTrackerFactory() {}
|
|
};
|
|
|
|
} // namespace ROCKSDB_NAMESPACE
|
|
|