Serenity Operating System
1/*
2 * Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/Array.h>
10#include <AK/Debug.h>
11#include <AK/DeprecatedString.h>
12#include <AK/HashMap.h>
13#include <AK/Vector.h>
14#include <LibCore/File.h>
15#include <LibCore/Object.h>
16
17namespace SQL {
18
19constexpr static u32 BLOCKSIZE = 1024;
20
21/**
22 * A Heap is a logical container for database (SQL) data. Conceptually a
23 * Heap can be a database file, or a memory block, or another storage medium.
24 * It contains datastructures, like B-Trees, hash_index tables, or tuple stores
25 * (basically a list of data tuples).
26 *
27 * A Heap can be thought of the backing storage of a single database. It's
28 * assumed that a single SQL database is backed by a single Heap.
29 *
30 * Currently only B-Trees and tuple stores are implemented.
31 */
32class Heap : public Core::Object {
33 C_OBJECT(Heap);
34
35public:
36 static constexpr inline u32 current_version = 3;
37
38 virtual ~Heap() override;
39
40 ErrorOr<void> open();
41 u32 size() const { return m_end_of_file; }
42 ErrorOr<ByteBuffer> read_block(u32);
43 [[nodiscard]] u32 new_record_pointer();
44 [[nodiscard]] bool valid() const { return static_cast<bool>(m_file); }
45
46 u32 schemas_root() const { return m_schemas_root; }
47
48 void set_schemas_root(u32 root)
49 {
50 m_schemas_root = root;
51 update_zero_block();
52 }
53
54 u32 tables_root() const { return m_tables_root; }
55
56 void set_tables_root(u32 root)
57 {
58 m_tables_root = root;
59 update_zero_block();
60 }
61
62 u32 table_columns_root() const { return m_table_columns_root; }
63
64 void set_table_columns_root(u32 root)
65 {
66 m_table_columns_root = root;
67 update_zero_block();
68 }
69 u32 version() const { return m_version; }
70
71 u32 user_value(size_t index) const
72 {
73 VERIFY(index < m_user_values.size());
74 return m_user_values[index];
75 }
76
77 void set_user_value(size_t index, u32 value)
78 {
79 VERIFY(index < m_user_values.size());
80 m_user_values[index] = value;
81 update_zero_block();
82 }
83
84 void add_to_wal(u32 block, ByteBuffer& buffer)
85 {
86 dbgln_if(SQL_DEBUG, "Adding to WAL: block #{}, size {}", block, buffer.size());
87 dbgln_if(SQL_DEBUG, "{:hex-dump}", buffer.bytes().trim(8));
88 m_write_ahead_log.set(block, buffer);
89 }
90
91 ErrorOr<void> flush();
92
93private:
94 explicit Heap(DeprecatedString);
95
96 ErrorOr<void> write_block(u32, ByteBuffer&);
97 ErrorOr<void> seek_block(u32);
98 ErrorOr<void> read_zero_block();
99 void initialize_zero_block();
100 void update_zero_block();
101
102 OwnPtr<Core::BufferedFile> m_file;
103 u32 m_free_list { 0 };
104 u32 m_next_block { 1 };
105 u32 m_end_of_file { 1 };
106 u32 m_schemas_root { 0 };
107 u32 m_tables_root { 0 };
108 u32 m_table_columns_root { 0 };
109 u32 m_version { current_version };
110 Array<u32, 16> m_user_values { 0 };
111 HashMap<u32, ByteBuffer> m_write_ahead_log;
112};
113
114}