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
initialize_ftnode(FTNODE node,BLOCKNUM blocknum)59 initialize_ftnode(FTNODE node, BLOCKNUM blocknum)
60 {
61     node->fullhash = 0xDEADBEEF; // <CER> Is this 'spoof' ok?
62     node->blocknum = blocknum;
63     node->clear_dirty();
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
read_and_check_magic(struct rbuf * rb)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
read_and_check_version(FTNODE node,struct rbuf * rb)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
read_node_info(FTNODE node,struct rbuf * rb,int version)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
allocate_and_read_partition_offsets(FTNODE node,struct rbuf * rb,FTNODE_DISK_DATA * ndd)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
check_node_info_checksum(struct rbuf * rb)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
read_legacy_node_info(FTNODE node,struct rbuf * rb,int version)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
check_legacy_end_checksum(struct rbuf * rb)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