* This file is part of the MindStudio project.
* Copyright (c) 2025 Huawei Technologies Co.,Ltd.
*
* MindStudio is licensed under Mulan PSL v2.
* 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 SERVICE_PROFILER_DB_BUFFER_H
#define SERVICE_PROFILER_DB_BUFFER_H
#include <atomic>
#include <thread>
#include <iomanip>
#include "msServiceProfiler/Log.h"
#ifdef ENABLE_SERVICE_PROF_UNIT_TEST
#define MS_SERVICE_INLINE_FLAG [[gnu::noinline]]
#else
#define MS_SERVICE_INLINE_FLAG inline
#endif
namespace msServiceProfiler {
template <typename T, size_t PTR_ARRAY_SIZE = 128, size_t PTR_ARRAY_PRE_SIZE = 256>
class DbBuffer {
struct NodeDbActivityMarker {
std::unique_ptr<T> pMarkerData = nullptr;
NodeDbActivityMarker *pNext = nullptr;
};
public:
DbBuffer() = default;
~DbBuffer()
{
for (auto &array : markerArray_) {
if (array != nullptr) {
delete[] array;
array = nullptr;
}
}
};
std::unique_ptr<T> Push(std::unique_ptr<T> pMarkerData)
{
#ifdef ENABLE_SERVICE_PROF_UNIT_TEST
pushCount_++;
#endif
if (pMarkerData == nullptr) {
return pMarkerData;
}
const auto size = Size();
auto *pNext = GetNext(pHead_);
if (size + 1 >= BufferSize()) {
if (bufferIndex_ > PTR_ARRAY_SIZE - 1) {
LOG_ONCE_E("no more new buffer. max size is: %lu", size);
return pMarkerData;
}
auto *pBuffer = NewBuffer(pHead_, pNext);
if (pBuffer != nullptr) {
pHead_ = pBuffer;
} else {
LOG_ONCE_E("no more new buffer. now size is: %lu", size);
return pMarkerData;
}
} else {
pHead_ = pNext;
}
if (pHead_ != nullptr) {
pHead_->pMarkerData = std::move(pMarkerData);
SizeAdd();
} else {
LOG_ONCE_E("pHead_ is null, cannot proceed.");
return nullptr;
}
return nullptr;
};
size_t Pop(const size_t maxPopSize, std::unique_ptr<T> *popDataArray)
{
const auto size = Size();
if (size == 0) {
return 0;
}
size_t popCntThisTime = 0;
while (popCntThisTime < std::min(maxPopSize, size)) {
if (pTail_ == nullptr) {
pTail_ = markerArray_[0];
} else {
pTail_ = GetNext(pTail_);
}
popDataArray[popCntThisTime] = std::move(pTail_->pMarkerData);
popCntThisTime++;
SizeSub();
}
#ifdef ENABLE_SERVICE_PROF_UNIT_TEST
maxCountInBuffer_ = std::max(maxCountInBuffer_, size);
popCount_ += popCntThisTime;
#endif
return popCntThisTime;
};
size_t Size() const
{
return Size_.load(std::memory_order_relaxed);
};
#ifdef ENABLE_SERVICE_PROF_UNIT_TEST
[[gnu::noinline]] size_t PopCnt() const
{
return popCount_;
};
[[gnu::noinline]] size_t PushCnt() const
{
return pushCount_;
};
[[gnu::noinline]] size_t MaxCntInBuffer() const
{
return maxCountInBuffer_;
};
#endif
private:
size_t BufferSize() const
{
return bufferSize_;
};
size_t SizeAdd()
{
return Size_.fetch_add(1, std::memory_order_release);
};
size_t SizeSub()
{
return Size_.fetch_sub(1, std::memory_order_acquire);
};
NodeDbActivityMarker *NewBuffer(NodeDbActivityMarker *pThis, NodeDbActivityMarker *pNext)
{
auto *pNodeArray = new (std::nothrow) NodeDbActivityMarker[PTR_ARRAY_PRE_SIZE];
if (pNodeArray == nullptr) {
return nullptr;
}
if (pNext == nullptr) {
pNodeArray[PTR_ARRAY_PRE_SIZE - 1].pNext = pNodeArray;
} else {
pNodeArray[PTR_ARRAY_PRE_SIZE - 1].pNext = pNext;
pThis->pNext = pNodeArray;
}
markerArray_[bufferIndex_] = pNodeArray;
bufferIndex_++;
bufferSize_ += PTR_ARRAY_PRE_SIZE;
return pNodeArray;
};
static NodeDbActivityMarker *GetNext(NodeDbActivityMarker *pNode)
{
if (pNode == nullptr) {
return nullptr;
}
NodeDbActivityMarker *pNext = pNode->pNext;
if (pNext == nullptr) {
pNext = ++pNode;
}
return pNext;
};
private:
NodeDbActivityMarker *markerArray_[PTR_ARRAY_SIZE] = {nullptr};
size_t bufferSize_ = 0;
size_t bufferIndex_ = 0;
NodeDbActivityMarker *pHead_ = nullptr;
NodeDbActivityMarker *pTail_ = nullptr;
std::atomic<size_t> Size_{};
#ifdef ENABLE_SERVICE_PROF_UNIT_TEST
size_t pushCount_ = 0;
size_t popCount_ = 0;
size_t maxCountInBuffer_ = 0;
#endif
};
}
#endif