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 #pragma once 6 #ifndef ROCKSDB_LITE 7 8 #include <sstream> 9 #include <string> 10 11 #include "rocksdb/options.h" 12 #include "util/coding.h" 13 #include "util/string_util.h" 14 15 namespace ROCKSDB_NAMESPACE { 16 17 // BlobIndex is a pointer to the blob and metadata of the blob. The index is 18 // stored in base DB as ValueType::kTypeBlobIndex. 19 // There are three types of blob index: 20 // 21 // kInlinedTTL: 22 // +------+------------+---------------+ 23 // | type | expiration | value | 24 // +------+------------+---------------+ 25 // | char | varint64 | variable size | 26 // +------+------------+---------------+ 27 // 28 // kBlob: 29 // +------+-------------+----------+----------+-------------+ 30 // | type | file number | offset | size | compression | 31 // +------+-------------+----------+----------+-------------+ 32 // | char | varint64 | varint64 | varint64 | char | 33 // +------+-------------+----------+----------+-------------+ 34 // 35 // kBlobTTL: 36 // +------+------------+-------------+----------+----------+-------------+ 37 // | type | expiration | file number | offset | size | compression | 38 // +------+------------+-------------+----------+----------+-------------+ 39 // | char | varint64 | varint64 | varint64 | varint64 | char | 40 // +------+------------+-------------+----------+----------+-------------+ 41 // 42 // There isn't a kInlined (without TTL) type since we can store it as a plain 43 // value (i.e. ValueType::kTypeValue). 44 class BlobIndex { 45 public: 46 enum class Type : unsigned char { 47 kInlinedTTL = 0, 48 kBlob = 1, 49 kBlobTTL = 2, 50 kUnknown = 3, 51 }; 52 BlobIndex()53 BlobIndex() : type_(Type::kUnknown) {} 54 IsInlined()55 bool IsInlined() const { return type_ == Type::kInlinedTTL; } 56 HasTTL()57 bool HasTTL() const { 58 return type_ == Type::kInlinedTTL || type_ == Type::kBlobTTL; 59 } 60 expiration()61 uint64_t expiration() const { 62 assert(HasTTL()); 63 return expiration_; 64 } 65 value()66 const Slice& value() const { 67 assert(IsInlined()); 68 return value_; 69 } 70 file_number()71 uint64_t file_number() const { 72 assert(!IsInlined()); 73 return file_number_; 74 } 75 offset()76 uint64_t offset() const { 77 assert(!IsInlined()); 78 return offset_; 79 } 80 size()81 uint64_t size() const { 82 assert(!IsInlined()); 83 return size_; 84 } 85 DecodeFrom(Slice slice)86 Status DecodeFrom(Slice slice) { 87 static const std::string kErrorMessage = "Error while decoding blob index"; 88 assert(slice.size() > 0); 89 type_ = static_cast<Type>(*slice.data()); 90 if (type_ >= Type::kUnknown) { 91 return Status::Corruption( 92 kErrorMessage, 93 "Unknown blob index type: " + ToString(static_cast<char>(type_))); 94 } 95 slice = Slice(slice.data() + 1, slice.size() - 1); 96 if (HasTTL()) { 97 if (!GetVarint64(&slice, &expiration_)) { 98 return Status::Corruption(kErrorMessage, "Corrupted expiration"); 99 } 100 } 101 if (IsInlined()) { 102 value_ = slice; 103 } else { 104 if (GetVarint64(&slice, &file_number_) && GetVarint64(&slice, &offset_) && 105 GetVarint64(&slice, &size_) && slice.size() == 1) { 106 compression_ = static_cast<CompressionType>(*slice.data()); 107 } else { 108 return Status::Corruption(kErrorMessage, "Corrupted blob offset"); 109 } 110 } 111 return Status::OK(); 112 } 113 DebugString(bool output_hex)114 std::string DebugString(bool output_hex) const { 115 std::ostringstream oss; 116 117 if (IsInlined()) { 118 oss << "[inlined blob] value:" << value_.ToString(output_hex); 119 } else { 120 oss << "[blob ref] file:" << file_number_ << " offset:" << offset_ 121 << " size:" << size_; 122 } 123 124 if (HasTTL()) { 125 oss << " exp:" << expiration_; 126 } 127 128 return oss.str(); 129 } 130 EncodeInlinedTTL(std::string * dst,uint64_t expiration,const Slice & value)131 static void EncodeInlinedTTL(std::string* dst, uint64_t expiration, 132 const Slice& value) { 133 assert(dst != nullptr); 134 dst->clear(); 135 dst->reserve(1 + kMaxVarint64Length + value.size()); 136 dst->push_back(static_cast<char>(Type::kInlinedTTL)); 137 PutVarint64(dst, expiration); 138 dst->append(value.data(), value.size()); 139 } 140 EncodeBlob(std::string * dst,uint64_t file_number,uint64_t offset,uint64_t size,CompressionType compression)141 static void EncodeBlob(std::string* dst, uint64_t file_number, 142 uint64_t offset, uint64_t size, 143 CompressionType compression) { 144 assert(dst != nullptr); 145 dst->clear(); 146 dst->reserve(kMaxVarint64Length * 3 + 2); 147 dst->push_back(static_cast<char>(Type::kBlob)); 148 PutVarint64(dst, file_number); 149 PutVarint64(dst, offset); 150 PutVarint64(dst, size); 151 dst->push_back(static_cast<char>(compression)); 152 } 153 EncodeBlobTTL(std::string * dst,uint64_t expiration,uint64_t file_number,uint64_t offset,uint64_t size,CompressionType compression)154 static void EncodeBlobTTL(std::string* dst, uint64_t expiration, 155 uint64_t file_number, uint64_t offset, 156 uint64_t size, CompressionType compression) { 157 assert(dst != nullptr); 158 dst->clear(); 159 dst->reserve(kMaxVarint64Length * 4 + 2); 160 dst->push_back(static_cast<char>(Type::kBlobTTL)); 161 PutVarint64(dst, expiration); 162 PutVarint64(dst, file_number); 163 PutVarint64(dst, offset); 164 PutVarint64(dst, size); 165 dst->push_back(static_cast<char>(compression)); 166 } 167 168 private: 169 Type type_ = Type::kUnknown; 170 uint64_t expiration_ = 0; 171 Slice value_; 172 uint64_t file_number_ = 0; 173 uint64_t offset_ = 0; 174 uint64_t size_ = 0; 175 CompressionType compression_ = kNoCompression; 176 }; 177 178 } // namespace ROCKSDB_NAMESPACE 179 #endif // ROCKSDB_LITE 180