forked from googleapis/google-cloud-cpp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtransaction.h
More file actions
290 lines (251 loc) · 9.99 KB
/
transaction.h
File metadata and controls
290 lines (251 loc) · 9.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_SPANNER_TRANSACTION_H
#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_SPANNER_TRANSACTION_H
#include "google/cloud/spanner/internal/transaction_impl.h"
#include "google/cloud/spanner/timestamp.h"
#include "google/cloud/spanner/version.h"
#include "absl/types/optional.h"
#include <google/spanner/v1/transaction.pb.h>
#include <chrono>
#include <memory>
#include <string>
namespace google {
namespace cloud {
namespace spanner_internal {
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
struct TransactionInternals;
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
} // namespace spanner_internal
namespace spanner {
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
/**
* The representation of a Cloud Spanner transaction.
*
* A transaction is a set of reads and writes that execute atomically at a
* single logical point in time across the columns/rows/tables in a database.
* Those reads and writes are grouped by passing them the same `Transaction`.
*
* All reads/writes in the transaction must be executed within the same
* session, and that session may have only one transaction active at a time.
*
* Spanner supports these transaction modes:
* - ReadOnly. Provides guaranteed consistency across several reads, but does
* not allow writes. Can be configured to read at timestamps in the past.
* Does not need to be committed and does not take locks.
* - ReadWrite. Supports reading and writing data at a single point in time.
* Uses pessimistic locking and, if necessary, two-phase commit. May abort,
* requiring the application to rerun.
* - SingleUse. A restricted form of a ReadOnly transaction where Spanner
* chooses the read timestamp.
*/
class Transaction {
public:
/**
* Options for ReadOnly transactions.
*/
class ReadOnlyOptions {
public:
// Strong: Guarantees visibility of the effects of all transactions that
// committed before the start of the reads.
ReadOnlyOptions();
// Exact Staleness: Executes all reads at `read_timestamp`.
explicit ReadOnlyOptions(Timestamp read_timestamp);
// Exact Staleness: Executes all reads at a timestamp `exact_staleness`
// old. The actual timestamp is chosen soon after the reads are started.
explicit ReadOnlyOptions(std::chrono::nanoseconds exact_staleness);
private:
friend Transaction;
google::spanner::v1::TransactionOptions_ReadOnly ro_opts_;
};
/**
* Read lock mode for ReadWrite transactions
* The Spanner V1 Transaction proto classes have their own enum
* implementations.
* See google::spanner::v1::TransactionOptions_ReadWrite_ReadLockMode
* This is a shorthand convenience for the developer.
*/
enum class ReadLockMode {
kUnspecified,
kPessimistic,
kOptimistic,
};
/**
* Options for ReadWrite transactions.
*/
class ReadWriteOptions {
public:
ReadWriteOptions();
explicit ReadWriteOptions(ReadLockMode read_lock_mode);
// A tag used for collecting statistics about the transaction.
ReadWriteOptions& WithTag(absl::optional<std::string> tag);
private:
friend Transaction;
google::spanner::v1::TransactionOptions_ReadWrite rw_opts_;
absl::optional<std::string> tag_;
};
/**
* Options for "single-use", ReadOnly transactions, where Spanner chooses
* the read timestamp, subject to user-provided bounds. This allows reading
* without blocking.
*
* Because selection of the timestamp requires knowledge of which rows will
* be read, a single-use transaction can only be used with one read. See
* Client::Read() and Client::ExecuteQuery(). SingleUseOptions cannot be used
* to construct an application-level Transaction.
*/
class SingleUseOptions {
public:
// Strong or Exact Staleness: See ReadOnlyOptions.
// NOLINTNEXTLINE(google-explicit-constructor)
SingleUseOptions(ReadOnlyOptions opts);
// Bounded Staleness: Executes all reads at a timestamp that is not
// before `min_read_timestamp`.
explicit SingleUseOptions(Timestamp min_read_timestamp);
// Bounded Staleness: Executes all reads at a timestamp that is not
// before `NOW - max_staleness`.
explicit SingleUseOptions(std::chrono::nanoseconds max_staleness);
private:
friend Transaction;
google::spanner::v1::TransactionOptions_ReadOnly ro_opts_;
};
/// @name Construction of read-only and read-write transactions.
///@{
/**
* @note This is a lazy evaluated operation. No RPCs are made as part of
* creating a `Transaction` object. Instead, the first request to the
* server (for example as part of a `ExecuteQuery()` call) will also
* create the transaction.
*/
explicit Transaction(ReadOnlyOptions opts);
/// @copydoc Transaction(ReadOnlyOptions)
explicit Transaction(ReadWriteOptions opts);
/// @copydoc Transaction(ReadOnlyOptions)
Transaction(Transaction const& txn, ReadWriteOptions opts);
///@}
~Transaction();
/// @name Regular value type, supporting copy, assign, move.
///@{
Transaction(Transaction&&) = default;
Transaction& operator=(Transaction&&) = default;
Transaction(Transaction const&) = default;
Transaction& operator=(Transaction const&) = default;
///@}
/// @name Equality operators
///@{
friend bool operator==(Transaction const& a, Transaction const& b) {
return a.impl_ == b.impl_;
}
friend bool operator!=(Transaction const& a, Transaction const& b) {
return !(a == b);
}
///@}
private:
// Friendship for access by internal helpers.
friend struct spanner_internal::TransactionInternals;
struct SingleUseCommitTag {};
// Construction of a single-use transaction.
explicit Transaction(SingleUseOptions opts);
// Construction of a single-use commit transaction.
Transaction(ReadWriteOptions opts, SingleUseCommitTag);
// Construction of a transaction with existing IDs.
Transaction(std::string session_id, std::string transaction_id,
bool route_to_leader, std::string transaction_tag);
std::shared_ptr<spanner_internal::TransactionImpl> impl_;
};
/**
* Create a read-only transaction configured with @p opts.
*
* @copydoc Transaction::Transaction(Transaction::ReadOnlyOptions)
*/
inline Transaction MakeReadOnlyTransaction(
Transaction::ReadOnlyOptions opts = {}) {
return Transaction(std::move(opts));
}
/**
* Create a read-write transaction configured with @p opts.
*
* @copydoc Transaction::Transaction(Transaction::ReadOnlyOptions)
*/
inline Transaction MakeReadWriteTransaction(
Transaction::ReadWriteOptions opts = {}) {
return Transaction(std::move(opts));
}
/**
* Create a read-write transaction configured with @p opts, and sharing
* lock priority with @p txn. This should be used when rerunning an aborted
* transaction, so that the new attempt has a slightly better chance of
* success.
*/
inline Transaction MakeReadWriteTransaction(
Transaction const& txn, Transaction::ReadWriteOptions opts = {}) {
return Transaction(txn, std::move(opts));
}
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
} // namespace spanner
namespace spanner_internal {
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
struct TransactionInternals {
template <typename T>
static spanner::Transaction MakeSingleUseTransaction(T&& opts) {
// Requires that `opts` is implicitly convertible to SingleUseOptions.
spanner::Transaction::SingleUseOptions su_opts = std::forward<T>(opts);
return spanner::Transaction(std::move(su_opts));
}
static spanner::Transaction MakeSingleUseCommitTransaction(
spanner::Transaction::ReadWriteOptions opts) {
return spanner::Transaction(std::move(opts),
spanner::Transaction::SingleUseCommitTag{});
}
template <typename Functor>
// Pass `txn` by value, despite being used only once. This avoids the
// possibility of `txn` being destroyed by `f` before `Visit()` can
// return. Therefore, ...
// NOLINTNEXTLINE(performance-unnecessary-value-param)
static VisitInvokeResult<Functor> Visit(spanner::Transaction txn,
Functor&& f) {
return txn.impl_->Visit(std::forward<Functor>(f));
}
static spanner::Transaction MakeTransactionFromIds(
std::string session_id, std::string transaction_id, bool route_to_leader,
std::string transaction_tag);
};
template <typename T>
spanner::Transaction MakeSingleUseTransaction(T&& opts) {
return TransactionInternals::MakeSingleUseTransaction(std::forward<T>(opts));
}
inline spanner::Transaction MakeSingleUseCommitTransaction(
spanner::Transaction::ReadWriteOptions opts) {
return TransactionInternals::MakeSingleUseCommitTransaction(std::move(opts));
}
template <typename Functor>
// Pass `txn` by value, despite being used only once. This avoids the
// possibility of `txn` being destroyed by `f` before `Visit()` can
// return. Therefore, ...
// NOLINTNEXTLINE(performance-unnecessary-value-param)
VisitInvokeResult<Functor> Visit(spanner::Transaction txn, Functor&& f) {
return TransactionInternals::Visit(std::move(txn), std::forward<Functor>(f));
}
inline spanner::Transaction MakeTransactionFromIds(
std::string session_id, std::string transaction_id, bool route_to_leader,
std::string transaction_tag) {
return TransactionInternals::MakeTransactionFromIds(
std::move(session_id), std::move(transaction_id), route_to_leader,
std::move(transaction_tag));
}
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
} // namespace spanner_internal
} // namespace cloud
} // namespace google
#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_SPANNER_TRANSACTION_H