slice.cc 6.4 KB

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