YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/common/transaction.h
Line
Count
Source (jump to first uncovered line)
1
//
2
// Copyright (c) YugaByte, Inc.
3
//
4
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5
// in compliance with the License.  You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software distributed under the License
10
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11
// or implied.  See the License for the specific language governing permissions and limitations
12
// under the License.
13
//
14
//
15
16
#ifndef YB_COMMON_TRANSACTION_H
17
#define YB_COMMON_TRANSACTION_H
18
19
#include <stdint.h>
20
21
#include <functional>
22
#include <iterator>
23
#include <string>
24
#include <type_traits>
25
#include <unordered_set>
26
#include <utility>
27
28
#include <boost/container/small_vector.hpp>
29
#include <boost/functional/hash/hash.hpp>
30
#include <boost/optional/optional.hpp>
31
32
#include "yb/common/common_fwd.h"
33
#include "yb/common/transaction.pb.h"
34
#include "yb/common/entity_ids_types.h"
35
#include "yb/common/hybrid_time.h"
36
37
#include "yb/gutil/template_util.h"
38
39
#include "yb/util/enums.h"
40
#include "yb/util/math_util.h"
41
#include "yb/util/strongly_typed_uuid.h"
42
#include "yb/util/uint_set.h"
43
44
namespace yb {
45
46
YB_STRONGLY_TYPED_UUID(TransactionId);
47
using TransactionIdSet = std::unordered_set<TransactionId, TransactionIdHash>;
48
using SubTransactionId = uint32_t;
49
50
// By default, postgres SubTransactionId's propagated to DocDB start at 1, so we use this as a
51
// minimum value on the DocDB side as well. All intents written without an explicit SubTransactionId
52
// are assumed to belong to the subtransaction with this kMinSubTransactionId.
53
constexpr SubTransactionId kMinSubTransactionId = 1;
54
55
// Decodes transaction id from its binary representation.
56
// Checks that slice contains only TransactionId.
57
Result<TransactionId> FullyDecodeTransactionId(const Slice& slice);
58
59
// Decodes transaction id from slice which contains binary encoding. Consumes corresponding bytes
60
// from slice.
61
Result<TransactionId> DecodeTransactionId(Slice* slice);
62
63
using AbortedSubTransactionSet = UnsignedIntSet<SubTransactionId>;
64
65
struct TransactionStatusResult {
66
  TransactionStatus status;
67
68
  // Meaning of status_time is related to status value.
69
  // PENDING - status_time reflects maximal guaranteed PENDING time, i.e. transaction cannot be
70
  // committed before this time.
71
  // COMMITTED - status_time is a commit time.
72
  // ABORTED - not used.
73
  HybridTime status_time;
74
75
  // Set of thus-far aborted subtransactions in this transaction.
76
  AbortedSubTransactionSet aborted_subtxn_set;
77
78
  TransactionStatusResult(TransactionStatus status_, HybridTime status_time_);
79
80
  TransactionStatusResult(
81
      TransactionStatus status_, HybridTime status_time_,
82
      AbortedSubTransactionSet aborted_subtxn_set_);
83
84
624k
  static TransactionStatusResult Aborted() {
85
624k
    return TransactionStatusResult(TransactionStatus::ABORTED, HybridTime());
86
624k
  }
87
88
0
  std::string ToString() const {
89
0
    return YB_STRUCT_TO_STRING(status, status_time, aborted_subtxn_set);
90
0
  }
Unexecuted instantiation: yb::TransactionStatusResult::ToString() const
Unexecuted instantiation: yb::TransactionStatusResult::ToString() const
91
};
92
93
0
inline std::ostream& operator<<(std::ostream& out, const TransactionStatusResult& result) {
94
0
  return out << "{ status: " << TransactionStatus_Name(result.status)
95
0
             << " status_time: " << result.status_time << " }";
96
0
}
97
98
typedef std::function<void(Result<TransactionStatusResult>)> TransactionStatusCallback;
99
struct TransactionMetadata;
100
101
YB_DEFINE_ENUM(TransactionLoadFlag, (kMustExist)(kCleanup));
102
typedef EnumBitSet<TransactionLoadFlag> TransactionLoadFlags;
103
104
// Used by RequestStatusAt.
105
struct StatusRequest {
106
  const TransactionId* id;
107
  HybridTime read_ht;
108
  HybridTime global_limit_ht;
109
  int64_t serial_no;
110
  const std::string* reason;
111
  TransactionLoadFlags flags;
112
  TransactionStatusCallback callback;
113
114
0
  std::string ToString() const {
115
0
    return Format("{ id: $0 read_ht: $1 global_limit_ht: $2 serial_no: $3 reason: $4 flags: $5}",
116
0
                  *id, read_ht, global_limit_ht, serial_no, *reason, flags);
117
0
  }
118
};
119
120
class RequestScope;
121
122
struct CommitMetadata {
123
  HybridTime commit_ht;
124
  AbortedSubTransactionSet aborted_subtxn_set;
125
};
126
127
class TransactionStatusManager {
128
 public:
129
44.9k
  virtual ~TransactionStatusManager() {}
130
131
  // If this tablet is aware that this transaction has committed, returns the commit ht for the
132
  // transaction. Otherwise, returns HybridTime::kInvalid.
133
  virtual HybridTime LocalCommitTime(const TransactionId& id) = 0;
134
135
  // If this tablet is aware that this transaction has committed, returns the CommitMetadata for the
136
  // transaction. Otherwise, returns boost::none.
137
  virtual boost::optional<CommitMetadata> LocalCommitData(const TransactionId& id) = 0;
138
139
  // Fetches status of specified transaction at specified time from transaction coordinator.
140
  // Callback would be invoked in any case.
141
  // There are the following potential cases:
142
  // 1. Status tablet knows transaction id and could determine it's status at this time. In this
143
  // case status structure is filled with transaction status with corresponding status time.
144
  // 2. Status tablet don't know this transaction id, in this case status structure contains
145
  // ABORTED status.
146
  // 3. Status tablet could not determine transaction status at this time. In this case callback
147
  // will be invoked with TryAgain result.
148
  // 4. Any kind of network/timeout errors would be reflected in error passed to callback.
149
  virtual void RequestStatusAt(const StatusRequest& request) = 0;
150
151
  // Prepares metadata for provided protobuf. Either trying to extract it from pb, or fetch
152
  // from existing metadatas.
153
  virtual Result<TransactionMetadata> PrepareMetadata(const TransactionMetadataPB& pb) = 0;
154
155
  virtual void Abort(const TransactionId& id, TransactionStatusCallback callback) = 0;
156
157
  virtual void Cleanup(TransactionIdSet&& set) = 0;
158
159
  // For each pair fills second with priority of transaction with id equals to first.
160
  virtual void FillPriorities(
161
      boost::container::small_vector_base<std::pair<TransactionId, uint64_t>>* inout) = 0;
162
163
  // Returns minimal running hybrid time of all running transactions.
164
  virtual HybridTime MinRunningHybridTime() const = 0;
165
166
  virtual Result<HybridTime> WaitForSafeTime(HybridTime safe_time, CoarseTimePoint deadline) = 0;
167
168
  virtual const TabletId& tablet_id() const = 0;
169
170
 private:
171
  friend class RequestScope;
172
173
  // Registers new request assigning next serial no to it. So this serial no could be used
174
  // to check whether one request happened before another one.
175
  virtual int64_t RegisterRequest() = 0;
176
177
  // request_id - is request id returned by RegisterRequest, that should be unregistered.
178
  virtual void UnregisterRequest(int64_t request_id) = 0;
179
};
180
181
// Utility class that invokes RegisterRequest on creation and UnregisterRequest on deletion.
182
class RequestScope {
183
 public:
184
12.8M
  RequestScope() noexcept : status_manager_(nullptr), request_id_(0) {}
185
186
  explicit RequestScope(TransactionStatusManager* status_manager)
187
6.71M
      : status_manager_(status_manager), request_id_(status_manager->RegisterRequest()) {
188
6.71M
  }
189
190
  RequestScope(RequestScope&& rhs) noexcept
191
0
      : status_manager_(rhs.status_manager_), request_id_(rhs.request_id_) {
192
0
    rhs.status_manager_ = nullptr;
193
0
  }
194
195
3.29M
  void operator=(RequestScope&& rhs) {
196
3.29M
    Reset();
197
3.29M
    status_manager_ = rhs.status_manager_;
198
3.29M
    request_id_ = rhs.request_id_;
199
3.29M
    rhs.status_manager_ = nullptr;
200
3.29M
  }
201
202
19.5M
  ~RequestScope() {
203
19.5M
    Reset();
204
19.5M
  }
205
206
1.90M
  int64_t request_id() const { return request_id_; }
207
208
  RequestScope(const RequestScope&) = delete;
209
  void operator=(const RequestScope&) = delete;
210
211
 private:
212
22.8M
  void Reset() {
213
22.8M
    if (status_manager_) {
214
6.71M
      status_manager_->UnregisterRequest(request_id_);
215
6.71M
      status_manager_ = nullptr;
216
6.71M
    }
217
22.8M
  }
218
219
  TransactionStatusManager* status_manager_;
220
  int64_t request_id_;
221
};
222
223
// Represents all metadata tracked about subtransaction state by the client in support of postgres
224
// savepoints. Can be serialized and deserialized to/from SubTransactionMetadataPB. This should be
225
// sent by the client on any transactional read/write requests where a savepoint has been created,
226
// and finally on transaction commit.
227
struct SubTransactionMetadata {
228
  SubTransactionId subtransaction_id = kMinSubTransactionId;
229
  AbortedSubTransactionSet aborted;
230
231
  void ToPB(SubTransactionMetadataPB* dest) const;
232
233
  static Result<SubTransactionMetadata> FromPB(
234
      const SubTransactionMetadataPB& source);
235
236
0
  std::string ToString() const {
237
0
    return YB_STRUCT_TO_STRING(subtransaction_id, aborted);
238
0
  }
Unexecuted instantiation: yb::SubTransactionMetadata::ToString() const
Unexecuted instantiation: yb::SubTransactionMetadata::ToString() const
239
240
  // Returns true if this is the default state, i.e. default subtransaction_id. This indicates
241
  // whether the client has interacted with savepoints at all in the context of a session. If true,
242
  // the client could, for example, skip sending subtransaction-related metadata in RPCs.
243
  // TODO(savepoints) -- update behavior and comment to track default aborted subtransaction state
244
  // as well.
245
  bool IsDefaultState() const;
246
};
247
248
std::ostream& operator<<(std::ostream& out, const SubTransactionMetadata& metadata);
249
250
struct TransactionOperationContext {
251
  TransactionOperationContext();
252
253
  TransactionOperationContext(
254
      const TransactionId& transaction_id_, TransactionStatusManager* txn_status_manager_);
255
256
  TransactionOperationContext(
257
      const TransactionId& transaction_id_,
258
      SubTransactionMetadata&& subtransaction_,
259
      TransactionStatusManager* txn_status_manager_);
260
261
  bool transactional() const;
262
263
20.7M
  explicit operator bool() const {
264
20.7M
    return txn_status_manager != nullptr;
265
20.7M
  }
266
267
  TransactionId transaction_id;
268
  SubTransactionMetadata subtransaction;
269
  TransactionStatusManager* txn_status_manager;
270
};
271
272
0
inline std::ostream& operator<<(std::ostream& out, const TransactionOperationContext& context) {
273
0
  if (context.transactional()) {
274
0
    out << context.transaction_id;
275
0
  } else {
276
0
    out << "<non transactional>";
277
0
  }
278
0
  return out;
279
0
}
280
281
struct TransactionMetadata {
282
  TransactionId transaction_id = TransactionId::Nil();
283
  IsolationLevel isolation = IsolationLevel::NON_TRANSACTIONAL;
284
  TabletId status_tablet;
285
286
  // By default, a random value is picked for a newly created transaction.
287
  uint64_t priority = 0;
288
289
  // Used for snapshot isolation (as read time and for conflict resolution).
290
  // start_time is used only for backward compability during rolling update.
291
  HybridTime start_time;
292
293
  // Indicates whether this transaction is a local transaction or global transaction.
294
  TransactionLocality locality = TransactionLocality::GLOBAL;
295
296
  static Result<TransactionMetadata> FromPB(const TransactionMetadataPB& source);
297
298
  void ToPB(TransactionMetadataPB* dest) const;
299
300
  void TransactionIdToPB(TransactionMetadataPB* dest) const;
301
302
  // Fill dest with full metadata even when isolation is non transactional.
303
  void ForceToPB(TransactionMetadataPB* dest) const;
304
305
10.2k
  std::string ToString() const {
306
10.2k
    return Format(
307
10.2k
        "{ transaction_id: $0 isolation: $1 status_tablet: $2 priority: $3 start_time: $4 }",
308
10.2k
        transaction_id, IsolationLevel_Name(isolation), status_tablet, priority, start_time);
309
10.2k
  }
310
};
311
312
bool operator==(const TransactionMetadata& lhs, const TransactionMetadata& rhs);
313
314
0
inline bool operator!=(const TransactionMetadata& lhs, const TransactionMetadata& rhs) {
315
0
  return !(lhs == rhs);
316
0
}
317
318
std::ostream& operator<<(std::ostream& out, const TransactionMetadata& metadata);
319
320
MonoDelta TransactionRpcTimeout();
321
CoarseTimePoint TransactionRpcDeadline();
322
323
extern const char* kGlobalTransactionsTableName;
324
extern const std::string kMetricsSnapshotsTableName;
325
extern const std::string kTransactionTablePrefix;
326
327
YB_DEFINE_ENUM(CleanupType, (kGraceful)(kImmediate))
328
329
} // namespace yb
330
331
#endif // YB_COMMON_TRANSACTION_H