From e7786281859d5d76a51619784700aae56742b25f Mon Sep 17 00:00:00 2001 From: Ludovic 'Archivist' Lagouardette Date: Mon, 14 Sep 2020 22:35:42 +0200 Subject: [PATCH] Basic tests for tagfs --- include/gp/pair.hpp | 30 +-- include/gp/tagfs/tagfs.hpp | 384 +++++++++++++++++++------------------ tests.cpp | 1 + tests/tagfs_test.cpp | 23 +++ 4 files changed, 243 insertions(+), 195 deletions(-) create mode 100644 tests/tagfs_test.cpp diff --git a/include/gp/pair.hpp b/include/gp/pair.hpp index 341063f..f6f09cd 100644 --- a/include/gp/pair.hpp +++ b/include/gp/pair.hpp @@ -8,28 +8,34 @@ namespace gp{ T1 first; T2 second; - pair() : first(), second() {} + constexpr pair() + : first() + , second() + {} - pair(const T1& a, const T2& b) : first(a), second(b) {} + constexpr pair(const T1& a, const T2& b) + : first(a) + , second(b) + {} - pair(pair&& v) + constexpr pair(pair&& v) : first(gp::move(v.first)) , second(gp::move(v.second)) {} template - pair(U1&& a, U2&& b) + constexpr pair(U1&& a, U2&& b) : first(gp::forward(a)) , second(gp::forward(b)) {} template - pair(pair&& v) + constexpr pair(pair&& v) : first(gp::move(v.first)) , second(gp::move(v.second)) {} - pair& operator=(pair&& v) + constexpr pair& operator=(pair&& v) { first = gp::move(v.first); second = gp::move(v.second); @@ -38,17 +44,17 @@ namespace gp{ }; template - bool operator==(const pair& lhs, const pair& rhs) { + constexpr bool operator==(const pair& lhs, const pair& rhs) { return lhs.first == rhs.first and lhs.second == rhs.second; } template - bool operator!=(const pair& lhs, const pair& rhs) { + constexpr bool operator!=(const pair& lhs, const pair& rhs) { return lhs.first != rhs.first or lhs.second != rhs.second; } template - bool operator<=(const pair& lhs, const pair& rhs) { + constexpr bool operator<=(const pair& lhs, const pair& rhs) { if(lhs.first > rhs.first) { return false; } else if(lhs.first == rhs.first) { @@ -58,7 +64,7 @@ namespace gp{ } template - bool operator>=(const pair& lhs, const pair& rhs) { + constexpr bool operator>=(const pair& lhs, const pair& rhs) { if(lhs.first < rhs.first) { return false; } else if(lhs.first == rhs.first) { @@ -68,12 +74,12 @@ namespace gp{ } template - bool operator<(const pair& lhs, const pair& rhs) { + constexpr bool operator<(const pair& lhs, const pair& rhs) { return !(lhs >= rhs); } template - bool operator>(const pair& lhs, const pair& rhs) { + constexpr bool operator>(const pair& lhs, const pair& rhs) { return !(lhs <= rhs); } } \ No newline at end of file diff --git a/include/gp/tagfs/tagfs.hpp b/include/gp/tagfs/tagfs.hpp index bf80b23..6831b05 100644 --- a/include/gp/tagfs/tagfs.hpp +++ b/include/gp/tagfs/tagfs.hpp @@ -2,209 +2,227 @@ #include "gp/array.hpp" #include "gp/algorithm/min_max.hpp" +#include "gp/algorithm/modifiers.hpp" #include "gp/algorithm/repeat.hpp" #include "gp/bitops.hpp" #include "gp/buffer.hpp" -#include "gp/pointers.hpp" +#include "gp/pair.hpp" #include #include -template -class memory_vdisk { - static_assert(sz%128 == 0, "in memory disk expects 128 bytes page alignment"); - alignas(128) gp::array data; - - gp::buffer read(gp::buffer buffer, uint64_t offset) { - auto it = data.begin()+offset; - auto ret = buffer; - for(auto& c : buffer) { - c = *(it++); - if(it == data.end()) { - ret = buffer.slice_start(it - (data.begin() + offset)); - break; +namespace gp { + template + class memory_vdisk { + static_assert(sz%128 == 0, "in memory disk expects 128 bytes page alignment"); + alignas(128) gp::array data; + + public: + gp::buffer read(gp::buffer buffer, uint64_t offset) { + auto it = data.begin()+offset; + auto ret = buffer; + for(auto& c : buffer) { + c = *(it++); + if(it == data.end()) { + ret = buffer.slice_start(it - (data.begin() + offset)); + break; + } } + return ret; } - return ret; - } - - gp::buffer write(gp::buffer buffer, uint64_t offset) { - auto it = data.begin()+offset; - auto ret = buffer; - for(auto& c : buffer) { - *(it++) = c; - if(it == data.end()) { - ret = buffer.slice_start(it - (data.begin() + offset)); - break; + + gp::buffer write(gp::buffer buffer, uint64_t offset) { + auto it = data.begin()+offset; + auto ret = buffer; + for(auto& c : buffer) { + *(it++) = c; + if(it == data.end()) { + ret = buffer.slice_start(it - (data.begin() + offset)); + break; + } } + return ret; } - return ret; - } - - constexpr uint64_t size() const noexcept { - return sz; - } - - static constexpr size_t page_size() noexcept { - return 128; - } - - constexpr uint64_t page_count() const noexcept { - return size() / page_size(); - } -}; - -template -class tagfs { - vdisk_ptr disk; - const gp::array empty_page; - - struct disk_root { - gp::endian_wrapper magic; - gp::endian_wrapper first_allocator_page; - gp::endian_wrapper allocator_shuttle; - gp::endian_wrapper allocator_page_count; - gp::endian_wrapper tag_list_node; - gp::endian_wrapper page_count; - }; - struct file_description { - gp::endian_wrapper reference_counter; + constexpr uint64_t size() const noexcept { + return sz; + } + + static constexpr size_t page_size() noexcept { + return 128; + } + + constexpr uint64_t page_count() const noexcept { + return size() / page_size(); + } }; - tagfs(vdisk_ptr&& _disk) - : disk(gp::forward(disk)) - , empty_page{[](){return 0;}} - {} - - disk_root get_disk_root() { - gp::array vret; - return *disk->read(vret.as_buffer().template cast(), 0).template cast().begin(); - } - - void set_disk_root(disk_root& root) { - gp::array vpar{root}; - disk->write(vpar.as_buffer().template cast(), 0); - } - - gp::optional try_set_bit(gp::buffer page) { - uint64_t idx = 0; - for(auto& elem : page) { - if(elem != 0xff) { - uint8_t copy = elem; - uint8_t setter = 1; - gp::repeat(8, [&](){ - bool value = copy & 1; - if(!value) { - return; - } - copy >>= 1; - setter <<= 1; - ++idx; - }); - elem |= setter; - return idx; - } - idx += 8; + template + class tagfs { + vdisk_ptr disk; + constexpr static size_t page_size = gp::remove_reference::type::page_size(); + const gp::array empty_page; + + + + struct disk_root { + gp::endian_wrapper magic; + gp::endian_wrapper first_allocator_page; + gp::endian_wrapper allocator_shuttle; + gp::endian_wrapper allocator_page_count; + gp::endian_wrapper tag_list_node; + gp::endian_wrapper page_count; + }; + + struct file_description { + gp::endian_wrapper reference_counter; + }; + + public: + tagfs(vdisk_ptr&& _disk) + : disk(gp::forward(disk)) + , empty_page{[](){return 0;}} + {} + + private: + disk_root get_disk_root() { + gp::array vret; + return *disk->read(vret.as_buffer().template cast(), 0).template cast().begin(); } - return gp::nullopt; - } - - uint64_t next_shuttle_page(disk_root root, uint64_t shuttle) { - return - shuttle + 1 == root.first_allocator_page + root.allocator_page_count ? - root.first_allocator_page - : shuttle + 1; - } - - bool try_unset_bit(gp::buffer page, uint64_t idx) { - uint8_t& target_byte = *(page.begin()+(idx/8)); - uint8_t flipper = 1 << (idx%8); - if(target_byte & flipper) { - target_byte ^= flipper; - return true; + + void set_disk_root(disk_root& root) { + gp::array vpar{root}; + disk->write(vpar.as_buffer().template cast(), 0); } - return false; - } - - uint64_t allocate_page() { - disk_root root = get_disk_root(); - uint64_t begin_page = root.first_allocator_page; - uint64_t shuttle_page = root.allocator_shuttle; - uint64_t end_page = root.first_allocator_page + root.allocator_page_count; - gp::array page_contents; - - gp::optional page; - do - { - auto allocator_page = disk->read(page_contents.as_buffer(), shuttle_page*decltype(*disk)::page_size()); - if(shuttle_page == end_page - 1) { - uint64_t existing_pages = root.page_count - end_page; - uint64_t allocable_pages = root.allocator_page_count*8*decltype(*disk)::page_size(); - if(existing_pages < allocable_pages) { - uint64_t extra = allocable_pages - existing_pages; - extra /= 8; - allocator_page = allocator_page.slice_start(decltype(*disk)::page_size() - extra); + + gp::optional try_set_bit(gp::buffer page) { + uint64_t idx = 0; + for(auto& elem : page) { + if(elem != 0xff) { + uint8_t copy = elem; + uint8_t setter = 1; + gp::repeat(8, [&](){ + bool value = copy & 1; + if(!value) { + return; + } + copy >>= 1; + setter <<= 1; + ++idx; + }); + elem |= setter; + return idx; } + idx += 8; } - page = try_set_bit(allocator_page); - if(!page.has_value()) { - root.allocator_shuttle = (shuttle_page = next_shuttle_page(shuttle_page)); - } else { - disk->write(page_contents.as_buffer(), shuttle_page*decltype(*disk)::page_size()); - page.value += decltype(*disk)::page_size()*8*(shuttle_page-begin_page); + return gp::nullopt; + } + + uint64_t next_shuttle_page(disk_root root, uint64_t shuttle) { + return + shuttle + 1 == root.first_allocator_page + root.allocator_page_count ? + root.first_allocator_page + : shuttle + 1; + } + + bool try_unset_bit(gp::buffer page, uint64_t idx) { + uint8_t& target_byte = *(page.begin()+(idx/8)); + uint8_t flipper = 1 << (idx%8); + if(target_byte & flipper) { + target_byte ^= flipper; + return true; } + return false; } - while(!page.has_value()); - set_disk_root(root); - return page.value() + end_page; - } - - bool deallocate_page(uint64_t page) { - disk_root root = get_disk_root(); - page -= root.first_allocator_page + root.allocator_page_count; - uint64_t discriminant = decltype(*disk)::page_size()*8; - uint64_t allocator_page = page/discriminant; - uint64_t pos_page = page%discriminant; - gp::array store; - disk->read(store.as_buffer(), decltype(*disk)::page_size()*allocator_page); - bool ret = try_unset_bit(store.as_buffer(), pos_page); - disk->write(store.as_buffer(), decltype(*disk)::page_size()*allocator_page); - return ret; - } - - void clear_page(uint64_t page) { - disk->write(empty_page.as_buffer(), page*decltype(*disk)::page_size()); - } - - void format() { - auto sz = disk->size(); - auto page_sz = disk->page_size(); - auto page_count = sz /page_sz; - auto remaining_pages = page_count; - - disk_root root; - // tagmebro - root.magic = 0x7461676D6562726F; - root.page_count = page_count; - root.first_allocator_page = 1; - root.allocator_shuttle = 1; - - // Removing the root page - remaining_pages -= 1; - - // calculating datapages - auto datapage_count = (8*remaining_pages*page_sz)/(1+8*page_sz); - auto allocator_pages = remaining_pages - datapage_count; - - root.allocator_page_count = allocator_pages; - - for(uint64_t offset = 0; offset < allocator_pages; ++offset) { - clear_page(root.first_allocator_page); + + uint64_t allocate_page() { + disk_root root = get_disk_root(); + uint64_t begin_page = root.first_allocator_page; + uint64_t shuttle_page = root.allocator_shuttle; + uint64_t end_page = root.first_allocator_page + root.allocator_page_count; + gp::array page_contents; + + gp::optional page; + do + { + auto allocator_page = disk->read(page_contents.as_buffer(), shuttle_page*page_size); + if(shuttle_page == end_page - 1) { + uint64_t existing_pages = root.page_count - end_page; + uint64_t allocable_pages = root.allocator_page_count*8*page_size; + if(existing_pages < allocable_pages) { + uint64_t extra = allocable_pages - existing_pages; + extra /= 8; + allocator_page = allocator_page.slice_start(page_size - extra); + } + } + page = try_set_bit(allocator_page); + if(!page.has_value()) { + root.allocator_shuttle = (shuttle_page = next_shuttle_page(shuttle_page)); + } else { + disk->write(page_contents.as_buffer(), shuttle_page*page_size); + page.value() += page_size*8*(shuttle_page-begin_page); + } + } + while(!page.has_value()); + set_disk_root(root); + return page.value() + end_page; + } + + bool deallocate_page(uint64_t page) { + disk_root root = get_disk_root(); + page -= root.first_allocator_page + root.allocator_page_count; + uint64_t discriminant = page_size*8; + uint64_t allocator_page = page/discriminant; + uint64_t pos_page = page%discriminant; + gp::array store; + disk->read(store.as_buffer(), page_size*allocator_page); + bool ret = try_unset_bit(store.as_buffer(), pos_page); + disk->write(store.as_buffer(), page_size*allocator_page); + return ret; + } + + void clear_page(uint64_t page) { + disk->write(empty_page.as_buffer(), page*page_size); + } + + + constexpr static gp::pair split_pages(uint64_t pagecount) { + auto datapage_count = (8*pagecount*page_size)/(1+8*page_size); + auto allocator_pages = pagecount - datapage_count; + + return {allocator_pages, datapage_count}; } - root.tag_list_node = 0; - set_disk_root(root); - } -}; \ No newline at end of file + void format() { + auto sz = disk->size(); + auto page_sz = page_size; + auto page_count = sz /page_sz; + auto remaining_pages = page_count; + + disk_root root; + // tagmebro + root.magic = 0x7461676D6562726F; + root.page_count = page_count; + root.first_allocator_page = 1; + root.allocator_shuttle = 1; + + // Removing the root page + remaining_pages -= 1; + + // calculating datapages + auto [allocator_pages, datapage_count] = split_pages(remaining_pages); + static_assert(split_pages(page_size*8+1).first == 1, "ideal 1 allocator page split doesn't work"); + static_assert(split_pages(page_size*8+2).first == 2, "worst 2 allocator page split doesn't work"); + + root.allocator_page_count = allocator_pages; + + for(uint64_t offset = 0; offset < allocator_pages; ++offset) { + clear_page(root.first_allocator_page); + } + + root.tag_list_node = 0; + set_disk_root(root); + } + }; +} \ No newline at end of file diff --git a/tests.cpp b/tests.cpp index e2bd564..9b7ef09 100644 --- a/tests.cpp +++ b/tests.cpp @@ -7,6 +7,7 @@ #include "meta_test.cpp" #include "pair_test.cpp" #include "quotient_filter.cpp" +#include "tagfs_test.cpp" #include "test_scaffold.h" #include diff --git a/tests/tagfs_test.cpp b/tests/tagfs_test.cpp new file mode 100644 index 0000000..b163297 --- /dev/null +++ b/tests/tagfs_test.cpp @@ -0,0 +1,23 @@ +#include "gp/tagfs/tagfs.hpp" +#include "test_scaffold.h" + +#include +#include + + +struct tagfs_test : public test_scaffold { + tagfs_test() { + name = __FILE__ ":1"; + } + + virtual int run() { + bool result = true; + + gp::memory_vdisk<128*1025> disk; + auto fs = gp::tagfs{&disk}; + + return !result; + } +}; + +append_test dummy_56d46qds(new tagfs_test{}); \ No newline at end of file