]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
11fdf7f2 TL |
2 | // This source code is licensed under both the GPLv2 (found in the |
3 | // COPYING file in the root directory) and Apache 2.0 License | |
4 | // (found in the LICENSE.Apache file in the root directory). | |
7c673cae FG |
5 | |
6 | #pragma once | |
7 | ||
8 | #ifndef ROCKSDB_LITE | |
9 | ||
10 | #include <algorithm> | |
11 | #include <atomic> | |
12 | #include <mutex> | |
13 | #include <stack> | |
14 | #include <string> | |
15 | #include <unordered_map> | |
16 | #include <vector> | |
17 | ||
18 | #include "db/write_callback.h" | |
19 | #include "rocksdb/db.h" | |
20 | #include "rocksdb/slice.h" | |
21 | #include "rocksdb/snapshot.h" | |
22 | #include "rocksdb/status.h" | |
23 | #include "rocksdb/types.h" | |
24 | #include "rocksdb/utilities/transaction.h" | |
25 | #include "rocksdb/utilities/transaction_db.h" | |
26 | #include "rocksdb/utilities/write_batch_with_index.h" | |
27 | #include "util/autovector.h" | |
28 | #include "utilities/transactions/transaction_base.h" | |
29 | #include "utilities/transactions/transaction_util.h" | |
30 | ||
31 | namespace rocksdb { | |
32 | ||
11fdf7f2 | 33 | class PessimisticTransactionDB; |
7c673cae | 34 | |
11fdf7f2 TL |
35 | // A transaction under pessimistic concurrency control. This class implements |
36 | // the locking API and interfaces with the lock manager as well as the | |
37 | // pessimistic transactional db. | |
38 | class PessimisticTransaction : public TransactionBaseImpl { | |
7c673cae | 39 | public: |
11fdf7f2 | 40 | PessimisticTransaction(TransactionDB* db, const WriteOptions& write_options, |
494da23a TL |
41 | const TransactionOptions& txn_options, |
42 | const bool init = true); | |
7c673cae | 43 | |
11fdf7f2 | 44 | virtual ~PessimisticTransaction(); |
7c673cae FG |
45 | |
46 | void Reinitialize(TransactionDB* txn_db, const WriteOptions& write_options, | |
47 | const TransactionOptions& txn_options); | |
48 | ||
49 | Status Prepare() override; | |
50 | ||
51 | Status Commit() override; | |
52 | ||
11fdf7f2 TL |
53 | // It is basically Commit without going through Prepare phase. The write batch |
54 | // is also directly provided instead of expecting txn to gradually batch the | |
55 | // transactions writes to an internal write batch. | |
7c673cae FG |
56 | Status CommitBatch(WriteBatch* batch); |
57 | ||
58 | Status Rollback() override; | |
59 | ||
60 | Status RollbackToSavePoint() override; | |
61 | ||
62 | Status SetName(const TransactionName& name) override; | |
63 | ||
64 | // Generate a new unique transaction identifier | |
65 | static TransactionID GenTxnID(); | |
66 | ||
67 | TransactionID GetID() const override { return txn_id_; } | |
68 | ||
69 | std::vector<TransactionID> GetWaitingTxns(uint32_t* column_family_id, | |
70 | std::string* key) const override { | |
71 | std::lock_guard<std::mutex> lock(wait_mutex_); | |
72 | std::vector<TransactionID> ids(waiting_txn_ids_.size()); | |
73 | if (key) *key = waiting_key_ ? *waiting_key_ : ""; | |
74 | if (column_family_id) *column_family_id = waiting_cf_id_; | |
75 | std::copy(waiting_txn_ids_.begin(), waiting_txn_ids_.end(), ids.begin()); | |
76 | return ids; | |
77 | } | |
78 | ||
79 | void SetWaitingTxn(autovector<TransactionID> ids, uint32_t column_family_id, | |
80 | const std::string* key) { | |
81 | std::lock_guard<std::mutex> lock(wait_mutex_); | |
82 | waiting_txn_ids_ = ids; | |
83 | waiting_cf_id_ = column_family_id; | |
84 | waiting_key_ = key; | |
85 | } | |
86 | ||
87 | void ClearWaitingTxn() { | |
88 | std::lock_guard<std::mutex> lock(wait_mutex_); | |
89 | waiting_txn_ids_.clear(); | |
90 | waiting_cf_id_ = 0; | |
91 | waiting_key_ = nullptr; | |
92 | } | |
93 | ||
94 | // Returns the time (in microseconds according to Env->GetMicros()) | |
95 | // that this transaction will be expired. Returns 0 if this transaction does | |
96 | // not expire. | |
97 | uint64_t GetExpirationTime() const { return expiration_time_; } | |
98 | ||
99 | // returns true if this transaction has an expiration_time and has expired. | |
100 | bool IsExpired() const; | |
101 | ||
102 | // Returns the number of microseconds a transaction can wait on acquiring a | |
103 | // lock or -1 if there is no timeout. | |
104 | int64_t GetLockTimeout() const { return lock_timeout_; } | |
105 | void SetLockTimeout(int64_t timeout) override { | |
106 | lock_timeout_ = timeout * 1000; | |
107 | } | |
108 | ||
109 | // Returns true if locks were stolen successfully, false otherwise. | |
110 | bool TryStealingLocks(); | |
111 | ||
112 | bool IsDeadlockDetect() const override { return deadlock_detect_; } | |
113 | ||
114 | int64_t GetDeadlockDetectDepth() const { return deadlock_detect_depth_; } | |
115 | ||
116 | protected: | |
11fdf7f2 TL |
117 | // Refer to |
118 | // TransactionOptions::use_only_the_last_commit_time_batch_for_recovery | |
119 | bool use_only_the_last_commit_time_batch_for_recovery_ = false; | |
120 | ||
121 | virtual Status PrepareInternal() = 0; | |
122 | ||
123 | virtual Status CommitWithoutPrepareInternal() = 0; | |
124 | ||
125 | // batch_cnt if non-zero is the number of sub-batches. A sub-batch is a batch | |
126 | // with no duplicate keys. If zero, then the number of sub-batches is unknown. | |
127 | virtual Status CommitBatchInternal(WriteBatch* batch, | |
128 | size_t batch_cnt = 0) = 0; | |
129 | ||
130 | virtual Status CommitInternal() = 0; | |
131 | ||
132 | virtual Status RollbackInternal() = 0; | |
133 | ||
134 | virtual void Initialize(const TransactionOptions& txn_options); | |
135 | ||
136 | Status LockBatch(WriteBatch* batch, TransactionKeyMap* keys_to_unlock); | |
137 | ||
7c673cae | 138 | Status TryLock(ColumnFamilyHandle* column_family, const Slice& key, |
494da23a TL |
139 | bool read_only, bool exclusive, const bool do_validate = true, |
140 | const bool assume_tracked = false) override; | |
7c673cae | 141 | |
11fdf7f2 TL |
142 | void Clear() override; |
143 | ||
144 | PessimisticTransactionDB* txn_db_impl_; | |
7c673cae FG |
145 | DBImpl* db_impl_; |
146 | ||
11fdf7f2 TL |
147 | // If non-zero, this transaction should not be committed after this time (in |
148 | // microseconds according to Env->NowMicros()) | |
149 | uint64_t expiration_time_; | |
150 | ||
151 | private: | |
152 | friend class TransactionTest_ValidateSnapshotTest_Test; | |
7c673cae FG |
153 | // Used to create unique ids for transactions. |
154 | static std::atomic<TransactionID> txn_id_counter_; | |
155 | ||
156 | // Unique ID for this transaction | |
157 | TransactionID txn_id_; | |
158 | ||
159 | // IDs for the transactions that are blocking the current transaction. | |
160 | // | |
161 | // empty if current transaction is not waiting. | |
162 | autovector<TransactionID> waiting_txn_ids_; | |
163 | ||
164 | // The following two represents the (cf, key) that a transaction is waiting | |
165 | // on. | |
166 | // | |
167 | // If waiting_key_ is not null, then the pointer should always point to | |
168 | // a valid string object. The reason is that it is only non-null when the | |
169 | // transaction is blocked in the TransactionLockMgr::AcquireWithTimeout | |
170 | // function. At that point, the key string object is one of the function | |
171 | // parameters. | |
172 | uint32_t waiting_cf_id_; | |
173 | const std::string* waiting_key_; | |
174 | ||
175 | // Mutex protecting waiting_txn_ids_, waiting_cf_id_ and waiting_key_. | |
176 | mutable std::mutex wait_mutex_; | |
177 | ||
7c673cae FG |
178 | // Timeout in microseconds when locking a key or -1 if there is no timeout. |
179 | int64_t lock_timeout_; | |
180 | ||
181 | // Whether to perform deadlock detection or not. | |
182 | bool deadlock_detect_; | |
183 | ||
184 | // Whether to perform deadlock detection or not. | |
185 | int64_t deadlock_detect_depth_; | |
186 | ||
11fdf7f2 TL |
187 | // Refer to TransactionOptions::skip_concurrency_control |
188 | bool skip_concurrency_control_; | |
7c673cae | 189 | |
11fdf7f2 TL |
190 | virtual Status ValidateSnapshot(ColumnFamilyHandle* column_family, |
191 | const Slice& key, | |
192 | SequenceNumber* tracked_at_seq); | |
7c673cae FG |
193 | |
194 | void UnlockGetForUpdate(ColumnFamilyHandle* column_family, | |
195 | const Slice& key) override; | |
196 | ||
197 | // No copying allowed | |
11fdf7f2 TL |
198 | PessimisticTransaction(const PessimisticTransaction&); |
199 | void operator=(const PessimisticTransaction&); | |
7c673cae FG |
200 | }; |
201 | ||
11fdf7f2 | 202 | class WriteCommittedTxn : public PessimisticTransaction { |
7c673cae | 203 | public: |
11fdf7f2 TL |
204 | WriteCommittedTxn(TransactionDB* db, const WriteOptions& write_options, |
205 | const TransactionOptions& txn_options); | |
7c673cae | 206 | |
11fdf7f2 | 207 | virtual ~WriteCommittedTxn() {} |
7c673cae FG |
208 | |
209 | private: | |
11fdf7f2 TL |
210 | Status PrepareInternal() override; |
211 | ||
212 | Status CommitWithoutPrepareInternal() override; | |
213 | ||
214 | Status CommitBatchInternal(WriteBatch* batch, size_t batch_cnt) override; | |
215 | ||
216 | Status CommitInternal() override; | |
217 | ||
218 | Status RollbackInternal() override; | |
219 | ||
220 | // No copying allowed | |
221 | WriteCommittedTxn(const WriteCommittedTxn&); | |
222 | void operator=(const WriteCommittedTxn&); | |
7c673cae FG |
223 | }; |
224 | ||
225 | } // namespace rocksdb | |
226 | ||
227 | #endif // ROCKSDB_LITE |