mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-11 17:00:37 +00:00
14c0f18de9
If a block is present in the cache, just overwrite the cached block.
140 lines
4.2 KiB
C++
140 lines
4.2 KiB
C++
#include "DiskBackedFileSystem.h"
|
|
#include "i386.h"
|
|
#include <AK/InlineLRUCache.h>
|
|
|
|
//#define DBFS_DEBUG
|
|
|
|
struct BlockIdentifier {
|
|
unsigned fsid { 0 };
|
|
unsigned index { 0 };
|
|
|
|
bool operator==(const BlockIdentifier& other) const { return fsid == other.fsid && index == other.index; }
|
|
};
|
|
|
|
namespace AK {
|
|
|
|
template<>
|
|
struct Traits<BlockIdentifier> {
|
|
static unsigned hash(const BlockIdentifier& block_id) { return pair_int_hash(block_id.fsid, block_id.index); }
|
|
static void dump(const BlockIdentifier& block_id) { kprintf("[block %02u:%08u]", block_id.fsid, block_id.index); }
|
|
};
|
|
|
|
}
|
|
|
|
class CachedBlock : public InlineLinkedListNode<CachedBlock> {
|
|
public:
|
|
CachedBlock(const BlockIdentifier& block_id, const ByteBuffer& buffer)
|
|
: m_key(block_id)
|
|
, m_buffer(buffer)
|
|
{
|
|
}
|
|
|
|
BlockIdentifier m_key;
|
|
CachedBlock* m_next { nullptr };
|
|
CachedBlock* m_prev { nullptr };
|
|
|
|
ByteBuffer m_buffer;
|
|
};
|
|
|
|
Lockable<InlineLRUCache<BlockIdentifier, CachedBlock>>& block_cache()
|
|
{
|
|
static Lockable<InlineLRUCache<BlockIdentifier, CachedBlock>>* s_cache;
|
|
if (!s_cache)
|
|
s_cache = new Lockable<InlineLRUCache<BlockIdentifier, CachedBlock>>;
|
|
return *s_cache;
|
|
}
|
|
|
|
DiskBackedFS::DiskBackedFS(RetainPtr<DiskDevice>&& device)
|
|
: m_device(move(device))
|
|
{
|
|
ASSERT(m_device);
|
|
}
|
|
|
|
DiskBackedFS::~DiskBackedFS()
|
|
{
|
|
}
|
|
|
|
bool DiskBackedFS::write_block(unsigned index, const ByteBuffer& data)
|
|
{
|
|
#ifdef DBFS_DEBUG
|
|
kprintf("DiskBackedFileSystem::write_block %u, size=%u\n", index, data.size());
|
|
#endif
|
|
ASSERT(data.size() == block_size());
|
|
|
|
{
|
|
LOCKER(block_cache().lock());
|
|
if (auto* cached_block = block_cache().resource().get({ fsid(), index }))
|
|
cached_block->m_buffer = data;
|
|
}
|
|
DiskOffset base_offset = static_cast<DiskOffset>(index) * static_cast<DiskOffset>(block_size());
|
|
return device().write(base_offset, block_size(), data.pointer());
|
|
}
|
|
|
|
bool DiskBackedFS::write_blocks(unsigned index, unsigned count, const ByteBuffer& data)
|
|
{
|
|
#ifdef DBFS_DEBUG
|
|
kprintf("DiskBackedFileSystem::write_blocks %u x%u\n", index, count);
|
|
#endif
|
|
// FIXME: Maybe reorder this so we send out the write commands before updating cache?
|
|
{
|
|
LOCKER(block_cache().lock());
|
|
for (unsigned i = 0; i < count; ++i) {
|
|
if (auto* cached_block = block_cache().resource().get({ fsid(), index + i }))
|
|
cached_block->m_buffer = data.slice(i * block_size(), block_size());
|
|
}
|
|
}
|
|
DiskOffset base_offset = static_cast<DiskOffset>(index) * static_cast<DiskOffset>(block_size());
|
|
return device().write(base_offset, count * block_size(), data.pointer());
|
|
}
|
|
|
|
ByteBuffer DiskBackedFS::read_block(unsigned index) const
|
|
{
|
|
#ifdef DBFS_DEBUG
|
|
kprintf("DiskBackedFileSystem::read_block %u\n", index);
|
|
#endif
|
|
{
|
|
LOCKER(block_cache().lock());
|
|
if (auto* cached_block = block_cache().resource().get({ fsid(), index }))
|
|
return cached_block->m_buffer;
|
|
}
|
|
|
|
auto buffer = ByteBuffer::create_uninitialized(block_size());
|
|
//kprintf("created block buffer with size %u\n", block_size());
|
|
DiskOffset base_offset = static_cast<DiskOffset>(index) * static_cast<DiskOffset>(block_size());
|
|
auto* buffer_pointer = buffer.pointer();
|
|
bool success = device().read(base_offset, block_size(), buffer_pointer);
|
|
ASSERT(success);
|
|
ASSERT(buffer.size() == block_size());
|
|
{
|
|
LOCKER(block_cache().lock());
|
|
block_cache().resource().put({ fsid(), index }, CachedBlock({ fsid(), index }, buffer));
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
ByteBuffer DiskBackedFS::read_blocks(unsigned index, unsigned count) const
|
|
{
|
|
if (!count)
|
|
return nullptr;
|
|
if (count == 1)
|
|
return read_block(index);
|
|
auto blocks = ByteBuffer::create_uninitialized(count * block_size());
|
|
byte* out = blocks.pointer();
|
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
|
auto block = read_block(index + i);
|
|
if (!block)
|
|
return nullptr;
|
|
memcpy(out, block.pointer(), block.size());
|
|
out += block_size();
|
|
}
|
|
|
|
return blocks;
|
|
}
|
|
|
|
void DiskBackedFS::set_block_size(unsigned block_size)
|
|
{
|
|
if (block_size == m_block_size)
|
|
return;
|
|
m_block_size = block_size;
|
|
}
|