* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#ifndef BOOST_SS_SLICE_BINARY_H
#define BOOST_SS_SLICE_BINARY_H
#include <iostream>
#include "binary/key_value.h"
#include "common/bss_def.h"
#include "common/state_id_interval.h"
#include "common/util/bss_math.h"
#include "state_id.h"
namespace ock {
namespace bss {
#pragma pack(1)
* The data structure of the key in the memory of the slice table
*/
struct SlicePriKey {
uint16_t mStateId;
uint32_t mKeyHashCode;
uint32_t mKeyLen;
uint8_t mKeyData[0];
};
struct SliceKey : public Key {
public:
SliceKey() = default;
inline void Unpack(const ByteBufferRef &buffer, uint32_t bufferOffset, uint32_t bufferLen, uint32_t mixedHashCode)
{
if (UNLIKELY(buffer == nullptr)) {
LOG_ERROR("unexpected input buffer is null.");
return;
}
uint8_t *data = buffer->Data() + bufferOffset;
uint16_t stateId = *reinterpret_cast<const uint16_t *>(data);
mHasSecKey = StateId::HasSecKey(stateId);
mHasNameSpace = StateId::HasNameSpace(stateId);
mMixedHashCode = mixedHashCode;
if (mHasSecKey) {
auto priKey = const_cast<SlicePriKey *>(reinterpret_cast<const SlicePriKey *>(data));
mPriKey.StateId(stateId);
mPriKey.KeyLen(priKey->mKeyLen);
mPriKey.KeyData(priKey->mKeyData);
uint32_t nsHashCode = mHasNameSpace ? *reinterpret_cast<uint32_t *>(priKey->mKeyData) : 0;
mPriKey.HashCode(priKey->mKeyHashCode ^ nsHashCode);
mSecKey.KeyLen(bufferLen - (mPriKey.KeyLen() + sizeof(SlicePriKey)));
mSecKey.KeyData(data + sizeof(SlicePriKey) + mPriKey.KeyLen());
mSecKey.HashCode(mixedHashCode ^ stateId ^ mPriKey.HashCode());
} else {
mPriKey.StateId(stateId);
mPriKey.KeyLen(bufferLen - sizeof(uint16_t));
mPriKey.KeyData(data + sizeof(uint16_t));
mPriKey.HashCode(mixedHashCode ^ stateId);
}
mBuffer = buffer;
}
inline bool ComparePrimaryKeyAndSecondKey(const SliceKey &k2) const
{
auto comp = mPriKey.CompareStateIdFirst(k2.mPriKey);
if (comp != 0) {
return comp < 0;
}
if (UNLIKELY(mHasSecKey != k2.mHasSecKey)) {
return mHasSecKey;
}
return mSecKey.CompareKeyNode(k2.mSecKey) < 0;
}
inline uint32_t GetSerializeLength() const
{
return mHasSecKey ? NO_10 + mPriKey.KeyLen() + mSecKey.KeyLen() : NO_2 + mPriKey.KeyLen();
}
inline BResult Serialize(const ByteBufferRef &buffer, uint32_t offset, uint32_t &serializeSize) const
{
if (UNLIKELY(buffer == nullptr)) {
return BSS_ERR;
}
serializeSize = GetSerializeLength();
if (mHasSecKey) {
RETURN_NOT_OK(buffer->WriteUint16(StateId(), offset));
RETURN_NOT_OK(buffer->WriteUint32(KeyHashCode(), offset + NO_2));
RETURN_NOT_OK(buffer->WriteUint32(mPriKey.KeyLen(), offset + NO_6));
auto pos = offset + NO_10;
auto ret = memcpy_s(buffer->Data() + pos, buffer->Capacity() - pos, mPriKey.KeyData(), mPriKey.KeyLen());
if (UNLIKELY(ret != EOK)) {
LOG_ERROR("memcpy_s failed, ret: " << ret);
return BSS_INNER_ERR;
}
pos = pos + mPriKey.KeyLen();
ret = memcpy_s(buffer->Data() + pos, buffer->Capacity() - pos, mSecKey.KeyData(), mSecKey.KeyLen());
if (UNLIKELY(ret != EOK)) {
LOG_ERROR("memcpy_s failed, ret: " << ret);
return BSS_INNER_ERR;
}
} else {
RETURN_NOT_OK(buffer->WriteUint16(StateId(), offset));
auto pos = offset + NO_2;
auto ret = memcpy_s(buffer->Data() + pos, buffer->Capacity() - pos, mPriKey.KeyData(), mPriKey.KeyLen());
if (UNLIKELY(ret != EOK)) {
LOG_ERROR("memcpy_s failed, ret: " << ret);
return BSS_INNER_ERR;
}
}
return BSS_OK;
}
inline uint32_t Pack(uint8_t *buffer) const
{
return 0;
}
inline static SliceKey &Of(Key &key)
{
return *reinterpret_cast<SliceKey *>(&key);
}
inline static const SliceKey &Of(const Key &key)
{
return *reinterpret_cast<const SliceKey *>(&key);
}
};
using SliceKeyPtr = SliceKey *;
struct SliceKeyHash {
std::size_t operator()(const SliceKey &data) const
{
return data.MixedHashCode();
}
};
struct SliceKeyEqual {
bool operator()(const SliceKey &a, const SliceKey &b) const
{
return a.Compare(b) == 0;
}
};
struct SliceValue : public Value {
public:
inline uint32_t Pack(uint8_t *buffer) const
{
return 0;
}
inline static SliceValue &Of(Value &value)
{
return *reinterpret_cast<SliceValue *>(&value);
}
};
using SliceValuePtr = SliceValue *;
struct SliceHead {
uint64_t sliceId;
uint64_t version;
uint32_t keyCount;
uint32_t indexCount;
uint32_t keyOffsetBase;
uint32_t valueOffsetBase;
uint32_t sortedKeyCount;
StateIdInterval stateIdInterval;
uint16_t formatVersion;
};
struct SliceShortIndex {
uint16_t count;
uint16_t firstIndex;
};
struct SliceLongIndex {
uint32_t count;
uint32_t firstIndex;
};
struct SliceIndex {
public:
using IndexGet = bool (SliceIndex::*)(uint32_t, uint32_t &, uint32_t &);
using IndexPut = void (SliceIndex::*)(uint32_t, uint32_t);
inline void Init(uint8_t *buffer, uint32_t bufferSize, uint32_t indexCount, uint32_t indexWidth, bool isRestore)
{
mIndexBase = buffer;
mTotalSize = indexCount * indexWidth;
if (!isRestore) {
auto ret = memset_s(mIndexBase, bufferSize, 0, mTotalSize);
if (UNLIKELY(ret != EOK)) {
LOG_ERROR("SliceIndex Init failed, ret" << ret << ".");
return;
}
}
if (indexWidth == NO_4) {
mGet = &SliceIndex::ShortIndexGet;
mPut = &SliceIndex::ShortIndexPut;
} else {
mGet = &SliceIndex::LongIndexGet;
mPut = &SliceIndex::LongIndexPut;
}
}
inline uint32_t TotalSize()
{
return mTotalSize;
}
inline bool Get(uint32_t indexId, uint32_t &count, uint32_t &firstIndex)
{
return (this->*mGet)(indexId, count, firstIndex);
}
inline void Put(uint32_t indexId, uint32_t curIndex)
{
(this->*mPut)(indexId, curIndex);
}
bool ShortIndexGet(uint32_t indexId, uint32_t &count, uint32_t &firstIndex)
{
SliceShortIndex *index = reinterpret_cast<SliceShortIndex *>(mIndexBase) + indexId;
count = index->count;
firstIndex = index->firstIndex;
return (index->count != 0);
}
bool LongIndexGet(uint32_t indexId, uint32_t &count, uint32_t &firstIndex)
{
SliceLongIndex *index = reinterpret_cast<SliceLongIndex *>(mIndexBase) + indexId;
count = index->count;
firstIndex = index->firstIndex;
return (index->count != 0);
}
void ShortIndexPut(uint32_t indexId, uint32_t curIndex)
{
SliceShortIndex *index = reinterpret_cast<SliceShortIndex *>(mIndexBase) + indexId;
if (UNLIKELY(index->count == 0)) {
index->firstIndex = static_cast<uint16_t>(curIndex);
}
index->count++;
}
void LongIndexPut(uint32_t indexId, uint32_t curIndex)
{
SliceLongIndex *index = reinterpret_cast<SliceLongIndex *>(mIndexBase) + indexId;
if (UNLIKELY(index->count == 0)) {
index->firstIndex = curIndex;
}
index->count++;
}
private:
IndexPut mPut{ nullptr };
IndexGet mGet{ nullptr };
uint8_t *mIndexBase{ nullptr };
uint32_t mTotalSize{ 0 };
};
struct SliceHeadSpace {
private:
SliceHead *mHead{ nullptr };
SliceIndex mIndex;
uint32_t *mSortedIndex{ nullptr };
uint32_t *mMixedHashCode{ nullptr };
uint64_t *mSeqId{ nullptr };
public:
inline uint32_t EvaluateSize(uint32_t keyCount)
{
uint32_t size = 0;
uint32_t indexCount = BssMath::RoundUpToPowerOfTwo(keyCount);
uint32_t indexWidth = NO_4;
if (indexCount > BYTE4_MAX_SLOT_SIZE) {
indexWidth = NO_8;
}
size += sizeof(SliceHead);
size += indexCount * indexWidth;
size += indexCount * NO_4;
size += sizeof(uint32_t) * keyCount;
size += sizeof(uint64_t) * keyCount;
return size;
}
inline void Init(const ByteBufferRef &buffer, uint32_t &bufferOffset, uint32_t keyCount, uint32_t sortedKeyCount,
bool isRestore)
{
uint8_t *data = buffer->Data() + bufferOffset;
uint32_t indexCount = BssMath::RoundUpToPowerOfTwo(keyCount);
uint32_t indexWidth = NO_4;
uint32_t originOffset = bufferOffset;
if (indexCount > BYTE4_MAX_SLOT_SIZE) {
indexWidth = NO_8;
}
mHead = reinterpret_cast<SliceHead *>(data);
mHead->indexCount = indexCount;
mHead->keyCount = keyCount;
bufferOffset += sizeof(SliceHead);
mIndex.Init(data + bufferOffset, buffer->Capacity() - originOffset - bufferOffset, indexCount, indexWidth,
isRestore);
bufferOffset += mIndex.TotalSize();
mSortedIndex = reinterpret_cast<uint32_t *>(data + bufferOffset);
bufferOffset += sortedKeyCount * sizeof(uint32_t);
mMixedHashCode = reinterpret_cast<uint32_t *>(data + bufferOffset);
bufferOffset += sizeof(uint32_t) * keyCount;
mSeqId = reinterpret_cast<uint64_t *>(data + bufferOffset);
bufferOffset += sizeof(uint64_t) * keyCount;
}
inline SliceHead &Head() const
{
return *mHead;
}
inline uint32_t MixedHashCode(uint32_t index) const
{
return mMixedHashCode[index];
}
inline uint64_t SeqId(uint32_t index) const
{
return mSeqId[index];
}
inline uint32_t GetIndexBySortedIndex(uint32_t sortedIndex) const
{
return mSortedIndex[sortedIndex];
}
inline void MixedHashCode(uint32_t index, uint32_t mixedHashCode)
{
mMixedHashCode[index] = mixedHashCode;
}
inline void SeqId(uint32_t index, uint64_t seqId)
{
mSeqId[index] = seqId;
}
};
struct SliceKeySpace {
private:
uint32_t *mKeyOffset{ nullptr };
uint8_t *mKey{ nullptr };
uint32_t mKeyBase{ 0 };
ByteBufferRef mBuffer{ nullptr };
public:
inline uint32_t EvaluateSize(uint32_t keyCount, uint32_t totalKeySize)
{
return sizeof(uint32_t) * keyCount + totalKeySize;
}
inline void Init(const ByteBufferRef &buffer, uint32_t &bufferOffset, uint32_t keyCount, uint32_t totalKeySize)
{
uint8_t *data = buffer->Data() + bufferOffset;
mKeyOffset = reinterpret_cast<uint32_t *>(data);
uint32_t keyOffsetTotalSize = sizeof(uint32_t) * keyCount;
bufferOffset += keyOffsetTotalSize;
mKey = data + keyOffsetTotalSize;
mKeyBase = bufferOffset;
bufferOffset += totalKeySize;
mBuffer = buffer;
}
inline void Get(uint32_t index, uint32_t mixedHashCode, Key &key) const
{
uint32_t startOffset = (index == 0) ? 0 : mKeyOffset[index - 1];
uint32_t endOffset = mKeyOffset[index];
SliceKey::Of(key).Unpack(mBuffer, mKeyBase + startOffset, endOffset - startOffset, mixedHashCode);
}
inline int32_t FindPriKey(uint32_t index, uint32_t mixedHashCode, const PriKeyNode &key) const
{
uint32_t startOffset = (index == 0) ? 0 : mKeyOffset[index - 1];
uint32_t endOffset = mKeyOffset[index];
return ComparePriKeyStateIdFirst(mBuffer, mKeyBase + startOffset, endOffset - startOffset, mixedHashCode, key);
}
inline int32_t ComparePriKeyStateIdFirst(const ByteBufferRef &buffer, uint32_t bufferOffset, uint32_t bufferLen,
uint32_t mixedHashCode, const PriKeyNode &key) const
{
const uint8_t *data = buffer->Data() + bufferOffset;
uint16_t stateId = *reinterpret_cast<const uint16_t *>(data);
int32_t cmp = BssMath::IntegerCompare(stateId, key.StateId());
if (cmp != 0) {
return cmp;
}
uint32_t priKeyLen;
const uint8_t *priKeyData;
uint32_t priKeyHashCode;
if (StateId::HasSecKey(stateId)) {
auto priKey = reinterpret_cast<const SlicePriKey *>(data);
priKeyLen = priKey->mKeyLen;
priKeyData = priKey->mKeyData;
priKeyHashCode = priKey->mKeyHashCode;
} else {
priKeyLen = bufferLen - sizeof(uint16_t);
priKeyData = data + sizeof(uint16_t);
priKeyHashCode = mixedHashCode ^ stateId;
}
cmp = BssMath::IntegerCompare(priKeyHashCode, key.KeyHashCode());
if (cmp != 0) {
return cmp;
}
cmp = memcmp(priKeyData, key.KeyData(), std::min(priKeyLen, key.KeyLen()));
if (cmp != 0) {
return cmp;
}
return BssMath::IntegerCompare(priKeyLen, key.KeyLen());
}
inline void Put(uint32_t index, const Key &key)
{
uint32_t preOffset = index == 0 ? 0 : mKeyOffset[index - 1];
mKeyOffset[index] = preOffset + SliceKey::Of(key).Pack(mKey + preOffset);
}
};
struct SliceValueIndicator {
private:
uint32_t mType : 4;
uint32_t mOffset : 28;
public:
inline SliceValueIndicator(uint32_t indicator)
{
mType = (indicator >> NO_28) & 0xF;
mOffset = indicator & 0xFFFFFFF;
}
inline void Init(uint32_t offset, uint8_t valueType)
{
mType = valueType & 0xF;
mOffset = offset & 0xFFFFFFF;
}
inline uint32_t Type() const
{
return mType;
}
inline uint32_t Offset() const
{
return mOffset;
}
inline void Type(uint8_t valueType)
{
mType = valueType & 0xF;
}
};
struct SliceValueSpace {
private:
uint32_t *mValueIndicator{ nullptr };
uint8_t *mValue{ nullptr };
ByteBufferRef mBuffer{ nullptr };
public:
inline uint32_t EvaluateSize(uint32_t valueCount, uint32_t totalValueSize)
{
return sizeof(SliceValueIndicator) * valueCount + totalValueSize;
}
inline void Init(const ByteBufferRef &buffer, uint32_t bufferOffset, uint32_t valueCount)
{
uint8_t *data = buffer->Data() + bufferOffset;
mValueIndicator = reinterpret_cast<uint32_t *>(data);
mValue = data + sizeof(SliceValueIndicator) * valueCount;
mBuffer = buffer;
}
inline void Get(uint32_t index, uint64_t seqId, Value &value) const
{
uint32_t startOffset = (index == 0) ? 0 : SliceValueIndicator(mValueIndicator[index - 1]).Offset();
SliceValueIndicator indicator(mValueIndicator[index]);
uint8_t valueType = indicator.Type();
uint32_t endOffset = indicator.Offset();
value.Init(valueType, endOffset - startOffset, mValue + startOffset, seqId, mBuffer);
}
inline void Put(uint32_t index, const SliceValue &value)
{
uint32_t preOffset = index == 0 ? 0 : SliceValueIndicator(mValueIndicator[index - 1]).Offset();
uint32_t valueLen = value.Pack(mValue + preOffset);
uint32_t offset = preOffset + valueLen;
SliceValueIndicator *indicator = reinterpret_cast<SliceValueIndicator *>(&mValueIndicator[index]);
indicator->Init(offset, value.ValueType());
}
};
struct SliceSpace {
private:
SliceHeadSpace mHeadSpace;
SliceKeySpace mKeySpace;
SliceValueSpace mValueSpace;
ByteBufferRef mBuffer{ nullptr };
public:
inline void Init(const ByteBufferRef &buffer, uint32_t keyCount, uint32_t sortedKeyCount, uint32_t totalKeySize,
bool isRestore)
{
mBuffer = buffer;
uint32_t bufferOffset = 0;
mHeadSpace.Init(mBuffer, bufferOffset, keyCount, sortedKeyCount, isRestore);
auto &head = mHeadSpace.Head();
head.keyOffsetBase = bufferOffset;
mKeySpace.Init(mBuffer, bufferOffset, keyCount, totalKeySize);
head.valueOffsetBase = bufferOffset;
mValueSpace.Init(mBuffer, bufferOffset, keyCount);
}
inline uint32_t KeyCount() const
{
return mHeadSpace.Head().keyCount;
}
inline uint32_t SortedKeyCount() const
{
return mHeadSpace.Head().sortedKeyCount;
}
inline uint32_t GetKeyMixedHashCode(uint32_t index) const
{
return mHeadSpace.MixedHashCode(index);
}
inline void GetKey(uint32_t index, Key &key) const
{
uint32_t mixedHashCode = GetKeyMixedHashCode(index);
mKeySpace.Get(index, mixedHashCode, key);
}
inline int32_t FindPriKey(uint32_t index, const PriKeyNode &key) const
{
uint32_t mixedHashCode = GetKeyMixedHashCode(index);
return mKeySpace.FindPriKey(index, mixedHashCode, key);
}
inline void GetKeyBySortedIndex(uint32_t sortedIndex, Key &key) const
{
GetKey(mHeadSpace.GetIndexBySortedIndex(sortedIndex), key);
}
inline int32_t FindPriKeyBySortedIndex(uint32_t sortedIndex, const PriKeyNode &key) const
{
return FindPriKey(mHeadSpace.GetIndexBySortedIndex(sortedIndex), key);
}
inline void GetValue(uint32_t index, Value &value) const
{
uint64_t seqId = mHeadSpace.SeqId(index);
mValueSpace.Get(index, seqId, value);
}
inline void GetKeyValue(uint32_t index, KeyValueRef &keyValue) const
{
GetKey(index, keyValue->key);
GetValue(index, keyValue->value);
}
inline uint32_t GetIndexBySortIndex(uint32_t index) const
{
return mHeadSpace.GetIndexBySortedIndex(index);
}
inline void PutKeyValue(uint32_t index, const SliceKey &key, const SliceValue &value)
{
mHeadSpace.MixedHashCode(index, key.MixedHashCode());
mHeadSpace.SeqId(index, value.SeqId());
mKeySpace.Put(index, key);
mValueSpace.Put(index, value);
}
};
#pragma pack()
}
}
#endif