| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 | //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.//  This source code is licensed under both the GPLv2 (found in the//  COPYING file in the root directory) and Apache 2.0 License//  (found in the LICENSE.Apache file in the root directory).#pragma once#include <sstream>#include <string>#include "rocksdb/compression_type.h"#include "util/coding.h"#include "util/compression.h"#include "util/string_util.h"namespace ROCKSDB_NAMESPACE {// BlobIndex is a pointer to the blob and metadata of the blob. The index is// stored in base DB as ValueType::kTypeBlobIndex.// There are three types of blob index:////    kInlinedTTL://      +------+------------+---------------+//      | type | expiration | value         |//      +------+------------+---------------+//      | char | varint64   | variable size |//      +------+------------+---------------+////    kBlob://      +------+-------------+----------+----------+-------------+//      | type | file number | offset   | size     | compression |//      +------+-------------+----------+----------+-------------+//      | char | varint64    | varint64 | varint64 | char        |//      +------+-------------+----------+----------+-------------+////    kBlobTTL://      +------+------------+-------------+----------+----------+-------------+//      | type | expiration | file number | offset   | size     | compression |//      +------+------------+-------------+----------+----------+-------------+//      | char | varint64   | varint64    | varint64 | varint64 | char        |//      +------+------------+-------------+----------+----------+-------------+//// There isn't a kInlined (without TTL) type since we can store it as a plain// value (i.e. ValueType::kTypeValue).class BlobIndex { public:  enum class Type : unsigned char {    kInlinedTTL = 0,    kBlob = 1,    kBlobTTL = 2,    kUnknown = 3,  };  BlobIndex() : type_(Type::kUnknown) {}  BlobIndex(const BlobIndex&) = default;  BlobIndex& operator=(const BlobIndex&) = default;  bool IsInlined() const { return type_ == Type::kInlinedTTL; }  bool HasTTL() const {    return type_ == Type::kInlinedTTL || type_ == Type::kBlobTTL;  }  uint64_t expiration() const {    assert(HasTTL());    return expiration_;  }  const Slice& value() const {    assert(IsInlined());    return value_;  }  uint64_t file_number() const {    assert(!IsInlined());    return file_number_;  }  uint64_t offset() const {    assert(!IsInlined());    return offset_;  }  uint64_t size() const {    assert(!IsInlined());    return size_;  }  CompressionType compression() const {    assert(!IsInlined());    return compression_;  }  Status DecodeFrom(Slice slice) {    const char* kErrorMessage = "Error while decoding blob index";    assert(slice.size() > 0);    type_ = static_cast<Type>(*slice.data());    if (type_ >= Type::kUnknown) {      return Status::Corruption(kErrorMessage,                                "Unknown blob index type: " +                                    std::to_string(static_cast<char>(type_)));    }    slice = Slice(slice.data() + 1, slice.size() - 1);    if (HasTTL()) {      if (!GetVarint64(&slice, &expiration_)) {        return Status::Corruption(kErrorMessage, "Corrupted expiration");      }    }    if (IsInlined()) {      value_ = slice;    } else {      if (GetVarint64(&slice, &file_number_) && GetVarint64(&slice, &offset_) &&          GetVarint64(&slice, &size_) && slice.size() == 1) {        compression_ = static_cast<CompressionType>(*slice.data());      } else {        return Status::Corruption(kErrorMessage, "Corrupted blob offset");      }    }    return Status::OK();  }  std::string DebugString(bool output_hex) const {    std::ostringstream oss;    if (IsInlined()) {      oss << "[inlined blob] value:" << value_.ToString(output_hex);    } else {      oss << "[blob ref] file:" << file_number_ << " offset:" << offset_          << " size:" << size_          << " compression: " << CompressionTypeToString(compression_);    }    if (HasTTL()) {      oss << " exp:" << expiration_;    }    return oss.str();  }  static void EncodeInlinedTTL(std::string* dst, uint64_t expiration,                               const Slice& value) {    assert(dst != nullptr);    dst->clear();    dst->reserve(1 + kMaxVarint64Length + value.size());    dst->push_back(static_cast<char>(Type::kInlinedTTL));    PutVarint64(dst, expiration);    dst->append(value.data(), value.size());  }  static void EncodeBlob(std::string* dst, uint64_t file_number,                         uint64_t offset, uint64_t size,                         CompressionType compression) {    assert(dst != nullptr);    dst->clear();    dst->reserve(kMaxVarint64Length * 3 + 2);    dst->push_back(static_cast<char>(Type::kBlob));    PutVarint64(dst, file_number);    PutVarint64(dst, offset);    PutVarint64(dst, size);    dst->push_back(static_cast<char>(compression));  }  static void EncodeBlobTTL(std::string* dst, uint64_t expiration,                            uint64_t file_number, uint64_t offset,                            uint64_t size, CompressionType compression) {    assert(dst != nullptr);    dst->clear();    dst->reserve(kMaxVarint64Length * 4 + 2);    dst->push_back(static_cast<char>(Type::kBlobTTL));    PutVarint64(dst, expiration);    PutVarint64(dst, file_number);    PutVarint64(dst, offset);    PutVarint64(dst, size);    dst->push_back(static_cast<char>(compression));  } private:  Type type_ = Type::kUnknown;  uint64_t expiration_ = 0;  Slice value_;  uint64_t file_number_ = 0;  uint64_t offset_ = 0;  uint64_t size_ = 0;  CompressionType compression_ = kNoCompression;};}  // namespace ROCKSDB_NAMESPACE
 |