1 | /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
2 | // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4: |
3 | #ident "$Id$" |
4 | /*====== |
5 | This file is part of PerconaFT. |
6 | |
7 | |
8 | Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. |
9 | |
10 | PerconaFT is free software: you can redistribute it and/or modify |
11 | it under the terms of the GNU General Public License, version 2, |
12 | as published by the Free Software Foundation. |
13 | |
14 | PerconaFT is distributed in the hope that it will be useful, |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | GNU General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU General Public License |
20 | along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. |
21 | |
22 | ---------------------------------------- |
23 | |
24 | PerconaFT is free software: you can redistribute it and/or modify |
25 | it under the terms of the GNU Affero General Public License, version 3, |
26 | as published by the Free Software Foundation. |
27 | |
28 | PerconaFT is distributed in the hope that it will be useful, |
29 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
31 | GNU Affero General Public License for more details. |
32 | |
33 | You should have received a copy of the GNU Affero General Public License |
34 | along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. |
35 | ======= */ |
36 | |
37 | #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved." |
38 | |
39 | #include "ft/node.h" |
40 | #include "ft/ft-internal.h" |
41 | #include "ft/serialize/ft_node-serialize.h" |
42 | |
43 | /* |
44 | * ft-node-deserialize.c - |
45 | * This file contains functions used by deserializtion |
46 | * code paths in and out of the engine. The functions can, |
47 | * essentially, be broken up into two types. Some of these |
48 | * functions return error codes based expected values inside |
49 | * the fractal tree node, others merely read the specific |
50 | * quantities of bytes out of the buffer. It is expeceted |
51 | * that these will be called in the correct order by users |
52 | * of these functions/this API. |
53 | * |
54 | */ |
55 | |
56 | // Sets initial values for the given fractal tree node to be |
57 | // deserialized |
58 | void |
59 | initialize_ftnode(FTNODE node, BLOCKNUM blocknum) |
60 | { |
61 | node->fullhash = 0xDEADBEEF; // <CER> Is this 'spoof' ok? |
62 | node->blocknum = blocknum; |
63 | node->dirty = 0; |
64 | node->bp = NULL; |
65 | // <CER> Can we use this initialization as a correctness assert in |
66 | // a later function? |
67 | node->layout_version_read_from_disk = 0; |
68 | } |
69 | |
70 | /************************ |
71 | * TODO: In other deserialization code, we check the rb size member. We |
72 | * verify that it is greater than or equal to 24. Ignoring this magic |
73 | * number for a moment, should we put this check in its own function? * |
74 | *************************/ |
75 | |
76 | |
77 | // Read and check the 'magic' bytes on disk. Returns an error if |
78 | // the magic does not match. |
79 | int |
80 | read_and_check_magic(struct rbuf *rb) |
81 | { |
82 | int r = 0; |
83 | const void *magic; |
84 | rbuf_literal_bytes(rb, &magic, 8); |
85 | if (memcmp(magic, "tokuleaf" , 8)!=0 && |
86 | memcmp(magic, "tokunode" , 8)!=0) { |
87 | r = DB_BADFORMAT; // TODO: Return more meaningful error. |
88 | } |
89 | |
90 | return r; |
91 | } |
92 | |
93 | // Read the version number from the given buffer |
94 | // and returns an error if the version is too old. |
95 | int |
96 | read_and_check_version(FTNODE node, struct rbuf *rb) |
97 | { |
98 | int r = 0; |
99 | int version = rbuf_int(rb); |
100 | node->layout_version_read_from_disk = version; |
101 | if (version < FT_LAYOUT_MIN_SUPPORTED_VERSION) { |
102 | r = 1; // TODO: Better error reporting. |
103 | } |
104 | |
105 | return r; |
106 | } |
107 | |
108 | // Reads the basic version, build, and child info from |
109 | // the given buffer. |
110 | void |
111 | read_node_info(FTNODE node, struct rbuf *rb, int version) |
112 | { |
113 | node->layout_version = version; |
114 | node->layout_version_original = rbuf_int(rb); |
115 | node->build_id = rbuf_int(rb); |
116 | node->n_children = rbuf_int(rb); |
117 | } |
118 | |
119 | // Allocates the partitions based on the given node's nubmer |
120 | // of children. It then reads, out of the given buffer, |
121 | // the start and size of each child partition. |
122 | // TODO: Should these be two seperate functions? |
123 | void |
124 | allocate_and_read_partition_offsets(FTNODE node, struct rbuf *rb, FTNODE_DISK_DATA *ndd) |
125 | { |
126 | XMALLOC_N(node->n_children, node->bp); |
127 | // TODO: Fix this to use xmalloc_n |
128 | XMALLOC_N(node->n_children, *ndd); |
129 | // Read the partition locations. |
130 | for (int i = 0; i < node->n_children; i++) { |
131 | BP_START(*ndd, i) = rbuf_int(rb); |
132 | BP_SIZE (*ndd, i) = rbuf_int(rb); |
133 | } |
134 | } |
135 | |
136 | // Compares checksum of stored (in the given buffer) checksum |
137 | // and the checksum of the buffer itself. If these are NOT |
138 | // equal, this function returns an appropriate error code. |
139 | int |
140 | check_node_info_checksum(struct rbuf *rb) |
141 | { |
142 | int r = 0; |
143 | // Verify checksum of header stored. |
144 | uint32_t checksum = toku_x1764_memory(rb->buf, rb->ndone); |
145 | uint32_t stored_checksum = rbuf_int(rb); |
146 | |
147 | if (stored_checksum != checksum) { |
148 | // TODO: dump_bad_block(rb->buf, rb->size); |
149 | r = TOKUDB_BAD_CHECKSUM; |
150 | } |
151 | |
152 | return r; |
153 | } |
154 | |
155 | // Reads node info from older (13 and 14) fractal tree nodes |
156 | // out of the given buffer. |
157 | void |
158 | read_legacy_node_info(FTNODE node, struct rbuf *rb, int version) |
159 | { |
160 | (void)rbuf_int(rb); // 1. nodesize |
161 | node->flags = rbuf_int(rb); // 2. flags |
162 | node->height = rbuf_int(rb); // 3. height |
163 | |
164 | // If the version is less than 14, there are two extra ints here. |
165 | // we would need to ignore them if they are there. |
166 | if (version == FT_LAYOUT_VERSION_13) { |
167 | (void) rbuf_int(rb); // 4. rand4 |
168 | (void) rbuf_int(rb); // 5. local |
169 | } |
170 | } |
171 | |
172 | // Assuming the given buffer is in the correct position, |
173 | // this checks to see if the stored checksum matches the |
174 | // checksum of the entire buffer. |
175 | int |
176 | check_legacy_end_checksum(struct rbuf *rb) |
177 | { |
178 | int r = 0; |
179 | uint32_t expected_xsum = rbuf_int(rb); |
180 | uint32_t actual_xsum = toku_x1764_memory(rb->buf, rb->size - 4); |
181 | if (expected_xsum != actual_xsum) { |
182 | r = TOKUDB_BAD_CHECKSUM; |
183 | } |
184 | |
185 | return r; |
186 | } |
187 | |