blob: 100a42633ec28fe6535492bc2d762ece6bf15b9e [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_STORAGE_F2FS_STORAGE_BUFFER_H_
#define SRC_STORAGE_F2FS_STORAGE_BUFFER_H_
#include <condition_variable>
#include <storage/buffer/vmo_buffer.h>
#include "src/storage/f2fs/layout.h"
namespace f2fs {
class BcacheMapper;
// StorageBuffer implements an allocator for vmo buffers attached to |bc|.
class StorageBuffer {
public:
explicit StorageBuffer(BcacheMapper *bc, size_t num_pages, std::string_view label);
StorageBuffer() = delete;
StorageBuffer(const StorageBuffer &) = delete;
StorageBuffer &operator=(const StorageBuffer &) = delete;
StorageBuffer(StorageBuffer &&) = delete;
StorageBuffer &operator=(StorageBuffer &&) = delete;
~StorageBuffer() = default;
zx::result<size_t> Reserve(size_t num_blocks = 1);
void *Data(const size_t offset);
storage::VmoBuffer &GetVmoBuffer() { return buffer_; }
size_t Size() const { return current_index_; }
size_t Capacity() const { return allocated_blocks_; }
bool IsFull() const { return current_index_ >= allocated_blocks_; }
void Reset() { current_index_ = 0; }
private:
const size_t allocated_blocks_;
size_t current_index_;
storage::VmoBuffer buffer_;
};
using ReleaseBuffer = fit::function<void(std::unique_ptr<StorageBuffer>)>;
// A wrapper class for users of StorageBuffer.
// It owns |buffer_| exclusively, and transfers its ownership to |release_| on destructor.
class OwnedStorageBuffer {
public:
explicit OwnedStorageBuffer(std::unique_ptr<StorageBuffer> buffer, ReleaseBuffer cb) {
ZX_ASSERT(buffer);
ZX_ASSERT(cb);
buffer_ = std::move(buffer);
buffer_->Reset();
release_ = std::move(cb);
}
~OwnedStorageBuffer() { release_(std::move(buffer_)); }
StorageBuffer *operator->() const { return buffer_.get(); }
private:
std::unique_ptr<StorageBuffer> buffer_;
ReleaseBuffer release_ = nullptr;
};
class StorageBufferPool {
public:
explicit StorageBufferPool(BcacheMapper *bcache_mapper, size_t default_size = kMaxReadaheadSize,
size_t large_size = kDefaultBlocksPerSegment,
int num_pager_threads = 1);
~StorageBufferPool();
OwnedStorageBuffer Get(size_t size) __TA_EXCLUDES(mutex_);
BcacheMapper *Block() { return bcache_mapper_; }
// for tests
size_t GetLargeBufferSize() const { return large_buffer_size_; }
private:
std::vector<std::unique_ptr<StorageBuffer>> &buffers(size_t size) __TA_REQUIRES(mutex_) {
if (size <= buffer_size_) {
return buffers_;
}
return large_buffers_;
}
// Every user should transfer the ownership of borrowed buffers to this method after use.
void Return(std::unique_ptr<StorageBuffer> buffer);
std::unique_ptr<StorageBuffer> Retrieve(size_t size) __TA_REQUIRES(mutex_);
const size_t buffer_size_;
const size_t large_buffer_size_;
const size_t num_buffers_;
std::vector<std::unique_ptr<StorageBuffer>> large_buffers_ __TA_GUARDED(mutex_);
std::vector<std::unique_ptr<StorageBuffer>> buffers_ __TA_GUARDED(mutex_);
BcacheMapper *const bcache_mapper_ = nullptr;
std::mutex mutex_;
std::condition_variable_any var_ __TA_GUARDED(mutex_);
std::unique_ptr<StorageBuffer> pool_ __TA_GUARDED(mutex_);
};
} // namespace f2fs
#endif // SRC_STORAGE_F2FS_STORAGE_BUFFER_H_