cachelib/navy/block_cache/Region.cpp (121 lines of code) (raw):

/* * Copyright (c) Facebook, Inc. and its affiliates. * * 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 "cachelib/navy/block_cache/Region.h" namespace facebook { namespace cachelib { namespace navy { bool Region::readyForReclaim() { std::lock_guard<std::mutex> l{lock_}; flags_ |= kBlockAccess; return activeOpenLocked() == 0; } uint32_t Region::activeOpenLocked() { return activePhysReaders_ + activeInMemReaders_ + activeWriters_; } std::tuple<RegionDescriptor, RelAddress> Region::openAndAllocate( uint32_t size) { std::lock_guard<std::mutex> l{lock_}; XDCHECK(!(flags_ & kBlockAccess)); if (!canAllocateLocked(size)) { return std::make_tuple(RegionDescriptor{OpenStatus::Error}, RelAddress{}); } activeWriters_++; return std::make_tuple( RegionDescriptor::makeWriteDescriptor(OpenStatus::Ready, regionId_), allocateLocked(size)); } RegionDescriptor Region::openForRead() { std::lock_guard<std::mutex> l{lock_}; if (flags_ & kBlockAccess) { // Region is currently in reclaim, retry later return RegionDescriptor{OpenStatus::Retry}; } bool physReadMode = false; if (isFlushedLocked() || !buffer_) { physReadMode = true; activePhysReaders_++; } else { activeInMemReaders_++; } return RegionDescriptor::makeReadDescriptor( OpenStatus::Ready, regionId_, physReadMode); } // This function flushes the attached buffer if there are no active writers // by calling the callBack function that is expected to write the buffer to // underlying device. If there are active writers, the caller is expected // to call this function again. Region::FlushRes Region::flushBuffer( std::function<bool(RelAddress, BufferView)> callBack) { std::unique_lock<std::mutex> lock{lock_}; if (activeWriters_ != 0) { return FlushRes::kRetryPendingWrites; } if (!isFlushedLocked()) { lock.unlock(); if (callBack(RelAddress{regionId_, 0}, buffer_->view())) { lock.lock(); flags_ |= kFlushed; return FlushRes::kSuccess; } return FlushRes::kRetryDeviceFailure; } return FlushRes::kSuccess; } bool Region::cleanupBuffer(std::function<void(RegionId, BufferView)> callBack) { std::unique_lock<std::mutex> lock{lock_}; if (activeWriters_ != 0) { return false; } if (!isCleanedupLocked()) { lock.unlock(); callBack(regionId_, buffer_->view()); lock.lock(); flags_ |= kCleanedup; } return true; } void Region::reset() { std::lock_guard<std::mutex> l{lock_}; XDCHECK_EQ(activeOpenLocked(), 0U); priority_ = 0; flags_ = 0; activeWriters_ = 0; activePhysReaders_ = 0; activeInMemReaders_ = 0; lastEntryEndOffset_ = 0; numItems_ = 0; } void Region::close(RegionDescriptor&& desc) { std::lock_guard<std::mutex> l{lock_}; switch (desc.mode()) { case OpenMode::Write: activeWriters_--; break; case OpenMode::Read: if (desc.isPhysReadMode()) { activePhysReaders_--; } else { activeInMemReaders_--; } break; default: XDCHECK(false); } } RelAddress Region::allocateLocked(uint32_t size) { XDCHECK(canAllocateLocked(size)); auto offset = lastEntryEndOffset_; lastEntryEndOffset_ += size; numItems_++; return RelAddress{regionId_, offset}; } void Region::writeToBuffer(uint32_t offset, BufferView buf) { std::lock_guard l{lock_}; XDCHECK_NE(buffer_, nullptr); auto size = buf.size(); XDCHECK_LE(offset + size, buffer_->size()); memcpy(buffer_->data() + offset, buf.data(), size); } void Region::readFromBuffer(uint32_t fromOffset, MutableBufferView outBuf) const { std::lock_guard l{lock_}; XDCHECK_NE(buffer_, nullptr); XDCHECK_LE(fromOffset + outBuf.size(), buffer_->size()); memcpy(outBuf.data(), buffer_->data() + fromOffset, outBuf.size()); } } // namespace navy } // namespace cachelib } // namespace facebook