* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "common_components/common/page_cache.h"
namespace common {
PageCache PageCache::instance_;
std::mutex& PageCache::GetPageMutex() { return pageMtx_; }
Span* PageCache::NewSpan(size_t k)
{
CHECK_CC(k > 0 && k < MAX_NPAGES);
if (!pageCacheSpans_[k].Empty()) {
Span* kSpan = pageCacheSpans_[k].PopFront();
for (size_t i = 0; i < kSpan->pageNum; ++i) {
idSpanMap_[kSpan->pageId + i] = kSpan;
}
return kSpan;
}
for (size_t n = k + 1; n < MAX_NPAGES; ++n) {
if (!pageCacheSpans_[n].Empty()) {
Span* kSpan = new Span();
Span* nSpan = pageCacheSpans_[n].PopFront();
kSpan->pageNum = k;
kSpan->pageId = nSpan->pageId;
nSpan->pageNum -= k;
nSpan->pageId += k;
pageCacheSpans_[nSpan->pageNum].PushFront(nSpan);
for (size_t i = 0; i < kSpan->pageNum; ++i) {
idSpanMap_[kSpan->pageId + i] = kSpan;
}
return kSpan;
}
}
Span* bigSpan = new Span;
void* ptr = SystemAlloc(MAX_NPAGES - 1);
bigSpan->pageNum = MAX_NPAGES - 1;
bigSpan->pageId = reinterpret_cast<pageID>(ptr) >> PAGE_SHIFT;
pageCacheSpans_[MAX_NPAGES - 1].PushFront(bigSpan);
return NewSpan(k);
}
Span* PageCache::MapObjectToSpan(void* obj)
{
CHECK_CC(obj != nullptr);
ScopedPageCacheMutex mtx;
pageID id = (reinterpret_cast<pageID>(obj) >> PAGE_SHIFT);
auto ret = idSpanMap_.find(id);
if (ret != idSpanMap_.end()) {
return ret->second;
} else {
LOGF_CHECK(false) << "MapObjectToSpan false";
return nullptr;
}
}
void PageCache::ReleaseSpanToPageCache(Span* span)
{
ScopedPageCacheMutex mtx;
while (1) {
pageID prevId = span->pageId - 1;
auto ret = idSpanMap_.find(prevId);
if (ret == idSpanMap_.end()) {
break;
}
Span* prevSpan = ret->second;
if (prevSpan->isUse) {
break;
}
if (prevSpan->pageNum + span->pageNum > MAX_NPAGES - 1) {
break;
}
span->pageNum += prevSpan->pageNum;
span->pageId = prevSpan->pageId;
pageCacheSpans_[prevSpan->pageNum].Erase(prevSpan);
delete prevSpan;
}
while (1) {
pageID nextId = span->pageId + span->pageNum;
auto ret = idSpanMap_.find(nextId);
if (ret == idSpanMap_.end()) {
break;
}
Span* nextSpan = ret->second;
if (nextSpan->isUse) {
break;
}
if (span->pageNum + nextSpan->pageNum > MAX_NPAGES - 1) {
break;
}
span->pageNum += nextSpan->pageNum;
pageCacheSpans_[nextSpan->pageNum].Erase(nextSpan);
delete nextSpan;
}
pageCacheSpans_[span->pageNum].PushFront(span);
span->isUse = false;
for (size_t i = 0; i < span->pageNum; ++i) {
idSpanMap_[span->pageId + i] = span;
}
}
}