diff --git a/AK/InlineLRUCache.h b/AK/InlineLRUCache.h new file mode 100644 index 00000000000..bc3375808b8 --- /dev/null +++ b/AK/InlineLRUCache.h @@ -0,0 +1,70 @@ +#pragma once + +#include +#include + +namespace AK { + +template +class InlineLRUCache { +public: + ~InlineLRUCache() + { + while (size()) + remove_last(); + } + + size_t size() const { return m_map.size(); } + size_t capacity() const { return m_capacity; } + + void set_capacity(size_t capacity) + { + if (capacity == m_capacity) + return; + m_capacity = capacity; + while (size() >= capacity) + remove_last(); + } + + V* get(const K& key) + { + auto it = m_map.find(key); + if (it == m_map.end()) + return nullptr; + V* entry = (*it).value; + m_entries.remove(entry); + m_entries.prepend(entry); + return entry; + } + + void put(K&& key, V&& value) + { + auto it = m_map.find(key); + if (it != m_map.end()) + return; + V* new_entry = new V(move(value)); + m_entries.prepend(new_entry); + m_map.set(key, new_entry); + + while (size() >= capacity()) + remove_last(); + } + +private: + void remove_last() + { + V* entry = m_entries.tail(); + ASSERT(entry); + m_entries.remove(entry); + m_map.remove(entry->m_key); + delete entry; + } + + InlineLinkedList m_entries; + HashMap m_map; + size_t m_capacity { 16 }; +}; + +} + +using AK::InlineLRUCache; diff --git a/Kernel/DiskBackedFileSystem.cpp b/Kernel/DiskBackedFileSystem.cpp index e28f18d4e90..638a5b817d7 100644 --- a/Kernel/DiskBackedFileSystem.cpp +++ b/Kernel/DiskBackedFileSystem.cpp @@ -1,8 +1,49 @@ #include "DiskBackedFileSystem.h" #include "i386.h" +#include //#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 { + 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 { +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>& block_cache() +{ + static Lockable>* s_cache; + if (!s_cache) + s_cache = new Lockable>; + return *s_cache; +} + DiskBackedFS::DiskBackedFS(RetainPtr&& device) : m_device(move(device)) { @@ -37,6 +78,12 @@ 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(index) * static_cast(block_size()); @@ -44,6 +91,10 @@ ByteBuffer DiskBackedFS::read_block(unsigned index) const 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; } diff --git a/Kernel/FileSystem.h b/Kernel/FileSystem.h index eab654ac51b..a6564b0de9c 100644 --- a/Kernel/FileSystem.h +++ b/Kernel/FileSystem.h @@ -147,8 +147,7 @@ namespace AK { template<> struct Traits { - // FIXME: This is a shitty hash. - static unsigned hash(const InodeIdentifier& inode) { return Traits::hash(inode.fsid()) + Traits::hash(inode.index()); } + static unsigned hash(const InodeIdentifier& inode) { return pair_int_hash(inode.fsid(), inode.index()); } static void dump(const InodeIdentifier& inode) { kprintf("%02u:%08u", inode.fsid(), inode.index()); } };