123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- /*
- * Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #pragma once
- #include <AK/WeakPtr.h>
- #include <LibCore/Object.h>
- #include <LibSQL/Forward.h>
- #include <LibSQL/Heap.h>
- #include <LibSQL/Index.h>
- #include <LibSQL/Key.h>
- namespace SQL {
- /**
- * The HashIndex class is a straightforward implementation of a persisted
- * extendible hash table (see
- * https://en.wikipedia.org/wiki/Extendible_hashing).
- */
- class HashBucket : public IndexNode
- , public Weakable<HashBucket> {
- public:
- HashBucket(HashIndex&, u32 index, u32 local_depth, u32 pointer);
- ~HashBucket() override = default;
- Optional<u32> get(Key&);
- bool insert(Key const&);
- Vector<Key> const& entries()
- {
- inflate();
- return m_entries;
- }
- Key const& operator[](size_t);
- Key const& operator[](size_t ix) const
- {
- VERIFY(ix < m_entries.size());
- return m_entries[ix];
- }
- [[nodiscard]] u32 local_depth() const { return m_local_depth; }
- [[nodiscard]] u32 size() { return entries().size(); }
- [[nodiscard]] u32 size() const { return m_entries.size(); }
- [[nodiscard]] u32 index() const { return m_index; }
- void serialize(ByteBuffer&) const override;
- IndexNode* as_index_node() override { return dynamic_cast<IndexNode*>(this); }
- [[nodiscard]] HashIndex const& hash_index() const { return m_hash_index; }
- [[nodiscard]] HashBucket const* next_bucket();
- [[nodiscard]] HashBucket const* previous_bucket();
- void list_bucket();
- private:
- Optional<size_t> find_key_in_bucket(Key const&);
- void set_index(u32 index) { m_index = index; }
- void set_local_depth(u32 depth) { m_local_depth = depth; }
- [[nodiscard]] size_t max_entries_in_bucket() const;
- void inflate();
- HashIndex& m_hash_index;
- u32 m_local_depth { 1 };
- u32 m_index { 0 };
- Vector<Key> m_entries;
- bool m_inflated { false };
- friend HashIndex;
- };
- class HashIndex : public Index {
- C_OBJECT(HashIndex);
- public:
- ~HashIndex() override = default;
- Optional<u32> get(Key&);
- bool insert(Key const&);
- bool insert(Key const&& entry) { return insert(entry); }
- HashIndexIterator find(Key const&);
- HashIndexIterator begin();
- static HashIndexIterator end();
- [[nodiscard]] u32 global_depth() const { return m_global_depth; }
- [[nodiscard]] u32 size() const { return 1 << m_global_depth; }
- [[nodiscard]] HashBucket* get_bucket(u32);
- [[nodiscard]] u32 node_pointer(u32 node_number) const { return m_nodes[node_number]; }
- [[nodiscard]] u32 first_node_pointer() const { return m_nodes[0]; }
- [[nodiscard]] size_t nodes() const { return m_nodes.size(); }
- void list_hash();
- private:
- HashIndex(Heap&, NonnullRefPtr<TupleDescriptor> const&, u32);
- void expand();
- void write_directory_to_write_ahead_log();
- HashBucket* append_bucket(u32 index, u32 local_depth, u32 pointer);
- HashBucket* get_bucket_for_insert(Key const&);
- [[nodiscard]] HashBucket* get_bucket_by_index(u32 index);
- u32 m_global_depth { 1 };
- Vector<u32> m_nodes;
- Vector<OwnPtr<HashBucket>> m_buckets;
- friend HashBucket;
- friend HashDirectoryNode;
- };
- class HashDirectoryNode : public IndexNode {
- public:
- HashDirectoryNode(HashIndex&, u32, size_t);
- HashDirectoryNode(HashIndex&, u32, ByteBuffer&);
- HashDirectoryNode(HashDirectoryNode const& other) = default;
- void serialize(ByteBuffer&) const override;
- IndexNode* as_index_node() override { return dynamic_cast<IndexNode*>(this); }
- [[nodiscard]] u32 number_of_pointers() const { return min(max_pointers_in_node(), m_hash_index.size() - m_offset); }
- [[nodiscard]] bool is_last() const { return m_is_last; }
- static constexpr size_t max_pointers_in_node() { return (BLOCKSIZE - 3 * sizeof(u32)) / (2 * sizeof(u32)); }
- private:
- HashIndex& m_hash_index;
- size_t m_node_number { 0 };
- size_t m_offset { 0 };
- bool m_is_last { false };
- };
- class HashIndexIterator {
- public:
- [[nodiscard]] bool is_end() const { return !m_current; }
- bool operator==(HashIndexIterator const& other) const;
- bool operator!=(HashIndexIterator const& other) const { return !(*this == other); }
- bool operator==(Key const& other) const;
- bool operator!=(Key const& other) const { return !(*this == other); }
- HashIndexIterator operator++()
- {
- *this = next();
- return *this;
- }
- HashIndexIterator operator++(int)
- {
- *this = next();
- return *this;
- }
- HashIndexIterator operator--()
- {
- *this = previous();
- return *this;
- }
- HashIndexIterator const operator--(int)
- {
- *this = previous();
- return *this;
- }
- Key const& operator*() const
- {
- VERIFY(!is_end());
- return (*m_current)[m_index];
- }
- Key const& operator->() const
- {
- VERIFY(!is_end());
- return (*m_current)[m_index];
- }
- HashIndexIterator& operator=(HashIndexIterator const&) = default;
- HashIndexIterator(HashIndexIterator const&) = default;
- private:
- HashIndexIterator() = default;
- explicit HashIndexIterator(HashBucket const*, size_t key_index = 0);
- static HashIndexIterator end() { return HashIndexIterator(); }
- [[nodiscard]] HashIndexIterator next();
- [[nodiscard]] HashIndexIterator previous();
- [[nodiscard]] Key key() const { return **this; }
- WeakPtr<HashBucket> m_current;
- size_t m_index { 0 };
- friend HashIndex;
- };
- }
|