2007-11-29 14:18:54 +00:00
|
|
|
/* -*- mode: C; c-basic-offset: 4 -*- */
|
2008-01-24 15:10:32 +00:00
|
|
|
#ident "Copyright (c) 2007, 2008 Tokutek Inc. All rights reserved."
|
2007-11-29 14:18:54 +00:00
|
|
|
|
2007-11-14 17:58:38 +00:00
|
|
|
/* Verify a BRT. */
|
|
|
|
/* Check:
|
|
|
|
* the fingerprint of every node (local check)
|
|
|
|
* the child's fingerprint matches the parent's copy
|
|
|
|
* the tree is of uniform depth (and the height is correct at every node)
|
|
|
|
* For non-dup trees: the values to the left are < the values to the right
|
|
|
|
* and < the pivot
|
|
|
|
* For dup trees: the values to the left are <= the values to the right
|
|
|
|
* the pivots are < or <= left values (according to the PresentL bit)
|
|
|
|
* the pivots are > or >= right values (according to the PresentR bit)
|
|
|
|
*
|
|
|
|
* Note: We don't yet have DUP trees, so thee checks on duplicate trees are unimplemented. (Nov 1 2007)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "brt-internal.h"
|
2008-02-08 03:17:38 +00:00
|
|
|
#include "toku_assert.h"
|
2008-04-02 23:40:36 +00:00
|
|
|
#include "kv-pair.h"
|
|
|
|
|
2007-11-14 17:58:38 +00:00
|
|
|
static void verify_local_fingerprint (BRTNODE node) {
|
|
|
|
u_int32_t fp=0;
|
|
|
|
int i;
|
|
|
|
if (node->height>0) {
|
|
|
|
for (i=0; i<node->u.n.n_children; i++)
|
2008-02-05 18:25:23 +00:00
|
|
|
FIFO_ITERATE(BNC_BUFFER(node,i), key, keylen, data, datalen, type, xid,
|
2007-11-14 17:58:38 +00:00
|
|
|
({
|
2008-07-27 22:16:49 +00:00
|
|
|
fp += node->rand4fingerprint * toku_calc_fingerprint_cmd(type, xid, key, keylen, data, datalen);
|
2007-11-14 17:58:38 +00:00
|
|
|
}));
|
|
|
|
assert(fp==node->local_fingerprint);
|
|
|
|
} else {
|
2008-04-07 01:30:25 +00:00
|
|
|
toku_verify_counts(node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int compare_pairs (BRT brt, struct kv_pair *a, struct kv_pair *b) {
|
|
|
|
DBT x,y;
|
|
|
|
int cmp = brt->compare_fun(brt->db,
|
|
|
|
toku_fill_dbt(&x, kv_pair_key(a), kv_pair_keylen(a)),
|
|
|
|
toku_fill_dbt(&y, kv_pair_key(b), kv_pair_keylen(b)));
|
|
|
|
if (cmp==0 && (brt->flags & TOKU_DB_DUPSORT)) {
|
|
|
|
cmp = brt->dup_compare(brt->db,
|
|
|
|
toku_fill_dbt(&x, kv_pair_val(a), kv_pair_vallen(a)),
|
|
|
|
toku_fill_dbt(&y, kv_pair_val(b), kv_pair_vallen(b)));
|
|
|
|
}
|
|
|
|
return cmp;
|
|
|
|
}
|
|
|
|
static int compare_leafentries (BRT brt, LEAFENTRY a, LEAFENTRY b) {
|
|
|
|
DBT x,y;
|
|
|
|
int cmp = brt->compare_fun(brt->db,
|
|
|
|
toku_fill_dbt(&x, le_any_key(a), le_any_keylen(a)),
|
|
|
|
toku_fill_dbt(&y, le_any_key(b), le_any_keylen(b)));
|
|
|
|
if (cmp==0 && (brt->flags & TOKU_DB_DUPSORT)) {
|
|
|
|
cmp = brt->dup_compare(brt->db,
|
|
|
|
toku_fill_dbt(&x, le_any_val(a), le_any_vallen(a)),
|
|
|
|
toku_fill_dbt(&y, le_any_val(b), le_any_vallen(b)));
|
2007-11-14 17:58:38 +00:00
|
|
|
}
|
2008-04-07 01:30:25 +00:00
|
|
|
return cmp;
|
2007-11-14 17:58:38 +00:00
|
|
|
}
|
|
|
|
|
2008-01-07 19:53:50 +00:00
|
|
|
int toku_verify_brtnode (BRT brt, DISKOFF off, bytevec lorange, ITEMLEN lolen, bytevec hirange, ITEMLEN hilen, int recurse) {
|
2007-11-14 17:58:38 +00:00
|
|
|
int result=0;
|
|
|
|
BRTNODE node;
|
|
|
|
void *node_v;
|
|
|
|
int r;
|
2008-06-17 17:05:19 +00:00
|
|
|
u_int32_t fullhash = toku_cachetable_hash(brt->cf, off);
|
|
|
|
if ((r = toku_cachetable_get_and_pin(brt->cf, off, fullhash, &node_v, NULL,
|
2007-11-29 15:09:14 +00:00
|
|
|
toku_brtnode_flush_callback, toku_brtnode_fetch_callback, (void*)(long)brt->h->nodesize)))
|
2007-11-14 17:58:38 +00:00
|
|
|
return r;
|
|
|
|
//printf("%s:%d pin %p\n", __FILE__, __LINE__, node_v);
|
|
|
|
node=node_v;
|
2008-06-17 17:05:19 +00:00
|
|
|
assert(node->fullhash==fullhash);
|
2007-11-14 17:58:38 +00:00
|
|
|
verify_local_fingerprint(node);
|
|
|
|
if (node->height>0) {
|
|
|
|
int i;
|
2008-04-07 01:30:25 +00:00
|
|
|
for (i=0; i< node->u.n.n_children; i++) {
|
2007-11-14 17:58:38 +00:00
|
|
|
bytevec thislorange,thishirange;
|
|
|
|
ITEMLEN thislolen, thishilen;
|
|
|
|
if (node->u.n.n_children==0 || i==0) {
|
|
|
|
thislorange=lorange;
|
|
|
|
thislolen =lolen;
|
|
|
|
} else {
|
2007-11-27 18:16:45 +00:00
|
|
|
thislorange=kv_pair_key(node->u.n.childkeys[i-1]);
|
2007-12-06 13:52:52 +00:00
|
|
|
thislolen =toku_brt_pivot_key_len(brt, node->u.n.childkeys[i-1]);
|
2007-11-14 17:58:38 +00:00
|
|
|
}
|
|
|
|
if (node->u.n.n_children==0 || i+1>=node->u.n.n_children) {
|
|
|
|
thishirange=hirange;
|
|
|
|
thishilen =hilen;
|
|
|
|
} else {
|
2007-11-27 18:16:45 +00:00
|
|
|
thishirange=kv_pair_key(node->u.n.childkeys[i]);
|
2007-12-06 13:52:52 +00:00
|
|
|
thishilen =toku_brt_pivot_key_len(brt, node->u.n.childkeys[i]);
|
2007-11-14 17:58:38 +00:00
|
|
|
}
|
|
|
|
{
|
|
|
|
void verify_pair (bytevec key, unsigned int keylen,
|
|
|
|
bytevec data __attribute__((__unused__)),
|
|
|
|
unsigned int datalen __attribute__((__unused__)),
|
|
|
|
int type __attribute__((__unused__)),
|
2008-02-05 18:25:23 +00:00
|
|
|
TXNID xid __attribute__((__unused__)),
|
2007-11-14 17:58:38 +00:00
|
|
|
void *ignore __attribute__((__unused__))) {
|
2008-06-19 11:32:25 +00:00
|
|
|
DBT k1,k2;
|
|
|
|
if (thislorange) assert(brt->compare_fun(brt->db,
|
|
|
|
toku_fill_dbt(&k1,thislorange,thislolen),
|
|
|
|
toku_fill_dbt(&k2,key,keylen))
|
|
|
|
<0);
|
|
|
|
if (thishirange && (brt->compare_fun(brt->db,
|
|
|
|
toku_fill_dbt(&k1,key,keylen),
|
|
|
|
toku_fill_dbt(&k2,thishirange,thishilen))
|
|
|
|
>0)) {
|
2007-11-14 17:58:38 +00:00
|
|
|
printf("%s:%d in buffer %d key %s is bigger than %s\n", __FILE__, __LINE__, i, (char*)key, (char*)thishirange);
|
|
|
|
result=1;
|
|
|
|
}
|
|
|
|
}
|
2008-01-31 22:05:43 +00:00
|
|
|
toku_fifo_iterate(BNC_BUFFER(node,i), verify_pair, 0);
|
2007-11-14 17:58:38 +00:00
|
|
|
}
|
|
|
|
}
|
2008-04-07 01:30:25 +00:00
|
|
|
//if (lorange) printf("%s:%d lorange=%s\n", __FILE__, __LINE__, (char*)lorange);
|
|
|
|
//if (hirange) printf("%s:%d lorange=%s\n", __FILE__, __LINE__, (char*)hirange);
|
|
|
|
for (i=0; i<node->u.n.n_children-2; i++) {
|
|
|
|
assert(compare_pairs(brt, node->u.n.childkeys[i], node->u.n.childkeys[i+1])<0);
|
|
|
|
}
|
2007-11-14 17:58:38 +00:00
|
|
|
for (i=0; i<node->u.n.n_children; i++) {
|
|
|
|
if (i>0) {
|
2008-04-07 01:30:25 +00:00
|
|
|
//printf(" %s:%d i=%d %p v=%s\n", __FILE__, __LINE__, i, node->u.n.childkeys[i-1], (char*)kv_pair_key(node->u.n.childkeys[i-1]));
|
2008-06-19 11:32:25 +00:00
|
|
|
DBT k1,k2,k3;
|
|
|
|
toku_fill_dbt(&k2, kv_pair_key(node->u.n.childkeys[i-1]), toku_brt_pivot_key_len(brt, node->u.n.childkeys[i-1]));
|
|
|
|
if (lorange) assert(brt->compare_fun(brt->db, toku_fill_dbt(&k1, lorange, lolen), &k2) <0);
|
|
|
|
if (hirange) assert(brt->compare_fun(brt->db, &k2, toku_fill_dbt(&k3, hirange, hilen)) <=0);
|
2007-11-14 17:58:38 +00:00
|
|
|
}
|
|
|
|
if (recurse) {
|
2008-01-31 22:05:43 +00:00
|
|
|
result|=toku_verify_brtnode(brt, BNC_DISKOFF(node, i),
|
2007-11-27 18:16:45 +00:00
|
|
|
(i==0) ? lorange : kv_pair_key(node->u.n.childkeys[i-1]),
|
2007-12-06 13:52:52 +00:00
|
|
|
(i==0) ? lolen : toku_brt_pivot_key_len(brt, node->u.n.childkeys[i-1]),
|
2007-11-27 18:16:45 +00:00
|
|
|
(i==node->u.n.n_children-1) ? hirange : kv_pair_key(node->u.n.childkeys[i]),
|
2007-12-06 13:52:52 +00:00
|
|
|
(i==node->u.n.n_children-1) ? hilen : toku_brt_pivot_key_len(brt, node->u.n.childkeys[i]),
|
2008-01-07 19:53:50 +00:00
|
|
|
recurse);
|
2007-11-14 17:58:38 +00:00
|
|
|
}
|
|
|
|
}
|
2008-04-07 01:30:25 +00:00
|
|
|
} else {
|
|
|
|
// Make sure that they are in increasing order.
|
2008-04-25 13:45:55 +00:00
|
|
|
int check_increasing (OMTVALUE lev, u_int32_t idx, void *vprevp) {
|
|
|
|
LEAFENTRY v=lev;
|
2008-04-22 20:39:50 +00:00
|
|
|
LEAFENTRY *prevp = vprevp;
|
|
|
|
if (idx>0)
|
|
|
|
assert(compare_leafentries(brt, *prevp, v)<0);
|
|
|
|
*prevp=v;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
LEAFENTRY prev=0;
|
|
|
|
toku_omt_iterate(node->u.l.buffer, check_increasing, &prev);
|
2007-11-14 17:58:38 +00:00
|
|
|
}
|
2008-06-17 17:05:19 +00:00
|
|
|
if ((r = toku_cachetable_unpin(brt->cf, off, fullhash, 0, 0))) return r;
|
2007-11-14 17:58:38 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2007-11-20 00:35:31 +00:00
|
|
|
int toku_verify_brt (BRT brt) {
|
2007-11-14 17:58:38 +00:00
|
|
|
int r;
|
|
|
|
CACHEKEY *rootp;
|
|
|
|
if ((r = toku_read_and_pin_brt_header(brt->cf, &brt->h))) {
|
|
|
|
if (0) { died0: toku_unpin_brt_header(brt); }
|
|
|
|
return r;
|
|
|
|
}
|
2008-06-18 21:38:01 +00:00
|
|
|
u_int32_t root_hash;
|
|
|
|
rootp = toku_calculate_root_offset_pointer(brt, &root_hash);
|
2008-01-07 19:53:50 +00:00
|
|
|
if ((r=toku_verify_brtnode(brt, *rootp, 0, 0, 0, 0, 1))) goto died0;
|
2007-11-14 17:58:38 +00:00
|
|
|
if ((r = toku_unpin_brt_header(brt))!=0) return r;
|
|
|
|
return 0;
|
|
|
|
}
|