]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
11fdf7f2 TL |
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). | |
7c673cae FG |
5 | // |
6 | // Copyright (c) 2012 The LevelDB Authors. All rights reserved. | |
7 | // Use of this source code is governed by a BSD-style license that can be | |
8 | // found in the LICENSE file. See the AUTHORS file for names of contributors. | |
9 | ||
10 | #include <algorithm> | |
11 | #include "rocksdb/slice_transform.h" | |
12 | #include "rocksdb/slice.h" | |
13 | #include "util/string_util.h" | |
14 | #include <stdio.h> | |
15 | ||
f67539c2 | 16 | namespace ROCKSDB_NAMESPACE { |
7c673cae FG |
17 | |
18 | namespace { | |
19 | ||
20 | class FixedPrefixTransform : public SliceTransform { | |
21 | private: | |
22 | size_t prefix_len_; | |
23 | std::string name_; | |
24 | ||
25 | public: | |
26 | explicit FixedPrefixTransform(size_t prefix_len) | |
27 | : prefix_len_(prefix_len), | |
28 | // Note that if any part of the name format changes, it will require | |
29 | // changes on options_helper in order to make RocksDBOptionsParser work | |
30 | // for the new change. | |
31 | // TODO(yhchiang): move serialization / deserializaion code inside | |
32 | // the class implementation itself. | |
33 | name_("rocksdb.FixedPrefix." + ToString(prefix_len_)) {} | |
34 | ||
494da23a | 35 | const char* Name() const override { return name_.c_str(); } |
7c673cae | 36 | |
494da23a | 37 | Slice Transform(const Slice& src) const override { |
7c673cae FG |
38 | assert(InDomain(src)); |
39 | return Slice(src.data(), prefix_len_); | |
40 | } | |
41 | ||
494da23a | 42 | bool InDomain(const Slice& src) const override { |
7c673cae FG |
43 | return (src.size() >= prefix_len_); |
44 | } | |
45 | ||
494da23a | 46 | bool InRange(const Slice& dst) const override { |
7c673cae FG |
47 | return (dst.size() == prefix_len_); |
48 | } | |
49 | ||
494da23a | 50 | bool FullLengthEnabled(size_t* len) const override { |
11fdf7f2 TL |
51 | *len = prefix_len_; |
52 | return true; | |
53 | } | |
54 | ||
494da23a | 55 | bool SameResultWhenAppended(const Slice& prefix) const override { |
7c673cae FG |
56 | return InDomain(prefix); |
57 | } | |
58 | }; | |
59 | ||
60 | class CappedPrefixTransform : public SliceTransform { | |
61 | private: | |
62 | size_t cap_len_; | |
63 | std::string name_; | |
64 | ||
65 | public: | |
66 | explicit CappedPrefixTransform(size_t cap_len) | |
67 | : cap_len_(cap_len), | |
68 | // Note that if any part of the name format changes, it will require | |
69 | // changes on options_helper in order to make RocksDBOptionsParser work | |
70 | // for the new change. | |
71 | // TODO(yhchiang): move serialization / deserializaion code inside | |
72 | // the class implementation itself. | |
73 | name_("rocksdb.CappedPrefix." + ToString(cap_len_)) {} | |
74 | ||
494da23a | 75 | const char* Name() const override { return name_.c_str(); } |
7c673cae | 76 | |
494da23a | 77 | Slice Transform(const Slice& src) const override { |
7c673cae FG |
78 | assert(InDomain(src)); |
79 | return Slice(src.data(), std::min(cap_len_, src.size())); | |
80 | } | |
81 | ||
494da23a | 82 | bool InDomain(const Slice& /*src*/) const override { return true; } |
7c673cae | 83 | |
494da23a | 84 | bool InRange(const Slice& dst) const override { |
7c673cae FG |
85 | return (dst.size() <= cap_len_); |
86 | } | |
87 | ||
494da23a | 88 | bool FullLengthEnabled(size_t* len) const override { |
11fdf7f2 TL |
89 | *len = cap_len_; |
90 | return true; | |
91 | } | |
92 | ||
494da23a | 93 | bool SameResultWhenAppended(const Slice& prefix) const override { |
7c673cae FG |
94 | return prefix.size() >= cap_len_; |
95 | } | |
96 | }; | |
97 | ||
98 | class NoopTransform : public SliceTransform { | |
99 | public: | |
100 | explicit NoopTransform() { } | |
101 | ||
494da23a | 102 | const char* Name() const override { return "rocksdb.Noop"; } |
7c673cae | 103 | |
494da23a | 104 | Slice Transform(const Slice& src) const override { return src; } |
7c673cae | 105 | |
494da23a | 106 | bool InDomain(const Slice& /*src*/) const override { return true; } |
7c673cae | 107 | |
494da23a | 108 | bool InRange(const Slice& /*dst*/) const override { return true; } |
7c673cae | 109 | |
494da23a | 110 | bool SameResultWhenAppended(const Slice& /*prefix*/) const override { |
7c673cae FG |
111 | return false; |
112 | } | |
113 | }; | |
114 | ||
115 | } | |
116 | ||
117 | // 2 small internal utility functions, for efficient hex conversions | |
118 | // and no need for snprintf, toupper etc... | |
119 | // Originally from wdt/util/EncryptionUtils.cpp - for ToString(true)/DecodeHex: | |
120 | char toHex(unsigned char v) { | |
121 | if (v <= 9) { | |
122 | return '0' + v; | |
123 | } | |
124 | return 'A' + v - 10; | |
125 | } | |
126 | // most of the code is for validation/error check | |
127 | int fromHex(char c) { | |
128 | // toupper: | |
129 | if (c >= 'a' && c <= 'f') { | |
130 | c -= ('a' - 'A'); // aka 0x20 | |
131 | } | |
132 | // validation | |
133 | if (c < '0' || (c > '9' && (c < 'A' || c > 'F'))) { | |
134 | return -1; // invalid not 0-9A-F hex char | |
135 | } | |
136 | if (c <= '9') { | |
137 | return c - '0'; | |
138 | } | |
139 | return c - 'A' + 10; | |
140 | } | |
141 | ||
142 | Slice::Slice(const SliceParts& parts, std::string* buf) { | |
143 | size_t length = 0; | |
144 | for (int i = 0; i < parts.num_parts; ++i) { | |
145 | length += parts.parts[i].size(); | |
146 | } | |
147 | buf->reserve(length); | |
148 | ||
149 | for (int i = 0; i < parts.num_parts; ++i) { | |
150 | buf->append(parts.parts[i].data(), parts.parts[i].size()); | |
151 | } | |
152 | data_ = buf->data(); | |
153 | size_ = buf->size(); | |
154 | } | |
155 | ||
156 | // Return a string that contains the copy of the referenced data. | |
157 | std::string Slice::ToString(bool hex) const { | |
158 | std::string result; // RVO/NRVO/move | |
159 | if (hex) { | |
160 | result.reserve(2 * size_); | |
161 | for (size_t i = 0; i < size_; ++i) { | |
162 | unsigned char c = data_[i]; | |
163 | result.push_back(toHex(c >> 4)); | |
164 | result.push_back(toHex(c & 0xf)); | |
165 | } | |
166 | return result; | |
167 | } else { | |
168 | result.assign(data_, size_); | |
169 | return result; | |
170 | } | |
171 | } | |
172 | ||
173 | // Originally from rocksdb/utilities/ldb_cmd.h | |
174 | bool Slice::DecodeHex(std::string* result) const { | |
175 | std::string::size_type len = size_; | |
176 | if (len % 2) { | |
177 | // Hex string must be even number of hex digits to get complete bytes back | |
178 | return false; | |
179 | } | |
180 | if (!result) { | |
181 | return false; | |
182 | } | |
183 | result->clear(); | |
184 | result->reserve(len / 2); | |
185 | ||
186 | for (size_t i = 0; i < len;) { | |
187 | int h1 = fromHex(data_[i++]); | |
188 | if (h1 < 0) { | |
189 | return false; | |
190 | } | |
191 | int h2 = fromHex(data_[i++]); | |
192 | if (h2 < 0) { | |
193 | return false; | |
194 | } | |
11fdf7f2 | 195 | result->push_back(static_cast<char>((h1 << 4) | h2)); |
7c673cae FG |
196 | } |
197 | return true; | |
198 | } | |
199 | ||
200 | const SliceTransform* NewFixedPrefixTransform(size_t prefix_len) { | |
201 | return new FixedPrefixTransform(prefix_len); | |
202 | } | |
203 | ||
204 | const SliceTransform* NewCappedPrefixTransform(size_t cap_len) { | |
205 | return new CappedPrefixTransform(cap_len); | |
206 | } | |
207 | ||
208 | const SliceTransform* NewNoopTransform() { | |
209 | return new NoopTransform; | |
210 | } | |
211 | ||
f67539c2 TL |
212 | PinnableSlice::PinnableSlice(PinnableSlice&& other) { |
213 | *this = std::move(other); | |
214 | } | |
215 | ||
216 | PinnableSlice& PinnableSlice::operator=(PinnableSlice&& other) { | |
217 | if (this != &other) { | |
218 | Cleanable::Reset(); | |
219 | Cleanable::operator=(std::move(other)); | |
220 | size_ = other.size_; | |
221 | pinned_ = other.pinned_; | |
222 | if (pinned_) { | |
223 | data_ = other.data_; | |
224 | // When it's pinned, buf should no longer be of use. | |
225 | } else { | |
226 | if (other.buf_ == &other.self_space_) { | |
227 | self_space_ = std::move(other.self_space_); | |
228 | buf_ = &self_space_; | |
229 | data_ = buf_->data(); | |
230 | } else { | |
231 | buf_ = other.buf_; | |
232 | data_ = other.data_; | |
233 | } | |
234 | } | |
235 | other.self_space_.clear(); | |
236 | other.buf_ = &other.self_space_; | |
237 | other.pinned_ = false; | |
238 | other.PinSelf(); | |
239 | } | |
240 | return *this; | |
241 | } | |
242 | ||
243 | } // namespace ROCKSDB_NAMESPACE |