Second Extended Filesystem (ext2) and other improvements (#33)
[lunaix-os.git] / lunaix-os / includes / lunaix / bcache.h
diff --git a/lunaix-os/includes/lunaix/bcache.h b/lunaix-os/includes/lunaix/bcache.h
new file mode 100644 (file)
index 0000000..ce03494
--- /dev/null
@@ -0,0 +1,179 @@
+#ifndef __LUNAIX_BCACHE_H
+#define __LUNAIX_BCACHE_H
+
+#include <lunaix/ds/btrie.h>
+#include <lunaix/ds/lru.h>
+#include <lunaix/ds/spinlock.h>
+#include <lunaix/ds/llist.h>
+#include <lunaix/spike.h>
+
+/*
+   Block cache. A cache built on top of
+   sparse array (trie tree) allow caching
+   any blocks that have spatial structure
+   attach to them. With intention to unify
+   all the existing caching construct, as
+   well as potential future use case.
+   
+   NB. block is not necessarily
+   equivalence to disk sector nor filesystem 
+   logical block. block can be anything 
+   discrete.
+
+   NB2. not to be confused with page cahce
+   (pcache), which is a special case of
+   bcache.
+*/
+
+struct bcache;
+struct bcache_ops
+{
+    void (*release_on_evict)(struct bcache*, void* data);
+    void (*sync_cached)(struct bcache*, unsigned long tag, void* data);
+};
+
+struct bcache
+{
+    struct {
+        unsigned int blksz;
+    };
+    
+    struct btrie root;
+    struct lru_zone* lru;
+    struct bcache_ops ops;
+    struct llist_header objs;
+    struct spinlock lock;
+};  // block cache
+
+struct bcache_node
+{
+    void* data;
+
+    unsigned long tag;
+    
+    struct bcache* holder;
+    unsigned int refs;
+    struct lru_node lru_node;
+    struct llist_header objs;
+};
+
+typedef void * bcobj_t;
+typedef struct lru_zone* bcache_zone_t;
+
+static inline void*
+bcached_data(bcobj_t obj)
+{
+    return ((struct bcache_node*)obj)->data;
+}
+
+#define to_bcache_node(cobj) \
+    ((struct bcache_node*)(cobj))
+
+#define bcache_holder_embed(cobj, type, member)   \
+    container_of(to_bcache_node(cobj)->holder, type, member)
+
+/**
+ * @brief Create a block cache with shared bcache zone
+ * 
+ * @param cache to be initialized
+ * @param name name of this cache
+ * @param log_ways ways-associative of this cache
+ * @param cap capacity of this cache, -1 for 'infinity' cache
+ * @param blk_size size of each cached object
+ * @param ops block cache operation
+ */
+void
+bcache_init_zone(struct bcache* cache, bcache_zone_t zone, 
+                 unsigned int log_ways, int cap, 
+                 unsigned int blk_size, struct bcache_ops* ops);
+
+bcache_zone_t
+bcache_create_zone(char* name);
+
+bcobj_t
+bcache_put_and_ref(struct bcache* cache, unsigned long tag, void* block);
+
+/**
+ * @brief Try look for a hit and return the reference to block.
+ * Now, this create a unmanaged pointer that could end up in
+ * everywhere and unsafe to evict. One should called `bcache_tryhit_unref`
+ * when the reference is no longer needed.
+ * 
+ * @param cache 
+ * @param tag 
+ * @param block_out 
+ * @return true 
+ * @return false 
+ */
+bool
+bcache_tryget(struct bcache* cache, unsigned long tag, bcobj_t* result);
+
+/**
+ * @brief Unreference a cached block that is returned 
+ * by `bcache_tryhit_ref`
+ * 
+ * @param cache 
+ * @param tag 
+ * @param block_out 
+ * @return true 
+ * @return false 
+ */
+void
+bcache_return(bcobj_t obj);
+
+static inline void
+bcache_refonce(bcobj_t obj)
+{
+    struct bcache_node* b_node;
+    b_node = to_bcache_node(obj);
+
+    assert(b_node->refs);
+    b_node->refs++;
+}
+
+void
+bcache_promote(bcobj_t obj);
+
+void
+bcache_evict(struct bcache* cache, unsigned long tag);
+
+static inline void
+bcache_evict_one(struct bcache* cache)
+{
+    lru_evict_one(cache->lru);
+}
+
+void
+bcache_flush(struct bcache* cache);
+
+void
+bcache_free(struct bcache* cache);
+
+void
+bcache_zone_free(bcache_zone_t zone);
+
+/**
+ * @brief Create a block cache
+ * 
+ * @param cache to be initialized
+ * @param name name of this cache
+ * @param log_ways ways-associative of this cache
+ * @param cap capacity of this cache, -1 for 'infinity' cache
+ * @param blk_size size of each cached object
+ * @param ops block cache operation
+ */
+static inline void
+bcache_init(struct bcache* cache, char* name, unsigned int log_ways, 
+            int cap, unsigned int blk_size, struct bcache_ops* ops)
+{
+    bcache_init_zone(cache, bcache_create_zone(name), 
+                     log_ways, cap, blk_size, ops);
+}
+
+static inline void
+bcache_put(struct bcache* cache, unsigned long tag, void* block)
+{
+    bcache_return(bcache_put_and_ref(cache, tag, block));
+}
+
+#endif /* __LUNAIX_BCACHE_H */