root / tags / 1.0.8 / xapian-core / backends / flint / flint_check.cc

Revision 9981, 6.9 kB (checked in by olly, 12 months ago)

backends/flint/flint_check.cc: Tweak a comparison so all the
constants are on the same side (micro-optimisation).
backends/quartz/btreecheck.cc: Equivalent change for quartz.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* flint_check.cc: Btree checking
2 *
3 * Copyright 1999,2000,2001 BrightStation PLC
4 * Copyright 2002 Ananova Ltd
5 * Copyright 2002,2004,2005,2008 Olly Betts
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
20 * USA
21 */
22
23#include <config.h>
24
25#include <limits.h>
26
27#include <iostream>
28
29using namespace std;
30
31#include "flint_check.h"
32
33#define REVISION(b)      static_cast<unsigned int>(getint4(b, 0))
34#define GET_LEVEL(b)     getint1(b, 4)
35#define MAX_FREE(b)      getint2(b, 5)
36#define TOTAL_FREE(b)    getint2(b, 7)
37#define DIR_END(b)       getint2(b, 9)
38#define DIR_START        11
39
40void BtreeCheck::print_spaces(int n) const
41{
42    while (n--) out.put(' ');
43}
44
45void BtreeCheck::print_bytes(int n, const byte * p) const
46{
47    out.write(reinterpret_cast<const char *>(p), n);
48}
49
50void BtreeCheck::print_key(const byte * p, int c, int j) const
51{
52    Item_ item(p, c);
53    string key;
54    if (item.key().length() >= 0)
55        item.key().read(&key);
56    if (j == 0) {
57        out << key << '/' << item.component_of();
58    } else {
59        for (string::const_iterator i = key.begin(); i != key.end(); ++i) {
60            // out << (*i < 32 ? '.' : *i);
61            char ch = *i;
62            if (ch < 32) out << '/' << unsigned(ch); else out << ch;
63        }
64    }
65}
66
67void BtreeCheck::print_tag(const byte * p, int c, int j) const
68{
69    Item_ item(p, c);
70    string tag;
71    item.append_chunk(&tag);
72    if (j == 0) {
73        out << "/" << item.components_of() << tag;
74    } else {
75        out << "--> [" << getint4(reinterpret_cast<const byte*>(tag.data()), 0)
76            << ']';
77    }
78}
79
80void BtreeCheck::report_block_full(int m, int n, const byte * p) const
81{
82    int j = GET_LEVEL(p);
83    int dir_end = DIR_END(p);
84    out << '\n';
85    print_spaces(m);
86    out << "Block [" << n << "] level " << j << ", revision *" << REVISION(p)
87         << " items (" << (dir_end - DIR_START)/D2 << ") usage "
88         << block_usage(p) << "%:\n";
89    for (int c = DIR_START; c < dir_end; c += D2) {
90        print_spaces(m);
91        print_key(p, c, j);
92        out << ' ';
93        print_tag(p, c, j);
94        out << '\n';
95    }
96}
97
98int BtreeCheck::block_usage(const byte * p) const
99{
100    int space = block_size - DIR_END(p);
101    int free = TOTAL_FREE(p);
102    return (space - free) * 100 / space;  /* a percentage */
103}
104
105/** BtreeCheck::report_block(m, n, p) prints the block at p, block number n,
106 *  indented by m spaces.
107 */
108void BtreeCheck::report_block(int m, int n, const byte * p) const
109{
110    int j = GET_LEVEL(p);
111    int dir_end = DIR_END(p);
112    int c;
113    print_spaces(m);
114    out << "[" << n << "] *" << REVISION(p) << " ("
115        << (dir_end - DIR_START)/D2 << ") " << block_usage(p) << "% ";
116
117    for (c = DIR_START; c < dir_end; c += D2) {
118        if (c == DIR_START + 6) out << "... ";
119        if (c >= DIR_START + 6 && c < dir_end - 6) continue;
120
121        print_key(p, c, j);
122        out << ' ';
123    }
124    out << endl;
125}
126
127void BtreeCheck::failure(int n) const
128{
129    out << "B-tree error " << n << endl;
130    throw "btree error";
131}
132
133void
134BtreeCheck::block_check(Cursor_ * C_, int j, int opts)
135{
136    byte * p = C_[j].p;
137    uint4 n = C_[j].n;
138    size_t c;
139    size_t significant_c = j == 0 ? DIR_START : DIR_START + D2;
140        /* the first key in an index block is dummy, remember */
141
142    size_t max_free = MAX_FREE(p);
143    size_t dir_end = DIR_END(p);
144    int total_free = block_size - dir_end;
145
146    if (base.block_free_at_start(n)) failure(0);
147    if (base.block_free_now(n)) failure(1);
148    base.free_block(n);
149
150    if (j != GET_LEVEL(p)) failure(10);
151    if (dir_end <= DIR_START || dir_end > block_size) failure(20);
152
153    if (opts & OPT_SHORT_TREE) report_block(3*(level - j), n, p);
154
155    if (opts & OPT_FULL_TREE) report_block_full(3*(level - j), n, p);
156
157    for (c = DIR_START; c < dir_end; c += D2) {
158        Item_ item(p, c);
159        int o = item.get_address() - p;
160        if (o > int(block_size)) failure(21);
161        if (o - dir_end < max_free) failure(30);
162
163        int kt_len = item.size();
164        if (o + kt_len > int(block_size)) failure(40);
165        total_free -= kt_len;
166
167        if (c > significant_c && Item_(p, c - D2).key() >= item.key())
168            failure(50);
169    }
170    if (total_free != TOTAL_FREE(p))
171        failure(60);
172
173    if (j == 0) return;
174    for (c = DIR_START; c < dir_end; c += D2) {
175        C_[j].c = c;
176        block_to_cursor(C_, j - 1, Item_(p, c).block_given_by());
177
178        block_check(C_, j - 1, opts);
179
180        byte * q = C_[j - 1].p;
181        /* if j == 1, and c > DIR_START, the first key of level j - 1 must be
182         * >= the key of p, c: */
183
184        if (j == 1 && c > DIR_START)
185            if (Item_(q, DIR_START).key() < Item_(p, c).key())
186                failure(70);
187
188        /* if j > 1, and c > DIR_START, the second key of level j - 1 must be
189         * >= the key of p, c: */
190
191        if (j > 1 && c > DIR_START && DIR_END(q) > DIR_START + D2 &&
192            Item_(q, DIR_START + D2).key() < Item_(p, c).key())
193            failure(80);
194
195        /* the last key of level j - 1 must be < the key of p, c + D2, if c +
196         * D2 < dir_end: */
197
198        if (c + D2 < dir_end &&
199            (j == 1 || DIR_START + D2 < DIR_END(q)) &&
200            Item_(q, DIR_END(q) - D2).key() >= Item_(p, c + D2).key())
201            failure(90);
202
203        if (REVISION(q) > REVISION(p)) failure(91);
204    }
205}
206
207void
208BtreeCheck::check(const string & name, int opts, ostream &out)
209{
210    BtreeCheck B(name, false, out);
211    B.open(); // throws exception if open fails
212    Cursor_ * C = B.C;
213
214    if (opts & OPT_SHOW_STATS) {
215        out << "base" << (char)B.base_letter
216            << " blocksize=" << B.block_size / 1024 << "K"
217               " items=" << B.item_count
218            << " lastblock=" << B.base.get_last_block()
219            << " revision=" << B.revision_number
220            << " levels=" << B.level
221            << " root=";
222        if (B.faked_root_block)
223            out << "(faked)";
224        else
225            out << C[B.level].n;
226        out << endl;
227    }
228
229    int limit = B.base.get_bit_map_size() - 1;
230
231    limit = limit * CHAR_BIT + CHAR_BIT - 1;
232
233    if (opts & OPT_SHOW_BITMAP) {
234        for (int j = 0; j <= limit; j++) {
235            out << (B.base.block_free_at_start(j) ? '.' : '*');
236            if (j > 0) {
237                if ((j + 1) % 100 == 0) {
238                    out << '\n';
239                } else if ((j + 1) % 10 == 0) {
240                    out << ' ';
241                }
242            }
243        }
244        out << '\n' << endl;
245    }
246
247    if (B.faked_root_block) {
248        if (opts) out << "void ";
249    } else {
250        B.block_check(C, B.level, opts);
251
252        /* the bit map should now be entirely clear: */
253
254        if (!B.base.is_empty()) {
255            B.failure(100);
256        }
257    }
258    if (opts) out << "B-tree checked okay" << endl;
259}
260
261void BtreeCheck::report_cursor(int N, const Cursor_ * C_) const
262{
263    out << N << ")\n";
264    for (int i = 0; i <= level; i++)
265        out << "p=" << C_[i].p << ", c=" << C_[i].c << ", n=[" << C_[i].n
266            << "], rewrite=" << C_[i].rewrite << endl;
267}
Note: See TracBrowser for help on using the browser.