Coverage Report

Created: 2024-07-27 06:53

/src/rocksdb/utilities/transactions/transaction_base.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
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).
5
6
#include "utilities/transactions/transaction_base.h"
7
8
#include <cinttypes>
9
10
#include "db/column_family.h"
11
#include "db/db_impl/db_impl.h"
12
#include "logging/logging.h"
13
#include "rocksdb/comparator.h"
14
#include "rocksdb/db.h"
15
#include "rocksdb/status.h"
16
#include "util/cast_util.h"
17
#include "util/string_util.h"
18
#include "utilities/transactions/lock/lock_tracker.h"
19
20
namespace ROCKSDB_NAMESPACE {
21
22
Status Transaction::CommitAndTryCreateSnapshot(
23
    std::shared_ptr<TransactionNotifier> notifier, TxnTimestamp ts,
24
0
    std::shared_ptr<const Snapshot>* snapshot) {
25
0
  if (snapshot) {
26
0
    snapshot->reset();
27
0
  }
28
0
  TxnTimestamp commit_ts = GetCommitTimestamp();
29
0
  if (commit_ts == kMaxTxnTimestamp) {
30
0
    if (ts == kMaxTxnTimestamp) {
31
0
      return Status::InvalidArgument("Commit timestamp unset");
32
0
    } else {
33
0
      const Status s = SetCommitTimestamp(ts);
34
0
      if (!s.ok()) {
35
0
        return s;
36
0
      }
37
0
    }
38
0
  } else if (ts != kMaxTxnTimestamp) {
39
0
    if (ts != commit_ts) {
40
      // For now we treat this as error.
41
0
      return Status::InvalidArgument("Different commit ts specified");
42
0
    }
43
0
  }
44
0
  SetSnapshotOnNextOperation(notifier);
45
0
  Status s = Commit();
46
0
  if (!s.ok()) {
47
0
    return s;
48
0
  }
49
0
  assert(s.ok());
50
  // If we reach here, we must return ok status for this function.
51
0
  std::shared_ptr<const Snapshot> new_snapshot = GetTimestampedSnapshot();
52
53
0
  if (snapshot) {
54
0
    *snapshot = new_snapshot;
55
0
  }
56
0
  return Status::OK();
57
0
}
58
59
TransactionBaseImpl::TransactionBaseImpl(
60
    DB* db, const WriteOptions& write_options,
61
    const LockTrackerFactory& lock_tracker_factory)
62
    : db_(db),
63
      dbimpl_(static_cast_with_check<DBImpl>(db)),
64
      write_options_(write_options),
65
      cmp_(GetColumnFamilyUserComparator(db->DefaultColumnFamily())),
66
      lock_tracker_factory_(lock_tracker_factory),
67
      start_time_(dbimpl_->GetSystemClock()->NowMicros()),
68
      write_batch_(cmp_, 0, true, 0, write_options.protection_bytes_per_key),
69
      tracked_locks_(lock_tracker_factory_.Create()),
70
      commit_time_batch_(0 /* reserved_bytes */, 0 /* max_bytes */,
71
                         write_options.protection_bytes_per_key,
72
                         0 /* default_cf_ts_sz */),
73
0
      indexing_enabled_(true) {
74
0
  assert(dynamic_cast<DBImpl*>(db_) != nullptr);
75
0
  log_number_ = 0;
76
0
  if (dbimpl_->allow_2pc()) {
77
0
    InitWriteBatch();
78
0
  }
79
0
}
80
81
0
TransactionBaseImpl::~TransactionBaseImpl() {
82
  // Release snapshot if snapshot is set
83
0
  SetSnapshotInternal(nullptr);
84
0
}
85
86
0
void TransactionBaseImpl::Clear() {
87
0
  save_points_.reset(nullptr);
88
0
  write_batch_.Clear();
89
0
  commit_time_batch_.Clear();
90
0
  tracked_locks_->Clear();
91
0
  num_puts_ = 0;
92
0
  num_put_entities_ = 0;
93
0
  num_deletes_ = 0;
94
0
  num_merges_ = 0;
95
96
0
  if (dbimpl_->allow_2pc()) {
97
0
    InitWriteBatch();
98
0
  }
99
0
}
100
101
void TransactionBaseImpl::Reinitialize(DB* db,
102
0
                                       const WriteOptions& write_options) {
103
0
  Clear();
104
0
  ClearSnapshot();
105
0
  id_ = 0;
106
0
  db_ = db;
107
0
  name_.clear();
108
0
  log_number_ = 0;
109
0
  write_options_ = write_options;
110
0
  start_time_ = dbimpl_->GetSystemClock()->NowMicros();
111
0
  indexing_enabled_ = true;
112
0
  cmp_ = GetColumnFamilyUserComparator(db_->DefaultColumnFamily());
113
0
  WriteBatchInternal::SetDefaultColumnFamilyTimestampSize(
114
0
      write_batch_.GetWriteBatch(), cmp_->timestamp_size());
115
0
  WriteBatchInternal::UpdateProtectionInfo(
116
0
      write_batch_.GetWriteBatch(), write_options_.protection_bytes_per_key)
117
0
      .PermitUncheckedError();
118
0
  WriteBatchInternal::UpdateProtectionInfo(
119
0
      &commit_time_batch_, write_options_.protection_bytes_per_key)
120
0
      .PermitUncheckedError();
121
0
}
122
123
0
void TransactionBaseImpl::SetSnapshot() {
124
0
  const Snapshot* snapshot = dbimpl_->GetSnapshotForWriteConflictBoundary();
125
0
  SetSnapshotInternal(snapshot);
126
0
}
127
128
0
void TransactionBaseImpl::SetSnapshotInternal(const Snapshot* snapshot) {
129
  // Set a custom deleter for the snapshot_ SharedPtr as the snapshot needs to
130
  // be released, not deleted when it is no longer referenced.
131
0
  snapshot_.reset(snapshot, std::bind(&TransactionBaseImpl::ReleaseSnapshot,
132
0
                                      this, std::placeholders::_1, db_));
133
0
  snapshot_needed_ = false;
134
0
  snapshot_notifier_ = nullptr;
135
0
}
136
137
void TransactionBaseImpl::SetSnapshotOnNextOperation(
138
0
    std::shared_ptr<TransactionNotifier> notifier) {
139
0
  snapshot_needed_ = true;
140
0
  snapshot_notifier_ = notifier;
141
0
}
142
143
0
void TransactionBaseImpl::SetSnapshotIfNeeded() {
144
0
  if (snapshot_needed_) {
145
0
    std::shared_ptr<TransactionNotifier> notifier = snapshot_notifier_;
146
0
    SetSnapshot();
147
0
    if (notifier != nullptr) {
148
0
      notifier->SnapshotCreated(GetSnapshot());
149
0
    }
150
0
  }
151
0
}
152
153
Status TransactionBaseImpl::TryLock(ColumnFamilyHandle* column_family,
154
                                    const SliceParts& key, bool read_only,
155
                                    bool exclusive, const bool do_validate,
156
0
                                    const bool assume_tracked) {
157
0
  size_t key_size = 0;
158
0
  for (int i = 0; i < key.num_parts; ++i) {
159
0
    key_size += key.parts[i].size();
160
0
  }
161
162
0
  std::string str;
163
0
  str.reserve(key_size);
164
165
0
  for (int i = 0; i < key.num_parts; ++i) {
166
0
    str.append(key.parts[i].data(), key.parts[i].size());
167
0
  }
168
169
0
  return TryLock(column_family, str, read_only, exclusive, do_validate,
170
0
                 assume_tracked);
171
0
}
172
173
0
void TransactionBaseImpl::SetSavePoint() {
174
0
  if (save_points_ == nullptr) {
175
0
    save_points_.reset(
176
0
        new std::stack<TransactionBaseImpl::SavePoint,
177
0
                       autovector<TransactionBaseImpl::SavePoint>>());
178
0
  }
179
0
  save_points_->emplace(snapshot_, snapshot_needed_, snapshot_notifier_,
180
0
                        num_puts_, num_put_entities_, num_deletes_, num_merges_,
181
0
                        lock_tracker_factory_);
182
0
  write_batch_.SetSavePoint();
183
0
}
184
185
0
Status TransactionBaseImpl::RollbackToSavePoint() {
186
0
  if (save_points_ != nullptr && save_points_->size() > 0) {
187
    // Restore saved SavePoint
188
0
    TransactionBaseImpl::SavePoint& save_point = save_points_->top();
189
0
    snapshot_ = save_point.snapshot_;
190
0
    snapshot_needed_ = save_point.snapshot_needed_;
191
0
    snapshot_notifier_ = save_point.snapshot_notifier_;
192
0
    num_puts_ = save_point.num_puts_;
193
0
    num_put_entities_ = save_point.num_put_entities_;
194
0
    num_deletes_ = save_point.num_deletes_;
195
0
    num_merges_ = save_point.num_merges_;
196
197
    // Rollback batch
198
0
    Status s = write_batch_.RollbackToSavePoint();
199
0
    assert(s.ok());
200
201
    // Rollback any keys that were tracked since the last savepoint
202
0
    tracked_locks_->Subtract(*save_point.new_locks_);
203
204
0
    save_points_->pop();
205
206
0
    return s;
207
0
  } else {
208
0
    assert(write_batch_.RollbackToSavePoint().IsNotFound());
209
0
    return Status::NotFound();
210
0
  }
211
0
}
212
213
0
Status TransactionBaseImpl::PopSavePoint() {
214
0
  if (save_points_ == nullptr || save_points_->empty()) {
215
    // No SavePoint yet.
216
0
    assert(write_batch_.PopSavePoint().IsNotFound());
217
0
    return Status::NotFound();
218
0
  }
219
220
0
  assert(!save_points_->empty());
221
  // If there is another savepoint A below the current savepoint B, then A needs
222
  // to inherit tracked_keys in B so that if we rollback to savepoint A, we
223
  // remember to unlock keys in B. If there is no other savepoint below, then we
224
  // can safely discard savepoint info.
225
0
  if (save_points_->size() == 1) {
226
0
    save_points_->pop();
227
0
  } else {
228
0
    TransactionBaseImpl::SavePoint top(lock_tracker_factory_);
229
0
    std::swap(top, save_points_->top());
230
0
    save_points_->pop();
231
232
0
    save_points_->top().new_locks_->Merge(*top.new_locks_);
233
0
  }
234
235
0
  return write_batch_.PopSavePoint();
236
0
}
237
238
Status TransactionBaseImpl::Get(const ReadOptions& _read_options,
239
                                ColumnFamilyHandle* column_family,
240
0
                                const Slice& key, std::string* value) {
241
0
  if (_read_options.io_activity != Env::IOActivity::kUnknown &&
242
0
      _read_options.io_activity != Env::IOActivity::kGet) {
243
0
    return Status::InvalidArgument(
244
0
        "Can only call Get with `ReadOptions::io_activity` is "
245
0
        "`Env::IOActivity::kUnknown` or `Env::IOActivity::kGet`");
246
0
  }
247
0
  ReadOptions read_options(_read_options);
248
0
  if (read_options.io_activity == Env::IOActivity::kUnknown) {
249
0
    read_options.io_activity = Env::IOActivity::kGet;
250
0
  }
251
0
  auto s = GetImpl(read_options, column_family, key, value);
252
0
  return s;
253
0
}
254
255
Status TransactionBaseImpl::GetImpl(const ReadOptions& read_options,
256
                                    ColumnFamilyHandle* column_family,
257
0
                                    const Slice& key, std::string* value) {
258
0
  assert(value != nullptr);
259
0
  PinnableSlice pinnable_val(value);
260
0
  assert(!pinnable_val.IsPinned());
261
0
  auto s = GetImpl(read_options, column_family, key, &pinnable_val);
262
0
  if (s.ok() && pinnable_val.IsPinned()) {
263
0
    value->assign(pinnable_val.data(), pinnable_val.size());
264
0
  }  // else value is already assigned
265
0
  return s;
266
0
}
267
268
Status TransactionBaseImpl::Get(const ReadOptions& _read_options,
269
                                ColumnFamilyHandle* column_family,
270
0
                                const Slice& key, PinnableSlice* pinnable_val) {
271
0
  if (_read_options.io_activity != Env::IOActivity::kUnknown &&
272
0
      _read_options.io_activity != Env::IOActivity::kGet) {
273
0
    return Status::InvalidArgument(
274
0
        "Can only call Get with `ReadOptions::io_activity` is "
275
0
        "`Env::IOActivity::kUnknown` or `Env::IOActivity::kGet`");
276
0
  }
277
0
  ReadOptions read_options(_read_options);
278
0
  if (read_options.io_activity == Env::IOActivity::kUnknown) {
279
0
    read_options.io_activity = Env::IOActivity::kGet;
280
0
  }
281
0
  return GetImpl(read_options, column_family, key, pinnable_val);
282
0
}
283
284
Status TransactionBaseImpl::GetImpl(const ReadOptions& read_options,
285
                                    ColumnFamilyHandle* column_family,
286
                                    const Slice& key,
287
0
                                    PinnableSlice* pinnable_val) {
288
0
  return write_batch_.GetFromBatchAndDB(db_, read_options, column_family, key,
289
0
                                        pinnable_val);
290
0
}
291
292
Status TransactionBaseImpl::GetEntity(const ReadOptions& read_options,
293
                                      ColumnFamilyHandle* column_family,
294
                                      const Slice& key,
295
0
                                      PinnableWideColumns* columns) {
296
0
  return GetEntityImpl(read_options, column_family, key, columns);
297
0
}
298
299
Status TransactionBaseImpl::GetForUpdate(const ReadOptions& read_options,
300
                                         ColumnFamilyHandle* column_family,
301
                                         const Slice& key, std::string* value,
302
                                         bool exclusive,
303
0
                                         const bool do_validate) {
304
0
  if (!do_validate && read_options.snapshot != nullptr) {
305
0
    return Status::InvalidArgument(
306
0
        "If do_validate is false then GetForUpdate with snapshot is not "
307
0
        "defined.");
308
0
  }
309
0
  if (read_options.io_activity != Env::IOActivity::kUnknown) {
310
0
    return Status::InvalidArgument(
311
0
        "Cannot call GetForUpdate with `ReadOptions::io_activity` != "
312
0
        "`Env::IOActivity::kUnknown`");
313
0
  }
314
0
  Status s =
315
0
      TryLock(column_family, key, true /* read_only */, exclusive, do_validate);
316
317
0
  if (s.ok() && value != nullptr) {
318
0
    assert(value != nullptr);
319
0
    PinnableSlice pinnable_val(value);
320
0
    assert(!pinnable_val.IsPinned());
321
0
    s = GetImpl(read_options, column_family, key, &pinnable_val);
322
0
    if (s.ok() && pinnable_val.IsPinned()) {
323
0
      value->assign(pinnable_val.data(), pinnable_val.size());
324
0
    }  // else value is already assigned
325
0
  }
326
0
  return s;
327
0
}
328
329
Status TransactionBaseImpl::GetForUpdate(const ReadOptions& read_options,
330
                                         ColumnFamilyHandle* column_family,
331
                                         const Slice& key,
332
                                         PinnableSlice* pinnable_val,
333
                                         bool exclusive,
334
0
                                         const bool do_validate) {
335
0
  if (!do_validate && read_options.snapshot != nullptr) {
336
0
    return Status::InvalidArgument(
337
0
        "If do_validate is false then GetForUpdate with snapshot is not "
338
0
        "defined.");
339
0
  }
340
0
  if (read_options.io_activity != Env::IOActivity::kUnknown) {
341
0
    return Status::InvalidArgument(
342
0
        "Cannot call GetForUpdate with `ReadOptions::io_activity` != "
343
0
        "`Env::IOActivity::kUnknown`");
344
0
  }
345
0
  Status s =
346
0
      TryLock(column_family, key, true /* read_only */, exclusive, do_validate);
347
348
0
  if (s.ok() && pinnable_val != nullptr) {
349
0
    s = GetImpl(read_options, column_family, key, pinnable_val);
350
0
  }
351
0
  return s;
352
0
}
353
354
Status TransactionBaseImpl::GetEntityForUpdate(
355
    const ReadOptions& read_options, ColumnFamilyHandle* column_family,
356
    const Slice& key, PinnableWideColumns* columns, bool exclusive,
357
0
    bool do_validate) {
358
0
  if (!do_validate && read_options.snapshot != nullptr) {
359
0
    return Status::InvalidArgument(
360
0
        "Snapshot must not be set if validation is disabled");
361
0
  }
362
363
0
  const Status s =
364
0
      TryLock(column_family, key, true /* read_only */, exclusive, do_validate);
365
0
  if (!s.ok()) {
366
0
    return s;
367
0
  }
368
369
0
  return GetEntityImpl(read_options, column_family, key, columns);
370
0
}
371
372
std::vector<Status> TransactionBaseImpl::MultiGet(
373
    const ReadOptions& _read_options,
374
    const std::vector<ColumnFamilyHandle*>& column_family,
375
0
    const std::vector<Slice>& keys, std::vector<std::string>* values) {
376
0
  size_t num_keys = keys.size();
377
0
  std::vector<Status> stat_list(num_keys);
378
0
  if (_read_options.io_activity != Env::IOActivity::kUnknown &&
379
0
      _read_options.io_activity != Env::IOActivity::kMultiGet) {
380
0
    Status s = Status::InvalidArgument(
381
0
        "Can only call MultiGet with `ReadOptions::io_activity` is "
382
0
        "`Env::IOActivity::kUnknown` or `Env::IOActivity::kMultiGet`");
383
384
0
    for (size_t i = 0; i < num_keys; ++i) {
385
0
      stat_list[i] = s;
386
0
    }
387
0
    return stat_list;
388
0
  }
389
0
  ReadOptions read_options(_read_options);
390
0
  if (read_options.io_activity == Env::IOActivity::kUnknown) {
391
0
    read_options.io_activity = Env::IOActivity::kMultiGet;
392
0
  }
393
394
0
  values->resize(num_keys);
395
0
  for (size_t i = 0; i < num_keys; ++i) {
396
0
    stat_list[i] =
397
0
        GetImpl(read_options, column_family[i], keys[i], &(*values)[i]);
398
0
  }
399
400
0
  return stat_list;
401
0
}
402
403
void TransactionBaseImpl::MultiGet(const ReadOptions& _read_options,
404
                                   ColumnFamilyHandle* column_family,
405
                                   const size_t num_keys, const Slice* keys,
406
                                   PinnableSlice* values, Status* statuses,
407
0
                                   const bool sorted_input) {
408
0
  if (_read_options.io_activity != Env::IOActivity::kUnknown &&
409
0
      _read_options.io_activity != Env::IOActivity::kMultiGet) {
410
0
    Status s = Status::InvalidArgument(
411
0
        "Can only call MultiGet with `ReadOptions::io_activity` is "
412
0
        "`Env::IOActivity::kUnknown` or `Env::IOActivity::kMultiGet`");
413
0
    for (size_t i = 0; i < num_keys; ++i) {
414
0
      if (statuses[i].ok()) {
415
0
        statuses[i] = s;
416
0
      }
417
0
    }
418
0
    return;
419
0
  }
420
0
  ReadOptions read_options(_read_options);
421
0
  if (read_options.io_activity == Env::IOActivity::kUnknown) {
422
0
    read_options.io_activity = Env::IOActivity::kMultiGet;
423
0
  }
424
0
  write_batch_.MultiGetFromBatchAndDB(db_, read_options, column_family,
425
0
                                      num_keys, keys, values, statuses,
426
0
                                      sorted_input);
427
0
}
428
429
void TransactionBaseImpl::MultiGetEntity(const ReadOptions& read_options,
430
                                         ColumnFamilyHandle* column_family,
431
                                         size_t num_keys, const Slice* keys,
432
                                         PinnableWideColumns* results,
433
0
                                         Status* statuses, bool sorted_input) {
434
0
  MultiGetEntityImpl(read_options, column_family, num_keys, keys, results,
435
0
                     statuses, sorted_input);
436
0
}
437
438
std::vector<Status> TransactionBaseImpl::MultiGetForUpdate(
439
    const ReadOptions& read_options,
440
    const std::vector<ColumnFamilyHandle*>& column_family,
441
0
    const std::vector<Slice>& keys, std::vector<std::string>* values) {
442
0
  size_t num_keys = keys.size();
443
0
  if (read_options.io_activity != Env::IOActivity::kUnknown) {
444
0
    Status s = Status::InvalidArgument(
445
0
        "Cannot call MultiGetForUpdate with `ReadOptions::io_activity` != "
446
0
        "`Env::IOActivity::kUnknown`");
447
0
    return std::vector<Status>(num_keys, s);
448
0
  }
449
  // Regardless of whether the MultiGet succeeded, track these keys.
450
0
  values->resize(num_keys);
451
452
  // Lock all keys
453
0
  for (size_t i = 0; i < num_keys; ++i) {
454
0
    Status s = TryLock(column_family[i], keys[i], true /* read_only */,
455
0
                       true /* exclusive */);
456
0
    if (!s.ok()) {
457
      // Fail entire multiget if we cannot lock all keys
458
0
      return std::vector<Status>(num_keys, s);
459
0
    }
460
0
  }
461
462
  // TODO(agiardullo): optimize multiget?
463
0
  std::vector<Status> stat_list(num_keys);
464
0
  for (size_t i = 0; i < num_keys; ++i) {
465
0
    stat_list[i] =
466
0
        GetImpl(read_options, column_family[i], keys[i], &(*values)[i]);
467
0
  }
468
469
0
  return stat_list;
470
0
}
471
472
0
Iterator* TransactionBaseImpl::GetIterator(const ReadOptions& read_options) {
473
0
  Iterator* db_iter = db_->NewIterator(read_options);
474
0
  assert(db_iter);
475
476
0
  return write_batch_.NewIteratorWithBase(db_->DefaultColumnFamily(), db_iter,
477
0
                                          &read_options);
478
0
}
479
480
Iterator* TransactionBaseImpl::GetIterator(const ReadOptions& read_options,
481
0
                                           ColumnFamilyHandle* column_family) {
482
0
  Iterator* db_iter = db_->NewIterator(read_options, column_family);
483
0
  assert(db_iter);
484
485
0
  return write_batch_.NewIteratorWithBase(column_family, db_iter,
486
0
                                          &read_options);
487
0
}
488
489
Status TransactionBaseImpl::PutEntityImpl(ColumnFamilyHandle* column_family,
490
                                          const Slice& key,
491
                                          const WideColumns& columns,
492
                                          bool do_validate,
493
0
                                          bool assume_tracked) {
494
0
  {
495
0
    constexpr bool read_only = false;
496
0
    constexpr bool exclusive = true;
497
0
    const Status s = TryLock(column_family, key, read_only, exclusive,
498
0
                             do_validate, assume_tracked);
499
0
    if (!s.ok()) {
500
0
      return s;
501
0
    }
502
0
  }
503
504
0
  {
505
0
    const Status s = GetBatchForWrite()->PutEntity(column_family, key, columns);
506
0
    if (!s.ok()) {
507
0
      return s;
508
0
    }
509
0
  }
510
511
0
  ++num_put_entities_;
512
0
  return Status::OK();
513
0
}
514
515
Status TransactionBaseImpl::Put(ColumnFamilyHandle* column_family,
516
                                const Slice& key, const Slice& value,
517
0
                                const bool assume_tracked) {
518
0
  const bool do_validate = !assume_tracked;
519
0
  Status s = TryLock(column_family, key, false /* read_only */,
520
0
                     true /* exclusive */, do_validate, assume_tracked);
521
522
0
  if (s.ok()) {
523
0
    s = GetBatchForWrite()->Put(column_family, key, value);
524
0
    if (s.ok()) {
525
0
      num_puts_++;
526
0
    }
527
0
  }
528
529
0
  return s;
530
0
}
531
532
Status TransactionBaseImpl::Put(ColumnFamilyHandle* column_family,
533
                                const SliceParts& key, const SliceParts& value,
534
0
                                const bool assume_tracked) {
535
0
  const bool do_validate = !assume_tracked;
536
0
  Status s = TryLock(column_family, key, false /* read_only */,
537
0
                     true /* exclusive */, do_validate, assume_tracked);
538
539
0
  if (s.ok()) {
540
0
    s = GetBatchForWrite()->Put(column_family, key, value);
541
0
    if (s.ok()) {
542
0
      num_puts_++;
543
0
    }
544
0
  }
545
546
0
  return s;
547
0
}
548
549
Status TransactionBaseImpl::Merge(ColumnFamilyHandle* column_family,
550
                                  const Slice& key, const Slice& value,
551
0
                                  const bool assume_tracked) {
552
0
  const bool do_validate = !assume_tracked;
553
0
  Status s = TryLock(column_family, key, false /* read_only */,
554
0
                     true /* exclusive */, do_validate, assume_tracked);
555
556
0
  if (s.ok()) {
557
0
    s = GetBatchForWrite()->Merge(column_family, key, value);
558
0
    if (s.ok()) {
559
0
      num_merges_++;
560
0
    }
561
0
  }
562
563
0
  return s;
564
0
}
565
566
Status TransactionBaseImpl::Delete(ColumnFamilyHandle* column_family,
567
                                   const Slice& key,
568
0
                                   const bool assume_tracked) {
569
0
  const bool do_validate = !assume_tracked;
570
0
  Status s = TryLock(column_family, key, false /* read_only */,
571
0
                     true /* exclusive */, do_validate, assume_tracked);
572
573
0
  if (s.ok()) {
574
0
    s = GetBatchForWrite()->Delete(column_family, key);
575
0
    if (s.ok()) {
576
0
      num_deletes_++;
577
0
    }
578
0
  }
579
580
0
  return s;
581
0
}
582
583
Status TransactionBaseImpl::Delete(ColumnFamilyHandle* column_family,
584
                                   const SliceParts& key,
585
0
                                   const bool assume_tracked) {
586
0
  const bool do_validate = !assume_tracked;
587
0
  Status s = TryLock(column_family, key, false /* read_only */,
588
0
                     true /* exclusive */, do_validate, assume_tracked);
589
590
0
  if (s.ok()) {
591
0
    s = GetBatchForWrite()->Delete(column_family, key);
592
0
    if (s.ok()) {
593
0
      num_deletes_++;
594
0
    }
595
0
  }
596
597
0
  return s;
598
0
}
599
600
Status TransactionBaseImpl::SingleDelete(ColumnFamilyHandle* column_family,
601
                                         const Slice& key,
602
0
                                         const bool assume_tracked) {
603
0
  const bool do_validate = !assume_tracked;
604
0
  Status s = TryLock(column_family, key, false /* read_only */,
605
0
                     true /* exclusive */, do_validate, assume_tracked);
606
607
0
  if (s.ok()) {
608
0
    s = GetBatchForWrite()->SingleDelete(column_family, key);
609
0
    if (s.ok()) {
610
0
      num_deletes_++;
611
0
    }
612
0
  }
613
614
0
  return s;
615
0
}
616
617
Status TransactionBaseImpl::SingleDelete(ColumnFamilyHandle* column_family,
618
                                         const SliceParts& key,
619
0
                                         const bool assume_tracked) {
620
0
  const bool do_validate = !assume_tracked;
621
0
  Status s = TryLock(column_family, key, false /* read_only */,
622
0
                     true /* exclusive */, do_validate, assume_tracked);
623
624
0
  if (s.ok()) {
625
0
    s = GetBatchForWrite()->SingleDelete(column_family, key);
626
0
    if (s.ok()) {
627
0
      num_deletes_++;
628
0
    }
629
0
  }
630
631
0
  return s;
632
0
}
633
634
Status TransactionBaseImpl::PutUntracked(ColumnFamilyHandle* column_family,
635
0
                                         const Slice& key, const Slice& value) {
636
0
  Status s = TryLock(column_family, key, false /* read_only */,
637
0
                     true /* exclusive */, false /* do_validate */);
638
639
0
  if (s.ok()) {
640
0
    s = GetBatchForWrite()->Put(column_family, key, value);
641
0
    if (s.ok()) {
642
0
      num_puts_++;
643
0
    }
644
0
  }
645
646
0
  return s;
647
0
}
648
649
Status TransactionBaseImpl::PutUntracked(ColumnFamilyHandle* column_family,
650
                                         const SliceParts& key,
651
0
                                         const SliceParts& value) {
652
0
  Status s = TryLock(column_family, key, false /* read_only */,
653
0
                     true /* exclusive */, false /* do_validate */);
654
655
0
  if (s.ok()) {
656
0
    s = GetBatchForWrite()->Put(column_family, key, value);
657
0
    if (s.ok()) {
658
0
      num_puts_++;
659
0
    }
660
0
  }
661
662
0
  return s;
663
0
}
664
665
Status TransactionBaseImpl::MergeUntracked(ColumnFamilyHandle* column_family,
666
                                           const Slice& key,
667
0
                                           const Slice& value) {
668
0
  Status s = TryLock(column_family, key, false /* read_only */,
669
0
                     true /* exclusive */, false /* do_validate */);
670
671
0
  if (s.ok()) {
672
0
    s = GetBatchForWrite()->Merge(column_family, key, value);
673
0
    if (s.ok()) {
674
0
      num_merges_++;
675
0
    }
676
0
  }
677
678
0
  return s;
679
0
}
680
681
Status TransactionBaseImpl::DeleteUntracked(ColumnFamilyHandle* column_family,
682
0
                                            const Slice& key) {
683
0
  Status s = TryLock(column_family, key, false /* read_only */,
684
0
                     true /* exclusive */, false /* do_validate */);
685
686
0
  if (s.ok()) {
687
0
    s = GetBatchForWrite()->Delete(column_family, key);
688
0
    if (s.ok()) {
689
0
      num_deletes_++;
690
0
    }
691
0
  }
692
693
0
  return s;
694
0
}
695
696
Status TransactionBaseImpl::DeleteUntracked(ColumnFamilyHandle* column_family,
697
0
                                            const SliceParts& key) {
698
0
  Status s = TryLock(column_family, key, false /* read_only */,
699
0
                     true /* exclusive */, false /* do_validate */);
700
701
0
  if (s.ok()) {
702
0
    s = GetBatchForWrite()->Delete(column_family, key);
703
0
    if (s.ok()) {
704
0
      num_deletes_++;
705
0
    }
706
0
  }
707
708
0
  return s;
709
0
}
710
711
Status TransactionBaseImpl::SingleDeleteUntracked(
712
0
    ColumnFamilyHandle* column_family, const Slice& key) {
713
0
  Status s = TryLock(column_family, key, false /* read_only */,
714
0
                     true /* exclusive */, false /* do_validate */);
715
716
0
  if (s.ok()) {
717
0
    s = GetBatchForWrite()->SingleDelete(column_family, key);
718
0
    if (s.ok()) {
719
0
      num_deletes_++;
720
0
    }
721
0
  }
722
723
0
  return s;
724
0
}
725
726
0
void TransactionBaseImpl::PutLogData(const Slice& blob) {
727
0
  auto s = write_batch_.PutLogData(blob);
728
0
  (void)s;
729
0
  assert(s.ok());
730
0
}
731
732
0
WriteBatchWithIndex* TransactionBaseImpl::GetWriteBatch() {
733
0
  return &write_batch_;
734
0
}
735
736
0
uint64_t TransactionBaseImpl::GetElapsedTime() const {
737
0
  return (dbimpl_->GetSystemClock()->NowMicros() - start_time_) / 1000;
738
0
}
739
740
0
uint64_t TransactionBaseImpl::GetNumPuts() const { return num_puts_; }
741
742
0
uint64_t TransactionBaseImpl::GetNumPutEntities() const {
743
0
  return num_put_entities_;
744
0
}
745
746
0
uint64_t TransactionBaseImpl::GetNumDeletes() const { return num_deletes_; }
747
748
0
uint64_t TransactionBaseImpl::GetNumMerges() const { return num_merges_; }
749
750
0
uint64_t TransactionBaseImpl::GetNumKeys() const {
751
0
  return tracked_locks_->GetNumPointLocks();
752
0
}
753
754
void TransactionBaseImpl::TrackKey(uint32_t cfh_id, const std::string& key,
755
                                   SequenceNumber seq, bool read_only,
756
0
                                   bool exclusive) {
757
0
  PointLockRequest r;
758
0
  r.column_family_id = cfh_id;
759
0
  r.key = key;
760
0
  r.seq = seq;
761
0
  r.read_only = read_only;
762
0
  r.exclusive = exclusive;
763
764
  // Update map of all tracked keys for this transaction
765
0
  tracked_locks_->Track(r);
766
767
0
  if (save_points_ != nullptr && !save_points_->empty()) {
768
    // Update map of tracked keys in this SavePoint
769
0
    save_points_->top().new_locks_->Track(r);
770
0
  }
771
0
}
772
773
// Gets the write batch that should be used for Put/PutEntity/Merge/Delete
774
// operations.
775
//
776
// Returns either a WriteBatch or WriteBatchWithIndex depending on whether
777
// DisableIndexing() has been called.
778
0
WriteBatchBase* TransactionBaseImpl::GetBatchForWrite() {
779
0
  if (indexing_enabled_) {
780
    // Use WriteBatchWithIndex
781
0
    return &write_batch_;
782
0
  } else {
783
    // Don't use WriteBatchWithIndex. Return base WriteBatch.
784
0
    return write_batch_.GetWriteBatch();
785
0
  }
786
0
}
787
788
0
void TransactionBaseImpl::ReleaseSnapshot(const Snapshot* snapshot, DB* db) {
789
0
  if (snapshot != nullptr) {
790
0
    ROCKS_LOG_DETAILS(dbimpl_->immutable_db_options().info_log,
791
0
                      "ReleaseSnapshot %" PRIu64 " Set",
792
0
                      snapshot->GetSequenceNumber());
793
0
    db->ReleaseSnapshot(snapshot);
794
0
  }
795
0
}
796
797
void TransactionBaseImpl::UndoGetForUpdate(ColumnFamilyHandle* column_family,
798
0
                                           const Slice& key) {
799
0
  PointLockRequest r;
800
0
  r.column_family_id = GetColumnFamilyID(column_family);
801
0
  r.key = key.ToString();
802
0
  r.read_only = true;
803
804
0
  bool can_untrack = false;
805
0
  if (save_points_ != nullptr && !save_points_->empty()) {
806
    // If there is no GetForUpdate of the key in this save point,
807
    // then cannot untrack from the global lock tracker.
808
0
    UntrackStatus s = save_points_->top().new_locks_->Untrack(r);
809
0
    can_untrack = (s != UntrackStatus::NOT_TRACKED);
810
0
  } else {
811
    // No save point, so can untrack from the global lock tracker.
812
0
    can_untrack = true;
813
0
  }
814
815
0
  if (can_untrack) {
816
    // If erased from the global tracker, then can unlock the key.
817
0
    UntrackStatus s = tracked_locks_->Untrack(r);
818
0
    bool can_unlock = (s == UntrackStatus::REMOVED);
819
0
    if (can_unlock) {
820
0
      UnlockGetForUpdate(column_family, key);
821
0
    }
822
0
  }
823
0
}
824
825
0
Status TransactionBaseImpl::RebuildFromWriteBatch(WriteBatch* src_batch) {
826
0
  struct IndexedWriteBatchBuilder : public WriteBatch::Handler {
827
0
    Transaction* txn_;
828
0
    DBImpl* db_;
829
0
    IndexedWriteBatchBuilder(Transaction* txn, DBImpl* db)
830
0
        : txn_(txn), db_(db) {
831
0
      assert(dynamic_cast<TransactionBaseImpl*>(txn_) != nullptr);
832
0
    }
833
834
0
    Status PutCF(uint32_t cf, const Slice& key, const Slice& val) override {
835
0
      Slice user_key = GetUserKey(cf, key);
836
0
      return txn_->Put(db_->GetColumnFamilyHandle(cf), user_key, val);
837
0
    }
838
839
0
    Status PutEntityCF(uint32_t cf, const Slice& key,
840
0
                       const Slice& entity) override {
841
0
      Slice user_key = GetUserKey(cf, key);
842
0
      Slice entity_copy = entity;
843
0
      WideColumns columns;
844
0
      const Status s =
845
0
          WideColumnSerialization::Deserialize(entity_copy, columns);
846
0
      if (!s.ok()) {
847
0
        return s;
848
0
      }
849
850
0
      return txn_->PutEntity(db_->GetColumnFamilyHandle(cf), user_key, columns);
851
0
    }
852
853
0
    Status DeleteCF(uint32_t cf, const Slice& key) override {
854
0
      Slice user_key = GetUserKey(cf, key);
855
0
      return txn_->Delete(db_->GetColumnFamilyHandle(cf), user_key);
856
0
    }
857
858
0
    Status SingleDeleteCF(uint32_t cf, const Slice& key) override {
859
0
      Slice user_key = GetUserKey(cf, key);
860
0
      return txn_->SingleDelete(db_->GetColumnFamilyHandle(cf), user_key);
861
0
    }
862
863
0
    Status MergeCF(uint32_t cf, const Slice& key, const Slice& val) override {
864
0
      Slice user_key = GetUserKey(cf, key);
865
0
      return txn_->Merge(db_->GetColumnFamilyHandle(cf), user_key, val);
866
0
    }
867
868
    // this is used for reconstructing prepared transactions upon
869
    // recovery. there should not be any meta markers in the batches
870
    // we are processing.
871
0
    Status MarkBeginPrepare(bool) override { return Status::InvalidArgument(); }
872
873
0
    Status MarkEndPrepare(const Slice&) override {
874
0
      return Status::InvalidArgument();
875
0
    }
876
877
0
    Status MarkCommit(const Slice&) override {
878
0
      return Status::InvalidArgument();
879
0
    }
880
881
0
    Status MarkCommitWithTimestamp(const Slice&, const Slice&) override {
882
0
      return Status::InvalidArgument();
883
0
    }
884
885
0
    Status MarkRollback(const Slice&) override {
886
0
      return Status::InvalidArgument();
887
0
    }
888
0
    size_t GetTimestampSize(uint32_t cf_id) {
889
0
      auto cfd = db_->versions_->GetColumnFamilySet()->GetColumnFamily(cf_id);
890
0
      const Comparator* ucmp = cfd->user_comparator();
891
0
      assert(ucmp);
892
0
      return ucmp->timestamp_size();
893
0
    }
894
895
0
    Slice GetUserKey(uint32_t cf_id, const Slice& key) {
896
0
      size_t ts_sz = GetTimestampSize(cf_id);
897
0
      if (ts_sz == 0) {
898
0
        return key;
899
0
      }
900
0
      assert(key.size() >= ts_sz);
901
0
      return Slice(key.data(), key.size() - ts_sz);
902
0
    }
903
0
  };
904
905
0
  IndexedWriteBatchBuilder copycat(this, dbimpl_);
906
0
  return src_batch->Iterate(&copycat);
907
0
}
908
909
0
WriteBatch* TransactionBaseImpl::GetCommitTimeWriteBatch() {
910
0
  return &commit_time_batch_;
911
0
}
912
}  // namespace ROCKSDB_NAMESPACE