* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
* ubs-io is licensed under the 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.
*/
#include "wcache_index.h"
#include "bio_tracepoint_helper.h"
namespace ock {
namespace bio {
WCacheIndex::~WCacheIndex()
{
for (const auto &sliceIndex : mTable) {
delete sliceIndex.second;
}
mTable.clear();
}
inline uint32_t WCacheIndex::Hash(const Key &key)
{
return std::hash<std::string>{}(key) % HASH_BUCKET_NUM;
}
BResult WCacheIndex::Insert(uint16_t ptId, const Key &key, const WCacheSliceRefPtr &sliceRef)
{
WCacheIndexTable *table = GetIndexTable(ptId);
ChkTrue(table != nullptr, BIO_INVALID_PARAM, "Get write cache index table fail, ptId:" << ptId << ", key:" << key);
auto bucket = Hash(key);
WriteLocker<ReadWriteLock> lock(&table->sliceIndexLock[bucket]);
auto sliceMeta = table->sliceIndex[bucket].find(key);
if (UNLIKELY(sliceMeta != table->sliceIndex[bucket].end())) {
LOG_WARN("Repeat put, key:" << key);
}
table->sliceIndex[bucket].emplace(key, sliceRef);
return BIO_OK;
}
WCacheSliceRefPtr WCacheIndex::Aquire(uint16_t ptId, const Key &key)
{
WCacheIndexTable *table = GetIndexTable(ptId);
ChkTrue(table != nullptr, nullptr, "Invalid table, ptId:" << ptId << ".");
auto bucket = Hash(key);
ReadLocker<ReadWriteLock> lock(&table->sliceIndexLock[bucket]);
auto sliceMeta = table->sliceIndex[bucket].find(key);
if (UNLIKELY(sliceMeta == table->sliceIndex[bucket].end())) {
return nullptr;
}
auto sliceRef = sliceMeta->second;
if (LIKELY(sliceRef->Aquire())) {
return sliceRef;
} else {
return nullptr;
}
}
BResult WCacheIndex::FuzzyAquire(uint16_t ptId, const char *prefix, std::unordered_map<std::string, CacheObjStat> &objs)
{
WCacheIndexTable *table = GetIndexTable(ptId);
ChkTrue(table != nullptr, BIO_INVALID_PARAM, "Get wcache index table failed.");
std::vector<WCacheSliceRefPtr> listSliceVec;
for (uint32_t bucket = 0; bucket < HASH_BUCKET_NUM; bucket++) {
ReadLocker<ReadWriteLock> lock(&table->sliceIndexLock[bucket]);
for (auto &info : table->sliceIndex[bucket]) {
if (UNLIKELY(objs.size() >= 1000U)) {
return BIO_OK;
}
if (info.first.find(prefix) == 0) {
auto sliceRef = info.second;
if (sliceRef->Aquire()) {
auto sliceLen = static_cast<uint32_t>(sliceRef->GetSlice()->GetLength());
listSliceVec.push_back(sliceRef);
LOG_DEBUG("Wcache list success, key:" << info.first << ", slice length:" << sliceLen
<< ", time:" << time(nullptr) << ".");
objs.insert({info.first, {sliceLen, time(nullptr)}});
}
}
}
}
for (const auto &slice : listSliceVec) {
slice->Release();
}
return BIO_OK;
}
BResult WCacheIndex::Delete(uint16_t ptId, const Key &key, WCacheSliceRefPtr sliceRef)
{
WCacheIndexTable *table = GetIndexTable(ptId);
ChkTrueNot(table != nullptr, BIO_ALLOC_FAIL);
auto bucket = Hash(key);
WriteLocker<ReadWriteLock> lock(&table->sliceIndexLock[bucket]);
auto iter = table->sliceIndex[bucket].find(key);
if (iter == table->sliceIndex[bucket].end()) {
LOG_DEBUG("Delete write cache key:" << key << " have not exist.");
return BIO_NOT_EXISTS;
}
if (iter->second != sliceRef) {
LOG_DEBUG("Expired slice, key:" << key);
return BIO_OK;
}
table->sliceIndex[bucket].erase(key);
LOG_DEBUG("Delete key:" << key << " success.");
return BIO_OK;
}
void WCacheIndex::ExpiredClear(uint16_t ptId)
{
WCacheIndexTable *table = GetIndexTable(ptId);
ChkTrueExNot(table != nullptr);
for (uint32_t bucket = 0; bucket < HASH_BUCKET_NUM; bucket++) {
WriteLocker<ReadWriteLock> lock(&table->sliceIndexLock[bucket]);
for (auto it = table->sliceIndex[bucket].begin(); it != table->sliceIndex[bucket].end();) {
if (it->second->GetSlice() == nullptr) {
LOG_DEBUG("Expired clear, ptId:" << ptId << ", key:" << it->first);
it = table->sliceIndex[bucket].erase(it);
} else {
++it;
}
}
}
return;
}
void WCacheIndex::Exit()
{
ReadLocker<ReadWriteLock> lock(&mTableLock);
for (auto iter = mTable.begin(); iter != mTable.end(); iter++) {
WCacheIndexTable *inTable = iter->second;
delete inTable;
}
mTable.clear();
}
WCacheIndexTable *WCacheIndex::GetIndexTable(uint16_t ptId)
{
{
ReadLocker<ReadWriteLock> lock(&mTableLock);
auto table = mTable.find(ptId);
if (table != mTable.end()) {
return table->second;
}
}
{
WriteLocker<ReadWriteLock> lock(&mTableLock);
auto table = mTable.find(ptId);
if (table != mTable.end()) {
return table->second;
}
WCacheIndexTable *inTable = nullptr;
BIO_TP_START(WCACHE_INDEX_TABLE_FAIL, &inTable, nullptr);
inTable = new (std::nothrow) WCacheIndexTable;
BIO_TP_END;
ChkTrue(inTable != nullptr, nullptr, "Alloc memory failed.");
mTable.insert(std::make_pair(ptId, inTable));
return mTable[ptId];
}
}
}
}