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).
8 #ifndef __STDC_FORMAT_MACROS
9 #define __STDC_FORMAT_MACROS
12 #include "utilities/transactions/transaction_util.h"
18 #include "db/db_impl.h"
19 #include "rocksdb/status.h"
20 #include "rocksdb/utilities/write_batch_with_index.h"
21 #include "util/string_util.h"
25 Status
TransactionUtil::CheckKeyForConflicts(
26 DBImpl
* db_impl
, ColumnFamilyHandle
* column_family
, const std::string
& key
,
27 SequenceNumber snap_seq
, bool cache_only
, ReadCallback
* snap_checker
) {
30 auto cfh
= reinterpret_cast<ColumnFamilyHandleImpl
*>(column_family
);
31 auto cfd
= cfh
->cfd();
32 SuperVersion
* sv
= db_impl
->GetAndRefSuperVersion(cfd
);
35 result
= Status::InvalidArgument("Could not access column family " +
40 SequenceNumber earliest_seq
=
41 db_impl
->GetEarliestMemTableSequenceNumber(sv
, true);
43 result
= CheckKey(db_impl
, sv
, earliest_seq
, snap_seq
, key
, cache_only
,
46 db_impl
->ReturnAndCleanupSuperVersion(cfd
, sv
);
52 Status
TransactionUtil::CheckKey(DBImpl
* db_impl
, SuperVersion
* sv
,
53 SequenceNumber earliest_seq
,
54 SequenceNumber snap_seq
,
55 const std::string
& key
, bool cache_only
,
56 ReadCallback
* snap_checker
) {
58 bool need_to_read_sst
= false;
60 // Since it would be too slow to check the SST files, we will only use
61 // the memtables to check whether there have been any recent writes
62 // to this key after it was accessed in this transaction. But if the
63 // Memtables do not contain a long enough history, we must fail the
65 if (earliest_seq
== kMaxSequenceNumber
) {
66 // The age of this memtable is unknown. Cannot rely on it to check
67 // for recent writes. This error shouldn't happen often in practice as
68 // the Memtable should have a valid earliest sequence number except in some
69 // corner cases (such as error cases during recovery).
70 need_to_read_sst
= true;
73 result
= Status::TryAgain(
74 "Transaction ould not check for conflicts as the MemTable does not "
75 "countain a long enough history to check write at SequenceNumber: ",
78 } else if (snap_seq
< earliest_seq
) {
79 need_to_read_sst
= true;
82 // The age of this memtable is too new to use to check for recent
85 snprintf(msg
, sizeof(msg
),
86 "Transaction could not check for conflicts for operation at "
87 "SequenceNumber %" PRIu64
88 " as the MemTable only contains changes newer than "
89 "SequenceNumber %" PRIu64
90 ". Increasing the value of the "
91 "max_write_buffer_number_to_maintain option could reduce the "
94 snap_seq
, earliest_seq
);
95 result
= Status::TryAgain(msg
);
100 SequenceNumber seq
= kMaxSequenceNumber
;
101 bool found_record_for_key
= false;
103 Status s
= db_impl
->GetLatestSequenceForKey(sv
, key
, !need_to_read_sst
,
104 &seq
, &found_record_for_key
);
106 if (!(s
.ok() || s
.IsNotFound() || s
.IsMergeInProgress())) {
108 } else if (found_record_for_key
) {
109 bool write_conflict
= snap_checker
== nullptr
111 : !snap_checker
->IsVisible(seq
);
112 if (write_conflict
) {
113 result
= Status::Busy();
121 Status
TransactionUtil::CheckKeysForConflicts(DBImpl
* db_impl
,
122 const TransactionKeyMap
& key_map
,
126 for (auto& key_map_iter
: key_map
) {
127 uint32_t cf_id
= key_map_iter
.first
;
128 const auto& keys
= key_map_iter
.second
;
130 SuperVersion
* sv
= db_impl
->GetAndRefSuperVersion(cf_id
);
132 result
= Status::InvalidArgument("Could not access column family " +
137 SequenceNumber earliest_seq
=
138 db_impl
->GetEarliestMemTableSequenceNumber(sv
, true);
140 // For each of the keys in this transaction, check to see if someone has
141 // written to this key since the start of the transaction.
142 for (const auto& key_iter
: keys
) {
143 const auto& key
= key_iter
.first
;
144 const SequenceNumber key_seq
= key_iter
.second
.seq
;
146 result
= CheckKey(db_impl
, sv
, earliest_seq
, key_seq
, key
, cache_only
);
153 db_impl
->ReturnAndCleanupSuperVersion(cf_id
, sv
);
164 } // namespace rocksdb
166 #endif // ROCKSDB_LITE