blob: 8dcd31eebd484b6d549f6ef5e8a5b79b79367e9c [file] [log] [blame] [edit]
// Copyright 2020 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_MINFS_LAZY_BUFFER_H_
#define SRC_STORAGE_MINFS_LAZY_BUFFER_H_
#include "src/storage/minfs/bcache.h"
#include "src/storage/minfs/buffer_view.h"
#include "src/storage/minfs/lazy_reader.h"
#include "src/storage/minfs/resizeable_buffer.h"
namespace minfs {
// A lazy buffer wraps a buffer with a lazy reader so that blocks in the buffer can be lazily
// read.
class LazyBuffer {
public:
// A callback responsible for writing the |range| blocks in buffer to |device_block|.
using Writer = fit::function<zx_status_t(ResizeableBufferType* buffer, BlockRange range,
DeviceBlock device_block)>;
class Reader : public MappedFileReader {
public:
Reader(Bcache* bcache, MapperInterface* mapper, LazyBuffer* buffer)
: MappedFileReader(bcache, mapper, &buffer->buffer()) {}
};
// Create an instance of LazyBuffer.
[[nodiscard]] static zx::status<std::unique_ptr<LazyBuffer>> Create(Bcache* bcache,
const char* name,
uint32_t block_size);
LazyBuffer(const LazyBuffer&) = delete;
LazyBuffer& operator=(const LazyBuffer&) = delete;
// Returns the size of the buffer in bytes.
size_t size() const { return buffer_.capacity() * buffer_.BlockSize(); }
ResizeableBufferType& buffer() { return buffer_; }
// Users must call Detach before destruction.
zx_status_t Detach(Bcache* bcache) { return buffer_.Detach(bcache); }
[[nodiscard]] zx_status_t Grow(size_t block_count) { return buffer_.Grow(block_count); }
// Shrink the buffer. Does nothing if buffer is smaller.
void Shrink(size_t block_count);
// Iterates through all the blocks in the view, maps from file offset to device offset using
// |mapper| and then calls |writer| to actually write the data to the backing store.
[[nodiscard]] zx_status_t Flush(PendingWork* transaction, MapperInterface* mapper,
BaseBufferView* view, const Writer& writer);
// Returns a read/write view for the given range. |flusher| will be called by the view if
// modified. Implementations should call the Flush method above to flush the buffer, which
// will do the mappings for you. For example:
//
// BufferView<uint64_t> view;
// status = buffer->GetView(
// offset, count, &reader,
// [buffer, transaction](BaseBufferView* view) {
// Mapper mapper;
// return buffer->Flush(transaction, &mapper, view, writer);
// }, &view);
//
template <typename T>
[[nodiscard]] zx::status<BufferView<T>> GetView(size_t index, size_t count, Reader* reader,
BaseBufferView::Flusher flusher) {
const size_t offset = index * sizeof(T);
zx_status_t status = Read(ByteRange(offset, offset + count * sizeof(T)), reader);
if (status != ZX_OK)
return zx::error(status);
return zx::ok(
BufferView<T>(BufferPtr::FromBlockBuffer(&buffer_), index, count, std::move(flusher)));
}
// Returns a read only view for the given range.
template <typename T>
[[nodiscard]] zx::status<BufferView<T>> GetView(size_t index, size_t count, Reader* reader) {
return GetView<T>(index, count, reader, nullptr);
}
private:
LazyBuffer(uint32_t block_size) : buffer_(block_size) {}
// Calls lazy_reader_ to read |range| bytes (if not already present).
zx_status_t Read(ByteRange range, Reader* reader);
LazyReader lazy_reader_;
ResizeableBufferType buffer_;
};
} // namespace minfs
#endif // SRC_STORAGE_MINFS_LAZY_BUFFER_H_