summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AK/InlineLRUCache.h70
-rw-r--r--Kernel/DiskBackedFileSystem.cpp51
-rw-r--r--Kernel/FileSystem.h3
3 files changed, 122 insertions, 2 deletions
diff --git a/AK/InlineLRUCache.h b/AK/InlineLRUCache.h
new file mode 100644
index 0000000000..bc3375808b
--- /dev/null
+++ b/AK/InlineLRUCache.h
@@ -0,0 +1,70 @@
+#pragma once
+
+#include <AK/HashMap.h>
+#include <AK/InlineLinkedList.h>
+
+namespace AK {
+
+template<typename K, typename V>
+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<V> m_entries;
+ HashMap<K, V*> m_map;
+ size_t m_capacity { 16 };
+};
+
+}
+
+using AK::InlineLRUCache;
diff --git a/Kernel/DiskBackedFileSystem.cpp b/Kernel/DiskBackedFileSystem.cpp
index e28f18d4e9..638a5b817d 100644
--- a/Kernel/DiskBackedFileSystem.cpp
+++ b/Kernel/DiskBackedFileSystem.cpp
@@ -1,8 +1,49 @@
#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))
{
@@ -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<DiskOffset>(index) * static_cast<DiskOffset>(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 eab654ac51..a6564b0de9 100644
--- a/Kernel/FileSystem.h
+++ b/Kernel/FileSystem.h
@@ -147,8 +147,7 @@ namespace AK {
template<>
struct Traits<InodeIdentifier> {
- // FIXME: This is a shitty hash.
- static unsigned hash(const InodeIdentifier& inode) { return Traits<unsigned>::hash(inode.fsid()) + Traits<unsigned>::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()); }
};