/* * 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_; } // Get a Span of a k-page. Span* PageCache::NewSpan(size_t k) { CHECK_CC(k > 0 && k < MAX_NPAGES); // 1. Check if the corresponding SpanList bucket contains a Span based on direct addressing using k. 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; } // 2. find bigger bucket 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; } } // 3. No suitable Span is available; allocate a 128KB Span. Span* bigSpan = new Span; void* ptr = SystemAlloc(MAX_NPAGES - 1); bigSpan->pageNum = MAX_NPAGES - 1; bigSpan->pageId = reinterpret_cast(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(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; // Merge copy 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; } // Merge backward 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; } // Hang the merged Span into the bucket. // Update the mapping relationship. pageCacheSpans_[span->pageNum].PushFront(span); span->isUse = false; for (size_t i = 0; i < span->pageNum; ++i) { idSpanMap_[span->pageId + i] = span; } } } // namespace common