* 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_OUTPUT_VIEW_H
#define BOOST_SS_OUTPUT_VIEW_H
#include <memory>
#include "common/util/bss_math.h"
#include "lsm_store/file/file_mem_allocator.h"
#include "slice_table/binary/byte_buffer.h"
namespace ock {
namespace bss {
class OutputView {
public:
explicit OutputView(const MemManagerRef &memManager, FileProcHolder holder = FileProcHolder::FILE_STORE_FLUSH)
: mMemManager(memManager), mHolder(holder)
{
}
explicit OutputView(uint32_t cap, const MemManagerRef &memManager,
FileProcHolder holder = FileProcHolder::FILE_STORE_FLUSH)
: mInitSize(cap), mMemManager(memManager), mHolder(holder)
{
}
~OutputView()
{
if (mMemManager != nullptr && mData != nullptr) {
auto tmp = reinterpret_cast<uintptr_t>(mData);
mMemManager->ReleaseMemory(tmp);
}
}
BResult Write(const uint8_t *buf, uint32_t len)
{
if (UNLIKELY(buf == nullptr || len == 0)) {
LOG_ERROR("The input parameter is invalid.");
return BSS_INVALID_PARAM;
}
BResult ret = BSS_OK;
RETURN_NOT_OK_AS_FALSE(mOffset > UINT32_MAX - len, BSS_INVALID_PARAM);
if (mOffset + len > mCapacity) {
ret = Grow(len + mOffset);
RETURN_NOT_OK_NO_LOG(ret);
}
ret = memcpy_s(mData + mOffset, mCapacity - mOffset, buf, len);
if (UNLIKELY(ret != BSS_OK)) {
LOG_ERROR("Memory copy failed, ret:" << ret << ", capacity:" << mCapacity << ", offset:" << mOffset
<< ", len:" << len << ", errno:" << errno);
return BSS_INNER_ERR;
}
mOffset += len;
mWritten += len;
return BSS_OK;
}
BResult WriteBoolean(bool value)
{
return Write(reinterpret_cast<uint8_t *>(&value), sizeof(value));
}
BResult WriteUint8(uint8_t value)
{
return Write(&value, sizeof(value));
}
BResult WriteInt16(int16_t value)
{
return Write(reinterpret_cast<uint8_t *>(&value), sizeof(value));
}
BResult WriteUint16(uint16_t value)
{
return Write(reinterpret_cast<uint8_t *>(&value), sizeof(value));
}
BResult WriteUint32(uint32_t value)
{
return Write(reinterpret_cast<uint8_t *>(&value), sizeof(value));
}
BResult WriteInt32(int32_t value)
{
return Write(reinterpret_cast<uint8_t *>(&value), sizeof(value));
}
BResult WriteUint64(uint64_t value)
{
return Write(reinterpret_cast<uint8_t *>(&value), sizeof(value));
}
BResult WriteUTF(std::string value)
{
uint64_t len = value.size();
auto ret = WriteUint64(len);
if (UNLIKELY(ret != BSS_OK)) {
LOG_ERROR("Write string value length failed.");
return BSS_ERR;
}
ret = Write(reinterpret_cast<const uint8_t *>(value.c_str()), len);
if (UNLIKELY(ret != BSS_OK)) {
LOG_ERROR("write string value failed.");
return BSS_ERR;
}
return BSS_OK;
}
BResult WriteBuffer(const ByteBufferRef &buffer, uint32_t offset, uint32_t len)
{
if (UNLIKELY(buffer == nullptr || offset + len > buffer->Capacity())) {
return BSS_INVALID_PARAM;
}
return Write(buffer->Data() + offset, len);
}
inline uint32_t GetOffset() const
{
return mOffset;
}
inline uint32_t GetCapacity() const
{
return mCapacity;
}
uint8_t *Data()
{
return mData;
}
BResult SetOffset(uint32_t requiredOffset)
{
if (UNLIKELY(requiredOffset > mCapacity)) {
auto ret = Grow(BssMath::RoundUpToPowerOfTwo(requiredOffset));
if (UNLIKELY(ret != BSS_OK)) {
return ret;
}
}
mOffset = requiredOffset;
mWritten = requiredOffset;
return BSS_OK;
}
BResult Reverse(uint32_t capacity)
{
if (UNLIKELY(UINT32_MAX < capacity || capacity == 0)) {
return BSS_ALLOC_FAIL;
}
if (mCapacity < capacity) {
auto addr = FileMemAllocator::Alloc(mMemManager, mHolder, capacity, __FUNCTION__);
if (UNLIKELY(addr == 0)) {
return BSS_ALLOC_FAIL;
}
if (UNLIKELY(mData != nullptr)) {
auto tmp = reinterpret_cast<uintptr_t>(mData);
RETURN_NOT_OK(mMemManager->ReleaseMemory(tmp));
}
mData = reinterpret_cast<uint8_t *>(addr);
mCapacity = capacity;
}
mOffset = 0;
mWritten = 0;
return BSS_OK;
}
void ReleaseMemory()
{
if (mCapacity < IO_SIZE_32M) {
SetOffset(0);
return;
}
LOG_INFO("release outputView memory size:" << mCapacity);
if (LIKELY(mMemManager != nullptr && mData != nullptr)) {
auto tmp = reinterpret_cast<uintptr_t>(mData);
mMemManager->ReleaseMemory(tmp);
mData = nullptr;
}
mCapacity = 0;
mOffset = 0;
mWritten = 0;
}
private:
BResult Grow(uint32_t size)
{
RETURN_ERROR_AS_NULLPTR(mMemManager);
if (UNLIKELY(UINT32_MAX - mCapacity < size)) {
return BSS_ALLOC_FAIL;
}
uint32_t newCapacity = 0;
if (LIKELY(mCapacity == 0)) {
newCapacity = mInitSize;
} else {
newCapacity = mCapacity << 1;
}
while ((newCapacity - mOffset) < size) {
if (UNLIKELY((newCapacity << 1) < newCapacity)) {
LOG_ERROR("Integer wraparound!");
return BSS_ERR;
}
newCapacity = newCapacity << 1;
}
while ((newCapacity - mOffset) > (size + IO_SIZE_1M)) {
newCapacity -= IO_SIZE_1M;
}
auto addr = FileMemAllocator::Alloc(mMemManager, mHolder, newCapacity, __FUNCTION__);
if (UNLIKELY(addr == 0)) {
return BSS_ALLOC_FAIL;
}
if (UNLIKELY(mData != nullptr)) {
auto ret = memcpy_s(reinterpret_cast<uint8_t *>(addr), newCapacity, mData, mCapacity);
if (UNLIKELY(ret != BSS_OK)) {
LOG_ERROR("Memory copy failed, ret:" << ret << ", errno:" << errno);
mMemManager->ReleaseMemory(addr);
return BSS_ALLOC_FAIL;
}
auto tmp = reinterpret_cast<uintptr_t>(mData);
mMemManager->ReleaseMemory(tmp);
}
mData = reinterpret_cast<uint8_t *>(addr);
mCapacity = newCapacity;
return BSS_OK;
}
private:
uint8_t *mData = nullptr;
uint32_t mCapacity = 0;
uint32_t mInitSize = NO_16;
uint32_t mOffset = 0;
uint32_t mWritten = 0;
MemManagerRef mMemManager = nullptr;
FileProcHolder mHolder;
};
using OutputViewRef = std::shared_ptr<OutputView>;
}
}
#endif