* 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_LSM_BINARY_H
#define BOOST_SS_LSM_BINARY_H
#include "binary_reader.h"
#include "bss_def.h"
#include "key_value.h"
namespace ock {
namespace bss {
#pragma pack(1)
struct LsmPriKeyNode {
* for primary key, hashcode is KeyHashCode
*/
uint32_t mKeyHashCode;
uint32_t mKeyLen;
uint8_t mKeyData[0];
public:
inline uint32_t NsHashCode(uint16_t stateId)
{
bool hasNamespace = StateId::HasNameSpace(stateId);
return hasNamespace ? *reinterpret_cast<uint32_t *>(mKeyData) : 0;
}
inline int32_t CompareKeyNode(const PriKeyNode &other)
{
if (StateId::GetStateType(other.StateId()) == PQ) {
return PQBinaryDataComparator::ComparePrefix(mKeyData, mKeyLen, other.KeyData(), other.KeyLen());
}
int32_t cmp = BssMath::IntegerCompare(mKeyHashCode, other.KeyHashCode());
if (cmp != 0) {
return cmp;
}
return ((cmp = memcmp(mKeyData, other.KeyData(), std::min(mKeyLen, other.KeyLen()))) != 0) ?
cmp :
BssMath::IntegerCompare(mKeyLen, other.KeyLen());
}
inline static LsmPriKeyNode &From(uint8_t *buffer)
{
return *reinterpret_cast<LsmPriKeyNode *>(buffer);
}
};
struct LsmSecKeyNode {
* for secondary key, hashcode is calculate by HashCode::Hash(SecondaryKeyData, SecondaryKeyLen);
*/
uint16_t mStateId;
uint32_t mHashCode;
uint32_t mKeyLen;
uint8_t mKeyData[0];
public:
inline int32_t CompareKeyNode(const KeyNode &other) const
{
return -other.CompareKeyNode(*this);
}
inline static LsmSecKeyNode &From(uint8_t *buffer)
{
return *reinterpret_cast<LsmSecKeyNode *>(buffer);
}
};
struct LsmValue {
uint64_t mSeqId;
uint8_t mValueType;
uint32_t mValueLen;
uint8_t mValueData[0];
};
struct LsmMultiSecKeyInfo {
uint32_t mSecKeyCount;
uint32_t mFirstSecKeyOffset;
uint8_t mSecKeyOffset[0];
public:
BResult SecKeyOffset(uint32_t index, uint32_t byteNum, uint32_t &secKeyOffset)
{
uint32_t offset = byteNum * index;
uint64_t resOffset = 0;
RETURN_NO_OK_AS_READ_BUFFER_ERROR(BinaryReader::ReadBytes(mSecKeyOffset + offset, byteNum, resOffset));
secKeyOffset = mFirstSecKeyOffset + static_cast<uint32_t>(resOffset);
return BSS_OK;
}
};
struct LsmKeyValueInfo {
public:
LsmKeyValueInfo() = default;
LsmKeyValueInfo(const ByteBufferRef &buffer, uint32_t bufferOffset)
{
}
BResult Unpack(const ByteBufferRef &buffer, uint32_t bufferOffset)
{
RETURN_INVALID_PARAM_AS_NULLPTR(buffer->Data());
uint8_t *data = buffer->Data() + bufferOffset;
RETURN_INNER_ERR_AS_BUFFER_OVER_FLOW(buffer->mCapacity, bufferOffset + sizeof(LsmPriKeyNode));
uint32_t offset = 0;
mPriKey = reinterpret_cast<LsmPriKeyNode *>(data);
RETURN_INVALID_PARAM_AS_NULLPTR(mPriKey);
offset += sizeof(LsmPriKeyNode) + mPriKey->mKeyLen;
uint8_t flag = *(data + offset);
offset += NO_1;
mHasMultiSecKey = (flag & 0x1) != 0;
BResult result;
if (mHasMultiSecKey) {
result = mMulti.Unpack(flag, bufferOffset + offset, buffer);
} else {
result = mSgl.Unpack(data + offset, buffer->Capacity() - bufferOffset - offset);
}
if (UNLIKELY(result != BSS_OK)) {
LOG_ERROR("unpack secKey faild, offset: " << (bufferOffset + offset));
return result;
}
mBuffer = buffer;
return BSS_OK;
}
inline uint16_t StateId() const
{
return mHasMultiSecKey ? mMulti.mStateId : mSgl.mStateId;
}
inline uint32_t GetSecKeyCount()
{
return mHasMultiSecKey ? mMulti.mMultiSecKey->mSecKeyCount : 1;
}
inline bool HasMultiSecKey()
{
return mHasMultiSecKey;
}
inline BResult GetKeyAndValue(uint32_t secIndex, KeyValueRef &keyValue)
{
BResult result = BSS_OK;
if (mHasMultiSecKey) {
result = GetKeyAndValueForMulti(secIndex, keyValue->key, keyValue->value);
} else {
GetKeyAndValueForSingle(keyValue->key, keyValue->value);
}
return result;
}
BResult UnpackToSglSecKey(const ByteBufferRef &buffer, uint32_t bufferOffset)
{
RETURN_INVALID_PARAM_AS_NULLPTR(buffer);
RETURN_INVALID_PARAM_AS_NULLPTR(buffer->Data());
uint8_t *data = buffer->Data() + bufferOffset;
RETURN_INNER_ERR_AS_BUFFER_OVER_FLOW(buffer->Capacity(), bufferOffset + sizeof(LsmPriKeyNode));
mPriKey = reinterpret_cast<LsmPriKeyNode *>(data);
RETURN_INVALID_PARAM_AS_NULLPTR(mPriKey);
mHasMultiSecKey = false;
uint32_t offset = sizeof(LsmPriKeyNode) + mPriKey->mKeyLen;
RETURN_INNER_ERR_AS_BUFFER_OVER_FLOW(buffer->Capacity(), bufferOffset + offset);
RETURN_NOT_OK(mSgl.Unpack(data + offset, buffer->Capacity() - bufferOffset - offset));
mBuffer = buffer;
return BSS_OK;
}
inline int32_t Compare(const Key &other) const
{
if (StateId::GetStateType(other.StateId()) == PQ) {
int32_t cmp = BssMath::IntegerCompare(mSgl.mStateId, other.StateId());
if (cmp != 0) {
return cmp;
}
cmp = PQBinaryDataComparator::ComparePrefix(mPriKey->mKeyData, mPriKey->mKeyLen, other.PriKey().KeyData(),
other.PriKey().KeyLen());
return cmp != 0 ? cmp : other.IsEndKey() ? -1 : cmp;
}
int32_t cmp = mPriKey->CompareKeyNode(other.PriKey());
if (cmp != 0) {
return cmp;
}
return CompareStateIdAndSecKey(mSgl.mStateId, mSgl.mSecKey, other);
}
inline int32_t CompareSecKeyNode(int32_t secIndex, const Key &other) const
{
uint16_t stateId = 0;
LsmSecKeyNode *secKey = nullptr;
GetStateIdAndSecKey(secIndex, stateId, secKey);
return CompareStateIdAndSecKey(stateId, secKey, other);
}
inline bool IsSecKeyInRange(int32_t secIndex, const Key &startKey, const Key &endKey) const
{
uint16_t stateId = 0;
LsmSecKeyNode *secKey = nullptr;
GetStateIdAndSecKey(secIndex, stateId, secKey);
return CompareStateIdAndSecKey(stateId, secKey, startKey) >= 0 &&
CompareStateIdAndSecKey(stateId, secKey, endKey) <= 0;
}
private:
inline void GetKeyAndValueForSingle(Key &key, Value &value)
{
PriKeyNode priKey(mSgl.mStateId, mPriKey->mKeyHashCode ^ mPriKey->NsHashCode(mSgl.mStateId), mPriKey->mKeyData,
mPriKey->mKeyLen);
auto &sglSecKey = mSgl.mSecKey;
SecKeyNode secKey = sglSecKey != nullptr ?
SecKeyNode(sglSecKey->mHashCode, sglSecKey->mKeyData, sglSecKey->mKeyLen) :
SecKeyNode();
key.Init(priKey, secKey, mBuffer);
auto &sglValue = mSgl.mValue;
value.Init(sglValue->mValueType, sglValue->mValueLen, sglValue->mValueData, sglValue->mSeqId, mBuffer);
}
inline BResult GetKeyAndValueForMulti(uint32_t secIndex, Key &key, Value &value)
{
uint8_t *data = mBuffer->Data();
uint32_t offset = 0;
RETURN_NO_OK_AS_READ_BUFFER_ERROR(
mMulti.mMultiSecKey->SecKeyOffset(secIndex, mMulti.mSecKeyOffsetByteNum, offset));
RETURN_INNER_ERR_AS_BUFFER_OVER_FLOW(mBuffer->Capacity(), offset + sizeof(uint16_t));
uint16_t stateId = *(reinterpret_cast<const uint16_t *>(data + offset));
PriKeyNode priKey(stateId, mPriKey->mKeyHashCode ^ mPriKey->NsHashCode(mSgl.mStateId), mPriKey->mKeyData,
mPriKey->mKeyLen);
bool hasSecKey = StateId::HasSecKey(stateId);
if (hasSecKey) {
SecKeyNode secKey;
RETURN_INNER_ERR_AS_BUFFER_OVER_FLOW(mBuffer->Capacity(), offset + sizeof(LsmSecKeyNode));
const LsmSecKeyNode *lsmSecKey = reinterpret_cast<const LsmSecKeyNode *>(data + offset);
offset += sizeof(LsmSecKeyNode) + lsmSecKey->mKeyLen;
secKey.Init(lsmSecKey->mHashCode, lsmSecKey->mKeyData, lsmSecKey->mKeyLen);
key.Init(priKey, secKey, mBuffer);
} else {
key.Init(priKey, mBuffer);
}
RETURN_INNER_ERR_AS_BUFFER_OVER_FLOW(mBuffer->Capacity(), offset + sizeof(LsmValue));
const LsmValue *lsmValue = reinterpret_cast<const LsmValue *>(data + offset);
value.Init(lsmValue->mValueType, lsmValue->mValueLen, lsmValue->mValueData, lsmValue->mSeqId, mBuffer);
return BSS_OK;
}
inline void GetStateIdAndSecKeyForSingle(uint16_t &stateId, LsmSecKeyNode *&secKey) const
{
stateId = mSgl.mStateId, secKey = mSgl.mSecKey;
}
inline BResult GetStateIdAndSecKeyForMulti(uint32_t secIndex, uint16_t &stateId, LsmSecKeyNode *&secKey) const
{
uint8_t *data = mBuffer->Data();
uint32_t offset = 0;
RETURN_NO_OK_AS_READ_BUFFER_ERROR(
mMulti.mMultiSecKey->SecKeyOffset(secIndex, mMulti.mSecKeyOffsetByteNum, offset));
RETURN_INNER_ERR_AS_BUFFER_OVER_FLOW(mBuffer->Capacity(), offset + sizeof(uint16_t));
stateId = *(reinterpret_cast<const uint16_t *>(data + offset));
if (StateId::HasSecKey(stateId)) {
RETURN_INNER_ERR_AS_BUFFER_OVER_FLOW(mBuffer->Capacity(), offset + sizeof(LsmSecKeyNode));
secKey = reinterpret_cast<LsmSecKeyNode *>(data + offset);
} else {
secKey = nullptr;
}
return BSS_OK;
}
inline void GetStateIdAndSecKey(int32_t secIndex, uint16_t &stateId, LsmSecKeyNode *&secKey) const
{
if (mHasMultiSecKey) {
GetStateIdAndSecKeyForMulti(secIndex, stateId, secKey);
} else {
GetStateIdAndSecKeyForSingle(stateId, secKey);
}
}
inline int32_t CompareStateIdAndSecKey(uint16_t stateId, const LsmSecKeyNode *secKey, const Key &other) const
{
int32_t cmp = BssMath::IntegerCompare(stateId, other.StateId());
if (cmp != 0) {
return cmp;
}
if (other.IsEndKey()) {
return -1;
}
if (secKey == nullptr) {
return 0;
}
if (other.IsPrefixKey()) {
return 1;
}
return secKey->CompareKeyNode(other.SecKey());
}
private:
* has single secondary key or multi secondary key?
*/
bool mHasMultiSecKey{ false };
* primary key.
*/
LsmPriKeyNode *mPriKey{ nullptr };
union {
* for single secondary key.
*/
struct {
uint16_t mStateId{ INVALID_U16 };
LsmSecKeyNode *mSecKey{ nullptr };
LsmValue *mValue{ nullptr };
inline BResult Unpack(uint8_t *data, uint32_t capacity)
{
RETURN_INVALID_PARAM_AS_NULLPTR(data);
RETURN_INNER_ERR_AS_BUFFER_OVER_FLOW(capacity, sizeof(uint16_t));
mStateId = *(reinterpret_cast<uint16_t *>(data));
bool hasSecKey = StateId::HasSecKey(mStateId);
uint32_t offset = 0;
if (hasSecKey) {
RETURN_INNER_ERR_AS_BUFFER_OVER_FLOW(capacity, sizeof(LsmSecKeyNode));
mSecKey = reinterpret_cast<LsmSecKeyNode *>(data);
RETURN_INVALID_PARAM_AS_NULLPTR(mSecKey);
offset = sizeof(LsmSecKeyNode) + mSecKey->mKeyLen;
} else {
mSecKey = nullptr;
offset = sizeof(uint16_t);
}
RETURN_INNER_ERR_AS_BUFFER_OVER_FLOW(capacity, offset + sizeof(LsmValue));
mValue = reinterpret_cast<LsmValue *>(data + offset);
return BSS_OK;
}
} mSgl{};
* for multi secondary key
*/
struct {
uint16_t mStateId;
uint8_t mSecKeyOffsetByteNum;
uint8_t mReserved2[3];
LsmMultiSecKeyInfo *mMultiSecKey;
inline BResult Unpack(uint8_t flag, uint32_t offset, const ByteBufferRef &buffer)
{
uint8_t *data = buffer->Data();
RETURN_INVALID_PARAM_AS_NULLPTR(data);
mSecKeyOffsetByteNum = (flag >> 1) & 0x7;
RETURN_INNER_ERR_AS_BUFFER_OVER_FLOW(buffer->Capacity(), offset + sizeof(LsmMultiSecKeyInfo));
mMultiSecKey = reinterpret_cast<LsmMultiSecKeyInfo *>(data + offset);
RETURN_INVALID_PARAM_AS_NULLPTR(mMultiSecKey);
uint32_t secKeyOffset = 0;
RETURN_NO_OK_AS_READ_BUFFER_ERROR(mMultiSecKey->SecKeyOffset(0, mSecKeyOffsetByteNum, secKeyOffset));
RETURN_INNER_ERR_AS_BUFFER_OVER_FLOW(buffer->Capacity(), secKeyOffset + sizeof(uint16_t));
mStateId = *(reinterpret_cast<uint16_t *>(data + secKeyOffset));
return BSS_OK;
}
} mMulti;
};
ByteBufferRef mBuffer{ nullptr };
};
#pragma pack()
}
}
#endif