| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246 |
- // 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).
- //
- // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file. See the AUTHORS file for names of contributors.
- #pragma once
- #include <stdio.h>
- #include <array>
- #include <memory>
- #include <optional>
- #include <string>
- #include <utility>
- #include "rocksdb/comparator.h"
- #include "rocksdb/slice.h"
- #include "rocksdb/slice_transform.h"
- #include "rocksdb/types.h"
- #include "util/coding.h"
- #include "util/user_comparator_wrapper.h"
- namespace ROCKSDB_NAMESPACE {
- // The file declares data structures and functions that deal with internal
- // keys.
- // Each internal key contains a user key, a sequence number (SequenceNumber)
- // and a type (ValueType), and they are usually encoded together.
- // There are some related helper classes here.
- class InternalKey;
- // Value types encoded as the last component of internal keys.
- // DO NOT CHANGE THESE ENUM VALUES: they are embedded in the on-disk
- // data structures.
- // The highest bit of the value type needs to be reserved to SST tables
- // for them to do more flexible encoding.
- enum ValueType : unsigned char {
- kTypeDeletion = 0x0,
- kTypeValue = 0x1,
- kTypeMerge = 0x2,
- kTypeLogData = 0x3, // WAL only.
- kTypeColumnFamilyDeletion = 0x4, // WAL only.
- kTypeColumnFamilyValue = 0x5, // WAL only.
- kTypeColumnFamilyMerge = 0x6, // WAL only.
- kTypeSingleDeletion = 0x7,
- kTypeColumnFamilySingleDeletion = 0x8, // WAL only.
- kTypeBeginPrepareXID = 0x9, // WAL only.
- kTypeEndPrepareXID = 0xA, // WAL only.
- kTypeCommitXID = 0xB, // WAL only.
- kTypeRollbackXID = 0xC, // WAL only.
- kTypeNoop = 0xD, // WAL only.
- kTypeColumnFamilyRangeDeletion = 0xE, // WAL only.
- kTypeRangeDeletion = 0xF, // meta block
- kTypeColumnFamilyBlobIndex = 0x10, // Blob DB only
- kTypeBlobIndex = 0x11, // Blob DB only
- // When the prepared record is also persisted in db, we use a different
- // record. This is to ensure that the WAL that is generated by a WritePolicy
- // is not mistakenly read by another, which would result into data
- // inconsistency.
- kTypeBeginPersistedPrepareXID = 0x12, // WAL only.
- // Similar to kTypeBeginPersistedPrepareXID, this is to ensure that WAL
- // generated by WriteUnprepared write policy is not mistakenly read by
- // another.
- kTypeBeginUnprepareXID = 0x13, // WAL only.
- kTypeDeletionWithTimestamp = 0x14,
- kTypeCommitXIDAndTimestamp = 0x15, // WAL only
- kTypeWideColumnEntity = 0x16,
- kTypeColumnFamilyWideColumnEntity = 0x17, // WAL only
- kTypeValuePreferredSeqno = 0x18, // Value with a unix write time
- kTypeColumnFamilyValuePreferredSeqno = 0x19, // WAL only
- kTypeMaxValid, // Should be after the last valid type, only used for
- // validation
- kMaxValue = 0x7F // Not used for storing records.
- };
- // Defined in dbformat.cc
- extern const ValueType kValueTypeForSeek;
- extern const ValueType kValueTypeForSeekForPrev;
- // A range of user keys used internally by RocksDB. Also see `Range` used by
- // public APIs.
- // TODO: merge with Range in pubic API, but this is generally inclusive limit
- // and it is maybe exclusive limit
- struct UserKeyRange {
- // In case of user_defined timestamp, if enabled, `start` and `limit` should
- // include user_defined timestamps.
- Slice start;
- Slice limit;
- UserKeyRange() = default;
- UserKeyRange(const Slice& s, const Slice& l) : start(s), limit(l) {}
- };
- // A range of user keys used internally by RocksDB. Also see `RangeOpt` used by
- // public APIs.
- struct UserKeyRangeOpt {
- // In case of user_defined timestamp, if enabled, `start` and `limit` should
- // point to key with timestamp part.
- // An optional range start, if missing, indicating a start before all keys.
- OptSlice start;
- // An optional range end, if missing, indicating an end after all keys.
- OptSlice limit;
- UserKeyRangeOpt(const OptSlice& s, const OptSlice& l) : start(s), limit(l) {}
- };
- // Checks whether a type is an inline value type
- // (i.e. a type used in memtable skiplist and sst file datablock).
- inline bool IsValueType(ValueType t) {
- return t <= kTypeMerge || kTypeSingleDeletion == t || kTypeBlobIndex == t ||
- kTypeDeletionWithTimestamp == t || kTypeWideColumnEntity == t ||
- kTypeValuePreferredSeqno == t;
- }
- // Checks whether a type is from user operation
- // kTypeRangeDeletion is in meta block so this API is separated from above
- // kTypeMaxValid can be from keys generated by
- // TruncatedRangeDelIterator::start_key()
- inline bool IsExtendedValueType(ValueType t) {
- return IsValueType(t) || t == kTypeRangeDeletion || t == kTypeMaxValid;
- }
- // We leave eight bits empty at the bottom so a type and sequence#
- // can be packed together into 64-bits.
- static const SequenceNumber kMaxSequenceNumber = ((0x1ull << 56) - 1);
- static const SequenceNumber kDisableGlobalSequenceNumber =
- std::numeric_limits<uint64_t>::max();
- constexpr uint64_t kNumInternalBytes = 8;
- // Defined in dbformat.cc
- extern const std::string kDisableUserTimestamp;
- // The data structure that represents an internal key in the way that user_key,
- // sequence number and type are stored in separated forms.
- struct ParsedInternalKey {
- Slice user_key;
- SequenceNumber sequence;
- ValueType type;
- ParsedInternalKey()
- : sequence(kMaxSequenceNumber),
- type(kTypeDeletion) // Make code analyzer happy
- {} // Intentionally left uninitialized (for speed)
- // u contains timestamp if user timestamp feature is enabled.
- ParsedInternalKey(const Slice& u, const SequenceNumber& seq, ValueType t)
- : user_key(u), sequence(seq), type(t) {}
- std::string DebugString(bool log_err_key, bool hex,
- const Comparator* ucmp = nullptr) const;
- void clear() {
- user_key.clear();
- sequence = 0;
- type = kTypeDeletion;
- }
- void SetTimestamp(const Slice& ts) {
- assert(ts.size() <= user_key.size());
- const char* addr = user_key.data() + user_key.size() - ts.size();
- memcpy(const_cast<char*>(addr), ts.data(), ts.size());
- }
- Slice GetTimestamp(size_t ts_sz) {
- assert(ts_sz <= user_key.size());
- const char* addr = user_key.data() + user_key.size() - ts_sz;
- return Slice(const_cast<char*>(addr), ts_sz);
- }
- };
- // Return the length of the encoding of "key".
- inline size_t InternalKeyEncodingLength(const ParsedInternalKey& key) {
- return key.user_key.size() + kNumInternalBytes;
- }
- // Pack a sequence number and a ValueType into a uint64_t
- inline uint64_t PackSequenceAndType(uint64_t seq, ValueType t) {
- assert(seq <= kMaxSequenceNumber);
- // kTypeMaxValid is used in TruncatedRangeDelIterator, see its constructor.
- assert(IsExtendedValueType(t) || t == kTypeMaxValid);
- return (seq << 8) | t;
- }
- // Given the result of PackSequenceAndType, store the sequence number in *seq
- // and the ValueType in *t.
- inline void UnPackSequenceAndType(uint64_t packed, uint64_t* seq,
- ValueType* t) {
- *seq = packed >> 8;
- *t = static_cast<ValueType>(packed & 0xff);
- // Commented the following two assertions in order to test key-value checksum
- // on corrupted keys without crashing ("DbKvChecksumTest").
- // assert(*seq <= kMaxSequenceNumber);
- // assert(IsExtendedValueType(*t));
- }
- const uint64_t kRangeTombstoneSentinel =
- PackSequenceAndType(kMaxSequenceNumber, kTypeRangeDeletion);
- EntryType GetEntryType(ValueType value_type);
- // Append the serialization of "key" to *result.
- //
- // input [internal key]: <user_key | seqno + type>
- // output before: empty
- // output: <user_key | seqno + type>
- void AppendInternalKey(std::string* result, const ParsedInternalKey& key);
- // Append the serialization of "key" to *result, replacing the original
- // timestamp with argument ts.
- //
- // input [internal key]: <user_provided_key | original_ts | seqno + type>
- // output before: empty
- // output after: <user_provided_key | ts | seqno + type>
- void AppendInternalKeyWithDifferentTimestamp(std::string* result,
- const ParsedInternalKey& key,
- const Slice& ts);
- // Append the user key to *result, replacing the original timestamp with
- // argument ts.
- //
- // input [user key]: <user_provided_key | original_ts>
- // output before: empty
- // output after: <user_provided_key | ts>
- void AppendUserKeyWithDifferentTimestamp(std::string* result, const Slice& key,
- const Slice& ts);
- // Serialized internal key consists of user key followed by footer.
- // This function appends the footer to *result, assuming that *result already
- // contains the user key at the end.
- //
- // output before: <user_key>
- // output after: <user_key | seqno + type>
- void AppendInternalKeyFooter(std::string* result, SequenceNumber s,
- ValueType t);
- // Append the key and a minimal timestamp to *result
- //
- // input [user key without ts]: <user_provided_key>
- // output before: empty
- // output after: <user_provided_key | min_ts>
- void AppendKeyWithMinTimestamp(std::string* result, const Slice& key,
- size_t ts_sz);
- // Append the key and a maximal timestamp to *result
- //
- // input [user key without ts]: <user_provided_key>
- // output before: empty
- // output after: <user_provided_key | max_ts>
- void AppendKeyWithMaxTimestamp(std::string* result, const Slice& key,
- size_t ts_sz);
- // `key` is a user key with timestamp. Append the user key without timestamp
- // and the minimum timestamp to *result.
- //
- // input [user key]: <user_provided_key | original_ts>
- // output before: empty
- // output after: <user_provided_key | min_ts>
- void AppendUserKeyWithMinTimestamp(std::string* result, const Slice& key,
- size_t ts_sz);
- // `key` is a user key with timestamp. Append the user key without timestamp
- // and the maximal timestamp to *result.
- //
- // input [user key]: <user_provided_key | original_ts>
- // output before: empty
- // output after: <user_provided_key | max_ts>
- void AppendUserKeyWithMaxTimestamp(std::string* result, const Slice& key,
- size_t ts_sz);
- // `key` is an internal key containing a user key without timestamp. Create a
- // new key in *result by padding a min timestamp of size `ts_sz` to the user key
- // and copying the remaining internal key bytes.
- //
- // input [internal key]: <user_provided_key | seqno + type>
- // output before: empty
- // output after: <user_provided_key | min_ts | seqno + type>
- void PadInternalKeyWithMinTimestamp(std::string* result, const Slice& key,
- size_t ts_sz);
- // `key` is an internal key containing a user key without timestamp. Create a
- // new key in *result by padding a max timestamp of size `ts_sz` to the user key
- // and copying the remaining internal key bytes.
- //
- // input [internal key]: <user_provided_key | seqno + type>
- // output before: empty
- // output after: <user_provided_key | max_ts | seqno + type>
- void PadInternalKeyWithMaxTimestamp(std::string* result, const Slice& key,
- size_t ts_sz);
- // `key` is an internal key containing a user key with timestamp of size
- // `ts_sz`. Create a new internal key in *result by stripping the timestamp from
- // the user key and copying the remaining internal key bytes.
- //
- // input [internal key]: <user_provided_key | original_ts | seqno + type>
- // output before: empty
- // output after: <user_provided_key | seqno + type>
- void StripTimestampFromInternalKey(std::string* result, const Slice& key,
- size_t ts_sz);
- // `key` is an internal key containing a user key with timestamp of size
- // `ts_sz`. Create a new internal key in *result while replace the original
- // timestamp with min timestamp.
- //
- // input [internal key]: <user_provided_key | original_ts | seqno + type>
- // output before: empty
- // output after: <user_provided_key | min_ts | seqno + type>
- void ReplaceInternalKeyWithMinTimestamp(std::string* result, const Slice& key,
- size_t ts_sz);
- // Attempt to parse an internal key from "internal_key". On success,
- // stores the parsed data in "*result", and returns true.
- //
- // On error, returns false, leaves "*result" in an undefined state.
- Status ParseInternalKey(const Slice& internal_key, ParsedInternalKey* result,
- bool log_err_key);
- // Returns the user key portion of an internal key.
- //
- // input [internal key]: <user_key | seqno + type>
- // output: <user_key>
- inline Slice ExtractUserKey(const Slice& internal_key) {
- assert(internal_key.size() >= kNumInternalBytes);
- return Slice(internal_key.data(), internal_key.size() - kNumInternalBytes);
- }
- // input [internal key]: <user_provided_key | ts | seqno + type>
- // output : <user_provided_key>
- inline Slice ExtractUserKeyAndStripTimestamp(const Slice& internal_key,
- size_t ts_sz) {
- assert(internal_key.size() >= kNumInternalBytes + ts_sz);
- return Slice(internal_key.data(),
- internal_key.size() - (kNumInternalBytes + ts_sz));
- }
- // input [user key]: <user_provided_key | ts>
- // output: <user_provided_key>
- inline Slice StripTimestampFromUserKey(const Slice& user_key, size_t ts_sz) {
- assert(user_key.size() >= ts_sz);
- return Slice(user_key.data(), user_key.size() - ts_sz);
- }
- // input [user key]: <user_provided_key | ts>
- // output: <ts>
- inline Slice ExtractTimestampFromUserKey(const Slice& user_key, size_t ts_sz) {
- assert(user_key.size() >= ts_sz);
- return Slice(user_key.data() + user_key.size() - ts_sz, ts_sz);
- }
- // input [internal key]: <user_provided_key | ts | seqno + type>
- // output: <ts>
- inline Slice ExtractTimestampFromKey(const Slice& internal_key, size_t ts_sz) {
- const size_t key_size = internal_key.size();
- assert(key_size >= kNumInternalBytes + ts_sz);
- return Slice(internal_key.data() + key_size - ts_sz - kNumInternalBytes,
- ts_sz);
- }
- // input [internal key]: <user_provided_key | ts | seqno + type>
- // output: <seqno + type>
- inline uint64_t ExtractInternalKeyFooter(const Slice& internal_key) {
- assert(internal_key.size() >= kNumInternalBytes);
- const size_t n = internal_key.size();
- return DecodeFixed64(internal_key.data() + n - kNumInternalBytes);
- }
- // input [internal key]: <user_provided_key | ts | seqno + type>
- // output: <type>
- inline ValueType ExtractValueType(const Slice& internal_key) {
- uint64_t num = ExtractInternalKeyFooter(internal_key);
- unsigned char c = num & 0xff;
- return static_cast<ValueType>(c);
- }
- // A comparator for internal keys that uses a specified comparator for
- // the user key portion and breaks ties by decreasing sequence number.
- class InternalKeyComparator
- #ifdef NDEBUG
- final
- #endif
- : public CompareInterface {
- private:
- UserComparatorWrapper user_comparator_;
- public:
- // `InternalKeyComparator`s constructed with the default constructor are not
- // usable and will segfault on any attempt to use them for comparisons.
- InternalKeyComparator() = default;
- // @param named If true, assign a name to this comparator based on the
- // underlying comparator's name. This involves an allocation and copy in
- // this constructor to precompute the result of `Name()`. To avoid this
- // overhead, set `named` to false. In that case, `Name()` will return a
- // generic name that is non-specific to the underlying comparator.
- explicit InternalKeyComparator(const Comparator* c) : user_comparator_(c) {}
- virtual ~InternalKeyComparator() {}
- int Compare(const Slice& a, const Slice& b) const override;
- bool Equal(const Slice& a, const Slice& b) const {
- // TODO Use user_comparator_.Equal(). Perhaps compare seqno before
- // comparing the user key too.
- return Compare(a, b) == 0;
- }
- // Same as Compare except that it excludes the value type from comparison
- int CompareKeySeq(const Slice& a, const Slice& b) const;
- int CompareKeySeq(const ParsedInternalKey& a, const Slice& b) const;
- const Comparator* user_comparator() const {
- return user_comparator_.user_comparator();
- }
- int Compare(const InternalKey& a, const InternalKey& b) const;
- int Compare(const ParsedInternalKey& a, const ParsedInternalKey& b) const;
- int Compare(const Slice& a, const ParsedInternalKey& b) const;
- int Compare(const ParsedInternalKey& a, const Slice& b) const;
- // In this `Compare()` overload, the sequence numbers provided in
- // `a_global_seqno` and `b_global_seqno` override the sequence numbers in `a`
- // and `b`, respectively. To disable sequence number override(s), provide the
- // value `kDisableGlobalSequenceNumber`.
- int Compare(const Slice& a, SequenceNumber a_global_seqno, const Slice& b,
- SequenceNumber b_global_seqno) const;
- };
- // The class represent the internal key in encoded form.
- class InternalKey {
- private:
- std::string rep_;
- public:
- InternalKey() {} // Leave rep_ as empty to indicate it is invalid
- InternalKey(const Slice& _user_key, SequenceNumber s, ValueType t) {
- AppendInternalKey(&rep_, ParsedInternalKey(_user_key, s, t));
- }
- InternalKey(const Slice& _user_key, SequenceNumber s, ValueType t, Slice ts) {
- AppendInternalKeyWithDifferentTimestamp(
- &rep_, ParsedInternalKey(_user_key, s, t), ts);
- }
- // sets the internal key to be bigger or equal to all internal keys with this
- // user key
- void SetMaxPossibleForUserKey(const Slice& _user_key) {
- AppendInternalKey(
- &rep_, ParsedInternalKey(_user_key, 0, static_cast<ValueType>(0)));
- }
- // sets the internal key to be smaller or equal to all internal keys with this
- // user key
- void SetMinPossibleForUserKey(const Slice& _user_key) {
- AppendInternalKey(&rep_, ParsedInternalKey(_user_key, kMaxSequenceNumber,
- kValueTypeForSeek));
- }
- bool Valid() const {
- ParsedInternalKey parsed;
- return (ParseInternalKey(Slice(rep_), &parsed, false /* log_err_key */)
- .ok()); // TODO
- }
- void DecodeFrom(const Slice& s) { rep_.assign(s.data(), s.size()); }
- Slice Encode() const {
- assert(!rep_.empty());
- return rep_;
- }
- Slice user_key() const { return ExtractUserKey(rep_); }
- size_t size() const { return rep_.size(); }
- bool unset() const { return rep_.empty(); }
- void Set(const Slice& _user_key, SequenceNumber s, ValueType t) {
- SetFrom(ParsedInternalKey(_user_key, s, t));
- }
- void Set(const Slice& _user_key_with_ts, SequenceNumber s, ValueType t,
- const Slice& ts) {
- ParsedInternalKey pik(_user_key_with_ts, s, t);
- // Should not call pik.SetTimestamp() directly as it overwrites the buffer
- // containing _user_key.
- SetFrom(pik, ts);
- }
- void SetFrom(const ParsedInternalKey& p) {
- rep_.clear();
- AppendInternalKey(&rep_, p);
- }
- void SetFrom(const ParsedInternalKey& p, const Slice& ts) {
- rep_.clear();
- AppendInternalKeyWithDifferentTimestamp(&rep_, p, ts);
- }
- void Clear() { rep_.clear(); }
- // The underlying representation.
- // Intended only to be used together with ConvertFromUserKey().
- std::string* rep() { return &rep_; }
- const std::string* const_rep() const { return &rep_; }
- // Assuming that *rep() contains a user key, this method makes internal key
- // out of it in-place. This saves a memcpy compared to Set()/SetFrom().
- void ConvertFromUserKey(SequenceNumber s, ValueType t) {
- AppendInternalKeyFooter(&rep_, s, t);
- }
- std::string DebugString(bool hex, const Comparator* ucmp = nullptr) const;
- };
- inline int InternalKeyComparator::Compare(const InternalKey& a,
- const InternalKey& b) const {
- return Compare(a.Encode(), b.Encode());
- }
- inline Status ParseInternalKey(const Slice& internal_key,
- ParsedInternalKey* result, bool log_err_key) {
- const size_t n = internal_key.size();
- if (n < kNumInternalBytes) {
- return Status::Corruption("Corrupted Key: Internal Key too small. Size=" +
- std::to_string(n) + ". ");
- }
- uint64_t num = DecodeFixed64(internal_key.data() + n - kNumInternalBytes);
- unsigned char c = num & 0xff;
- result->sequence = num >> 8;
- result->type = static_cast<ValueType>(c);
- assert(result->type <= ValueType::kMaxValue);
- result->user_key = Slice(internal_key.data(), n - kNumInternalBytes);
- if (IsExtendedValueType(result->type)) {
- return Status::OK();
- } else {
- return Status::Corruption("Corrupted Key",
- result->DebugString(log_err_key, true));
- }
- }
- // Update the sequence number in the internal key.
- // Guarantees not to invalidate ikey.data().
- inline void UpdateInternalKey(std::string* ikey, uint64_t seq, ValueType t) {
- size_t ikey_sz = ikey->size();
- assert(ikey_sz >= kNumInternalBytes);
- uint64_t newval = (seq << 8) | t;
- // Note: Since C++11, strings are guaranteed to be stored contiguously and
- // string::operator[]() is guaranteed not to change ikey.data().
- EncodeFixed64(&(*ikey)[ikey_sz - kNumInternalBytes], newval);
- }
- // Get the sequence number from the internal key
- inline uint64_t GetInternalKeySeqno(const Slice& internal_key) {
- const size_t n = internal_key.size();
- assert(n >= kNumInternalBytes);
- uint64_t num = DecodeFixed64(internal_key.data() + n - kNumInternalBytes);
- return num >> 8;
- }
- // The class to store keys in an efficient way. It allows:
- // 1. Users can either copy the key into it, or have it point to an unowned
- // address.
- // 2. For copied key, a short inline buffer is kept to reduce memory
- // allocation for smaller keys.
- // 3. It tracks user key or internal key, and allow conversion between them.
- class IterKey {
- static constexpr size_t kInlineBufferSize = 39;
- // This is only used by user-defined timestamps in MemTable only feature,
- // which only supports uint64_t timestamps.
- static constexpr char kTsMin[] = "\x00\x00\x00\x00\x00\x00\x00\x00";
- public:
- IterKey()
- : buf_(space_),
- key_(buf_),
- key_size_(0),
- buf_size_(kInlineBufferSize),
- is_user_key_(true),
- secondary_buf_(space_for_secondary_buf_),
- secondary_buf_size_(kInlineBufferSize) {}
- // No copying allowed
- IterKey(const IterKey&) = delete;
- void operator=(const IterKey&) = delete;
- ~IterKey() {
- ResetBuffer();
- ResetSecondaryBuffer();
- }
- // The bool will be picked up by the next calls to SetKey
- void SetIsUserKey(bool is_user_key) { is_user_key_ = is_user_key; }
- // Returns the key in whichever format that was provided to KeyIter
- // If user-defined timestamp is enabled, then timestamp is included in the
- // return result.
- Slice GetKey() const { return Slice(key_, key_size_); }
- Slice GetInternalKey() const {
- assert(!IsUserKey());
- return Slice(key_, key_size_);
- }
- // If user-defined timestamp is enabled, then timestamp is included in the
- // return result of GetUserKey();
- Slice GetUserKey() const {
- if (IsUserKey()) {
- return Slice(key_, key_size_);
- } else {
- assert(key_size_ >= kNumInternalBytes);
- return Slice(key_, key_size_ - kNumInternalBytes);
- }
- }
- size_t Size() const { return key_size_; }
- void Clear() { key_size_ = 0; }
- // Append "non_shared_data" to its back, from "shared_len"
- // This function is used in Block::Iter::ParseNextKey
- // shared_len: bytes in [0, shard_len-1] would be remained
- // non_shared_data: data to be append, its length must be >= non_shared_len
- void TrimAppend(const size_t shared_len, const char* non_shared_data,
- const size_t non_shared_len) {
- assert(shared_len <= key_size_);
- size_t total_size = shared_len + non_shared_len;
- if (IsKeyPinned() /* key is not in buf_ */) {
- // Copy the key from external memory to buf_ (copy shared_len bytes)
- EnlargeBufferIfNeeded(total_size);
- memcpy(buf_, key_, shared_len);
- } else if (total_size > buf_size_) {
- // Need to allocate space, delete previous space
- char* p = new char[total_size];
- memcpy(p, key_, shared_len);
- if (buf_ != space_) {
- delete[] buf_;
- }
- buf_ = p;
- buf_size_ = total_size;
- }
- memcpy(buf_ + shared_len, non_shared_data, non_shared_len);
- key_ = buf_;
- key_size_ = total_size;
- }
- // A version of `TrimAppend` assuming the last bytes of length `ts_sz` in the
- // user key part of `key_` is not counted towards shared bytes. And the
- // decoded key needed a min timestamp of length `ts_sz` pad to the user key.
- void TrimAppendWithTimestamp(const size_t shared_len,
- const char* non_shared_data,
- const size_t non_shared_len,
- const size_t ts_sz) {
- // This function is only used by the UDT in memtable feature, which only
- // support built in comparators with uint64 timestamps.
- assert(ts_sz == sizeof(uint64_t));
- size_t next_key_slice_index = 0;
- if (IsUserKey()) {
- key_slices_[next_key_slice_index++] = Slice(key_, shared_len);
- key_slices_[next_key_slice_index++] =
- Slice(non_shared_data, non_shared_len);
- key_slices_[next_key_slice_index++] = Slice(kTsMin, ts_sz);
- } else {
- assert(shared_len + non_shared_len >= kNumInternalBytes);
- // Invaraint: shared_user_key_len + shared_internal_bytes_len = shared_len
- // In naming below `*_len` variables, keyword `user_key` refers to the
- // user key part of the existing key in `key_` as apposed to the new key.
- // Similary, `internal_bytes` refers to the footer part of the existing
- // key. These bytes potentially will move between user key part and the
- // footer part in the new key.
- const size_t user_key_len = key_size_ - kNumInternalBytes;
- const size_t sharable_user_key_len = user_key_len - ts_sz;
- const size_t shared_user_key_len =
- std::min(shared_len, sharable_user_key_len);
- const size_t shared_internal_bytes_len = shared_len - shared_user_key_len;
- // One Slice among the three Slices will get split into two Slices, plus
- // a timestamp slice.
- bool ts_added = false;
- // Add slice parts and find the right location to add the min timestamp.
- MaybeAddKeyPartsWithTimestamp(
- key_, shared_user_key_len,
- shared_internal_bytes_len + non_shared_len < kNumInternalBytes,
- shared_len + non_shared_len - kNumInternalBytes, ts_sz,
- &next_key_slice_index, &ts_added);
- MaybeAddKeyPartsWithTimestamp(
- key_ + user_key_len, shared_internal_bytes_len,
- non_shared_len < kNumInternalBytes,
- shared_internal_bytes_len + non_shared_len - kNumInternalBytes, ts_sz,
- &next_key_slice_index, &ts_added);
- MaybeAddKeyPartsWithTimestamp(non_shared_data, non_shared_len,
- non_shared_len >= kNumInternalBytes,
- non_shared_len - kNumInternalBytes, ts_sz,
- &next_key_slice_index, &ts_added);
- assert(ts_added);
- }
- SetKeyImpl(next_key_slice_index,
- /* total_bytes= */ shared_len + non_shared_len + ts_sz);
- }
- Slice SetKeyWithPaddedMinTimestamp(const Slice& key, size_t ts_sz) {
- // This function is only used by the UDT in memtable feature, which only
- // support built in comparators with uint64 timestamps.
- assert(ts_sz == sizeof(uint64_t));
- size_t num_key_slices = 0;
- if (is_user_key_) {
- key_slices_[0] = key;
- key_slices_[1] = Slice(kTsMin, ts_sz);
- num_key_slices = 2;
- } else {
- assert(key.size() >= kNumInternalBytes);
- size_t user_key_size = key.size() - kNumInternalBytes;
- key_slices_[0] = Slice(key.data(), user_key_size);
- key_slices_[1] = Slice(kTsMin, ts_sz);
- key_slices_[2] = Slice(key.data() + user_key_size, kNumInternalBytes);
- num_key_slices = 3;
- }
- return SetKeyImpl(num_key_slices, key.size() + ts_sz);
- }
- Slice SetKey(const Slice& key, bool copy = true) {
- // is_user_key_ expected to be set already via SetIsUserKey
- return SetKeyImpl(key, copy);
- }
- // If user-defined timestamp is enabled, then `key` includes timestamp.
- // TODO(yanqin) this is also used to set prefix, which do not include
- // timestamp. Should be handled.
- Slice SetUserKey(const Slice& key, bool copy = true) {
- is_user_key_ = true;
- return SetKeyImpl(key, copy);
- }
- Slice SetInternalKey(const Slice& key, bool copy = true) {
- is_user_key_ = false;
- return SetKeyImpl(key, copy);
- }
- // Copies the content of key, updates the reference to the user key in ikey
- // and returns a Slice referencing the new copy.
- Slice SetInternalKey(const Slice& key, ParsedInternalKey* ikey) {
- size_t key_n = key.size();
- assert(key_n >= kNumInternalBytes);
- SetInternalKey(key);
- ikey->user_key = Slice(key_, key_n - kNumInternalBytes);
- return Slice(key_, key_n);
- }
- // Update the sequence number in the internal key. Guarantees not to
- // invalidate slices to the key (and the user key).
- void UpdateInternalKey(uint64_t seq, ValueType t, const Slice* ts = nullptr) {
- assert(!IsKeyPinned());
- assert(key_size_ >= kNumInternalBytes);
- if (ts) {
- assert(key_size_ >= kNumInternalBytes + ts->size());
- memcpy(&buf_[key_size_ - kNumInternalBytes - ts->size()], ts->data(),
- ts->size());
- }
- uint64_t newval = (seq << 8) | t;
- if (key_ == buf_) {
- EncodeFixed64(&buf_[key_size_ - kNumInternalBytes], newval);
- } else {
- assert(key_ == secondary_buf_);
- EncodeFixed64(&secondary_buf_[key_size_ - kNumInternalBytes], newval);
- }
- }
- bool IsKeyPinned() const { return key_ != buf_ && key_ != secondary_buf_; }
- // If `ts` is provided, user_key should not contain timestamp,
- // and `ts` is appended after user_key.
- // TODO: more efficient storage for timestamp.
- void SetInternalKey(const Slice& key_prefix, const Slice& user_key,
- SequenceNumber s,
- ValueType value_type = kValueTypeForSeek,
- const Slice* ts = nullptr) {
- size_t psize = key_prefix.size();
- size_t usize = user_key.size();
- size_t ts_sz = (ts != nullptr ? ts->size() : 0);
- EnlargeBufferIfNeeded(psize + usize + sizeof(uint64_t) + ts_sz);
- if (psize > 0) {
- memcpy(buf_, key_prefix.data(), psize);
- }
- memcpy(buf_ + psize, user_key.data(), usize);
- if (ts) {
- memcpy(buf_ + psize + usize, ts->data(), ts_sz);
- }
- EncodeFixed64(buf_ + usize + psize + ts_sz,
- PackSequenceAndType(s, value_type));
- key_ = buf_;
- key_size_ = psize + usize + sizeof(uint64_t) + ts_sz;
- is_user_key_ = false;
- }
- void SetInternalKey(const Slice& user_key, SequenceNumber s,
- ValueType value_type = kValueTypeForSeek,
- const Slice* ts = nullptr) {
- SetInternalKey(Slice(), user_key, s, value_type, ts);
- }
- void Reserve(size_t size) {
- EnlargeBufferIfNeeded(size);
- key_size_ = size;
- }
- void SetInternalKey(const ParsedInternalKey& parsed_key) {
- SetInternalKey(Slice(), parsed_key);
- }
- void SetInternalKey(const Slice& key_prefix,
- const ParsedInternalKey& parsed_key_suffix) {
- SetInternalKey(key_prefix, parsed_key_suffix.user_key,
- parsed_key_suffix.sequence, parsed_key_suffix.type);
- }
- void EncodeLengthPrefixedKey(const Slice& key) {
- auto size = key.size();
- EnlargeBufferIfNeeded(size + static_cast<size_t>(VarintLength(size)));
- char* ptr = EncodeVarint32(buf_, static_cast<uint32_t>(size));
- memcpy(ptr, key.data(), size);
- key_ = buf_;
- is_user_key_ = true;
- }
- bool IsUserKey() const { return is_user_key_; }
- private:
- char* buf_;
- const char* key_;
- size_t key_size_;
- size_t buf_size_;
- char space_[kInlineBufferSize]; // Avoid allocation for short keys
- bool is_user_key_;
- // Below variables are only used by user-defined timestamps in MemTable only
- // feature for iterating keys in an index block or a data block.
- //
- // We will alternate between buf_ and secondary_buf_ to hold the key. key_
- // will be modified in accordance to point to the right one. This is to avoid
- // an extra copy when we need to copy some shared bytes from previous key
- // (delta encoding), and we need to pad a min timestamp at the right location.
- char space_for_secondary_buf_[kInlineBufferSize]; // Avoid allocation for
- // short keys
- char* secondary_buf_;
- size_t secondary_buf_size_;
- // Use to track the pieces that together make the whole key. We then copy
- // these pieces in order either into buf_ or secondary_buf_ depending on where
- // the previous key is held.
- std::array<Slice, 5> key_slices_;
- // End of variables used by user-defined timestamps in MemTable only feature.
- Slice SetKeyImpl(const Slice& key, bool copy) {
- size_t size = key.size();
- if (copy) {
- // Copy key to buf_
- EnlargeBufferIfNeeded(size);
- memcpy(buf_, key.data(), size);
- key_ = buf_;
- } else {
- // Update key_ to point to external memory
- key_ = key.data();
- }
- key_size_ = size;
- return Slice(key_, key_size_);
- }
- Slice SetKeyImpl(size_t num_key_slices, size_t total_bytes) {
- assert(num_key_slices <= 5);
- char* buf_start = nullptr;
- if (key_ == buf_) {
- // If the previous key is in buf_, we copy key_slices_ in order into
- // secondary_buf_.
- EnlargeSecondaryBufferIfNeeded(total_bytes);
- buf_start = secondary_buf_;
- key_ = secondary_buf_;
- } else {
- // Copy key_slices_ in order into buf_.
- EnlargeBufferIfNeeded(total_bytes);
- buf_start = buf_;
- key_ = buf_;
- }
- #ifndef NDEBUG
- size_t actual_total_bytes = 0;
- #endif // NDEBUG
- for (size_t i = 0; i < num_key_slices; i++) {
- size_t key_slice_size = key_slices_[i].size();
- memcpy(buf_start, key_slices_[i].data(), key_slice_size);
- buf_start += key_slice_size;
- #ifndef NDEBUG
- actual_total_bytes += key_slice_size;
- #endif // NDEBUG
- }
- #ifndef NDEBUG
- assert(actual_total_bytes == total_bytes);
- #endif // NDEBUG
- key_size_ = total_bytes;
- return Slice(key_, key_size_);
- }
- void ResetBuffer() {
- if (key_ == buf_) {
- key_size_ = 0;
- }
- if (buf_ != space_) {
- delete[] buf_;
- buf_ = space_;
- }
- buf_size_ = kInlineBufferSize;
- }
- void ResetSecondaryBuffer() {
- if (key_ == secondary_buf_) {
- key_size_ = 0;
- }
- if (secondary_buf_ != space_for_secondary_buf_) {
- delete[] secondary_buf_;
- secondary_buf_ = space_for_secondary_buf_;
- }
- secondary_buf_size_ = kInlineBufferSize;
- }
- // Enlarge the buffer size if needed based on key_size.
- // By default, inline buffer is used. Once there is a key
- // larger than the inline buffer, another buffer is dynamically
- // allocated, until a larger key buffer is requested. In that case, we
- // reallocate buffer and delete the old one.
- void EnlargeBufferIfNeeded(size_t key_size) {
- // If size is smaller than buffer size, continue using current buffer,
- // or the static allocated one, as default
- if (key_size > buf_size_) {
- EnlargeBuffer(key_size);
- }
- }
- void EnlargeSecondaryBufferIfNeeded(size_t key_size);
- void EnlargeBuffer(size_t key_size);
- void MaybeAddKeyPartsWithTimestamp(const char* slice_data,
- const size_t slice_sz, bool add_timestamp,
- const size_t left_sz, const size_t ts_sz,
- size_t* next_key_slice_idx,
- bool* ts_added) {
- assert(next_key_slice_idx);
- if (add_timestamp && !*ts_added) {
- assert(slice_sz >= left_sz);
- key_slices_[(*next_key_slice_idx)++] = Slice(slice_data, left_sz);
- key_slices_[(*next_key_slice_idx)++] = Slice(kTsMin, ts_sz);
- key_slices_[(*next_key_slice_idx)++] =
- Slice(slice_data + left_sz, slice_sz - left_sz);
- *ts_added = true;
- } else {
- key_slices_[(*next_key_slice_idx)++] = Slice(slice_data, slice_sz);
- }
- assert(*next_key_slice_idx <= 5);
- }
- };
- // Convert from a SliceTransform of user keys, to a SliceTransform of
- // internal keys.
- class InternalKeySliceTransform : public SliceTransform {
- public:
- explicit InternalKeySliceTransform(const SliceTransform* transform)
- : transform_(transform) {}
- const char* Name() const override { return transform_->Name(); }
- Slice Transform(const Slice& src) const override {
- auto user_key = ExtractUserKey(src);
- return transform_->Transform(user_key);
- }
- bool InDomain(const Slice& src) const override {
- auto user_key = ExtractUserKey(src);
- return transform_->InDomain(user_key);
- }
- bool InRange(const Slice& dst) const override {
- auto user_key = ExtractUserKey(dst);
- return transform_->InRange(user_key);
- }
- const SliceTransform* user_prefix_extractor() const { return transform_; }
- private:
- // Like comparator, InternalKeySliceTransform will not take care of the
- // deletion of transform_
- const SliceTransform* const transform_;
- };
- // Read the key of a record from a write batch.
- // if this record represent the default column family then cf_record
- // must be passed as false, otherwise it must be passed as true.
- bool ReadKeyFromWriteBatchEntry(Slice* input, Slice* key, bool cf_record);
- // Read record from a write batch piece from input.
- // tag, column_family, key, value and blob are return values. Callers own the
- // slice they point to.
- // Tag is defined as ValueType.
- // input will be advanced to after the record.
- // If user-defined timestamp is enabled for a column family, then the `key`
- // resulting from this call will include timestamp.
- Status ReadRecordFromWriteBatch(Slice* input, char* tag,
- uint32_t* column_family, Slice* key,
- Slice* value, Slice* blob, Slice* xid,
- uint64_t* write_unix_time);
- // When user call DeleteRange() to delete a range of keys,
- // we will store a serialized RangeTombstone in MemTable and SST.
- // the struct here is an easy-understood form
- // start/end_key_ is the start/end user key of the range to be deleted
- struct RangeTombstone {
- Slice start_key_;
- Slice end_key_;
- SequenceNumber seq_;
- // TODO: we should optimize the storage here when user-defined timestamp
- // is NOT enabled: they currently take up (16 + 32 + 32) bytes per tombstone.
- Slice ts_;
- std::string pinned_start_key_;
- std::string pinned_end_key_;
- RangeTombstone() = default;
- RangeTombstone(Slice sk, Slice ek, SequenceNumber sn)
- : start_key_(sk), end_key_(ek), seq_(sn) {}
- // User-defined timestamp is enabled, `sk` and `ek` should be user key
- // with timestamp, `ts` will replace the timestamps in `sk` and
- // `ek`.
- RangeTombstone(Slice sk, Slice ek, SequenceNumber sn, Slice ts) : seq_(sn) {
- const size_t ts_sz = ts.size();
- assert(ts_sz > 0);
- pinned_start_key_.reserve(sk.size());
- pinned_end_key_.reserve(ek.size());
- AppendUserKeyWithDifferentTimestamp(&pinned_start_key_, sk, ts);
- AppendUserKeyWithDifferentTimestamp(&pinned_end_key_, ek, ts);
- start_key_ = pinned_start_key_;
- end_key_ = pinned_end_key_;
- ts_ = Slice(pinned_start_key_.data() + sk.size() - ts_sz, ts_sz);
- }
- RangeTombstone(ParsedInternalKey parsed_key, Slice value) {
- start_key_ = parsed_key.user_key;
- seq_ = parsed_key.sequence;
- end_key_ = value;
- }
- // be careful to use Serialize(), allocates new memory
- std::pair<InternalKey, Slice> Serialize() const {
- auto key = InternalKey(start_key_, seq_, kTypeRangeDeletion);
- return std::make_pair(std::move(key), end_key_);
- }
- // be careful to use SerializeKey(), allocates new memory
- InternalKey SerializeKey() const {
- return InternalKey(start_key_, seq_, kTypeRangeDeletion);
- }
- // The tombstone end-key is exclusive, so we generate an internal-key here
- // which has a similar property. Using kMaxSequenceNumber guarantees that
- // the returned internal-key will compare less than any other internal-key
- // with the same user-key. This in turn guarantees that the serialized
- // end-key for a tombstone such as [a-b] will compare less than the key "b".
- //
- // be careful to use SerializeEndKey(), allocates new memory
- InternalKey SerializeEndKey() const {
- if (!ts_.empty()) {
- static constexpr char kTsMax[] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff";
- if (ts_.size() <= strlen(kTsMax)) {
- return InternalKey(end_key_, kMaxSequenceNumber, kTypeRangeDeletion,
- Slice(kTsMax, ts_.size()));
- } else {
- return InternalKey(end_key_, kMaxSequenceNumber, kTypeRangeDeletion,
- std::string(ts_.size(), '\xff'));
- }
- }
- return InternalKey(end_key_, kMaxSequenceNumber, kTypeRangeDeletion);
- }
- };
- inline int InternalKeyComparator::Compare(const Slice& akey,
- const Slice& bkey) const {
- // Order by:
- // increasing user key (according to user-supplied comparator)
- // decreasing sequence number
- // decreasing type (though sequence# should be enough to disambiguate)
- int r = user_comparator_.Compare(ExtractUserKey(akey), ExtractUserKey(bkey));
- if (r == 0) {
- const uint64_t anum =
- DecodeFixed64(akey.data() + akey.size() - kNumInternalBytes);
- const uint64_t bnum =
- DecodeFixed64(bkey.data() + bkey.size() - kNumInternalBytes);
- if (anum > bnum) {
- r = -1;
- } else if (anum < bnum) {
- r = +1;
- }
- }
- return r;
- }
- inline int InternalKeyComparator::CompareKeySeq(const Slice& akey,
- const Slice& bkey) const {
- // Order by:
- // increasing user key (according to user-supplied comparator)
- // decreasing sequence number
- int r = user_comparator_.Compare(ExtractUserKey(akey), ExtractUserKey(bkey));
- if (r == 0) {
- // Shift the number to exclude the last byte which contains the value type
- const uint64_t anum =
- DecodeFixed64(akey.data() + akey.size() - kNumInternalBytes) >> 8;
- const uint64_t bnum =
- DecodeFixed64(bkey.data() + bkey.size() - kNumInternalBytes) >> 8;
- if (anum > bnum) {
- r = -1;
- } else if (anum < bnum) {
- r = +1;
- }
- }
- return r;
- }
- inline int InternalKeyComparator::CompareKeySeq(const ParsedInternalKey& a,
- const Slice& b) const {
- // Order by:
- // increasing user key (according to user-supplied comparator)
- // decreasing sequence number
- int r = user_comparator_.Compare(a.user_key, ExtractUserKey(b));
- if (r == 0) {
- // Shift the number to exclude the last byte which contains the value type
- const uint64_t anum = a.sequence;
- const uint64_t bnum =
- DecodeFixed64(b.data() + b.size() - kNumInternalBytes) >> 8;
- if (anum > bnum) {
- r = -1;
- } else if (anum < bnum) {
- r = +1;
- }
- }
- return r;
- }
- inline int InternalKeyComparator::Compare(const Slice& a,
- SequenceNumber a_global_seqno,
- const Slice& b,
- SequenceNumber b_global_seqno) const {
- int r = user_comparator_.Compare(ExtractUserKey(a), ExtractUserKey(b));
- if (r == 0) {
- uint64_t a_footer, b_footer;
- if (a_global_seqno == kDisableGlobalSequenceNumber) {
- a_footer = ExtractInternalKeyFooter(a);
- } else {
- a_footer = PackSequenceAndType(a_global_seqno, ExtractValueType(a));
- }
- if (b_global_seqno == kDisableGlobalSequenceNumber) {
- b_footer = ExtractInternalKeyFooter(b);
- } else {
- b_footer = PackSequenceAndType(b_global_seqno, ExtractValueType(b));
- }
- if (a_footer > b_footer) {
- r = -1;
- } else if (a_footer < b_footer) {
- r = +1;
- }
- }
- return r;
- }
- // Wrap InternalKeyComparator as a comparator class for ParsedInternalKey.
- struct ParsedInternalKeyComparator {
- explicit ParsedInternalKeyComparator(const InternalKeyComparator* c)
- : cmp(c) {}
- bool operator()(const ParsedInternalKey& a,
- const ParsedInternalKey& b) const {
- return cmp->Compare(a, b) < 0;
- }
- const InternalKeyComparator* cmp;
- };
- class PredecessorWALInfo {
- public:
- PredecessorWALInfo()
- : log_number_(0),
- size_bytes_(0),
- last_seqno_recorded_(0),
- initialized_(false) {}
- explicit PredecessorWALInfo(uint64_t log_number, uint64_t size_bytes,
- SequenceNumber last_seqno_recorded)
- : log_number_(log_number),
- size_bytes_(size_bytes),
- last_seqno_recorded_(last_seqno_recorded),
- initialized_(true) {}
- uint64_t GetLogNumber() const {
- assert(initialized_);
- return log_number_;
- }
- uint64_t GetSizeBytes() const {
- assert(initialized_);
- return size_bytes_;
- }
- SequenceNumber GetLastSeqnoRecorded() const {
- assert(initialized_);
- return last_seqno_recorded_;
- }
- bool IsInitialized() const { return initialized_; }
- inline void EncodeTo(std::string* dst) const {
- assert(dst != nullptr);
- assert(initialized_);
- PutFixed64(dst, log_number_);
- PutFixed64(dst, size_bytes_);
- PutFixed64(dst, last_seqno_recorded_);
- }
- inline Status DecodeFrom(Slice* src) {
- if (!GetFixed64(src, &log_number_)) {
- return Status::Corruption("Error decoding log number");
- }
- if (!GetFixed64(src, &size_bytes_)) {
- return Status::Corruption("Error decoding size bytes");
- }
- if (!GetFixed64(src, &last_seqno_recorded_)) {
- return Status::Corruption("Error decoding last seqno recorded");
- }
- initialized_ = true;
- return Status::OK();
- }
- private:
- uint64_t log_number_;
- uint64_t size_bytes_;
- SequenceNumber last_seqno_recorded_;
- bool initialized_;
- };
- } // namespace ROCKSDB_NAMESPACE
|