00001
00002
00003
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #ifndef _STX_CBTREEDB_H_
00028 #define _STX_CBTREEDB_H_
00029
00030 #include <string.h>
00031 #include <stdint.h>
00032
00033 #include <stdexcept>
00034 #include <vector>
00035 #include <map>
00036 #include <iostream>
00037
00039 namespace stx {
00040
00041
00042
00043 #ifndef STX_STATIC_ASSERT
00044
00045 template <bool> struct STATIC_ASSERTION_FAILURE;
00046 template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
00047 template <int x> struct static_assert_test {};
00048
00049 #define STX_MACRO_JOIN(X,Y) STX_MACRO_DO_JOIN(X,Y)
00050 #define STX_MACRO_DO_JOIN(X,Y) STX_MACRO_DO_JOIN2(X,Y)
00051 #define STX_MACRO_DO_JOIN2(X,Y) X##Y
00052
00053 #define STX_STATIC_ASSERT(A) \
00054 typedef static_assert_test<sizeof(STATIC_ASSERTION_FAILURE< static_cast<bool>(A) >)> \
00055 STX_MACRO_JOIN(static_assert_typedef_, __LINE__)
00056
00057 #endif
00058
00086 template < typename _Key = uint32_t,
00087 typename _Compare = std::less<_Key>,
00088 unsigned int _BTreePageSize = 1024,
00089 uint32_t _AppVersionId = 0>
00090 class CBTreeDB
00091 {
00092 public:
00093
00094
00097 typedef _Key key_type;
00098
00100 typedef _Compare key_compare;
00101
00103 static const unsigned int BTreePageSize = _BTreePageSize;
00104
00107 static const uint32_t AppVersionId = _AppVersionId;
00108
00109
00110
00113 static const unsigned int LeafNodeHead = 2 * sizeof(uint16_t) + sizeof(uint64_t) + sizeof(uint32_t);
00114
00116 static const unsigned int LeafNodeNumKeys = (BTreePageSize - LeafNodeHead) / (sizeof(key_type) + sizeof(uint32_t));
00117
00118 STX_STATIC_ASSERT( LeafNodeNumKeys >= 1 );
00119
00121 static const unsigned int LeafNodeFiller = BTreePageSize - LeafNodeHead - LeafNodeNumKeys * (sizeof(key_type) + sizeof(uint32_t));
00122
00124 static const unsigned int InnerNodeHead = 2 * sizeof(uint16_t) + sizeof(uint32_t);
00125
00127 static const unsigned int InnerNodeNumKeys = (BTreePageSize - InnerNodeHead) / sizeof(key_type);
00128
00129 STX_STATIC_ASSERT( InnerNodeNumKeys >= 2 );
00130
00132 static const unsigned int InnerNodeFiller = BTreePageSize - InnerNodeHead - InnerNodeNumKeys * sizeof(key_type);
00133
00134 public:
00138 class Exception : public std::runtime_error
00139 {
00140 public:
00142 explicit Exception(const std::string& str)
00143 : std::runtime_error("CBTreeDB: " + str)
00144 {
00145 }
00146 };
00147
00150 #define CBTREEDB_ASSERT(x) do { if (!(x)) throw(Exception("Assertion failed: " #x)); } while(0)
00151
00155 #define CBTREEDB_CHECK(x,msg) do { if (!(x)) throw(Exception(msg)); } while(0)
00156
00157 public:
00165 struct SignaturePage
00166 {
00167 char signature[8];
00168 uint32_t header_crc32;
00169 uint32_t version;
00170 uint32_t app_version_id;
00171
00172 uint32_t items;
00173 uint32_t key_size;
00174
00175 uint64_t btree_offset;
00176 uint64_t btree_size;
00177 uint64_t btree_firstleaf;
00178 uint32_t btree_pagesize;
00179 uint32_t btree_levels;
00180 uint32_t btree_leaves;
00181 uint8_t btree_sha256[32];
00182
00183 uint64_t value_offset;
00184 uint64_t value_size;
00185 uint8_t value_sha256[32];
00186 }
00187 __attribute__((packed));
00188
00190 static const unsigned int SignaturePageSize = BTreePageSize;
00191
00192 STX_STATIC_ASSERT( sizeof(SignaturePage) <= BTreePageSize );
00193
00194 protected:
00206 struct LeafNode
00207 {
00209 uint16_t level;
00210
00212 uint16_t slots;
00213
00215 uint64_t baseoffset;
00216
00217 union
00218 {
00219 struct
00220 {
00222 key_type keys[LeafNodeNumKeys];
00223
00225 uint32_t offsets[LeafNodeNumKeys+1];
00226 }
00227 __attribute__((packed));
00228
00230 char filler[BTreePageSize - LeafNodeHead + sizeof(uint32_t)];
00231 };
00232
00234 inline explicit LeafNode()
00235 : level(0), slots(0), baseoffset(0)
00236 {
00237 memset(filler, 0, sizeof(filler));
00238 }
00239
00241 inline bool IsFull() const
00242 {
00243 return (slots >= LeafNodeNumKeys);
00244 }
00245
00247 inline const key_type& LastKey() const
00248 {
00249 CBTREEDB_ASSERT(slots > 0 && slots < LeafNodeNumKeys+1);
00250 return keys[slots-1];
00251 }
00252 }
00253 __attribute__((packed));
00254
00255 STX_STATIC_ASSERT( sizeof(LeafNode) == BTreePageSize );
00256
00264 struct InnerNode
00265 {
00267 uint16_t level;
00268
00270 uint16_t slots;
00271
00273 uint32_t childrenoffset;
00274
00275 union
00276 {
00278 key_type keys[InnerNodeNumKeys];
00279
00281 char filler[BTreePageSize - InnerNodeHead];
00282 };
00283
00285 inline explicit InnerNode(uint16_t level_)
00286 : level(level_), slots(0), childrenoffset(0)
00287 {
00288 memset(filler, 0, sizeof(filler));
00289 }
00290
00292 inline bool IsFull() const
00293 {
00294 return (slots >= InnerNodeNumKeys);
00295 }
00296
00298 inline const key_type& LastKey() const
00299 {
00300 CBTREEDB_ASSERT(slots > 0 && slots < InnerNodeNumKeys+1);
00301 return keys[slots-1];
00302 }
00303 }
00304 __attribute__((packed));
00305
00306 STX_STATIC_ASSERT( sizeof(InnerNode) == BTreePageSize );
00307
00308 protected:
00314 class CRC32
00315 {
00316 private:
00318 uint32_t m_crc;
00319
00320 public:
00322 CRC32()
00323 {
00324 clear();
00325 }
00326
00328 void clear()
00329 {
00330 m_crc = 0xFFFFFFFF;
00331 }
00332
00334 CRC32& update(const unsigned char* input, uint32_t length)
00335 {
00336 static const uint32_t table[256] = {
00337 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419,
00338 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
00339 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07,
00340 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
00341 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856,
00342 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
00343 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
00344 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
00345 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
00346 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A,
00347 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599,
00348 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
00349 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190,
00350 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
00351 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E,
00352 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
00353 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
00354 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
00355 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3,
00356 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
00357 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
00358 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
00359 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010,
00360 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
00361 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17,
00362 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6,
00363 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
00364 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
00365 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344,
00366 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
00367 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A,
00368 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
00369 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1,
00370 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
00371 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
00372 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
00373 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE,
00374 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
00375 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C,
00376 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
00377 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B,
00378 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
00379 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1,
00380 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
00381 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
00382 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
00383 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66,
00384 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
00385 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
00386 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8,
00387 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
00388 0x2D02EF8D };
00389
00390 register uint32_t tmp = m_crc;
00391
00392 while(length >= 16)
00393 {
00394 tmp = table[(tmp ^ input[ 0]) & 0xFF] ^ (tmp >> 8);
00395 tmp = table[(tmp ^ input[ 1]) & 0xFF] ^ (tmp >> 8);
00396 tmp = table[(tmp ^ input[ 2]) & 0xFF] ^ (tmp >> 8);
00397 tmp = table[(tmp ^ input[ 3]) & 0xFF] ^ (tmp >> 8);
00398 tmp = table[(tmp ^ input[ 4]) & 0xFF] ^ (tmp >> 8);
00399 tmp = table[(tmp ^ input[ 5]) & 0xFF] ^ (tmp >> 8);
00400 tmp = table[(tmp ^ input[ 6]) & 0xFF] ^ (tmp >> 8);
00401 tmp = table[(tmp ^ input[ 7]) & 0xFF] ^ (tmp >> 8);
00402 tmp = table[(tmp ^ input[ 8]) & 0xFF] ^ (tmp >> 8);
00403 tmp = table[(tmp ^ input[ 9]) & 0xFF] ^ (tmp >> 8);
00404 tmp = table[(tmp ^ input[10]) & 0xFF] ^ (tmp >> 8);
00405 tmp = table[(tmp ^ input[11]) & 0xFF] ^ (tmp >> 8);
00406 tmp = table[(tmp ^ input[12]) & 0xFF] ^ (tmp >> 8);
00407 tmp = table[(tmp ^ input[13]) & 0xFF] ^ (tmp >> 8);
00408 tmp = table[(tmp ^ input[14]) & 0xFF] ^ (tmp >> 8);
00409 tmp = table[(tmp ^ input[15]) & 0xFF] ^ (tmp >> 8);
00410 input += 16;
00411 length -= 16;
00412 }
00413
00414 for(uint32_t j = 0; j != length; ++j)
00415 tmp = table[(tmp ^ input[j]) & 0xFF] ^ (tmp >> 8);
00416
00417 m_crc = tmp;
00418
00419 return *this;
00420 }
00421
00423 CRC32& update(const void* input, uint32_t length)
00424 {
00425 return update(reinterpret_cast<const unsigned char*>(input), length);
00426 }
00427
00429 uint32_t final() const
00430 {
00431 return (m_crc ^ 0xFFFFFFFF);
00432 }
00433
00435 static uint32_t digest(const void* input, uint32_t length)
00436 {
00437 return CRC32().update(input, length).final();
00438 }
00439
00441 static uint32_t digest(const std::string& input)
00442 {
00443 return digest(input.data(), input.size());
00444 }
00445 };
00446
00447 protected:
00453 class SHA256
00454 {
00455 private:
00457 typedef uint8_t byte;
00458
00460 typedef uint32_t u32bit;
00461
00463 typedef uint64_t u64bit;
00464
00466 static const u32bit OUTPUT_LENGTH = 32;
00467
00469 static const u32bit HASH_BLOCK_SIZE = 64;
00470
00472 static const u32bit COUNT_SIZE = 8;
00473
00474 private:
00475 u32bit W[64];
00476 u32bit digest[8];
00477
00478 byte buffer[HASH_BLOCK_SIZE];
00479
00480 u64bit count;
00481 u32bit position;
00482
00483 private:
00485 template<typename T> inline T rotate_left(T input, u32bit rot)
00486 { return static_cast<T>((input << rot) | (input >> (8*sizeof(T)-rot))); }
00487
00489 template<typename T> inline T rotate_right(T input, u32bit rot)
00490 { return static_cast<T>((input >> rot) | (input << (8*sizeof(T)-rot))); }
00491
00493 template<typename T> inline byte get_byte(u32bit byte_num, T input)
00494 { return static_cast<byte>(input >> ((sizeof(T)-1-(byte_num&(sizeof(T)-1))) << 3)); }
00495
00497 inline u32bit make_u32bit(byte input0, byte input1, byte input2, byte input3)
00498 { return static_cast<u32bit>((static_cast<u32bit>(input0) << 24) |
00499 (static_cast<u32bit>(input1) << 16) |
00500 (static_cast<u32bit>(input2) << 8) | input3); }
00501
00503 inline u32bit rho(u32bit X, u32bit rot1, u32bit rot2, u32bit rot3)
00504 {
00505 return (rotate_right(X, rot1) ^ rotate_right(X, rot2) ^
00506 rotate_right(X, rot3));
00507 }
00508
00510 inline u32bit sigma(u32bit X, u32bit rot1, u32bit rot2, u32bit shift)
00511 {
00512 return (rotate_right(X, rot1) ^ rotate_right(X, rot2) ^ (X >> shift));
00513 }
00514
00516 inline void F1(u32bit A, u32bit B, u32bit C, u32bit& D,
00517 u32bit E, u32bit F, u32bit G, u32bit& H,
00518 u32bit msg, u32bit magic)
00519 {
00520 magic += rho(E, 6, 11, 25) + ((E & F) ^ (~E & G)) + msg;
00521 D += magic + H;
00522 H += magic + rho(A, 2, 13, 22) + ((A & B) ^ (A & C) ^ (B & C));
00523 }
00524
00526 void hash(const byte input[])
00527 {
00528 for(u32bit j = 0; j != 16; ++j)
00529 W[j] = make_u32bit(input[4*j], input[4*j+1], input[4*j+2], input[4*j+3]);
00530 for(u32bit j = 16; j != 64; ++j)
00531 W[j] = sigma(W[j- 2], 17, 19, 10) + W[j- 7] +
00532 sigma(W[j-15], 7, 18, 3) + W[j-16];
00533
00534 u32bit A = digest[0], B = digest[1], C = digest[2],
00535 D = digest[3], E = digest[4], F = digest[5],
00536 G = digest[6], H = digest[7];
00537
00538 F1(A,B,C,D,E,F,G,H,W[ 0],0x428A2F98);
00539 F1(H,A,B,C,D,E,F,G,W[ 1],0x71374491);
00540 F1(G,H,A,B,C,D,E,F,W[ 2],0xB5C0FBCF);
00541 F1(F,G,H,A,B,C,D,E,W[ 3],0xE9B5DBA5);
00542 F1(E,F,G,H,A,B,C,D,W[ 4],0x3956C25B);
00543 F1(D,E,F,G,H,A,B,C,W[ 5],0x59F111F1);
00544 F1(C,D,E,F,G,H,A,B,W[ 6],0x923F82A4);
00545 F1(B,C,D,E,F,G,H,A,W[ 7],0xAB1C5ED5);
00546 F1(A,B,C,D,E,F,G,H,W[ 8],0xD807AA98);
00547 F1(H,A,B,C,D,E,F,G,W[ 9],0x12835B01);
00548 F1(G,H,A,B,C,D,E,F,W[10],0x243185BE);
00549 F1(F,G,H,A,B,C,D,E,W[11],0x550C7DC3);
00550 F1(E,F,G,H,A,B,C,D,W[12],0x72BE5D74);
00551 F1(D,E,F,G,H,A,B,C,W[13],0x80DEB1FE);
00552 F1(C,D,E,F,G,H,A,B,W[14],0x9BDC06A7);
00553 F1(B,C,D,E,F,G,H,A,W[15],0xC19BF174);
00554 F1(A,B,C,D,E,F,G,H,W[16],0xE49B69C1);
00555 F1(H,A,B,C,D,E,F,G,W[17],0xEFBE4786);
00556 F1(G,H,A,B,C,D,E,F,W[18],0x0FC19DC6);
00557 F1(F,G,H,A,B,C,D,E,W[19],0x240CA1CC);
00558 F1(E,F,G,H,A,B,C,D,W[20],0x2DE92C6F);
00559 F1(D,E,F,G,H,A,B,C,W[21],0x4A7484AA);
00560 F1(C,D,E,F,G,H,A,B,W[22],0x5CB0A9DC);
00561 F1(B,C,D,E,F,G,H,A,W[23],0x76F988DA);
00562 F1(A,B,C,D,E,F,G,H,W[24],0x983E5152);
00563 F1(H,A,B,C,D,E,F,G,W[25],0xA831C66D);
00564 F1(G,H,A,B,C,D,E,F,W[26],0xB00327C8);
00565 F1(F,G,H,A,B,C,D,E,W[27],0xBF597FC7);
00566 F1(E,F,G,H,A,B,C,D,W[28],0xC6E00BF3);
00567 F1(D,E,F,G,H,A,B,C,W[29],0xD5A79147);
00568 F1(C,D,E,F,G,H,A,B,W[30],0x06CA6351);
00569 F1(B,C,D,E,F,G,H,A,W[31],0x14292967);
00570 F1(A,B,C,D,E,F,G,H,W[32],0x27B70A85);
00571 F1(H,A,B,C,D,E,F,G,W[33],0x2E1B2138);
00572 F1(G,H,A,B,C,D,E,F,W[34],0x4D2C6DFC);
00573 F1(F,G,H,A,B,C,D,E,W[35],0x53380D13);
00574 F1(E,F,G,H,A,B,C,D,W[36],0x650A7354);
00575 F1(D,E,F,G,H,A,B,C,W[37],0x766A0ABB);
00576 F1(C,D,E,F,G,H,A,B,W[38],0x81C2C92E);
00577 F1(B,C,D,E,F,G,H,A,W[39],0x92722C85);
00578 F1(A,B,C,D,E,F,G,H,W[40],0xA2BFE8A1);
00579 F1(H,A,B,C,D,E,F,G,W[41],0xA81A664B);
00580 F1(G,H,A,B,C,D,E,F,W[42],0xC24B8B70);
00581 F1(F,G,H,A,B,C,D,E,W[43],0xC76C51A3);
00582 F1(E,F,G,H,A,B,C,D,W[44],0xD192E819);
00583 F1(D,E,F,G,H,A,B,C,W[45],0xD6990624);
00584 F1(C,D,E,F,G,H,A,B,W[46],0xF40E3585);
00585 F1(B,C,D,E,F,G,H,A,W[47],0x106AA070);
00586 F1(A,B,C,D,E,F,G,H,W[48],0x19A4C116);
00587 F1(H,A,B,C,D,E,F,G,W[49],0x1E376C08);
00588 F1(G,H,A,B,C,D,E,F,W[50],0x2748774C);
00589 F1(F,G,H,A,B,C,D,E,W[51],0x34B0BCB5);
00590 F1(E,F,G,H,A,B,C,D,W[52],0x391C0CB3);
00591 F1(D,E,F,G,H,A,B,C,W[53],0x4ED8AA4A);
00592 F1(C,D,E,F,G,H,A,B,W[54],0x5B9CCA4F);
00593 F1(B,C,D,E,F,G,H,A,W[55],0x682E6FF3);
00594 F1(A,B,C,D,E,F,G,H,W[56],0x748F82EE);
00595 F1(H,A,B,C,D,E,F,G,W[57],0x78A5636F);
00596 F1(G,H,A,B,C,D,E,F,W[58],0x84C87814);
00597 F1(F,G,H,A,B,C,D,E,W[59],0x8CC70208);
00598 F1(E,F,G,H,A,B,C,D,W[60],0x90BEFFFA);
00599 F1(D,E,F,G,H,A,B,C,W[61],0xA4506CEB);
00600 F1(C,D,E,F,G,H,A,B,W[62],0xBEF9A3F7);
00601 F1(B,C,D,E,F,G,H,A,W[63],0xC67178F2);
00602
00603 digest[0] += A; digest[1] += B; digest[2] += C;
00604 digest[3] += D; digest[4] += E; digest[5] += F;
00605 digest[6] += G; digest[7] += H;
00606 }
00607
00609 void copy_out(byte output[])
00610 {
00611 for(u32bit j = 0; j != OUTPUT_LENGTH; ++j)
00612 output[j] = get_byte(j % 4, digest[j/4]);
00613 }
00614
00615 protected:
00616
00618 void add_data(const byte input[], u32bit length)
00619 {
00620 count += length;
00621
00622 if (position)
00623 {
00624 memcpy(buffer + position, input,
00625 std::min<u32bit>(length, sizeof(buffer) - position));
00626
00627 if(position + length >= HASH_BLOCK_SIZE)
00628 {
00629 hash(buffer);
00630 input += (HASH_BLOCK_SIZE - position);
00631 length -= (HASH_BLOCK_SIZE - position);
00632 position = 0;
00633 }
00634 }
00635
00636 while(length >= HASH_BLOCK_SIZE)
00637 {
00638 hash(input);
00639 input += HASH_BLOCK_SIZE;
00640 length -= HASH_BLOCK_SIZE;
00641 }
00642
00643 memcpy(buffer + position, input,
00644 std::min<u32bit>(length, sizeof(buffer) - position));
00645
00646 position += length;
00647 }
00648
00650 void write_count(byte out[])
00651 {
00652 for(u32bit j = 0; j != 8; ++j)
00653 {
00654 out[j+COUNT_SIZE-8] = get_byte(j % 8, 8 * count);
00655 }
00656 }
00657
00659 void final_result(byte output[OUTPUT_LENGTH])
00660 {
00661 buffer[position] = 0x80;
00662 for(u32bit j = position+1; j != HASH_BLOCK_SIZE; ++j)
00663 buffer[j] = 0;
00664 if(position >= HASH_BLOCK_SIZE - COUNT_SIZE)
00665 {
00666 hash(buffer);
00667 memset(buffer, 0, sizeof(buffer));
00668 }
00669 write_count(buffer + HASH_BLOCK_SIZE - COUNT_SIZE);
00670
00671 hash(buffer);
00672 copy_out(output);
00673 clear();
00674 }
00675
00676 public:
00678 SHA256()
00679 {
00680 clear();
00681 }
00682
00684 void clear() throw()
00685 {
00686 memset(buffer, 0, sizeof(buffer));
00687 count = position = 0;
00688
00689 memset(W, 0, sizeof(W));
00690 digest[0] = 0x6A09E667;
00691 digest[1] = 0xBB67AE85;
00692 digest[2] = 0x3C6EF372;
00693 digest[3] = 0xA54FF53A;
00694 digest[4] = 0x510E527F;
00695 digest[5] = 0x9B05688C;
00696 digest[6] = 0x1F83D9AB;
00697 digest[7] = 0x5BE0CD19;
00698 }
00699
00701 SHA256& update(const void* input, uint32_t length)
00702 {
00703 add_data(reinterpret_cast<const unsigned char*>(input), length);
00704 return *this;
00705 }
00706
00708 void final(byte output[OUTPUT_LENGTH])
00709 {
00710 final_result(output);
00711 }
00712
00714 std::string final()
00715 {
00716 byte result[OUTPUT_LENGTH];
00717 final_result(result);
00718 return std::string(reinterpret_cast<char*>(result), OUTPUT_LENGTH);
00719 }
00720
00723 bool final_equals(byte compare[OUTPUT_LENGTH])
00724 {
00725 byte result[OUTPUT_LENGTH];
00726 final_result(result);
00727 return (memcmp(compare, result, OUTPUT_LENGTH) == 0);
00728 }
00729
00732 std::string final_hex()
00733 {
00734 byte result[OUTPUT_LENGTH];
00735 final_result(result);
00736
00737 std::string out(OUTPUT_LENGTH*2, '\0');
00738
00739 static const char xdigits[16] = {
00740 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
00741 };
00742
00743 std::string::iterator oi = out.begin();
00744 for (unsigned int i = 0; i < OUTPUT_LENGTH; ++i)
00745 {
00746 *oi++ = xdigits[ (result[i] & 0xF0) >> 4 ];
00747 *oi++ = xdigits[ (result[i] & 0x0F) ];
00748 }
00749
00750 return out;
00751 }
00752
00754 static std::string digest_bin(const void* input, uint32_t length)
00755 {
00756 return SHA256().update(input, length).final();
00757 }
00758
00760 static std::string digest_bin(const std::string& input)
00761 {
00762 return digest_bin(input.data(), input.size());
00763 }
00764
00767 static std::string digest_hex(const void* input, uint32_t length)
00768 {
00769 return SHA256().update(input, length).final_hex();
00770 }
00771
00774 static std::string digest_hex(const std::string& input)
00775 {
00776 return digest_hex(input.data(), input.size());
00777 }
00778 };
00779
00780 protected:
00790 class BTreePage
00791 {
00792 protected:
00797 struct Impl
00798 {
00800 unsigned int refs;
00801
00803 char data[BTreePageSize];
00804 };
00805
00807 struct Impl* m_impl;
00808
00809 public:
00811 BTreePage()
00812 : m_impl(NULL)
00813 {
00814 }
00815
00817 BTreePage(const BTreePage& btp)
00818 : m_impl(btp.m_impl)
00819 {
00820 if (m_impl)
00821 ++m_impl->refs;
00822 }
00823
00826 ~BTreePage()
00827 {
00828 if (m_impl && --m_impl->refs == 0)
00829 delete m_impl;
00830 }
00831
00833 BTreePage& operator=(const BTreePage& btp)
00834 {
00835 if (this != &btp)
00836 {
00837 if (m_impl && --m_impl->refs == 0)
00838 delete m_impl;
00839
00840 m_impl = btp.m_impl;
00841
00842 if (m_impl)
00843 ++m_impl->refs;
00844 }
00845
00846 return *this;
00847 }
00848
00850 bool IsValid() const
00851 {
00852 return (m_impl != NULL);
00853 }
00854
00856 void Create()
00857 {
00858 if (m_impl && --m_impl->refs == 0)
00859 delete m_impl;
00860
00861 m_impl = new Impl;
00862 m_impl->refs = 1;
00863 }
00864
00866 char* GetBuffer()
00867 {
00868 CBTREEDB_ASSERT(m_impl);
00869 return m_impl->data;
00870 }
00871
00873 uint16_t GetLevel() const
00874 {
00875 CBTREEDB_ASSERT(m_impl);
00876 return reinterpret_cast<InnerNode*>(m_impl->data)->level;
00877 }
00878
00880 bool IsLeafNode() const
00881 {
00882 return (GetLevel() == 0);
00883 }
00884
00886 InnerNode* GetAsInnerNode() const
00887 {
00888 CBTREEDB_ASSERT(m_impl && !IsLeafNode());
00889 return reinterpret_cast<InnerNode*>(m_impl->data);
00890 }
00891
00893 LeafNode* GetAsLeafNode() const
00894 {
00895 CBTREEDB_ASSERT(m_impl && IsLeafNode());
00896 return reinterpret_cast<LeafNode*>(m_impl->data);
00897 }
00898 };
00899
00900 protected:
00924 class PageCacheImpl
00925 {
00926 protected:
00927
00929 unsigned int m_refs;
00930
00932 unsigned int m_maxsize;
00933
00935 unsigned int m_size;
00936
00937 #ifdef CBTREEDB_SELF_VERIFY
00938
00943 uint32_t m_lrutime;
00944 #endif
00945
00947 struct HashCell
00948 {
00950 struct HashCell *bucket_next;
00951
00953 struct HashCell *bucket_prev;
00954
00956 struct HashCell *list_next;
00957
00959 struct HashCell *list_prev;
00960
00961 #ifdef CBTREEDB_SELF_VERIFY
00962
00963 uint32_t lrutime;
00964 #endif
00965
00967 void* btreeid;
00968
00970 uint32_t pageid;
00971
00973 BTreePage page;
00974 };
00975
00977 std::vector<struct HashCell*> m_hasharray;
00978
00983 struct HashCell m_sentinel;
00984
00986 inline unsigned int hashfunc(void* btreeid, uint32_t pageid)
00987 {
00988
00989
00990 return (reinterpret_cast<uintptr_t>(btreeid) + pageid) % m_hasharray.size();
00991 }
00992
00993 public:
00995 explicit PageCacheImpl(unsigned int maxsize)
00996 : m_refs(0), m_maxsize(maxsize), m_size(0)
00997 {
00998 m_hasharray.resize(m_maxsize / 2, NULL);
00999
01000 m_sentinel.list_prev = m_sentinel.list_next = &m_sentinel;
01001 #ifdef CBTREEDB_SELF_VERIFY
01002 m_lrutime = 0;
01003 m_sentinel.lrutime = 0;
01004 #endif
01005 }
01006
01008 ~PageCacheImpl()
01009 {
01010 Clear();
01011 }
01012
01014 void RefInc()
01015 {
01016 ++m_refs;
01017 }
01018
01020 unsigned int RefDec()
01021 {
01022 return --m_refs;
01023 }
01024
01026 void Clear()
01027 {
01028
01029 struct HashCell* hc = m_sentinel.list_next;
01030 while (hc != &m_sentinel)
01031 {
01032 struct HashCell* nc = hc->list_next;
01033 delete hc;
01034 hc = nc;
01035 }
01036
01037
01038 for (unsigned int i = 0; i < m_hasharray.size(); ++i)
01039 m_hasharray[i] = NULL;
01040
01041 m_sentinel.list_prev = m_sentinel.list_next = &m_sentinel;
01042 m_size = 0;
01043 #ifdef CBTREEDB_SELF_VERIFY
01044 m_sentinel.lrutime = 0;
01045 m_lrutime = 0;
01046 #endif
01047 }
01048
01050 void Store(void* btreeid, uint32_t pageid, const BTreePage& page)
01051 {
01052
01053
01054 unsigned int h = hashfunc(btreeid, pageid);
01055
01056 struct HashCell* hc = m_hasharray[h];
01057
01058 while( hc && ! (hc->btreeid == btreeid && hc->pageid == pageid) )
01059 {
01060
01061 hc = hc->bucket_next;
01062 }
01063
01064 if ( hc )
01065 {
01066 if (hc != m_sentinel.list_next)
01067 {
01068
01069 hc->list_next->list_prev = hc->list_prev;
01070 hc->list_prev->list_next = hc->list_next;
01071
01072
01073 hc->list_prev = &m_sentinel;
01074 hc->list_next = m_sentinel.list_next;
01075 m_sentinel.list_next->list_prev = hc;
01076 m_sentinel.list_next = hc;
01077
01078
01079 hc->page = page;
01080
01081 #ifdef CBTREEDB_SELF_VERIFY
01082 hc->lrutime = ++m_lrutime;
01083 #endif
01084 }
01085
01086 }
01087 else
01088 {
01089
01090 while (m_size >= m_maxsize)
01091 {
01092 struct HashCell* lc = m_sentinel.list_prev;
01093
01094 CBTREEDB_ASSERT( lc != &m_sentinel );
01095
01096
01097 if (reinterpret_cast<uintptr_t>(lc->bucket_prev) > m_hasharray.size())
01098 {
01099 if (lc->bucket_next)
01100 lc->bucket_next->bucket_prev = lc->bucket_prev;
01101
01102 lc->bucket_prev->bucket_next = lc->bucket_next;
01103 }
01104 else
01105 {
01106 if (lc->bucket_next)
01107 lc->bucket_next->bucket_prev = lc->bucket_prev;
01108
01109 m_hasharray[ reinterpret_cast<uintptr_t>(lc->bucket_prev) ] = lc->bucket_next;
01110 }
01111
01112
01113 lc->list_next->list_prev = lc->list_prev;
01114 lc->list_prev->list_next = lc->list_next;
01115
01116 delete lc;
01117
01118 --m_size;
01119 }
01120
01121
01122 hc = new HashCell;
01123
01124 #ifdef CBTREEDB_SELF_VERIFY
01125 hc->lrutime = ++m_lrutime;
01126 #endif
01127 hc->btreeid = btreeid;
01128 hc->pageid = pageid;
01129 hc->page = page;
01130
01131
01132 hc->list_prev = &m_sentinel;
01133 hc->list_next = m_sentinel.list_next;
01134 m_sentinel.list_next->list_prev = hc;
01135 m_sentinel.list_next = hc;
01136
01137
01138 hc->bucket_prev = reinterpret_cast<HashCell*>( h );
01139 hc->bucket_next = m_hasharray[h];
01140
01141 if (m_hasharray[h])
01142 m_hasharray[h]->bucket_prev = hc;
01143
01144 m_hasharray[h] = hc;
01145
01146 ++m_size;
01147 }
01148
01149 #ifdef CBTREEDB_SELF_VERIFY
01150 CBTREEDB_ASSERT( Verify() );
01151 #endif
01152 }
01153
01156 bool Retrieve(void* btreeid, uint32_t pageid, BTreePage& outpage)
01157 {
01158
01159
01160 unsigned int h = hashfunc(btreeid, pageid);
01161
01162 struct HashCell* hc = m_hasharray[h];
01163
01164 while( hc && ! (hc->btreeid == btreeid && hc->pageid == pageid) )
01165 {
01166
01167 hc = hc->bucket_next;
01168 }
01169
01170 if ( hc )
01171 {
01172 if (hc != m_sentinel.list_next)
01173 {
01174
01175 hc->list_next->list_prev = hc->list_prev;
01176 hc->list_prev->list_next = hc->list_next;
01177
01178
01179 hc->list_prev = &m_sentinel;
01180 hc->list_next = m_sentinel.list_next;
01181 m_sentinel.list_next->list_prev = hc;
01182 m_sentinel.list_next = hc;
01183
01184 #ifdef CBTREEDB_SELF_VERIFY
01185 hc->lrutime = ++m_lrutime;
01186 #endif
01187 }
01188
01189
01190 outpage = hc->page;
01191
01192 #ifdef CBTREEDB_SELF_VERIFY
01193 CBTREEDB_ASSERT( Verify() );
01194 #endif
01195 return true;
01196 }
01197 else
01198 {
01199 #ifdef CBTREEDB_SELF_VERIFY
01200 CBTREEDB_ASSERT( Verify() );
01201 #endif
01202 return false;
01203 }
01204 }
01205
01208 void SetMaxSize(unsigned int maxsize)
01209 {
01210 m_maxsize = maxsize;
01211 }
01212
01215 std::vector< std::pair<void*, uint32_t> > GetPagelist() const
01216 {
01217 std::vector< std::pair<void*, uint32_t> > v;
01218
01219 struct HashCell* hc = m_sentinel.list_next;
01220
01221 while (hc != &m_sentinel)
01222 {
01223 v.push_back( std::make_pair(hc->btreeid, hc->pageid) );
01224 hc = hc->list_next;
01225 }
01226
01227 return v;
01228 }
01229
01231 bool Verify() const
01232 {
01233 {
01234
01235 unsigned int size = 0;
01236 struct HashCell* hc = m_sentinel.list_next;
01237
01238 while (hc != &m_sentinel)
01239 {
01240 if (!(hc->list_prev->list_next == hc)) return false;
01241 if (!(hc->list_next->list_prev == hc)) return false;
01242 #ifdef CBTREEDB_SELF_VERIFY
01243 if (!(hc->lrutime > hc->list_next->lrutime)) return false;
01244 #endif
01245
01246 ++size;
01247 hc = hc->list_next;
01248 }
01249
01250 if (size != m_size) return false;
01251 }
01252
01253 {
01254
01255 unsigned int size = 0;
01256 struct HashCell* hc = m_sentinel.list_prev;
01257
01258 while (hc != &m_sentinel)
01259 {
01260 if (!(hc->list_prev->list_next == hc)) return false;
01261 if (!(hc->list_next->list_prev == hc)) return false;
01262 #ifdef CBTREEDB_SELF_VERIFY
01263 if (!(hc->lrutime < hc->list_prev->lrutime || hc->list_prev == &m_sentinel)) return false;
01264 #endif
01265
01266 ++size;
01267 hc = hc->list_prev;
01268 }
01269
01270 if (size != m_size) return false;
01271 }
01272
01273 {
01274
01275 unsigned int size = 0;
01276
01277 for (unsigned int b = 0; b < m_hasharray.size(); ++b)
01278 {
01279 struct HashCell* hc = m_hasharray[b];
01280
01281 if (!hc) continue;
01282
01283 if (!(reinterpret_cast<uintptr_t>(hc->bucket_prev) == b)) return false;
01284
01285 ++size;
01286
01287 while (hc->bucket_next != NULL)
01288 {
01289 if (!(hc->bucket_next->bucket_prev == hc)) return false;
01290
01291 hc = hc->bucket_next;
01292
01293 ++size;
01294 }
01295 }
01296
01297 if (size != m_size) return false;
01298 }
01299
01300 return true;
01301 }
01302 };
01303
01304 public:
01328 class PageCache
01329 {
01330 protected:
01331
01333 PageCacheImpl* m_impl;
01334
01335 public:
01337 explicit PageCache(unsigned int maxpages)
01338 : m_impl(new PageCacheImpl(maxpages))
01339 {
01340 m_impl->RefInc();
01341 }
01342
01344 PageCache(const PageCache& pc)
01345 : m_impl(pc.m_impl)
01346 {
01347 m_impl->RefInc();
01348 }
01349
01352 ~PageCache()
01353 {
01354 if (m_impl->RefDec() == 0)
01355 delete m_impl;
01356 }
01357
01359 PageCache& operator=(const PageCache& pc)
01360 {
01361 if (this != &pc)
01362 {
01363 if (m_impl->RefDec() == 0)
01364 delete m_impl;
01365
01366 m_impl = pc.m_impl;
01367 m_impl->RefInc();
01368 }
01369
01370 return *this;
01371 }
01372
01374 void Clear()
01375 {
01376 return m_impl->Clear();
01377 }
01378
01380 void Store(void* btreeid, uint32_t pageid, const BTreePage& page)
01381 {
01382 return m_impl->Store(btreeid, pageid, page);
01383 }
01384
01387 bool Retrieve(void* btreeid, uint32_t pageid, BTreePage& outpage)
01388 {
01389 return m_impl->Retrieve(btreeid, pageid, outpage);
01390 }
01391
01394 void SetMaxSize(unsigned int maxsize)
01395 {
01396 return m_impl->SetMaxSize(maxsize);
01397 }
01398
01401 std::vector< std::pair<void*, uint32_t> > GetPagelist() const
01402 {
01403 return m_impl->GetPagelist();
01404 }
01405
01407 bool Verify() const
01408 {
01409 return m_impl->Verify();
01410 }
01411 };
01412
01413 protected:
01419 class ReaderImpl
01420 {
01421 protected:
01422
01424 unsigned int m_refs;
01425
01427 key_compare m_key_less;
01428
01430 char m_signaturestr[8];
01431
01433 std::istream* m_istream;
01434
01436 SignaturePage m_signature;
01437
01439 PageCache* m_pagecache;
01440
01442 BTreePage ReadIndexPage(uint32_t pageoffset)
01443 {
01444 CBTREEDB_CHECK(pageoffset + m_signature.btree_pagesize <= m_signature.btree_size,
01445 "Invalid B-tree page offset to retrieve.");
01446
01447 CBTREEDB_ASSERT(m_istream);
01448
01449 BTreePage page;
01450
01451 if (m_pagecache)
01452 {
01453 if (m_pagecache->Retrieve(this, pageoffset, page))
01454 return page;
01455 }
01456
01457 m_istream->seekg(m_signature.btree_offset + pageoffset);
01458 CBTREEDB_CHECK(m_istream->good(), "Could not read B-tree page.");
01459
01460 page.Create();
01461
01462 m_istream->read(page.GetBuffer(), BTreePageSize);
01463 CBTREEDB_CHECK(m_istream->good(), "Could not read B-tree page.");
01464
01465 if (m_pagecache)
01466 {
01467 m_pagecache->Store(this, pageoffset, page);
01468 }
01469
01470 return page;
01471 }
01472
01475 bool ReadValueRange(uint64_t offset, void* data, uint32_t size)
01476 {
01477 CBTREEDB_ASSERT(m_istream);
01478
01479 if (offset + size > m_signature.value_size) return false;
01480
01481 m_istream->seekg(m_signature.value_offset + offset);
01482 if (m_istream->bad()) return false;
01483
01484 m_istream->read(reinterpret_cast<char*>(data), size);
01485 if (m_istream->bad()) return false;
01486
01487 return true;
01488 }
01489
01491 bool KeyEqual(const key_type& a, const key_type& b)
01492 {
01493 return !m_key_less(a,b) && !m_key_less(b,a);
01494 }
01495
01497 bool KeyUnequal(const key_type& a, const key_type& b)
01498 {
01499 return m_key_less(a,b) || m_key_less(b,a);
01500 }
01501
01503 template <typename NodeType>
01504 int BinarySearch(const NodeType* node, key_type key)
01505 {
01506 register int lo = 0, hi = node->slots;
01507
01508 while (lo < hi)
01509 {
01510 register int mid = (hi + lo) >> 1;
01511
01512 if (m_key_less(node->keys[mid], key)) {
01513 lo = mid + 1;
01514 }
01515 else {
01516 hi = mid;
01517 }
01518 }
01519
01520 #ifdef CBTREEDB_SELF_VERIFY
01521
01522 {
01523 int i = 0;
01524 while(i < node->slots && m_key_less(node->keys[i], key))
01525 ++i;
01526
01527 CBTREEDB_ASSERT(i == lo);
01528 }
01529 #endif
01530 return lo;
01531 }
01532
01533 public:
01535 ReaderImpl(const key_compare& key_less)
01536 : m_refs(0), m_key_less(key_less), m_istream(NULL), m_pagecache(NULL)
01537 {
01538 memcpy(m_signaturestr, "cbtreedb", 8);
01539 }
01540
01542 void RefInc()
01543 {
01544 ++m_refs;
01545 }
01546
01548 unsigned int RefDec()
01549 {
01550 return --m_refs;
01551 }
01552
01558 void SetSignature(const char* newsignature)
01559 {
01560 unsigned int i = 0;
01561 for(; i < 8 && newsignature[i]; ++i)
01562 m_signaturestr[i] = newsignature[i];
01563
01564 for(; i < 8; ++i)
01565 m_signaturestr[i] = 0;
01566 }
01567
01578 bool Open(std::istream& file, std::string* errortext = NULL)
01579 {
01580 m_istream = NULL;
01581
01582 file.seekg(0, std::ios::beg);
01583 if (file.bad()) {
01584 if (errortext) *errortext = "Could not open database.";
01585 return false;
01586 }
01587
01588 file.read(reinterpret_cast<char*>(&m_signature), sizeof(m_signature));
01589 if (file.bad()) {
01590 if (errortext) *errortext = "Could not read signature.";
01591 return false;
01592 }
01593
01594 if (memcmp(m_signature.signature, m_signaturestr, 8) != 0) {
01595 if (errortext) *errortext = "Could not verify signature.";
01596 return false;
01597 }
01598
01599 if (m_signature.version != 0x00010000) {
01600 if (errortext) *errortext = "Signature contains unknown version.";
01601 return false;
01602 }
01603
01604 if (m_signature.app_version_id != AppVersionId) {
01605 if (errortext) *errortext = "Signature mismatches application version identifier.";
01606 return false;
01607 }
01608
01609 uint32_t crc = CRC32::digest(reinterpret_cast<char*>(&m_signature)+16, sizeof(m_signature)-16);
01610
01611 if (m_signature.header_crc32 != crc) {
01612 if (errortext) *errortext = "Header checksum mismatches.";
01613 return false;
01614 }
01615
01616 if (m_signature.key_size != sizeof(key_type)) {
01617 if (errortext) *errortext = "Database not compatible with this reader: key sizes mismatch.";
01618 return false;
01619 }
01620
01621 if (m_signature.btree_pagesize != BTreePageSize) {
01622 if (errortext) *errortext = "Database not compatible with this reader: page sizes mismatch.";
01623 return false;
01624 }
01625
01626
01627
01628
01629 m_istream = &file;
01630
01631 BTreePage root = ReadIndexPage(0);
01632
01633 if ( root.IsLeafNode() )
01634 {
01635 LeafNode* leaf = root.GetAsLeafNode();
01636
01637 for(uint16_t s = 0; s < leaf->slots - 1; ++s)
01638 {
01639 if (!m_key_less(leaf->keys[s], leaf->keys[s+1])) {
01640 m_istream = NULL;
01641 if (errortext) *errortext = "Database not compatible with this reader: root keys order mismatches.";
01642 return false;
01643 }
01644 }
01645 }
01646 else
01647 {
01648 InnerNode* inner = root.GetAsInnerNode();
01649
01650 for(uint16_t s = 0; s < inner->slots - 1; ++s)
01651 {
01652 if (!m_key_less(inner->keys[s], inner->keys[s+1])) {
01653 m_istream = NULL;
01654 if (errortext) *errortext = "Database not compatible with this reader: root keys order mismatches.";
01655 return false;
01656 }
01657 }
01658 }
01659
01660 return true;
01661 }
01662
01666 void Close()
01667 {
01668 if (m_istream)
01669 m_istream = NULL;
01670 }
01671
01673 void SetPageCache(PageCache* newpagecache)
01674 {
01675 m_pagecache = newpagecache;
01676 }
01677
01681 uint32_t Size() const
01682 {
01683 CBTREEDB_CHECK(m_istream, "No database loaded.");
01684
01685 return m_signature.items;
01686 }
01687
01692 const SignaturePage& GetSignature() const
01693 {
01694 return m_signature;
01695 }
01696
01697 protected:
01702 bool FindKey(const key_type& key, uint64_t& outoffset, uint32_t& outsize)
01703 {
01704 if (m_signature.btree_size == 0) return false;
01705
01706 BTreePage page = ReadIndexPage(0);
01707
01708 bool checklastkey = false;
01709 key_type lastkey = key_type();
01710
01711 while( ! page.IsLeafNode() )
01712 {
01713 InnerNode* inner = page.GetAsInnerNode();
01714
01715 CBTREEDB_CHECK(!checklastkey || !m_key_less(lastkey, inner->LastKey()),
01716 "BTree corrupt (lastkey does not match).");
01717
01718 int slot = BinarySearch(inner, key);
01719
01720 uint32_t next = inner->childrenoffset;
01721 if (inner->level > 1)
01722 next += slot * sizeof(InnerNode);
01723 else
01724 next += slot * sizeof(LeafNode);
01725
01726 int oldlevel = inner->level;
01727
01728 if (slot < inner->slots) {
01729 checklastkey = true;
01730 lastkey = inner->keys[slot];
01731 }
01732
01733 page = ReadIndexPage(next);
01734
01735 CBTREEDB_CHECK(page.GetLevel() == oldlevel-1,
01736 "BTree corrupt (level order mismatch).");
01737 }
01738
01739 LeafNode* leaf = page.GetAsLeafNode();
01740
01741 CBTREEDB_CHECK(!checklastkey || KeyEqual(leaf->LastKey(), lastkey),
01742 "BTree corrupt (lastkey in leaf does not match).");
01743
01744 int slot = BinarySearch(leaf, key);
01745
01746 if (slot >= leaf->slots || KeyUnequal(leaf->keys[slot], key))
01747 return false;
01748
01749
01750
01751 outoffset = leaf->baseoffset + leaf->offsets[slot];
01752
01753
01754 CBTREEDB_CHECK(leaf->offsets[slot] <= leaf->offsets[slot+1],
01755 "BTree corrupt (offsets are not ascending).");
01756
01757 outsize = leaf->offsets[slot+1] - leaf->offsets[slot];
01758
01759 return true;
01760 }
01761
01762 public:
01769 bool Exists(const key_type& key)
01770 {
01771 CBTREEDB_CHECK(m_istream, "No database loaded.");
01772
01773 uint64_t offset;
01774 uint32_t size;
01775
01776 return FindKey(key, offset, size);
01777 }
01778
01788 bool Lookup(const key_type& key, void* outvalue, uint32_t maxsize)
01789 {
01790 CBTREEDB_CHECK(m_istream, "No database loaded.");
01791
01792 uint64_t offset;
01793 uint32_t size;
01794
01795 if (!FindKey(key, offset, size))
01796 return false;
01797
01798 uint32_t readsize = size;
01799 if (readsize > maxsize) readsize = maxsize;
01800
01801 return ReadValueRange(offset, outvalue, readsize);
01802 }
01803
01812 bool Lookup(const key_type& key, std::string& outvalue)
01813 {
01814 CBTREEDB_CHECK(m_istream, "No database loaded.");
01815
01816 uint64_t offset;
01817 uint32_t size;
01818
01819 if (!FindKey(key, offset, size))
01820 return false;
01821
01822 outvalue.resize(size);
01823
01824 return ReadValueRange(offset, const_cast<char*>(outvalue.data()), size);
01825 }
01826
01835 std::string operator[](const key_type& key)
01836 {
01837 CBTREEDB_CHECK(m_istream, "No database loaded.");
01838
01839 uint64_t offset;
01840 uint32_t size;
01841
01842 if (!FindKey(key, offset, size))
01843 return std::string();
01844
01845 std::string outvalue;
01846 outvalue.resize(size);
01847
01848 if (!ReadValueRange(offset, const_cast<char*>(outvalue.data()), size))
01849 return std::string();
01850
01851 return outvalue;
01852 }
01853
01854 protected:
01860 bool FindIndex(uint32_t index, key_type& outkey, uint64_t& outoffset, uint32_t& outsize)
01861 {
01862 if (index >= m_signature.items) return false;
01863
01864
01865
01866 uint32_t offset = index / LeafNodeNumKeys * BTreePageSize;
01867 unsigned int slot = index % LeafNodeNumKeys;
01868
01869 BTreePage page = ReadIndexPage(m_signature.btree_firstleaf + offset);
01870
01871 CBTREEDB_CHECK(page.IsLeafNode(),
01872 "BTree corrupt (expecting leaf node).");
01873
01874 LeafNode* leaf = page.GetAsLeafNode();
01875
01876 CBTREEDB_CHECK(slot < leaf->slots,
01877 "BTree corrupt (index beyond range in leaf node).");
01878
01879
01880 outkey = leaf->keys[slot];
01881 outoffset = leaf->baseoffset + leaf->offsets[slot];
01882
01883
01884 CBTREEDB_CHECK(leaf->offsets[slot] <= leaf->offsets[slot+1],
01885 "BTree corrupt (offsets are not ascending).");
01886
01887 outsize = leaf->offsets[slot+1] - leaf->offsets[slot];
01888
01889 return true;
01890 }
01891
01892 public:
01900 uint32_t GetIndex(uint32_t index, key_type& outkey)
01901 {
01902 CBTREEDB_CHECK(m_istream, "No database loaded.");
01903
01904 uint64_t offset;
01905 uint32_t size;
01906
01907 if (!FindIndex(index, outkey, offset, size))
01908 return 0;
01909
01910 return size;
01911 }
01912
01923 uint32_t GetIndex(uint32_t index, key_type& outkey, void* outvalue, uint32_t maxsize)
01924 {
01925 CBTREEDB_CHECK(m_istream, "No database loaded.");
01926
01927 uint64_t offset;
01928 uint32_t size;
01929
01930 if (!FindIndex(index, outkey, offset, size))
01931 return 0;
01932
01933 uint32_t outsize = size;
01934 if (outsize > maxsize) outsize = maxsize;
01935
01936 if (!ReadValueRange(offset, outvalue, outsize))
01937 return 0;
01938
01939 return size;
01940 }
01941
01951 uint32_t GetIndex(uint32_t index, key_type& outkey, std::string& outvalue)
01952 {
01953 CBTREEDB_CHECK(m_istream, "No database loaded.");
01954
01955 uint64_t offset;
01956 uint32_t size;
01957
01958 if (!FindIndex(index, outkey, offset, size))
01959 return 0;
01960
01961 outvalue.resize(size);
01962
01963 if (!ReadValueRange(offset, const_cast<char*>(outvalue.data()), size))
01964 return 0;
01965
01966 return size;
01967 }
01968
01974 bool Verify()
01975 {
01976 CBTREEDB_CHECK(m_istream, "No database loaded.");
01977
01978 if (!VerifyBTree()) return false;
01979
01980 if (!VerifyBTreeChecksum()) return false;
01981
01982 if (!VerifyValueChecksum()) return false;
01983
01984 return true;
01985 }
01986
01992 bool VerifyBTree()
01993 {
01994 CBTREEDB_CHECK(m_istream, "No database loaded.");
01995
01996 if (m_signature.btree_size == 0) return true;
01997
01998 key_type minkey = key_type(), maxkey = key_type();
01999 uint64_t lastoffset = 0;
02000 return VerifyBTreeNode(0, &minkey, &maxkey, &lastoffset);
02001 }
02002
02003 protected:
02007 bool VerifyBTreeNode(uint32_t offset, key_type* minkey, key_type* maxkey, uint64_t* lastoffset)
02008 {
02009 BTreePage page = ReadIndexPage(offset);
02010
02011 if ( page.IsLeafNode() )
02012 {
02013 LeafNode* leaf = page.GetAsLeafNode();
02014
02015 if (*lastoffset != leaf->baseoffset + leaf->offsets[0]) return false;
02016
02017 for(uint16_t s = 0; s < leaf->slots - 1; ++s)
02018 {
02019 if (!m_key_less(leaf->keys[s], leaf->keys[s+1])) return false;
02020
02021 if (!(leaf->offsets[s] <= leaf->offsets[s+1])) return false;
02022 }
02023
02024 *minkey = leaf->keys[0];
02025 *maxkey = leaf->keys[leaf->slots - 1];
02026 *lastoffset = leaf->baseoffset + leaf->offsets[leaf->slots];
02027 }
02028 else
02029 {
02030 InnerNode* inner = page.GetAsInnerNode();
02031
02032 for(uint16_t s = 0; s < inner->slots - 1; ++s)
02033 {
02034 if (!m_key_less(inner->keys[s], inner->keys[s+1])) return false;
02035 }
02036
02037 for(uint16_t s = 0; s <= inner->slots; ++s)
02038 {
02039 uint32_t childoffset = inner->childrenoffset;
02040
02041 if (inner->level > 1)
02042 childoffset += s * sizeof(InnerNode);
02043 else
02044 childoffset += s * sizeof(LeafNode);
02045
02046 key_type subminkey = key_type(), submaxkey = key_type();
02047
02048 if (!VerifyBTreeNode(childoffset, &subminkey, &submaxkey, lastoffset)) return false;
02049
02050 if (s == 0)
02051 *minkey = subminkey;
02052 else
02053 if (!m_key_less(inner->keys[s-1], subminkey)) return false;
02054
02055 if (s == inner->slots)
02056 *maxkey = submaxkey;
02057 else
02058 if (!KeyEqual(inner->keys[s], submaxkey)) return false;
02059 }
02060 }
02061
02062 return true;
02063 }
02064
02065 public:
02072 bool VerifyBTreeChecksum()
02073 {
02074 CBTREEDB_CHECK(m_istream, "No database loaded.");
02075
02076 SHA256 sha;
02077
02078 for(uint32_t offset = 0; offset < m_signature.btree_size; offset += BTreePageSize)
02079 {
02080 BTreePage page = ReadIndexPage(offset);
02081
02082 sha.update(page.GetBuffer(), BTreePageSize);
02083 }
02084
02085 return ( sha.final_equals(m_signature.btree_sha256) );
02086 }
02087
02094 bool VerifyValueChecksum()
02095 {
02096 CBTREEDB_CHECK(m_istream, "No database loaded.");
02097
02098 SHA256 sha;
02099
02100 char buffer[64*1024];
02101
02102 for(uint64_t offset = 0; offset < m_signature.value_size; offset += sizeof(buffer))
02103 {
02104 uint64_t remsize = std::min<uint64_t>(sizeof(buffer), m_signature.value_size - offset);
02105
02106 if (!ReadValueRange(offset, buffer, remsize))
02107 return false;
02108
02109 sha.update(buffer, remsize);
02110 }
02111
02112 return( sha.final_equals(m_signature.value_sha256) );
02113 }
02114 };
02115
02116 public:
02124 class Reader
02125 {
02126 protected:
02127
02129 ReaderImpl* m_impl;
02130
02131 public:
02133 Reader(const key_compare& key_less=key_compare())
02134 : m_impl(new ReaderImpl(key_less))
02135 {
02136 m_impl->RefInc();
02137 }
02138
02140 Reader(const Reader& rd)
02141 : m_impl(rd.m_impl)
02142 {
02143 m_impl->RefInc();
02144 }
02145
02148 ~Reader()
02149 {
02150 if (m_impl->RefDec() == 0)
02151 delete m_impl;
02152 }
02153
02155 Reader& operator=(const Reader& rd)
02156 {
02157 if (this != &rd)
02158 {
02159 if (m_impl->RefDec() == 0)
02160 delete m_impl;
02161
02162 m_impl = rd.m_impl;
02163 m_impl->RefInc();
02164 }
02165
02166 return *this;
02167 }
02168
02174 void SetSignature(const char* newsignature)
02175 {
02176 return m_impl->SetSignature(newsignature);
02177 }
02178
02189 bool Open(std::istream& file, std::string* errortext = NULL)
02190 {
02191 return m_impl->Open(file, errortext);
02192 }
02193
02197 void Close()
02198 {
02199 return m_impl->Close();
02200 }
02201
02203 void SetPageCache(PageCache* newpagecache)
02204 {
02205 return m_impl->SetPageCache(newpagecache);
02206 }
02207
02211 uint32_t Size() const
02212 {
02213 return m_impl->Size();
02214 }
02215
02220 const SignaturePage& GetSignature() const
02221 {
02222 return m_impl->GetSignature();
02223 }
02224
02231 bool Exists(const key_type& key)
02232 {
02233 return m_impl->Exists(key);
02234 }
02235
02245 bool Lookup(const key_type& key, void* outvalue, uint32_t maxsize)
02246 {
02247 return m_impl->Lookup(key, outvalue, maxsize);
02248 }
02249
02258 bool Lookup(const key_type& key, std::string& outvalue)
02259 {
02260 return m_impl->Lookup(key, outvalue);
02261 }
02262
02271 std::string operator[](const key_type& key)
02272 {
02273 return (*m_impl)[key];
02274 }
02275
02283 uint32_t GetIndex(uint32_t index, key_type& outkey)
02284 {
02285 return m_impl->GetIndex(index, outkey);
02286 }
02287
02298 uint32_t GetIndex(uint32_t index, key_type& outkey, void* outvalue, uint32_t maxsize)
02299 {
02300 return m_impl->GetIndex(index, outkey, outvalue, maxsize);
02301 }
02302
02312 uint32_t GetIndex(uint32_t index, key_type& outkey, std::string& outvalue)
02313 {
02314 return m_impl->GetIndex(index, outkey, outvalue);
02315 }
02316
02322 bool Verify()
02323 {
02324 return m_impl->Verify();
02325 }
02326
02332 bool VerifyBTree()
02333 {
02334 return m_impl->VerifyBTree();
02335 }
02336
02343 bool VerifyBTreeChecksum()
02344 {
02345 return m_impl->VerifyBTreeChecksum();
02346 }
02347
02354 bool VerifyValueChecksum()
02355 {
02356 return m_impl->VerifyValueChecksum();
02357 }
02358 };
02359
02360 protected:
02361
02370 class BTreeBuilder
02371 {
02372 protected:
02373
02375 key_compare m_key_less;
02376
02378 unsigned int m_size;
02379
02381 std::vector<LeafNode> m_leaves;
02382
02384 typedef std::vector<InnerNode> innerlevel_type;
02385
02388 std::vector<innerlevel_type> m_inners;
02389
02390 public:
02392 BTreeBuilder(const key_compare& key_less)
02393 : m_key_less(key_less), m_size(0)
02394 {
02395 }
02396
02397 protected:
02400 void AddInner(uint16_t level, const key_type& key)
02401 {
02402 if (m_inners.size() < level)
02403 {
02404 CBTREEDB_ASSERT(m_inners.size()+1 == level);
02405
02406
02407 m_inners.push_back(innerlevel_type());
02408 }
02409
02410 if (m_inners[level-1].size() == 0)
02411 {
02412
02413 m_inners[level-1].push_back(InnerNode(level));
02414 }
02415
02416 InnerNode* inner = &m_inners[level-1].back();
02417
02418 CBTREEDB_ASSERT(inner->slots == 0 || m_key_less(inner->LastKey(), key));
02419
02420 if (inner->IsFull())
02421 {
02422 CBTREEDB_ASSERT(m_key_less(inner->LastKey(), key));
02423
02424
02425 AddInner(inner->level + 1, key);
02426
02427
02428 m_inners[level-1].push_back(InnerNode(level));
02429 inner = &m_inners[level-1].back();
02430 }
02431 else
02432 {
02433
02434 inner->keys[inner->slots++] = key;
02435 }
02436 }
02437
02438 public:
02444 void Add(const key_type& key, uint64_t offset, uint32_t size)
02445 {
02446 if (m_leaves.size() == 0) {
02447
02448 m_leaves.push_back(LeafNode());
02449 }
02450
02451 LeafNode* leaf = &m_leaves.back();
02452
02453 if (leaf->slots > 0) {
02454 CBTREEDB_ASSERT(m_key_less(leaf->LastKey(), key));
02455 }
02456
02457 if (leaf->IsFull())
02458 {
02459
02460 AddInner(1, leaf->LastKey());
02461
02462
02463 m_leaves.push_back(LeafNode());
02464 leaf = &m_leaves.back();
02465 leaf->baseoffset = offset;
02466 }
02467
02468
02469 leaf->keys[leaf->slots] = key;
02470
02471 CBTREEDB_ASSERT(offset >= leaf->baseoffset);
02472 leaf->offsets[leaf->slots] = offset - leaf->baseoffset;
02473 leaf->offsets[leaf->slots+1] = leaf->offsets[leaf->slots] + size;
02474
02475 ++leaf->slots;
02476 ++m_size;
02477 }
02478
02480 unsigned int Size() const
02481 {
02482 return m_size;
02483 }
02484
02486 const key_type& GetLastKey() const
02487 {
02488 CBTREEDB_CHECK(m_size > 0, "No keys inserted in the tree yet");
02489
02490 return m_leaves.back().LastKey();
02491 }
02492
02494 void GetIndex(unsigned int index, key_type& outkey, uint32_t& outsize) const
02495 {
02496 CBTREEDB_CHECK(index < m_size, "Attempting to retrieve out of bounds index.");
02497
02498 unsigned int leafnum = index / LeafNodeNumKeys;
02499 unsigned int slot = index % LeafNodeNumKeys;
02500
02501 CBTREEDB_ASSERT(leafnum < m_leaves.size());
02502
02503 const LeafNode* leaf = &m_leaves[leafnum];
02504
02505 CBTREEDB_ASSERT(slot < leaf->slots);
02506
02507 outkey = leaf->keys[slot];
02508 outsize = leaf->offsets[slot+1] - leaf->offsets[slot];
02509 }
02510
02511 #if 0 // extra debug code for printing the tree
02512
02517 void Print(std::ostream& os) const
02518 {
02519 os << "Leaves:" << std::endl;
02520 for (unsigned int i = 0; i < m_leaves.size(); ++i)
02521 {
02522 os << i << ":";
02523 for (unsigned int j = 0; j < m_leaves[i].slots; ++j)
02524 {
02525 os << " " << m_leaves[i].keys[j];
02526 }
02527 os << std::endl;
02528 }
02529
02530 for (unsigned int l = 0; l < m_inners.size(); ++l)
02531 {
02532 os << "Level " << (l+1) << std::endl;
02533
02534 for (unsigned int i = 0; i < m_inners[l].size(); ++i)
02535 {
02536 os << i << ":";
02537 for (unsigned int j = 0; j < m_inners[l][i].slots; ++j)
02538 {
02539 os << " " << m_inners[l][i].keys[j];
02540 }
02541 os << std::endl;
02542 }
02543 }
02544 }
02545
02546 #endif // extra debug code for printing the tree
02547
02553 void Write(std::ostream& os, SignaturePage& signature)
02554 {
02555 signature.btree_pagesize = BTreePageSize;
02556 signature.btree_levels = m_inners.size() + 1;
02557 signature.btree_leaves = m_leaves.size();
02558
02559
02560 {
02561
02562 uint32_t offset = sizeof(InnerNode);
02563
02564 for (int l = m_inners.size()-1; l >= 0; --l)
02565 {
02566 for (unsigned int i = 0; i < m_inners[l].size(); ++i)
02567 {
02568 InnerNode& inner = m_inners[l][i];
02569
02570 inner.childrenoffset = offset;
02571
02572
02573 offset += (inner.slots + 1) * sizeof(InnerNode);
02574 }
02575 }
02576 }
02577
02578
02579
02580 uint64_t writesize = 0;
02581 SHA256 sha;
02582
02583 for (int l = m_inners.size()-1; l >= 0; --l)
02584 {
02585 for (unsigned int i = 0; i < m_inners[l].size(); ++i)
02586 {
02587 os.write(reinterpret_cast<char*>(&m_inners[l][i]), sizeof(m_inners[l][i]));
02588 CBTREEDB_CHECK(os.good(), "Error writing B-tree inner node page to output stream.");
02589
02590 sha.update(&m_inners[l][i], sizeof(m_inners[l][i]));
02591
02592 writesize += sizeof(m_inners[l][i]);
02593 }
02594 }
02595
02596
02597
02598 signature.btree_firstleaf = writesize;
02599
02600 for (unsigned int i = 0; i < m_leaves.size(); ++i)
02601 {
02602 os.write(reinterpret_cast<char*>(&m_leaves[i]), sizeof(m_leaves[i]));
02603 CBTREEDB_CHECK(os.good(), "Error writing B-tree leaf node page to output stream.");
02604
02605 sha.update(&m_leaves[i], sizeof(m_leaves[i]));
02606
02607 writesize += sizeof(m_leaves[i]);
02608 }
02609
02610 sha.final(signature.btree_sha256);
02611 signature.btree_size = writesize;
02612 }
02613 };
02614
02615 public:
02625 class Writer
02626 {
02627 protected:
02629 typedef std::map<key_type, std::string, key_compare> datamap_type;
02630
02632 datamap_type m_datamap;
02633
02635 key_compare m_key_less;
02636
02638 char m_signaturestr[8];
02639
02640 public:
02642 Writer(const key_compare& key_less=key_compare())
02643 : m_datamap(key_less),
02644 m_key_less(key_less)
02645 {
02646 memcpy(m_signaturestr, "cbtreedb", 8);
02647 }
02648
02650 void Add(const key_type& key, const void* data, size_t size)
02651 {
02652 m_datamap.insert( typename datamap_type::value_type(key, std::string(reinterpret_cast<const char*>(data), size)) );
02653 }
02654
02656 void Add(const key_type& key, const std::string& data)
02657 {
02658 Add(key, data.data(), data.size());
02659 }
02660
02662 size_t Size() const
02663 {
02664 return m_datamap.size();
02665 }
02666
02672 void SetSignature(const char* newsignature)
02673 {
02674 unsigned int i = 0;
02675 for(; i < 8 && newsignature[i]; ++i)
02676 m_signaturestr[i] = newsignature[i];
02677
02678 for(; i < 8; ++i)
02679 m_signaturestr[i] = 0;
02680 }
02681
02684 void Write(std::ostream& os) const
02685 {
02686 os.clear();
02687 os.seekp(0, std::ios::beg);
02688
02689
02690
02691
02692 SignaturePage signature;
02693 memset(&signature, 0, sizeof(signature));
02694 os.write(reinterpret_cast<char*>(&signature), sizeof(signature));
02695
02696 char signature_padding[SignaturePageSize - sizeof(SignaturePage)];
02697 memset(signature_padding, 0, SignaturePageSize - sizeof(SignaturePage));
02698 os.write(signature_padding, SignaturePageSize - sizeof(SignaturePage));
02699
02700 CBTREEDB_CHECK(os.good(), "Error writing signature block out output stream.");
02701
02702
02703
02704 memcpy(signature.signature, m_signaturestr, 8);
02705 signature.version = 0x00010000;
02706 signature.app_version_id = AppVersionId;
02707 signature.items = m_datamap.size();
02708 signature.key_size = sizeof(key_type);
02709
02710
02711
02712 BTreeBuilder btree(m_key_less);
02713 uint64_t dataoffset = 0;
02714
02715 for (typename datamap_type::const_iterator di = m_datamap.begin();
02716 di != m_datamap.end(); ++di)
02717 {
02718 btree.Add(di->first, dataoffset, di->second.size());
02719 dataoffset += di->second.size();
02720 }
02721
02722 signature.btree_offset = BTreePageSize;
02723 btree.Write(os, signature);
02724
02725 CBTREEDB_CHECK(os.good(), "Error writing B-tree pages to output stream.");
02726 CBTREEDB_ASSERT(os.tellp() == std::ostream::pos_type(SignaturePageSize + signature.btree_size));
02727
02728
02729
02730 SHA256 sha;
02731
02732 for (typename datamap_type::const_iterator di = m_datamap.begin();
02733 di != m_datamap.end(); ++di)
02734 {
02735 os.write(di->second.data(), di->second.size());
02736 CBTREEDB_CHECK(os.good(), "Error writing data block to output stream.");
02737
02738 sha.update(di->second.data(), di->second.size());
02739 }
02740
02741 CBTREEDB_ASSERT(os.tellp() == std::ostream::pos_type(SignaturePageSize + signature.btree_size + dataoffset));
02742
02743
02744
02745 signature.value_offset = SignaturePageSize + signature.btree_size;
02746 signature.value_size = dataoffset;
02747 sha.final(signature.value_sha256);
02748
02749
02750
02751 signature.header_crc32 = CRC32::digest(reinterpret_cast<char*>(&signature)+16, sizeof(signature)-16);
02752
02753 os.seekp(0, std::ios::beg);
02754 CBTREEDB_CHECK(os.good(), "Error seeking back to signature page in output stream.");
02755 CBTREEDB_ASSERT(os.tellp() == std::ostream::pos_type(0));
02756
02757 os.write(reinterpret_cast<char*>(&signature), sizeof(signature));
02758 CBTREEDB_CHECK(os.good(), "Error writing signature page to output stream.");
02759 }
02760 };
02761
02762 public:
02775 class WriterSequential
02776 {
02777 protected:
02779 key_compare m_key_less;
02780
02782 BTreeBuilder m_btree;
02783
02785 uint64_t m_dataoffset;
02786
02788 char m_signaturestr[8];
02789
02791 SignaturePage m_signature;
02792
02794 std::ostream* m_ostream;
02795
02797 uint32_t m_currpos;
02798
02800 uint64_t m_curroffset;
02801
02803 SHA256 m_datasha;
02804
02805 public:
02807 WriterSequential(const key_compare& key_less=key_compare())
02808 : m_key_less(key_less),
02809 m_btree(key_less),
02810 m_dataoffset(0),
02811 m_ostream(NULL),
02812 m_currpos(-1)
02813 {
02814 memcpy(m_signaturestr, "cbtreedb", 8);
02815 }
02816
02819 void Add(const key_type& key, uint32_t size)
02820 {
02821 CBTREEDB_CHECK(m_btree.Size() == 0 || m_key_less(m_btree.GetLastKey(), key),
02822 "Key sequence for Add() must be ascending.");
02823 CBTREEDB_CHECK(m_ostream == NULL,
02824 "Cannot declare keys after starting phase 2.");
02825
02826 m_btree.Add(key, m_dataoffset, size);
02827 m_dataoffset += size;
02828 }
02829
02831 size_t Size() const
02832 {
02833 return m_btree.Size();
02834 }
02835
02841 void SetSignature(const char* newsignature)
02842 {
02843 unsigned int i = 0;
02844 for(; i < 8 && newsignature[i]; ++i)
02845 m_signaturestr[i] = newsignature[i];
02846
02847 for(; i < 8; ++i)
02848 m_signaturestr[i] = 0;
02849 }
02850
02852 void WriteHeader(std::ostream& os)
02853 {
02854 CBTREEDB_CHECK(m_ostream == NULL,
02855 "Cannot write header again in phase 2.");
02856
02857 os.seekp(0, std::ios::beg);
02858
02859
02860
02861 memset(&m_signature, 0, sizeof(m_signature));
02862 os.write(reinterpret_cast<char*>(&m_signature), sizeof(m_signature));
02863
02864 char signature_padding[SignaturePageSize - sizeof(SignaturePage)];
02865 memset(signature_padding, 0, SignaturePageSize - sizeof(SignaturePage));
02866 os.write(signature_padding, SignaturePageSize - sizeof(SignaturePage));
02867
02868 CBTREEDB_CHECK(os.good(), "Error writing signature page to output stream.");
02869
02870
02871
02872 memcpy(m_signature.signature, m_signaturestr, 8);
02873 m_signature.version = 0x00010000;
02874 m_signature.app_version_id = AppVersionId;
02875 m_signature.btree_offset = SignaturePageSize;
02876 m_signature.items = m_btree.Size();
02877 m_signature.key_size = sizeof(key_type);
02878 m_signature.value_size = m_dataoffset;
02879
02880
02881
02882 m_btree.Write(os, m_signature);
02883 CBTREEDB_CHECK(os.good(), "Error writing B-tree pages to output stream.");
02884 CBTREEDB_ASSERT(os.tellp() == std::ostream::pos_type(SignaturePageSize + m_signature.btree_size));
02885
02886
02887
02888 m_ostream = &os;
02889 m_currpos = 0;
02890 m_curroffset = 0;
02891 m_datasha.clear();
02892 }
02893
02896 void WriteValue(const key_type& key, const void* data, uint32_t size)
02897 {
02898 CBTREEDB_CHECK(m_ostream != NULL,
02899 "Cannot write data, because phase 2 was not started.");
02900
02901 CBTREEDB_CHECK(m_currpos < m_btree.Size(),
02902 "Invalid key in WriteData() beyond end of predeclaration.");
02903
02904 CBTREEDB_CHECK(m_ostream->tellp() == std::ostream::pos_type(SignaturePageSize + m_signature.btree_size + m_curroffset),
02905 "Output stream data position is incorrect.");
02906
02907 key_type expectedkey;
02908 uint32_t expectedsize;
02909
02910 m_btree.GetIndex(m_currpos, expectedkey, expectedsize);
02911
02912 CBTREEDB_CHECK(!m_key_less(key, expectedkey) && !m_key_less(expectedkey, key),
02913 "Key in WriteData() mismatches predeclared sequence.");
02914
02915 CBTREEDB_CHECK(size == expectedsize,
02916 "Value data size in WriteData() mismatches predeclared sequence.");
02917
02918 m_ostream->write(reinterpret_cast<const char*>(data), size);
02919 CBTREEDB_CHECK(m_ostream->good(), "Error writing data blocks to output stream.");
02920
02921 m_datasha.update(data, size);
02922
02923 ++m_currpos;
02924 m_curroffset += size;
02925 }
02926
02929 void WriteValue(const key_type& key, const std::string& data)
02930 {
02931 return WriteValue(key, data.data(), data.size());
02932 }
02933
02935 void WriteFinalize()
02936 {
02937 CBTREEDB_CHECK(m_ostream != NULL,
02938 "Cannot write data, because phase 2 was not started.");
02939
02940 CBTREEDB_CHECK(m_currpos == m_btree.Size(),
02941 "WriteFinalize() called before end of predeclared sequence.");
02942
02943 CBTREEDB_CHECK(m_ostream->tellp() == std::ostream::pos_type(SignaturePageSize + m_signature.btree_size + m_signature.value_size),
02944 "Output stream data position is incorrect.");
02945
02946
02947
02948 m_signature.value_offset = SignaturePageSize + m_signature.btree_size;
02949 m_datasha.final(m_signature.value_sha256);
02950
02951
02952
02953 m_signature.header_crc32 = CRC32::digest(reinterpret_cast<char*>(&m_signature)+16, sizeof(m_signature)-16);
02954
02955 m_ostream->seekp(0, std::ios::beg);
02956 CBTREEDB_CHECK(m_ostream->good(), "Error seeking back to signature page in output stream.");
02957
02958 m_ostream->write(reinterpret_cast<char*>(&m_signature), sizeof(m_signature));
02959 CBTREEDB_CHECK(m_ostream->good(), "Error writing signature page to output stream.");
02960
02961 m_ostream->flush();
02962 m_ostream = NULL;
02963 }
02964 };
02965 };
02966
02967 }
02968
02969 #endif // _STX_CBTREEDB_H_