/Users/deen/code/yugabyte-db/src/yb/rocksdb/db/dbformat.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 the BSD-style license found in the |
3 | | // LICENSE file in the root directory of this source tree. An additional grant |
4 | | // of patent rights can be found in the PATENTS file in the same directory. |
5 | | // |
6 | | // The following only applies to changes made to this file as part of YugaByte development. |
7 | | // |
8 | | // Portions Copyright (c) YugaByte, Inc. |
9 | | // |
10 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
11 | | // in compliance with the License. You may obtain a copy of the License at |
12 | | // |
13 | | // http://www.apache.org/licenses/LICENSE-2.0 |
14 | | // |
15 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
16 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
17 | | // or implied. See the License for the specific language governing permissions and limitations |
18 | | // under the License. |
19 | | // |
20 | | // Copyright (c) 2011 The LevelDB Authors. All rights reserved. |
21 | | // Use of this source code is governed by a BSD-style license that can be |
22 | | // found in the LICENSE file. See the AUTHORS file for names of contributors. |
23 | | #include "yb/rocksdb/db/dbformat.h" |
24 | | |
25 | | #ifndef __STDC_FORMAT_MACROS |
26 | | #define __STDC_FORMAT_MACROS |
27 | | #endif |
28 | | |
29 | | #include <inttypes.h> |
30 | | #include <stdio.h> |
31 | | |
32 | | #include "yb/util/logging.h" |
33 | | #include "yb/util/result.h" |
34 | | |
35 | | #include "yb/rocksdb/port/port.h" |
36 | | #include "yb/rocksdb/util/coding.h" |
37 | | #include "yb/rocksdb/util/logging.h" |
38 | | #include "yb/rocksdb/util/perf_context_imp.h" |
39 | | |
40 | | namespace rocksdb { |
41 | | |
42 | 621M | uint64_t PackSequenceAndType(uint64_t seq, ValueType t) { |
43 | 621M | assert(seq <= kMaxSequenceNumber); |
44 | 0 | assert(IsValueType(t)); |
45 | 0 | return (seq << 8) | t; |
46 | 621M | } |
47 | | |
48 | 13.9M | SequenceAndType UnPackSequenceAndTypeFromEnd(const void* end) { |
49 | 13.9M | uint64_t packed; |
50 | 13.9M | memcpy(&packed, static_cast<const char*>(end) - kLastInternalComponentSize, sizeof(packed)); |
51 | 13.9M | auto result = SequenceAndType { |
52 | 13.9M | .sequence = packed >> 8, |
53 | 13.9M | .type = static_cast<ValueType>(packed & 0xff), |
54 | 13.9M | }; |
55 | | |
56 | 13.9M | assert(result.sequence <= kMaxSequenceNumber); |
57 | 0 | assert(IsValueType(result.type)); |
58 | | |
59 | 0 | return result; |
60 | 13.9M | } |
61 | | |
62 | 1.37M | void AppendInternalKey(std::string* result, const ParsedInternalKey& key) { |
63 | 1.37M | result->append(key.user_key.cdata(), key.user_key.size()); |
64 | 1.37M | PutFixed64(result, PackSequenceAndType(key.sequence, key.type)); |
65 | 1.37M | } |
66 | | |
67 | 1.63k | std::string ParsedInternalKey::DebugString(bool hex) const { |
68 | 1.63k | char buf[50]; |
69 | 1.63k | snprintf(buf, sizeof(buf), "' @ %" PRIu64 ": %d", sequence, |
70 | 1.63k | static_cast<int>(type)); |
71 | 1.63k | std::string result = "'"; |
72 | 1.63k | result += user_key.ToString(hex); |
73 | 1.63k | result += buf; |
74 | 1.63k | return result; |
75 | 1.63k | } |
76 | | |
77 | 1.63k | std::string InternalKey::DebugString(const std::string& rep, bool hex) { |
78 | 1.63k | std::string result; |
79 | 1.63k | ParsedInternalKey parsed; |
80 | 1.63k | if (ParseInternalKey(rep, &parsed)) { |
81 | 1.63k | result = parsed.DebugString(hex); |
82 | 1.63k | } else { |
83 | 0 | result = "(bad)"; |
84 | 0 | result.append(EscapeString(rep)); |
85 | 0 | } |
86 | 1.63k | return result; |
87 | 1.63k | } |
88 | | |
89 | | yb::Result<FileBoundaryValues<InternalKey>> MakeFileBoundaryValues( |
90 | | BoundaryValuesExtractor* extractor, |
91 | | const Slice& key, |
92 | 158M | const Slice& value) { |
93 | 158M | ParsedInternalKey parsed = { Slice(), 0, kTypeDeletion }; |
94 | 158M | ParseInternalKey(key, &parsed); |
95 | | |
96 | 158M | FileBoundaryValues<InternalKey> result; |
97 | 158M | result.key = InternalKey::DecodeFrom(key); |
98 | 158M | result.seqno = parsed.sequence; |
99 | | |
100 | 158M | if (extractor) { |
101 | 115M | auto status = extractor->Extract(parsed.user_key, value, &result.user_values); |
102 | 115M | if (!status.ok()) { |
103 | 0 | return status; |
104 | 0 | } |
105 | 115M | } |
106 | 158M | return result; |
107 | 158M | } |
108 | | |
109 | 17.7k | const char* InternalKeyComparator::Name() const { |
110 | 17.7k | return name_.c_str(); |
111 | 17.7k | } |
112 | | |
113 | 27.8G | int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const { |
114 | | // Order by: |
115 | | // increasing user key (according to user-supplied comparator) |
116 | | // decreasing sequence number |
117 | | // decreasing type (though sequence# should be enough to disambiguate) |
118 | 27.8G | int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey)); |
119 | 27.8G | PERF_COUNTER_ADD(user_key_comparison_count, 1); |
120 | 27.8G | if (r == 0) { |
121 | 478M | const uint64_t anum = DecodeFixed64(akey.end() - 8); |
122 | 478M | const uint64_t bnum = DecodeFixed64(bkey.end() - 8); |
123 | 478M | if (anum > bnum) { |
124 | 166M | r = -1; |
125 | 311M | } else if (anum < bnum) { |
126 | 292M | r = +1; |
127 | 292M | } |
128 | 478M | } |
129 | 27.8G | return r; |
130 | 27.8G | } |
131 | | |
132 | | int InternalKeyComparator::Compare(const ParsedInternalKey& a, |
133 | 865k | const ParsedInternalKey& b) const { |
134 | | // Order by: |
135 | | // increasing user key (according to user-supplied comparator) |
136 | | // decreasing sequence number |
137 | | // decreasing type (though sequence# should be enough to disambiguate) |
138 | 865k | int r = user_comparator_->Compare(a.user_key, b.user_key); |
139 | 865k | PERF_COUNTER_ADD(user_key_comparison_count, 1); |
140 | 865k | if (r == 0) { |
141 | 89.9k | if (a.sequence > b.sequence) { |
142 | 32 | r = -1; |
143 | 89.9k | } else if (a.sequence < b.sequence) { |
144 | 80.8k | r = +1; |
145 | 80.8k | } else if (9.08k a.type > b.type9.08k ) { |
146 | 0 | r = -1; |
147 | 9.08k | } else if (a.type < b.type) { |
148 | 240 | r = +1; |
149 | 240 | } |
150 | 89.9k | } |
151 | 865k | return r; |
152 | 865k | } |
153 | | |
154 | | void InternalKeyComparator::FindShortestSeparator( |
155 | | std::string* start, |
156 | 2.78M | const Slice& limit) const { |
157 | | // Attempt to shorten the user portion of the key |
158 | 2.78M | Slice user_start = ExtractUserKey(*start); |
159 | 2.78M | Slice user_limit = ExtractUserKey(limit); |
160 | 2.78M | std::string tmp = user_start.ToBuffer(); |
161 | 2.78M | user_comparator_->FindShortestSeparator(&tmp, user_limit); |
162 | 2.78M | if (tmp.size() < user_start.size() && |
163 | 2.78M | user_comparator_->Compare(user_start, tmp) < 01.51M ) { |
164 | | // User key has become shorter physically, but larger logically. |
165 | | // Tack on the earliest possible number to the shortened user key. |
166 | 1.51M | PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber, kValueTypeForSeek)); |
167 | 1.51M | assert(this->Compare(*start, tmp) < 0); |
168 | 0 | assert(this->Compare(tmp, limit) < 0); |
169 | 0 | start->swap(tmp); |
170 | 1.51M | } |
171 | 2.78M | } |
172 | | |
173 | 62.3k | void InternalKeyComparator::FindShortSuccessor(std::string* key) const { |
174 | 62.3k | Slice user_key = ExtractUserKey(*key); |
175 | 62.3k | std::string tmp = user_key.ToBuffer(); |
176 | 62.3k | user_comparator_->FindShortSuccessor(&tmp); |
177 | 62.3k | if (tmp.size() < user_key.size() && |
178 | 62.3k | user_comparator_->Compare(user_key, tmp) < 058.2k ) { |
179 | | // User key has become shorter physically, but larger logically. |
180 | | // Tack on the earliest possible number to the shortened user key. |
181 | 58.2k | PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber, kValueTypeForSeek)); |
182 | 58.2k | assert(this->Compare(*key, tmp) < 0); |
183 | 0 | key->swap(tmp); |
184 | 58.2k | } |
185 | 62.3k | } |
186 | | |
187 | 21.1M | LookupKey::LookupKey(const Slice& _user_key, SequenceNumber s) { |
188 | 21.1M | size_t usize = _user_key.size(); |
189 | 21.1M | size_t needed = usize + 13; // A conservative estimate |
190 | 21.1M | char* dst; |
191 | 21.1M | if (needed <= sizeof(space_)) { |
192 | 21.1M | dst = space_; |
193 | 21.1M | } else { |
194 | 6.49k | dst = new char[needed]; |
195 | 6.49k | } |
196 | 21.1M | start_ = dst; |
197 | | // NOTE: We don't support users keys of more than 2GB :) |
198 | 21.1M | dst = EncodeVarint32(dst, static_cast<uint32_t>(usize + 8)); |
199 | 21.1M | kstart_ = dst; |
200 | 21.1M | memcpy(dst, _user_key.data(), usize); |
201 | 21.1M | dst += usize; |
202 | 21.1M | EncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek)); |
203 | 21.1M | dst += 8; |
204 | 21.1M | end_ = dst; |
205 | 21.1M | } |
206 | | |
207 | | } // namespace rocksdb |