1 : // -*- mode: c++; fill-column: 79 -*-
2 : // $Id: test_format.cc 2 2010-04-14 07:34:58Z tb $
3 :
4 : /*
5 : * STX Constant B-Tree Database Template Classes v0.7.0
6 : * Copyright (C) 2010 Timo Bingmann
7 : *
8 : * This library is free software; you can redistribute it and/or modify it
9 : * under the terms of the GNU Lesser General Public License as published by the
10 : * Free Software Foundation; either version 2.1 of the License, or (at your
11 : * option) any later version.
12 : *
13 : * This library is distributed in the hope that it will be useful, but WITHOUT
14 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 : * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16 : * for more details.
17 : *
18 : * You should have received a copy of the GNU Lesser General Public License
19 : * along with this library; if not, write to the Free Software Foundation,
20 : * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 : */
22 :
23 : /*
24 : * Freeze database format. Two databases are frozen and included with
25 : * this test case. Both class configurations are reproduced and the
26 : * same items inserted. The resulting databases are compared against
27 : * the frozen database files, both Writer and WriterSequential must
28 : * produce databases equal to the frozen reference files. Also test
29 : * error checking in Open() by attempting to load incompatible files.
30 : */
31 :
32 : #define CBTREEDB_SELF_VERIFY
33 : #include "stx-cbtreedb.h"
34 :
35 : #include <iostream>
36 : #include <sstream>
37 : #include <fstream>
38 : #include <assert.h>
39 : #include <stdlib.h>
40 :
41 : static const unsigned int items = 10000;
42 :
43 : template <typename cbtreedb>
44 2 : void run_test_random(const std::string& dbname)
45 : {
46 2 : std::cout << "Creating test database using random writer." << std::endl;
47 :
48 2 : typename cbtreedb::Writer writer;
49 2 : writer.SetSignature("cbtestdb");
50 :
51 20004 : for(unsigned int i = 0; i <= items; ++i)
52 : {
53 20002 : writer.Add(2*i, &i, sizeof(i));
54 : }
55 :
56 : // write new database into string object
57 :
58 2 : std::ostringstream testdb;
59 2 : writer.Write(testdb);
60 :
61 2 : std::string testdbstr = testdb.str();
62 : // std::cout << "dbsize " << testdbstr.size() << std::endl;
63 :
64 : // read reference database from file
65 :
66 2 : std::string refdbstr;
67 :
68 : {
69 2 : std::ifstream ifdb((AM_TOP_SRCDIR "/testsuite/" + dbname).c_str());
70 :
71 2 : if (!ifdb.good()) {
72 0 : ifdb.open(("testsuite/" + dbname).c_str());
73 : }
74 :
75 : char buffer[32*1024];
76 10 : do
77 : {
78 10 : ifdb.read(buffer, sizeof(buffer));
79 12 : refdbstr.append(buffer, ifdb.gcount());
80 : }
81 : while ( ifdb.good() && !ifdb.eof() );
82 : }
83 :
84 : // compare reference db and created db
85 :
86 2 : if (testdbstr != refdbstr)
87 : {
88 0 : std::cout << "Reference database does not match!" << std::endl;
89 :
90 0 : std::ofstream ofdb((dbname + "-new").c_str());
91 0 : ofdb << testdbstr;
92 0 : ofdb.close();
93 :
94 0 : assert( testdbstr == refdbstr );
95 : }
96 2 : }
97 :
98 : template <typename cbtreedb>
99 2 : void run_test_sequential(const std::string& dbname)
100 : {
101 2 : std::cout << "Creating test database using sequential writer." << std::endl;
102 :
103 2 : typename cbtreedb::WriterSequential writer;
104 2 : writer.SetSignature("cbtestdb");
105 :
106 20004 : for(unsigned int i = 0; i <= items; ++i)
107 : {
108 : // phase 1: declare key and valuesize mappings.
109 20002 : writer.Add(2*i, sizeof(i));
110 : }
111 :
112 2 : std::ostringstream testdb;
113 :
114 2 : writer.WriteHeader(testdb); // write header and btree
115 :
116 20004 : for(unsigned int i = 0; i <= items; ++i)
117 : {
118 : // phase 2: write value objects
119 20002 : writer.WriteValue(2*i, &i, sizeof(i));
120 : }
121 :
122 2 : writer.WriteFinalize();
123 :
124 2 : std::string testdbstr = testdb.str();
125 : // std::cout << "dbsize " << testdbstr.size() << std::endl;
126 :
127 : // read reference database from file
128 :
129 2 : std::string refdbstr;
130 :
131 : {
132 2 : std::ifstream ifdb((AM_TOP_SRCDIR "/testsuite/" + dbname).c_str());
133 :
134 2 : if (!ifdb.good()) {
135 0 : ifdb.open(("testsuite/" + dbname).c_str());
136 : }
137 :
138 : char buffer[32*1024];
139 10 : do
140 : {
141 10 : ifdb.read(buffer, sizeof(buffer));
142 12 : refdbstr.append(buffer, ifdb.gcount());
143 : }
144 : while ( ifdb.good() && !ifdb.eof() );
145 : }
146 :
147 : // compare reference db and created db
148 :
149 2 : if (testdbstr != refdbstr)
150 : {
151 0 : std::cout << "Reference database does not match!" << std::endl;
152 :
153 0 : std::ofstream ofdb((dbname + "-new").c_str());
154 0 : ofdb << testdbstr;
155 0 : ofdb.close();
156 :
157 0 : assert( testdbstr == refdbstr );
158 : }
159 2 : }
160 :
161 : template <typename cbtreedb>
162 8 : void run_test_open(const std::string& dbname, const std::string& expectederrorstring)
163 : {
164 : // read database from file
165 :
166 8 : std::string dbstr;
167 :
168 : {
169 8 : std::ifstream ifdb((AM_TOP_SRCDIR "/testsuite/" + dbname).c_str());
170 :
171 8 : if (!ifdb.good()) {
172 0 : ifdb.open(("testsuite/" + dbname).c_str());
173 : }
174 :
175 : char buffer[32*1024];
176 40 : do
177 : {
178 40 : ifdb.read(buffer, sizeof(buffer));
179 48 : dbstr.append(buffer, ifdb.gcount());
180 : }
181 : while ( ifdb.good() && !ifdb.eof() );
182 : }
183 :
184 8 : assert(dbstr.size());
185 : // std::cout << "dbsize " << dbstr.size() << std::endl;
186 :
187 : // create reader object
188 :
189 8 : typename cbtreedb::Reader reader;
190 8 : reader.SetSignature("cbtestdb");
191 :
192 8 : typename cbtreedb::PageCache cache(128);
193 8 : reader.SetPageCache(&cache);
194 :
195 8 : std::istringstream testdb(dbstr);
196 8 : std::string errorstring;
197 :
198 8 : if (! reader.Open(testdb,&errorstring) )
199 : {
200 6 : if (errorstring != expectederrorstring)
201 : {
202 0 : std::cout << "Open errorstring mismatched: " << std::endl
203 : << "Got: " << errorstring << std::endl
204 : << "Expected: " << expectederrorstring << std::endl;
205 0 : abort();
206 : }
207 6 : return;
208 : }
209 :
210 2 : assert( reader.Verify() );
211 2 : assert( reader.Size() == items+1 );
212 : }
213 :
214 1 : int main()
215 : {
216 : // check binary format compatibility with two common configurations
217 :
218 1 : run_test_random< stx::CBTreeDB<uint32_t, std::less<uint32_t>, 1024> >("test_format1.db");
219 2 : run_test_sequential< stx::CBTreeDB<uint32_t, std::less<uint32_t>, 1024> >("test_format1.db");
220 :
221 2 : run_test_random< stx::CBTreeDB<uint64_t, std::less<uint64_t>, 2048> >("test_format2.db");
222 2 : run_test_sequential< stx::CBTreeDB<uint64_t, std::less<uint64_t>, 2048> >("test_format2.db");
223 :
224 : // check error when opening database with wrong configurations
225 :
226 : run_test_open< stx::CBTreeDB<uint32_t, std::less<uint32_t>, 1024> >
227 2 : ("test_format1.db", "");
228 :
229 : run_test_open< stx::CBTreeDB<uint32_t, std::less<uint32_t>, 2048> >
230 2 : ("test_format1.db", "Database not compatible with this reader: page sizes mismatch.");
231 :
232 : run_test_open< stx::CBTreeDB<uint64_t, std::less<uint64_t>, 1024> >
233 2 : ("test_format1.db", "Database not compatible with this reader: key sizes mismatch.");
234 :
235 : run_test_open< stx::CBTreeDB<uint32_t, std::greater<uint32_t>, 1024> >
236 2 : ("test_format1.db", "Database not compatible with this reader: root keys order mismatches.");
237 :
238 :
239 : run_test_open< stx::CBTreeDB<uint64_t, std::less<uint64_t>, 2048> >
240 2 : ("test_format2.db", "");
241 :
242 : run_test_open< stx::CBTreeDB<uint64_t, std::less<uint64_t>, 1024> >
243 2 : ("test_format2.db", "Database not compatible with this reader: page sizes mismatch.");
244 :
245 : run_test_open< stx::CBTreeDB<uint32_t, std::less<uint32_t>, 2048> >
246 2 : ("test_format2.db", "Database not compatible with this reader: key sizes mismatch.");
247 :
248 : run_test_open< stx::CBTreeDB<uint64_t, std::greater<uint64_t>, 2048> >
249 2 : ("test_format2.db", "Database not compatible with this reader: root keys order mismatches.");
250 :
251 1 : return 0;
252 3 : }
|