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 7 #include <sstream> 8 #include <string> 9 10 #include "rocksdb/compression_type.h" 11 #include "util/coding.h" 12 #include "util/compression.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 compression()86 CompressionType compression() const { 87 assert(!IsInlined()); 88 return compression_; 89 } 90 DecodeFrom(Slice slice)91 Status DecodeFrom(Slice slice) { 92 static const std::string kErrorMessage = "Error while decoding blob index"; 93 assert(slice.size() > 0); 94 type_ = static_cast<Type>(*slice.data()); 95 if (type_ >= Type::kUnknown) { 96 return Status::Corruption( 97 kErrorMessage, 98 "Unknown blob index type: " + ToString(static_cast<char>(type_))); 99 } 100 slice = Slice(slice.data() + 1, slice.size() - 1); 101 if (HasTTL()) { 102 if (!GetVarint64(&slice, &expiration_)) { 103 return Status::Corruption(kErrorMessage, "Corrupted expiration"); 104 } 105 } 106 if (IsInlined()) { 107 value_ = slice; 108 } else { 109 if (GetVarint64(&slice, &file_number_) && GetVarint64(&slice, &offset_) && 110 GetVarint64(&slice, &size_) && slice.size() == 1) { 111 compression_ = static_cast<CompressionType>(*slice.data()); 112 } else { 113 return Status::Corruption(kErrorMessage, "Corrupted blob offset"); 114 } 115 } 116 return Status::OK(); 117 } 118 DebugString(bool output_hex)119 std::string DebugString(bool output_hex) const { 120 std::ostringstream oss; 121 122 if (IsInlined()) { 123 oss << "[inlined blob] value:" << value_.ToString(output_hex); 124 } else { 125 oss << "[blob ref] file:" << file_number_ << " offset:" << offset_ 126 << " size:" << size_ 127 << " compression: " << CompressionTypeToString(compression_); 128 } 129 130 if (HasTTL()) { 131 oss << " exp:" << expiration_; 132 } 133 134 return oss.str(); 135 } 136 EncodeInlinedTTL(std::string * dst,uint64_t expiration,const Slice & value)137 static void EncodeInlinedTTL(std::string* dst, uint64_t expiration, 138 const Slice& value) { 139 assert(dst != nullptr); 140 dst->clear(); 141 dst->reserve(1 + kMaxVarint64Length + value.size()); 142 dst->push_back(static_cast<char>(Type::kInlinedTTL)); 143 PutVarint64(dst, expiration); 144 dst->append(value.data(), value.size()); 145 } 146 EncodeBlob(std::string * dst,uint64_t file_number,uint64_t offset,uint64_t size,CompressionType compression)147 static void EncodeBlob(std::string* dst, uint64_t file_number, 148 uint64_t offset, uint64_t size, 149 CompressionType compression) { 150 assert(dst != nullptr); 151 dst->clear(); 152 dst->reserve(kMaxVarint64Length * 3 + 2); 153 dst->push_back(static_cast<char>(Type::kBlob)); 154 PutVarint64(dst, file_number); 155 PutVarint64(dst, offset); 156 PutVarint64(dst, size); 157 dst->push_back(static_cast<char>(compression)); 158 } 159 EncodeBlobTTL(std::string * dst,uint64_t expiration,uint64_t file_number,uint64_t offset,uint64_t size,CompressionType compression)160 static void EncodeBlobTTL(std::string* dst, uint64_t expiration, 161 uint64_t file_number, uint64_t offset, 162 uint64_t size, CompressionType compression) { 163 assert(dst != nullptr); 164 dst->clear(); 165 dst->reserve(kMaxVarint64Length * 4 + 2); 166 dst->push_back(static_cast<char>(Type::kBlobTTL)); 167 PutVarint64(dst, expiration); 168 PutVarint64(dst, file_number); 169 PutVarint64(dst, offset); 170 PutVarint64(dst, size); 171 dst->push_back(static_cast<char>(compression)); 172 } 173 174 private: 175 Type type_ = Type::kUnknown; 176 uint64_t expiration_ = 0; 177 Slice value_; 178 uint64_t file_number_ = 0; 179 uint64_t offset_ = 0; 180 uint64_t size_ = 0; 181 CompressionType compression_ = kNoCompression; 182 }; 183 184 } // namespace ROCKSDB_NAMESPACE 185