Replace tracked_keys with a new LockTracker interface in TransactionDB (#7013)
Summary:
We're going to support more locking protocols such as range lock in transaction.
However, in current design, `TransactionBase` has a member `tracked_keys` which assumes that point lock (lock a single key) is used, and is used in snapshot checking (isolation protocol). When using range lock, we may use read committed instead of snapshot checking as the isolation protocol.
The most significant usage scenarios of `tracked_keys` are:
1. pessimistic transaction uses it to track the locked keys, and unlock these keys when commit or rollback.
2. optimistic transaction does not lock keys upfront, it only tracks the lock intentions in tracked_keys, and do write conflict checking when commit.
3. each `SavePoint` tracks the keys that are locked since the `SavePoint`, `RollbackToSavePoint` or `PopSavePoint` relies on both the tracked keys in `SavePoint`s and `tracked_keys`.
Based on these scenarios, if we can abstract out a `LockTracker` interface to hold a set of tracked locks (can be keys or key ranges), and have methods that can be composed together to implement the scenarios, then `tracked_keys` can be an internal data structure of one implementation of `LockTracker`. See `utilities/transactions/lock/lock_tracker.h` for the detailed interface design, and `utilities/transactions/lock/point_lock_tracker.cc` for the implementation.
In the future, a `RangeLockTracker` can be implemented to track range locks without affecting other components.
After this PR, a clean interface for lock manager should be possible, and then ideally, we can have pluggable locking protocols.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/7013
Test Plan: Run `transaction_test` and `optimistic_transaction_test`.
Reviewed By: ajkr
Differential Revision: D22163706
Pulled By: cheng-chang
fbshipit-source-id: f2860577b5334e31dd2994f5bc6d7c40d502b1b4
4 years ago
|
|
|
// 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
|
|
|
|
#ifndef ROCKSDB_LITE
|
Replace tracked_keys with a new LockTracker interface in TransactionDB (#7013)
Summary:
We're going to support more locking protocols such as range lock in transaction.
However, in current design, `TransactionBase` has a member `tracked_keys` which assumes that point lock (lock a single key) is used, and is used in snapshot checking (isolation protocol). When using range lock, we may use read committed instead of snapshot checking as the isolation protocol.
The most significant usage scenarios of `tracked_keys` are:
1. pessimistic transaction uses it to track the locked keys, and unlock these keys when commit or rollback.
2. optimistic transaction does not lock keys upfront, it only tracks the lock intentions in tracked_keys, and do write conflict checking when commit.
3. each `SavePoint` tracks the keys that are locked since the `SavePoint`, `RollbackToSavePoint` or `PopSavePoint` relies on both the tracked keys in `SavePoint`s and `tracked_keys`.
Based on these scenarios, if we can abstract out a `LockTracker` interface to hold a set of tracked locks (can be keys or key ranges), and have methods that can be composed together to implement the scenarios, then `tracked_keys` can be an internal data structure of one implementation of `LockTracker`. See `utilities/transactions/lock/lock_tracker.h` for the detailed interface design, and `utilities/transactions/lock/point_lock_tracker.cc` for the implementation.
In the future, a `RangeLockTracker` can be implemented to track range locks without affecting other components.
After this PR, a clean interface for lock manager should be possible, and then ideally, we can have pluggable locking protocols.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/7013
Test Plan: Run `transaction_test` and `optimistic_transaction_test`.
Reviewed By: ajkr
Differential Revision: D22163706
Pulled By: cheng-chang
fbshipit-source-id: f2860577b5334e31dd2994f5bc6d7c40d502b1b4
4 years ago
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <string>
|
|
|
|
#include <unordered_map>
|
|
|
|
|
|
|
|
#include "utilities/transactions/lock/lock_tracker.h"
|
|
|
|
|
|
|
|
namespace ROCKSDB_NAMESPACE {
|
|
|
|
|
|
|
|
struct TrackedKeyInfo {
|
|
|
|
// Earliest sequence number that is relevant to this transaction for this key
|
|
|
|
SequenceNumber seq;
|
|
|
|
|
|
|
|
uint32_t num_writes;
|
|
|
|
uint32_t num_reads;
|
|
|
|
|
|
|
|
bool exclusive;
|
|
|
|
|
|
|
|
explicit TrackedKeyInfo(SequenceNumber seq_no)
|
|
|
|
: seq(seq_no), num_writes(0), num_reads(0), exclusive(false) {}
|
|
|
|
|
|
|
|
void Merge(const TrackedKeyInfo& info) {
|
|
|
|
assert(seq <= info.seq);
|
|
|
|
num_reads += info.num_reads;
|
|
|
|
num_writes += info.num_writes;
|
|
|
|
exclusive = exclusive || info.exclusive;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
using TrackedKeyInfos = std::unordered_map<std::string, TrackedKeyInfo>;
|
|
|
|
|
|
|
|
using TrackedKeys = std::unordered_map<ColumnFamilyId, TrackedKeyInfos>;
|
|
|
|
|
|
|
|
// Tracks point locks on single keys.
|
|
|
|
class PointLockTracker : public LockTracker {
|
|
|
|
public:
|
|
|
|
PointLockTracker() = default;
|
|
|
|
|
|
|
|
PointLockTracker(const PointLockTracker&) = delete;
|
|
|
|
PointLockTracker& operator=(const PointLockTracker&) = delete;
|
|
|
|
|
|
|
|
bool IsPointLockSupported() const override { return true; }
|
|
|
|
|
|
|
|
bool IsRangeLockSupported() const override { return false; }
|
|
|
|
|
|
|
|
void Track(const PointLockRequest& lock_request) override;
|
|
|
|
|
|
|
|
UntrackStatus Untrack(const PointLockRequest& lock_request) override;
|
|
|
|
|
|
|
|
void Track(const RangeLockRequest& /*lock_request*/) override {}
|
|
|
|
|
|
|
|
UntrackStatus Untrack(const RangeLockRequest& /*lock_request*/) override {
|
|
|
|
return UntrackStatus::NOT_TRACKED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Merge(const LockTracker& tracker) override;
|
|
|
|
|
|
|
|
void Subtract(const LockTracker& tracker) override;
|
|
|
|
|
|
|
|
void Clear() override;
|
|
|
|
|
|
|
|
virtual LockTracker* GetTrackedLocksSinceSavePoint(
|
|
|
|
const LockTracker& save_point_tracker) const override;
|
|
|
|
|
|
|
|
PointLockStatus GetPointLockStatus(ColumnFamilyId column_family_id,
|
|
|
|
const std::string& key) const override;
|
|
|
|
|
|
|
|
uint64_t GetNumPointLocks() const override;
|
|
|
|
|
|
|
|
ColumnFamilyIterator* GetColumnFamilyIterator() const override;
|
|
|
|
|
|
|
|
KeyIterator* GetKeyIterator(ColumnFamilyId column_family_id) const override;
|
|
|
|
|
|
|
|
private:
|
|
|
|
TrackedKeys tracked_keys_;
|
|
|
|
};
|
|
|
|
|
|
|
|
class PointLockTrackerFactory : public LockTrackerFactory {
|
|
|
|
public:
|
|
|
|
static const PointLockTrackerFactory& Get() {
|
|
|
|
static const PointLockTrackerFactory instance;
|
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
LockTracker* Create() const override { return new PointLockTracker(); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
PointLockTrackerFactory() {}
|
|
|
|
};
|
|
|
|
|
Replace tracked_keys with a new LockTracker interface in TransactionDB (#7013)
Summary:
We're going to support more locking protocols such as range lock in transaction.
However, in current design, `TransactionBase` has a member `tracked_keys` which assumes that point lock (lock a single key) is used, and is used in snapshot checking (isolation protocol). When using range lock, we may use read committed instead of snapshot checking as the isolation protocol.
The most significant usage scenarios of `tracked_keys` are:
1. pessimistic transaction uses it to track the locked keys, and unlock these keys when commit or rollback.
2. optimistic transaction does not lock keys upfront, it only tracks the lock intentions in tracked_keys, and do write conflict checking when commit.
3. each `SavePoint` tracks the keys that are locked since the `SavePoint`, `RollbackToSavePoint` or `PopSavePoint` relies on both the tracked keys in `SavePoint`s and `tracked_keys`.
Based on these scenarios, if we can abstract out a `LockTracker` interface to hold a set of tracked locks (can be keys or key ranges), and have methods that can be composed together to implement the scenarios, then `tracked_keys` can be an internal data structure of one implementation of `LockTracker`. See `utilities/transactions/lock/lock_tracker.h` for the detailed interface design, and `utilities/transactions/lock/point_lock_tracker.cc` for the implementation.
In the future, a `RangeLockTracker` can be implemented to track range locks without affecting other components.
After this PR, a clean interface for lock manager should be possible, and then ideally, we can have pluggable locking protocols.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/7013
Test Plan: Run `transaction_test` and `optimistic_transaction_test`.
Reviewed By: ajkr
Differential Revision: D22163706
Pulled By: cheng-chang
fbshipit-source-id: f2860577b5334e31dd2994f5bc6d7c40d502b1b4
4 years ago
|
|
|
} // namespace ROCKSDB_NAMESPACE
|
|
|
|
#endif // ROCKSDB_LITE
|