/Users/deen/code/yugabyte-db/src/yb/docdb/kv_debug.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) YugaByte, Inc. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
4 | | // in compliance with the License. You may obtain a copy of the License at |
5 | | // |
6 | | // http://www.apache.org/licenses/LICENSE-2.0 |
7 | | // |
8 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
9 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
10 | | // or implied. See the License for the specific language governing permissions and limitations |
11 | | // under the License. |
12 | | // |
13 | | #include "yb/docdb/kv_debug.h" |
14 | | |
15 | | #include <string> |
16 | | |
17 | | #include "yb/common/common.pb.h" |
18 | | |
19 | | #include "yb/docdb/doc_key.h" |
20 | | #include "yb/docdb/doc_kv_util.h" |
21 | | #include "yb/docdb/docdb-internal.h" |
22 | | #include "yb/docdb/docdb_types.h" |
23 | | #include "yb/docdb/intent.h" |
24 | | #include "yb/docdb/value.h" |
25 | | #include "yb/docdb/value_type.h" |
26 | | |
27 | | #include "yb/gutil/casts.h" |
28 | | |
29 | | #include "yb/util/bytes_formatter.h" |
30 | | #include "yb/util/fast_varint.h" |
31 | | #include "yb/util/result.h" |
32 | | #include "yb/util/status_format.h" |
33 | | |
34 | | namespace yb { |
35 | | namespace docdb { |
36 | | |
37 | 188k | Result<std::string> DocDBKeyToDebugStr(Slice key_slice, StorageDbType db_type) { |
38 | 188k | auto key_type = GetKeyType(key_slice, db_type); |
39 | 188k | SubDocKey subdoc_key; |
40 | 188k | switch (key_type) { |
41 | 2.47k | case KeyType::kIntentKey: |
42 | 2.47k | { |
43 | 2.47k | auto decoded_intent_key = VERIFY_RESULT(DecodeIntentKey(key_slice)); |
44 | 2.47k | RETURN_NOT_OK(subdoc_key.FullyDecodeFromKeyWithOptionalHybridTime( |
45 | 2.47k | decoded_intent_key.intent_prefix)); |
46 | 2.47k | return subdoc_key.ToString(AutoDecodeKeys::kTrue) + " " + |
47 | 2.47k | ToString(decoded_intent_key.intent_types) + " " + |
48 | 2.47k | decoded_intent_key.doc_ht.ToString(); |
49 | 2.47k | } |
50 | 1.22k | case KeyType::kReverseTxnKey: |
51 | 1.22k | { |
52 | 1.22k | RETURN_NOT_OK(key_slice.consume_byte(ValueTypeAsChar::kTransactionId)); |
53 | 1.22k | auto transaction_id = VERIFY_RESULT(DecodeTransactionId(&key_slice)); |
54 | 1.22k | auto doc_ht = VERIFY_RESULT_PREPEND( |
55 | 1.22k | DecodeInvertedDocHt(key_slice), Format("Reverse txn record for: $0", transaction_id)); |
56 | 0 | return Format("TXN REV $0 $1", transaction_id, doc_ht); |
57 | 1.22k | } |
58 | 0 | case KeyType::kTransactionMetadata: |
59 | 0 | { |
60 | 0 | RETURN_NOT_OK(key_slice.consume_byte(ValueTypeAsChar::kTransactionId)); |
61 | 0 | auto transaction_id = DecodeTransactionId(&key_slice); |
62 | 0 | RETURN_NOT_OK(transaction_id); |
63 | 0 | return Format("TXN META $0", *transaction_id); |
64 | 0 | } |
65 | 0 | case KeyType::kEmpty: FALLTHROUGH_INTENDED; |
66 | 184k | case KeyType::kPlainSubDocKey: |
67 | 184k | RETURN_NOT_OK_PREPEND( |
68 | 184k | subdoc_key.FullyDecodeFrom(key_slice), |
69 | 184k | "Error: failed decoding SubDocKey " + |
70 | 184k | FormatSliceAsStr(key_slice)); |
71 | 184k | return subdoc_key.ToString(AutoDecodeKeys::kTrue); |
72 | 4 | case KeyType::kExternalIntents: |
73 | 4 | { |
74 | 4 | RETURN_NOT_OK(key_slice.consume_byte(ValueTypeAsChar::kExternalTransactionId)); |
75 | 4 | auto transaction_id = VERIFY_RESULT(DecodeTransactionId(&key_slice)); |
76 | 4 | auto doc_hybrid_time = VERIFY_RESULT_PREPEND( |
77 | 4 | DecodeInvertedDocHt(key_slice), Format("External txn record for: $0", transaction_id)); |
78 | 0 | return Format("TXN EXT $0 $1", transaction_id, doc_hybrid_time); |
79 | 4 | } |
80 | 188k | } |
81 | 0 | return STATUS_FORMAT(Corruption, "Invalid KeyType: $0", yb::ToString(key_type)); |
82 | 188k | } |
83 | | |
84 | | namespace { |
85 | | |
86 | 185k | Result<std::string> DocDBValueToDebugStrInternal(Slice value_slice, KeyType key_type) { |
87 | 185k | std::string prefix; |
88 | 185k | if (key_type == KeyType::kIntentKey) { |
89 | 1.24k | auto txn_id_res = VERIFY_RESULT(DecodeTransactionIdFromIntentValue(&value_slice)); |
90 | 0 | prefix = Format("TransactionId($0) ", txn_id_res); |
91 | 1.24k | if (!value_slice.empty()) { |
92 | 496 | RETURN_NOT_OK(value_slice.consume_byte(ValueTypeAsChar::kWriteId)); |
93 | 496 | if (value_slice.size() < sizeof(IntraTxnWriteId)) { |
94 | 0 | return STATUS_FORMAT(Corruption, "Not enough bytes for write id: $0", value_slice.size()); |
95 | 0 | } |
96 | 496 | auto write_id = BigEndian::Load32(value_slice.data()); |
97 | 496 | value_slice.remove_prefix(sizeof(write_id)); |
98 | 496 | prefix += Format("WriteId($0) ", write_id); |
99 | 496 | } |
100 | 1.24k | } |
101 | | |
102 | | // Empty values are allowed for weak intents. |
103 | 185k | if (!value_slice.empty() || key_type != KeyType::kIntentKey749 ) { |
104 | 184k | Value v; |
105 | 184k | RETURN_NOT_OK_PREPEND( |
106 | 184k | v.Decode(value_slice), |
107 | 184k | Format("Error: failed to decode value $0", prefix)); |
108 | 184k | return prefix + v.ToString(); |
109 | 184k | } else { |
110 | 749 | return prefix + "none"; |
111 | 749 | } |
112 | 185k | } |
113 | | |
114 | | } // namespace |
115 | | |
116 | 186k | Result<std::string> DocDBValueToDebugStr(KeyType key_type, Slice key, Slice value) { |
117 | 186k | switch (key_type) { |
118 | 0 | case KeyType::kTransactionMetadata: { |
119 | 0 | TransactionMetadataPB metadata_pb; |
120 | 0 | if (!metadata_pb.ParseFromArray(value.cdata(), narrow_cast<int>(value.size()))) { |
121 | 0 | return STATUS_FORMAT(Corruption, "Bad metadata: $0", value.ToDebugHexString()); |
122 | 0 | } |
123 | 0 | return ToString(VERIFY_RESULT(TransactionMetadata::FromPB(metadata_pb))); |
124 | 0 | } |
125 | 1.22k | case KeyType::kReverseTxnKey: |
126 | 1.22k | return DocDBKeyToDebugStr(value, StorageDbType::kIntents); |
127 | | |
128 | 0 | case KeyType::kEmpty: FALLTHROUGH_INTENDED; |
129 | 1.24k | case KeyType::kIntentKey: FALLTHROUGH_INTENDED; |
130 | 185k | case KeyType::kPlainSubDocKey: |
131 | 185k | return DocDBValueToDebugStrInternal(value, key_type); |
132 | | |
133 | 4 | case KeyType::kExternalIntents: { |
134 | 4 | std::vector<std::string> intents; |
135 | 4 | SubDocKey sub_doc_key; |
136 | 4 | RETURN_NOT_OK(value.consume_byte(ValueTypeAsChar::kUuid)); |
137 | 4 | Uuid involved_tablet; |
138 | 4 | RETURN_NOT_OK(involved_tablet.FromSlice(value.Prefix(kUuidSize))); |
139 | 4 | value.remove_prefix(kUuidSize); |
140 | 4 | RETURN_NOT_OK(value.consume_byte(ValueTypeAsChar::kExternalIntents)); |
141 | 12 | for (;;)4 { |
142 | 12 | auto len = VERIFY_RESULT(util::FastDecodeUnsignedVarInt(&value)); |
143 | 12 | if (len == 0) { |
144 | 4 | break; |
145 | 4 | } |
146 | 8 | RETURN_NOT_OK(sub_doc_key.FullyDecodeFrom(value.Prefix(len), HybridTimeRequired::kFalse)); |
147 | 8 | value.remove_prefix(len); |
148 | 8 | len = VERIFY_RESULT(util::FastDecodeUnsignedVarInt(&value)); |
149 | 0 | intents.push_back(Format( |
150 | 8 | "$0 -> $1", |
151 | 8 | sub_doc_key, |
152 | 8 | VERIFY_RESULT(DocDBValueToDebugStrInternal( |
153 | 8 | value.Prefix(len), KeyType::kPlainSubDocKey)))); |
154 | 0 | value.remove_prefix(len); |
155 | 8 | } |
156 | 4 | DCHECK(value.empty()); |
157 | 4 | return Format("IT $0 $1", involved_tablet.ToHexString(), intents); |
158 | 4 | } |
159 | 186k | } |
160 | 0 | FATAL_INVALID_ENUM_VALUE(KeyType, key_type); |
161 | 0 | } |
162 | | |
163 | | } // namespace docdb |
164 | | } // namespace yb |