Line data Source code
1 : // Copyright (c) 2019 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/snapdatabase
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 :
20 :
21 : /** \file
22 : * \brief Database file implementation.
23 : *
24 : * Each table uses one or more files. Each file is handled by a dbfile
25 : * object and a corresponding set of blocks.
26 : */
27 :
28 : // self
29 : //
30 : #include "snapdatabase/block/block_schema.h"
31 :
32 : #include "snapdatabase/block/block_header.h"
33 : #include "snapdatabase/database/table.h"
34 :
35 :
36 : // C++ lib
37 : //
38 : #include <iostream>
39 :
40 :
41 : // last include
42 : //
43 : #include <snapdev/poison.h>
44 :
45 :
46 :
47 : namespace snapdatabase
48 : {
49 :
50 :
51 :
52 : namespace
53 : {
54 :
55 :
56 :
57 : // 'SCHM'
58 : constexpr struct_description_t g_description[] =
59 : {
60 : define_description(
61 : FieldName("header")
62 : , FieldType(struct_type_t::STRUCT_TYPE_STRUCTURE)
63 : , FieldSubDescription(detail::g_block_header)
64 : ),
65 : define_description(
66 : FieldName("size")
67 : , FieldType(struct_type_t::STRUCT_TYPE_UINT32)
68 : ),
69 : define_description(
70 : FieldName("next_schema_block")
71 : , FieldType(struct_type_t::STRUCT_TYPE_REFERENCE)
72 : ),
73 : end_descriptions()
74 : };
75 :
76 :
77 : constexpr descriptions_by_version_t const g_descriptions_by_version[] =
78 : {
79 : define_description_by_version(
80 : DescriptionVersion(0, 1),
81 : DescriptionDescription(g_description)
82 : ),
83 : end_descriptions_by_version()
84 : };
85 :
86 :
87 :
88 : }
89 : // no name namespace
90 :
91 :
92 :
93 1 : block_schema::block_schema(dbfile::pointer_t f, reference_t offset)
94 1 : : block(g_descriptions_by_version, f, offset)
95 : {
96 1 : }
97 :
98 :
99 0 : std::uint32_t block_schema::get_size()
100 : {
101 0 : return static_cast<uint32_t>(f_structure->get_uinteger("size"));
102 : }
103 :
104 :
105 1 : void block_schema::set_size(std::uint32_t size)
106 : {
107 1 : f_structure->set_uinteger("size", size);
108 1 : }
109 :
110 :
111 1 : reference_t block_schema::get_next_schema_block()
112 : {
113 1 : return static_cast<reference_t>(f_structure->get_uinteger("next_schema_block"));
114 : }
115 :
116 :
117 1 : void block_schema::set_next_schema_block(reference_t offset)
118 : {
119 1 : f_structure->set_uinteger("next_schema_block", offset);
120 1 : }
121 :
122 :
123 0 : virtual_buffer::pointer_t block_schema::get_schema() const
124 : {
125 0 : virtual_buffer::pointer_t result(std::make_shared<virtual_buffer>());
126 :
127 0 : reference_t const offset(f_structure->get_size());
128 0 : block_schema::pointer_t s(std::static_pointer_cast<block_schema>(const_cast<block_schema *>(this)->shared_from_this()));
129 : for(;;)
130 : {
131 0 : block::pointer_t block_ptr(s);
132 0 : result->add_buffer(block_ptr, offset, s->get_size());
133 0 : reference_t next(s->get_next_schema_block());
134 0 : if(next == 0)
135 : {
136 0 : return result;
137 : }
138 :
139 0 : s = std::static_pointer_cast<block_schema>(get_table()->get_block(next));
140 0 : if(s == nullptr)
141 : {
142 0 : throw snapdatabase_logic_error("block_schema::get_schema() failed reading the list of blocks (bad pointer).");
143 : }
144 0 : }
145 : }
146 :
147 :
148 1 : void block_schema::set_schema(virtual_buffer::pointer_t schema)
149 : {
150 1 : reference_t const offset(f_structure->get_size());
151 : #ifdef _DEBUG
152 1 : if(offset == 0)
153 : {
154 0 : throw snapdatabase_logic_error("the structure of the block_schema block cannot be dynamic.");
155 : }
156 : #endif
157 1 : std::uint32_t const size_per_page(get_table()->get_page_size() - offset);
158 :
159 1 : std::uint32_t remaining_size(schema->size());
160 1 : block_schema * s(this);
161 1 : for(std::uint32_t pos(0);;)
162 : {
163 1 : data_t d(s->data());
164 1 : std::uint32_t const size(std::min(size_per_page, remaining_size));
165 1 : schema->pread(d + offset, size, pos);
166 1 : s->set_size(size);
167 :
168 1 : reference_t next(s->get_next_schema_block());
169 :
170 1 : pos += size;
171 1 : remaining_size -= size;
172 1 : if(remaining_size == 0)
173 : {
174 1 : s->set_next_schema_block(NULL_FILE_ADDR);
175 1 : s->sync(false);
176 :
177 : // free any "next" block (happens when a schema shrinks)
178 : //
179 1 : while(next != NULL_FILE_ADDR)
180 : {
181 0 : block_schema::pointer_t next_schema(std::static_pointer_cast<block_schema>(get_table()->get_block(next)));
182 0 : if(next_schema == nullptr)
183 : {
184 : throw snapdatabase_logic_error(
185 : "reading of the next schema block at "
186 0 : + std::to_string(next)
187 0 : + " failed.");
188 : }
189 0 : next = next_schema->get_next_schema_block();
190 0 : get_table()->free_block(next_schema, false);
191 : }
192 :
193 1 : break;
194 : }
195 :
196 0 : if(next == NULL_FILE_ADDR)
197 : {
198 : // create a new block and link it
199 : //
200 0 : block_schema::pointer_t new_block(std::static_pointer_cast<block_schema>(get_table()->allocate_new_block(dbtype_t::BLOCK_TYPE_SCHEMA)));
201 0 : s->set_next_schema_block(new_block->get_offset());
202 0 : s->sync(false);
203 0 : s = new_block.get();
204 : }
205 : else
206 : {
207 0 : block_schema::pointer_t next_schema(std::static_pointer_cast<block_schema>(get_table()->get_block(next)));
208 0 : if(next_schema == nullptr)
209 : {
210 : throw snapdatabase_logic_error(
211 : "reading of the next schema block at "
212 0 : + std::to_string(next)
213 0 : + " failed.");
214 : }
215 :
216 0 : s->sync(false);
217 0 : s = next_schema.get();
218 : }
219 0 : }
220 1 : }
221 :
222 :
223 6 : } // namespace snapdatabase
224 : // vim: ts=4 sw=4 et
|