00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <sys/types.h>
00021 #include <stdio.h>
00022 #include <stdint.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025
00026 #include <ccn/charbuf.h>
00027 #include <ccn/hashtb.h>
00028
00029 #include <ccn/btree.h>
00030
00031 static void
00032 ccn_btree_update_cached_parent(struct ccn_btree *btree,
00033 struct ccn_btree_internal_payload *olink,
00034 ccn_btnodeid parentid);
00035
00036 #ifndef MYFETCH
00037 #define MYFETCH(p, f) ccn_btree_fetchval(&((p)->f[0]), sizeof((p)->f))
00038 #endif
00039 unsigned
00040 ccn_btree_fetchval(const unsigned char *p, int size)
00041 {
00042 int i;
00043 unsigned v;
00044
00045 for (v = 0, i = 0; i < size; i++)
00046 v = (v << 8) + p[i];
00047 return(v);
00048 }
00049
00050 #ifndef MYSTORE
00051 #define MYSTORE(p, f, v) ccn_btree_storeval(&((p)->f[0]), sizeof((p)->f), (v))
00052 #endif
00053 void
00054 ccn_btree_storeval(unsigned char *p, int size, unsigned v)
00055 {
00056 int i;
00057
00058 for (i = size; i > 0; i--, v >>= 8)
00059 p[i-1] = v;
00060 }
00061
00062
00063
00064
00065 #define MIN_NODE_BYTES (sizeof(struct ccn_btree_node_header) + sizeof(struct ccn_btree_entry_trailer))
00066
00067
00068
00069
00070
00071
00072
00073 static struct ccn_btree_entry_trailer *
00074 seek_trailer(struct ccn_btree_node *node, int i)
00075 {
00076 struct ccn_btree_entry_trailer *t;
00077 unsigned last;
00078 unsigned ent;
00079
00080 if (node->corrupt || node->buf->length < MIN_NODE_BYTES)
00081 return(NULL);
00082 t = (struct ccn_btree_entry_trailer *)(node->buf->buf +
00083 (node->buf->length - sizeof(struct ccn_btree_entry_trailer)));
00084 last = MYFETCH(t, entdx);
00085 ent = MYFETCH(t, entsz) * CCN_BT_SIZE_UNITS;
00086 if (ent < sizeof(struct ccn_btree_entry_trailer))
00087 return(node->corrupt = __LINE__, NULL);
00088 if (ent * (last + 1) >= node->buf->length)
00089 return(node->corrupt = __LINE__, NULL);
00090 if ((unsigned)i > last)
00091 return(NULL);
00092 t = (struct ccn_btree_entry_trailer *)(node->buf->buf + node->buf->length
00093 - (ent * (last - i))
00094 - sizeof(struct ccn_btree_entry_trailer));
00095 if (MYFETCH(t, entdx) != i)
00096 return(node->corrupt = __LINE__, NULL);
00097 return(t);
00098 }
00099
00100
00101
00102
00103
00104
00105
00106
00107 void *
00108 ccn_btree_node_getentry(size_t payload_bytes, struct ccn_btree_node *node, int i)
00109 {
00110 struct ccn_btree_entry_trailer *t;
00111 size_t entry_bytes;
00112
00113 entry_bytes = payload_bytes + sizeof(struct ccn_btree_entry_trailer);
00114 t = seek_trailer(node, i);
00115 if (t == NULL)
00116 return(NULL);
00117 if (MYFETCH(t, entsz) * CCN_BT_SIZE_UNITS != entry_bytes)
00118 return(node->corrupt = __LINE__, NULL);
00119 return(((unsigned char *)t) + sizeof(*t) - entry_bytes);
00120 }
00121
00122
00123
00124
00125 static struct ccn_btree_internal_payload *
00126 ccn_btree_node_internal_entry(struct ccn_btree_node *node, int i)
00127 {
00128 struct ccn_btree_internal_payload *ans;
00129
00130 ans = ccn_btree_node_getentry(sizeof(*ans), node, i);
00131 if (ans == NULL)
00132 return(NULL);
00133 if (MYFETCH(ans, magic) != CCN_BT_INTERNAL_MAGIC)
00134 return(node->corrupt = __LINE__, NULL);
00135 return(ans);
00136 }
00137
00138
00139
00140
00141
00142
00143 int
00144 ccn_btree_node_nent(struct ccn_btree_node *node)
00145 {
00146 struct ccn_btree_entry_trailer *t;
00147
00148 if (node->corrupt)
00149 return(-1);
00150 if (node->buf->length < MIN_NODE_BYTES)
00151 return(0);
00152 t = (struct ccn_btree_entry_trailer *)(node->buf->buf +
00153 (node->buf->length - sizeof(struct ccn_btree_entry_trailer)));
00154 return(MYFETCH(t, entdx) + 1);
00155 }
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165 int
00166 ccn_btree_node_getentrysize(struct ccn_btree_node *node)
00167 {
00168 struct ccn_btree_entry_trailer *t;
00169
00170 if (node->corrupt)
00171 return(-1);
00172 if (node->buf->length < MIN_NODE_BYTES)
00173 return(0);
00174 t = (struct ccn_btree_entry_trailer *)(node->buf->buf +
00175 (node->buf->length - sizeof(struct ccn_btree_entry_trailer)));
00176 return(MYFETCH(t, entsz) * CCN_BT_SIZE_UNITS);
00177 }
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188 int
00189 ccn_btree_node_payloadsize(struct ccn_btree_node *node)
00190 {
00191 int ans;
00192
00193 ans = ccn_btree_node_getentrysize(node);
00194 if (ans >= sizeof(struct ccn_btree_entry_trailer))
00195 ans -= sizeof(struct ccn_btree_entry_trailer);
00196 return(ans);
00197 }
00198
00199
00200
00201
00202
00203 int ccn_btree_node_level(struct ccn_btree_node *node)
00204 {
00205 struct ccn_btree_node_header *hdr = NULL;
00206
00207 if (node->corrupt || node->buf->length < sizeof(struct ccn_btree_node_header))
00208 return(-1);
00209 hdr = (struct ccn_btree_node_header *)(node->buf->buf);
00210 return(MYFETCH(hdr, level));
00211 }
00212
00213
00214
00215
00216
00217 int
00218 ccn_btree_key_fetch(struct ccn_charbuf *dst,
00219 struct ccn_btree_node *node,
00220 int i)
00221 {
00222 dst->length = 0;
00223 return(ccn_btree_key_append(dst, node, i));
00224 }
00225
00226
00227
00228
00229
00230 int
00231 ccn_btree_key_append(struct ccn_charbuf *dst,
00232 struct ccn_btree_node *node,
00233 int i)
00234 {
00235 struct ccn_btree_entry_trailer *p = NULL;
00236 unsigned koff = 0;
00237 unsigned ksiz = 0;
00238
00239 p = seek_trailer(node, i);
00240 if (p == NULL)
00241 return(-1);
00242 koff = MYFETCH(p, koff0);
00243 ksiz = MYFETCH(p, ksiz0);
00244 if (koff > node->buf->length)
00245 return(node->corrupt = __LINE__, -1);
00246 if (ksiz > node->buf->length - koff)
00247 return(node->corrupt = __LINE__, -1);
00248 ccn_charbuf_append(dst, node->buf->buf + koff, ksiz);
00249 koff = MYFETCH(p, koff1);
00250 ksiz = MYFETCH(p, ksiz1);
00251 if (koff > node->buf->length)
00252 return(node->corrupt = __LINE__, -1);
00253 if (ksiz > node->buf->length - koff)
00254 return(node->corrupt = __LINE__, -1);
00255 ccn_charbuf_append(dst, node->buf->buf + koff, ksiz);
00256 return(0);
00257 }
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270 int
00271 ccn_btree_compare(const unsigned char *key,
00272 size_t size,
00273 struct ccn_btree_node *node,
00274 int i)
00275 {
00276 struct ccn_btree_entry_trailer *p = NULL;
00277 size_t cmplen;
00278 unsigned koff = 0;
00279 unsigned ksiz = 0;
00280 int res;
00281
00282 p = seek_trailer(node, i);
00283 if (p == NULL)
00284 return(i < 0 ? 999 : -999);
00285 koff = MYFETCH(p, koff0);
00286 ksiz = MYFETCH(p, ksiz0);
00287 if (koff > node->buf->length)
00288 return(node->corrupt = __LINE__, -1);
00289 if (ksiz > node->buf->length - koff)
00290 return(node->corrupt = __LINE__, -1);
00291 cmplen = size;
00292 if (cmplen > ksiz)
00293 cmplen = ksiz;
00294 res = memcmp(key, node->buf->buf + koff, cmplen);
00295 if (res != 0)
00296 return(res);
00297 if (size < ksiz)
00298 return(-9999);
00299
00300 key += cmplen;
00301 size -= cmplen;
00302 koff = MYFETCH(p, koff1);
00303 ksiz = MYFETCH(p, ksiz1);
00304 if (koff > node->buf->length)
00305 return(node->corrupt = __LINE__, -1);
00306 if (ksiz > node->buf->length - koff)
00307 return(node->corrupt = __LINE__, -1);
00308 cmplen = size;
00309 if (cmplen > ksiz)
00310 cmplen = ksiz;
00311 res = memcmp(key, node->buf->buf + koff, cmplen);
00312 if (res != 0)
00313 return(res);
00314 if (size < ksiz)
00315 return(-9999);
00316 return(size > ksiz);
00317 }
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331 int
00332 ccn_btree_searchnode(const unsigned char *key,
00333 size_t size,
00334 struct ccn_btree_node *node)
00335 {
00336 int i, j, mid, res;
00337
00338 if (node->corrupt)
00339 return(-1);
00340 i = 0;
00341 j = ccn_btree_node_nent(node);
00342 while (i < j) {
00343 mid = (i + j) >> 1;
00344 res = ccn_btree_compare(key, size, node, mid);
00345
00346 if (res == 0)
00347 return(CCN_BT_ENCRES(mid, 1));
00348 if (res < 0)
00349 j = mid;
00350 else
00351 i = mid + 1;
00352 }
00353 if (i != j) {
00354 abort();
00355 }
00356 return(CCN_BT_ENCRES(i, 0));
00357 }
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370 int
00371 ccn_btree_lookup(struct ccn_btree *btree,
00372 const unsigned char *key, size_t size,
00373 struct ccn_btree_node **leafp)
00374 {
00375 struct ccn_btree_node *node = NULL;
00376 node = ccn_btree_getnode(btree, 1, 0);
00377 if (node == NULL || node->corrupt)
00378 return(-1);
00379 return(ccn_btree_lookup_internal(btree, node, 0, key, size, leafp));
00380 }
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394 int
00395 ccn_btree_lookup_internal(struct ccn_btree *btree,
00396 struct ccn_btree_node *root, int stoplevel,
00397 const unsigned char *key, size_t size,
00398 struct ccn_btree_node **ansp)
00399 {
00400 struct ccn_btree_node *node = NULL;
00401 struct ccn_btree_node *child = NULL;
00402 struct ccn_btree_internal_payload *e = NULL;
00403 ccn_btnodeid childid;
00404 ccn_btnodeid parent;
00405 int entdx;
00406 int level;
00407 int newlevel;
00408 int srchres;
00409
00410 node = root;
00411 if (node == NULL || node->corrupt)
00412 return(-1);
00413 parent = node->nodeid;
00414 level = ccn_btree_node_level(node);
00415 if (level < stoplevel)
00416 return(-1);
00417 srchres = ccn_btree_searchnode(key, size, node);
00418 if (srchres < 0)
00419 return(-1);
00420 while (level > stoplevel) {
00421 entdx = CCN_BT_SRCH_INDEX(srchres) + CCN_BT_SRCH_FOUND(srchres) - 1;
00422 if (entdx < 0)
00423 abort();
00424 e = ccn_btree_node_internal_entry(node, entdx);
00425 if (e == NULL)
00426 return(-1);
00427 childid = MYFETCH(e, child);
00428 child = ccn_btree_getnode(btree, childid, node->nodeid);
00429 if (child == NULL)
00430 return(-1);
00431 newlevel = ccn_btree_node_level(child);
00432 if (newlevel != level - 1) {
00433 ccn_btree_note_error(btree, __LINE__);
00434 node->corrupt = __LINE__;
00435 return(-1);
00436 }
00437 node = child;
00438 level = newlevel;
00439 srchres = ccn_btree_searchnode(key, size, node);
00440 }
00441 if (ansp != NULL)
00442 *ansp = node;
00443 return(srchres);
00444 }
00445
00446
00447
00448
00449
00450
00451 static int
00452 ccn_btree_smallest_key_under(struct ccn_btree *btree,
00453 struct ccn_btree_node *node,
00454 struct ccn_charbuf *result)
00455 {
00456 struct ccn_btree_node *leaf = NULL;
00457 int res;
00458
00459 res = ccn_btree_lookup_internal(btree, node, 0, NULL, 0, &leaf);
00460 if (res < 0 || leaf == NULL)
00461 return(-1);
00462 res = ccn_btree_key_fetch(result, leaf, 0);
00463 return(res);
00464 }
00465
00466
00467
00468
00469 static void
00470 scan_reusable(const unsigned char *key, size_t keysize,
00471 struct ccn_btree_node *node, int ndx, unsigned reuse[2])
00472 {
00473
00474
00475 if (ndx == 0 && keysize > 0 && ccn_btree_node_level(node) != 0) {
00476 abort();
00477 }
00478 }
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490 int
00491 ccn_btree_insert_entry(struct ccn_btree_node *node, int i,
00492 const unsigned char *key, size_t keysize,
00493 void *payload, size_t payload_bytes)
00494 {
00495 size_t k, grow, minnewsize, pb, pre, post, org;
00496 unsigned char *to = NULL;
00497 unsigned char *from = NULL;
00498 struct ccn_btree_entry_trailer space = {};
00499 struct ccn_btree_entry_trailer *t = &space;
00500 unsigned reuse[2] = {0, 0};
00501 int j, n;
00502
00503 if (node->freelow == 0)
00504 ccn_btree_chknode(node);
00505 if (node->corrupt)
00506 return(-1);
00507 if (keysize > CCN_BT_MAX_KEY_SIZE)
00508 return(-1);
00509 pb = (payload_bytes + CCN_BT_SIZE_UNITS - 1)
00510 / CCN_BT_SIZE_UNITS
00511 * CCN_BT_SIZE_UNITS;
00512 n = ccn_btree_node_nent(node);
00513 if (i > n)
00514 return(-1);
00515 if (n == 0) {
00516 org = node->buf->length;
00517 k = pb + sizeof(struct ccn_btree_entry_trailer);
00518 }
00519 else {
00520 unsigned char *x = ccn_btree_node_getentry(pb, node, 0);
00521 if (x == NULL) return(-1);
00522 org = x - node->buf->buf;
00523 k = ccn_btree_node_getentrysize(node);
00524 }
00525 if (k != pb + sizeof(struct ccn_btree_entry_trailer))
00526 return(-1);
00527 scan_reusable(key, keysize, node, i, reuse);
00528 if (reuse[1] != 0) {
00529 MYSTORE(t, koff0, reuse[0]);
00530 MYSTORE(t, ksiz0, reuse[1]);
00531 MYSTORE(t, koff1, node->freelow);
00532 MYSTORE(t, ksiz1, keysize - reuse[1]);
00533 }
00534 else {
00535 MYSTORE(t, koff0, node->freelow);
00536 MYSTORE(t, ksiz0, keysize);
00537 }
00538 MYSTORE(t, level, ccn_btree_node_level(node));
00539 MYSTORE(t, entsz, k / CCN_BT_SIZE_UNITS);
00540 if (keysize != reuse[1] && node->clean > node->freelow)
00541 node->clean = node->freelow;
00542 minnewsize = (n + 1) * k + node->freelow + keysize - reuse[1];
00543 minnewsize = (minnewsize + CCN_BT_SIZE_UNITS - 1)
00544 / CCN_BT_SIZE_UNITS
00545 * CCN_BT_SIZE_UNITS;
00546 pre = i * k;
00547 post = (n - i) * k;
00548 if (minnewsize <= node->buf->length) {
00549
00550 to = node->buf->buf + org - k;
00551 if (node->clean > org - k)
00552 node->clean = org - k;
00553 memmove(to, to + k, pre);
00554
00555 to += pre;
00556 }
00557 else {
00558
00559 grow = minnewsize - node->buf->length;
00560 if (NULL == ccn_charbuf_reserve(node->buf, grow))
00561 return(-1);
00562 to = node->buf->buf + minnewsize - (pre + k + post);
00563 from = node->buf->buf + org;
00564 if (node->clean > org)
00565 node->clean = org;
00566 node->buf->length = minnewsize;
00567 memmove(to + pre + k, from + pre, post);
00568 memmove(to, from, pre);
00569
00570 if (to > from)
00571 memset(from, 0x33, to - from);
00572 to = to + pre;
00573 }
00574
00575 memset(to, 0, k);
00576 memmove(to, payload, payload_bytes);
00577 memmove(to + pb, t, sizeof(*t));
00578
00579 for (j = i, to = to + pb; j <= n; j++, to += k) {
00580 t = (void*)to;
00581 MYSTORE(t, entdx, j);
00582 }
00583
00584 to = node->buf->buf + node->freelow;
00585 memmove(to, key + reuse[0], keysize - reuse[1]);
00586 node->freelow += keysize - reuse[1];
00587 return(n + 1);
00588 }
00589
00590
00591
00592
00593
00594
00595
00596
00597 int
00598 ccn_btree_delete_entry(struct ccn_btree_node *node, int i)
00599 {
00600 struct ccn_btree_entry_trailer *t;
00601 unsigned char *to;
00602 size_t k, off;
00603 int j;
00604 int n;
00605
00606 if (node->corrupt)
00607 return(-1);
00608 n = ccn_btree_node_nent(node);
00609 if (i >= n)
00610 return(-1);
00611 if (n == 1) {
00612
00613 struct ccn_btree_node_header *hdr;
00614 hdr = (void*)node->buf->buf;
00615 k = sizeof(*hdr) + MYFETCH(hdr, extsz) * CCN_BT_SIZE_UNITS;
00616 node->buf->length = node->freelow = k;
00617 if (k < node->clean)
00618 node->clean = k;
00619 return(0);
00620 }
00621 k = ccn_btree_node_getentrysize(node);
00622 off = node->buf->length - k * (n - i);
00623 to = node->buf->buf + off;
00624 memmove(to, to + k, k * (n - i - 1));
00625 node->buf->length -= k;
00626 n -= 1;
00627 if (off < node->clean)
00628 node->clean = off;
00629
00630 for (j = i; j < n; j++, to += k) {
00631 t = (void*)(to + k - sizeof(*t));
00632 MYSTORE(t, entdx, j);
00633 }
00634 return(n);
00635 }
00636
00637 #if 0
00638 #define MSG(fmt, ...) fprintf(stderr, fmt "\n", __VA_ARGS__)
00639 #else
00640 #define MSG(fmt, ...) ((void)0)
00641 #endif
00642
00643
00644
00645
00646
00647
00648 static struct ccn_btree_node *
00649 ccn_btree_grow_a_level(struct ccn_btree *btree, struct ccn_btree_node *node)
00650 {
00651 struct ccn_btree_internal_payload link = {{CCN_BT_INTERNAL_MAGIC}};
00652 struct ccn_btree_node *child = NULL;
00653 struct ccn_charbuf *t = NULL;
00654 int level;
00655 int res;
00656
00657 level = ccn_btree_node_level(node);
00658 if (level < 0)
00659 return(NULL);
00660 child = ccn_btree_getnode(btree, btree->nextnodeid++, node->nodeid);
00661 if (child == NULL)
00662 return(NULL);
00663 res = ccn_btree_prepare_for_update(btree, child);
00664 if (res < 0)
00665 ccn_btree_note_error(btree, __LINE__);
00666 res = ccn_btree_prepare_for_update(btree, node);
00667 if (res < 0)
00668 ccn_btree_note_error(btree, __LINE__);
00669 child->clean = 0;
00670 node->clean = 0;
00671 t = child->buf;
00672 child->buf = node->buf;
00673 node->buf = t;
00674 res = ccn_btree_init_node(node, level + 1, 'R', 0);
00675 if (res < 0)
00676 ccn_btree_note_error(btree, __LINE__);
00677 MYSTORE(&link, child, child->nodeid);
00678 res = ccn_btree_insert_entry(node, 0, NULL, 0, &link, sizeof(link));
00679 if (res < 0)
00680 ccn_btree_note_error(btree, __LINE__);
00681 child->parent = node->nodeid;
00682 MSG("New root %u at level %d over node %u (%d errors)",
00683 (unsigned)node->nodeid, level + 1,
00684 (unsigned)child->nodeid, btree->errors);
00685 return(child);
00686 }
00687
00688
00689
00690
00691
00692
00693 static int
00694 ccn_btree_shrink_a_level(struct ccn_btree *btree)
00695 {
00696 struct ccn_btree_internal_payload *olink = NULL;
00697 struct ccn_btree_node *child = NULL;
00698 struct ccn_btree_node *root = NULL;
00699 struct ccn_charbuf *key = NULL;
00700 void *payload = NULL;
00701 int level;
00702 int i, n;
00703 int pb;
00704 int res;
00705
00706 root = ccn_btree_getnode(btree, 1, 0);
00707 if (root == NULL)
00708 return(-1);
00709 level = ccn_btree_node_level(root);
00710 if (level == 0)
00711 return(0);
00712 n = ccn_btree_node_nent(root);
00713 if (n != 1)
00714 return(0);
00715 olink = ccn_btree_node_internal_entry(root, 0);
00716 if (olink == NULL) goto Bail;
00717 child = ccn_btree_getnode(btree, MYFETCH(olink, child), root->parent);
00718 if (child == NULL) goto Bail;
00719 pb = ccn_btree_node_payloadsize(child);
00720 n = ccn_btree_node_nent(child);
00721 level = ccn_btree_node_level(child);
00722 res = ccn_btree_prepare_for_update(btree, root);
00723 if (res < 0) goto Bail;
00724 res = ccn_btree_prepare_for_update(btree, child);
00725 if (res < 0) goto Bail;
00726 res = ccn_btree_init_node(root, level, 'R', 0);
00727 if (res < 0) goto Bail;
00728 key = ccn_charbuf_create();
00729 for (i = 0; i < n; i++) {
00730 res = ccn_btree_key_fetch(key, child, i);
00731 payload = ccn_btree_node_getentry(pb, child, i);
00732 if (res < 0 || payload == NULL) goto Bail;
00733 res = ccn_btree_insert_entry(root, i, key->buf, key->length, payload, pb);
00734 if (res < 0) goto Bail;
00735 if (level > 0)
00736 ccn_btree_update_cached_parent(btree, payload, root->nodeid);
00737 }
00738 ccn_charbuf_destroy(&key);
00739 child->parent = 0;
00740 child->clean = 0;
00741 child->freelow = 0;
00742 ccn_charbuf_reset(child->buf);
00743 return(1);
00744 Bail:
00745 ccn_charbuf_destroy(&key);
00746 ccn_btree_note_error(btree, __LINE__);
00747 return(-1);
00748 }
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758 int
00759 ccn_btree_oversize(struct ccn_btree *btree, struct ccn_btree_node *node)
00760 {
00761 return(ccn_btree_unbalance(btree, node) > 0);
00762 }
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772 int
00773 ccn_btree_unbalance(struct ccn_btree *btree, struct ccn_btree_node *node)
00774 {
00775 int n;
00776
00777 n = ccn_btree_node_nent(node);
00778 if (n > 4 && btree->nodebytes != 0 && node->buf->length > btree->nodebytes)
00779 return(1);
00780 if (ccn_btree_node_level(node) == 0 && btree->full0 > 0) {
00781 if (n > btree->full0)
00782 return(1);
00783 if (2 * n < btree->full0)
00784 return(-1);
00785 }
00786 if (n > btree->full)
00787 return(1);
00788 if (2 * n < btree->full)
00789 return(-1);
00790 return(0);
00791 }
00792
00793
00794
00795
00796 static void
00797 ccn_btree_update_cached_parent(struct ccn_btree *btree,
00798 struct ccn_btree_internal_payload *olink,
00799 ccn_btnodeid parentid)
00800 {
00801 struct ccn_btree_node *chld = NULL;
00802
00803 if (MYFETCH(olink, magic) == CCN_BT_INTERNAL_MAGIC)
00804 chld = ccn_btree_rnode(btree, MYFETCH(olink, child));
00805 if (chld != NULL) {
00806 if (chld->parent != parentid) {
00807 MSG("Parent of %u changed from %u to %u",
00808 (unsigned)chld->nodeid,
00809 (unsigned)chld->parent,
00810 (unsigned)parentid);
00811 }
00812 chld->parent = parentid;
00813 }
00814 }
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827 int
00828 ccn_btree_split(struct ccn_btree *btree, struct ccn_btree_node *node)
00829 {
00830 int i, j, k, n, pb, res;
00831 struct ccn_btree_node newnode = {};
00832 struct ccn_btree_node *a[2] = {NULL, NULL};
00833 struct ccn_btree_node *parent = NULL;
00834 void *payload = NULL;
00835 struct ccn_charbuf *key = NULL;
00836 struct ccn_btree_internal_payload link = {{CCN_BT_INTERNAL_MAGIC}};
00837 struct ccn_btree_internal_payload *olink = NULL;
00838 int level;
00839
00840 if (btree->nextsplit == node->nodeid)
00841 btree->nextsplit = 0;
00842 n = ccn_btree_node_nent(node);
00843 if (n < 4)
00844 return(-1);
00845 res = ccn_btree_prepare_for_update(btree, node);
00846 if (res < 0)
00847 return(-1);
00848 if (node->nodeid == 1) {
00849 node = ccn_btree_grow_a_level(btree, node);
00850 if (node == NULL)
00851 abort();
00852 if (node->nodeid == 1 || node->parent != 1 || ccn_btree_node_nent(node) != n)
00853 abort();
00854 }
00855 parent = ccn_btree_getnode(btree, node->parent, 0);
00856 if (parent == NULL || ccn_btree_node_nent(parent) < 1)
00857 return(node->corrupt = __LINE__, -1);
00858 if (ccn_btree_node_payloadsize(parent) != sizeof(link))
00859 return(node->corrupt = __LINE__, -1);
00860 res = ccn_btree_prepare_for_update(btree, parent);
00861 if (res < 0)
00862 return(-1);
00863 pb = ccn_btree_node_payloadsize(node);
00864 level = ccn_btree_node_level(node);
00865 MSG("Splitting %d entries of node %u, child of %u", n,
00866 (unsigned)node->nodeid, (unsigned)node->parent);
00867
00868
00869 newnode.buf = ccn_charbuf_create();
00870 if (newnode.buf == NULL)
00871 goto Bail;
00872 newnode.nodeid = node->nodeid;
00873 a[0] = &newnode;
00874
00875 a[1] = ccn_btree_getnode(btree, btree->nextnodeid++, 0);
00876 if (a[1] == NULL)
00877 goto Bail;
00878 res = ccn_btree_prepare_for_update(btree, a[1]);
00879 if (res < 0)
00880 return(-1);
00881 for (k = 0; k < 2; k++) {
00882 if (ccn_btree_node_nent(a[k]) != 0)
00883 goto Bail;
00884 res = ccn_btree_init_node(a[k], ccn_btree_node_level(node), 0, 0);
00885 if (res < 0)
00886 goto Bail;
00887 a[k]->parent = node->parent;
00888 }
00889
00890 key = ccn_charbuf_create();
00891 if (key == NULL) goto Bail;
00892 for (i = 0, j = 0, k = 0, res = 0; i < n; i++, j++) {
00893 res = ccn_btree_key_fetch(key, node, i);
00894 if (i == n / 2) {
00895 k = 1; j = 0;
00896 if (level > 0)
00897 key->length = 0;
00898 }
00899 payload = ccn_btree_node_getentry(pb, node, i);
00900 if (res < 0 || payload == NULL)
00901 goto Bail;
00902 res = ccn_btree_insert_entry(a[k], j, key->buf, key->length, payload, pb);
00903 MSG("Splitting [%u %d] into [%u %d] (res = %d)",
00904 (unsigned)node->nodeid, i, (unsigned)a[k]->nodeid, j, res);
00905 if (res < 0)
00906 goto Bail;
00907 if (level > 0) {
00908
00909 ccn_btree_update_cached_parent(btree, payload, a[k]->nodeid);
00910 }
00911 }
00912
00913 res = ccn_btree_key_fetch(key, node, n / 2);
00914 if (res < 0)
00915 goto Bail;
00916
00917
00918
00919
00920
00921 MYSTORE(&link, child, a[1]->nodeid);
00922 res = ccn_btree_searchnode(key->buf, key->length, parent);
00923 if (res < 0)
00924 goto Bail;
00925 if (CCN_BT_SRCH_FOUND(res) && key->length != 0)
00926 goto Bail;
00927 i = CCN_BT_SRCH_INDEX(res);
00928 olink = ccn_btree_node_internal_entry(parent, i - 1);
00929 if (olink == NULL || MYFETCH(olink, child) != a[0]->nodeid) {
00930 node->corrupt = __LINE__;
00931 parent->corrupt = __LINE__;
00932 goto Bail;
00933 }
00934
00935 res = ccn_btree_insert_entry(parent, i,
00936 key->buf, key->length,
00937 &link, sizeof(link));
00938 if (res < 0) {
00939 parent->corrupt = __LINE__;
00940 goto Bail;
00941 }
00942 else if (ccn_btree_oversize(btree, parent)) {
00943 btree->missedsplit = btree->nextsplit;
00944 btree->nextsplit = parent->nodeid;
00945 }
00946 node->clean = 0;
00947 ccn_charbuf_destroy(&node->buf);
00948 node->buf = newnode.buf;
00949 newnode.buf = NULL;
00950 res = ccn_btree_chknode(node);
00951 if (res < 0)
00952 goto Bail;
00953 ccn_charbuf_destroy(&key);
00954 return(0);
00955 Bail:
00956 ccn_charbuf_destroy(&newnode.buf);
00957 ccn_charbuf_destroy(&key);
00958 ccn_btree_note_error(btree, __LINE__);
00959 return(-1);
00960 }
00961
00962
00963
00964
00965
00966
00967
00968
00969 int
00970 ccn_btree_index_in_parent(struct ccn_btree_node *parent, ccn_btnodeid nodeid)
00971 {
00972 struct ccn_btree_internal_payload *e = NULL;
00973 int i, n;
00974
00975 n = ccn_btree_node_nent(parent);
00976 for (i = n - 1; i >= 0; i--) {
00977 e = ccn_btree_node_internal_entry(parent, i);
00978 if (e == NULL)
00979 break;
00980 if (MYFETCH(e, child) == nodeid)
00981 return(i);
00982 }
00983 return(-1);
00984 }
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998 int
00999 ccn_btree_spill(struct ccn_btree *btree, struct ccn_btree_node *node)
01000 {
01001 struct ccn_btree_internal_payload *e = NULL;
01002 struct ccn_btree_node *parent = NULL;
01003 struct ccn_btree_node *s = NULL;
01004 void *payload = NULL;
01005 struct ccn_charbuf *key = NULL;
01006 int i, j, n, pb, ndx, res;
01007 int level;
01008
01009 if (btree->nextspill == node->nodeid)
01010 btree->nextspill = 0;
01011 n = ccn_btree_node_nent(node);
01012 if (node->nodeid == 1) {
01013
01014 res = ccn_btree_shrink_a_level(btree);
01015 if (res == 1)
01016 res = 0;
01017 return(res);
01018 }
01019 res = ccn_btree_prepare_for_update(btree, node);
01020 if (res < 0)
01021 return(-1);
01022 parent = ccn_btree_getnode(btree, node->parent, 0);
01023 if (parent == NULL)
01024 return(-1);
01025 res = ccn_btree_prepare_for_update(btree, parent);
01026 if (res < 0)
01027 return(-1);
01028 pb = ccn_btree_node_payloadsize(node);
01029 ndx = ccn_btree_index_in_parent(parent, node->nodeid);
01030 MSG("Spilling %d entries of node %u, child %d of %u", n,
01031 (unsigned)node->nodeid, ndx, (unsigned)node->parent);
01032 if (ndx == 0) {
01033
01034 e = ccn_btree_node_internal_entry(parent, ndx + 1);
01035 if (e != NULL) {
01036 btree->nextspill = MYFETCH(e, child);
01037 return(1);
01038 }
01039 return(-1);
01040 }
01041 e = ccn_btree_node_internal_entry(parent, ndx - 1);
01042 if (e == NULL)
01043 return(-1);
01044 s = ccn_btree_getnode(btree, MYFETCH(e, child), 0);
01045 if (s == NULL)
01046 return(-1);
01047 res = ccn_btree_prepare_for_update(btree, s);
01048 if (res < 0)
01049 return(-1);
01050 level = ccn_btree_node_level(node);
01051 key = ccn_charbuf_create();
01052 for (i = 0, j = ccn_btree_node_nent(s); i < n; i++, j++) {
01053 if (i == 0 && level > 0)
01054 res = ccn_btree_smallest_key_under(btree, node, key);
01055 else
01056 res = ccn_btree_key_fetch(key, node, i);
01057 payload = ccn_btree_node_getentry(pb, node, i);
01058 if (res < 0 || payload == NULL)
01059 goto Bail;
01060 res = ccn_btree_insert_entry(s, j, key->buf, key->length, payload, pb);
01061 if (res < 0)
01062 goto Bail;
01063 if (level > 0)
01064 ccn_btree_update_cached_parent(btree, payload, s->nodeid);
01065 }
01066 res = ccn_btree_delete_entry(parent, ndx);
01067 if (res < 0)
01068 goto Bail;
01069 node->parent = 0;
01070 node->clean = 0;
01071 node->freelow = 0;
01072 ccn_charbuf_reset(node->buf);
01073 ccn_charbuf_destroy(&key);
01074 res = ccn_btree_unbalance(btree, s);
01075 if (res > 0) {
01076 btree->missedsplit = btree->nextsplit;
01077 btree->nextsplit = s->nodeid;
01078
01079 return(0);
01080 }
01081 res = ccn_btree_unbalance(btree, parent);
01082 if (res < 0)
01083 btree->nextspill = parent->nodeid;
01084 return(0);
01085 Bail:
01086 ccn_charbuf_destroy(&key);
01087 ccn_btree_note_error(btree, __LINE__);
01088 return(-1);
01089 }
01090
01091 #undef MSG
01092
01093
01094
01095
01096
01097
01098
01099
01100 int
01101 ccn_btree_next_leaf(struct ccn_btree *btree,
01102 struct ccn_btree_node *node,
01103 struct ccn_btree_node **ansp)
01104 {
01105 struct ccn_btree_internal_payload *e = NULL;
01106 struct ccn_btree_node *p = NULL;
01107 struct ccn_btree_node *q = NULL;
01108 struct ccn_btree_node *parent = NULL;
01109 int i;
01110 int n;
01111 int ans;
01112 int res;
01113 struct ccn_charbuf *key = NULL;
01114
01115 ans = -1;
01116 key = ccn_charbuf_create();
01117 p = node;
01118 n = ccn_btree_node_nent(p);
01119 if (n < 1 && p->parent != 0)
01120 goto Bail;
01121 while (p->parent != 0) {
01122 res = ccn_btree_key_fetch(key, p, n - 1);
01123 if (res < 0)
01124 goto Bail;
01125 parent = ccn_btree_getnode(btree, p->parent, 0);
01126 if (parent == NULL)
01127 goto Bail;
01128 res = ccn_btree_searchnode(key->buf, key->length, parent);
01129 if (res < 0)
01130 goto Bail;
01131 n = ccn_btree_node_nent(parent);
01132 if (n < 1)
01133 goto Bail;
01134 i = CCN_BT_SRCH_INDEX(res) + CCN_BT_SRCH_FOUND(res) - 1;
01135 if (i < n - 1) {
01136
01137 q = NULL;
01138 e = ccn_btree_node_internal_entry(parent, i + 1);
01139 q = ccn_btree_getnode(btree, MYFETCH(e, child), parent->nodeid);
01140 if (q == NULL)
01141 goto Bail;
01142 res = ccn_btree_lookup_internal(btree, q, 0, key->buf, 0, ansp);
01143 if (res < 0)
01144 goto Bail;
01145 ans = 1;
01146 break;
01147 }
01148 p = parent;
01149
01150 }
01151 if (ans != 1) {
01152 *ansp = NULL;
01153 ans = 0;
01154 }
01155 Bail:
01156 ccn_charbuf_destroy(&key);
01157 return(ans);
01158 }
01159
01160
01161
01162
01163
01164
01165
01166
01167 int
01168 ccn_btree_prev_leaf(struct ccn_btree *btree,
01169 struct ccn_btree_node *node,
01170 struct ccn_btree_node **ansp)
01171 {
01172 struct ccn_btree_internal_payload *e = NULL;
01173 struct ccn_btree_node *p = NULL;
01174 struct ccn_btree_node *q = NULL;
01175 struct ccn_btree_node *parent = NULL;
01176 int ans;
01177 int i;
01178
01179 ans = -1;
01180 p = node;
01181 while (p->parent != 0) {
01182 parent = ccn_btree_getnode(btree, p->parent, 0);
01183 if (parent == NULL)
01184 goto Bail;
01185 i = ccn_btree_index_in_parent(parent, p->nodeid);
01186 if (i < 0) goto Bail;
01187 if (i > 0) {
01188
01189 for (q = parent; ccn_btree_node_level(q) != 0;) {
01190 e = ccn_btree_node_internal_entry(q, i - 1);
01191 q = ccn_btree_getnode(btree, MYFETCH(e, child), q->nodeid);
01192 if (q == NULL)
01193 goto Bail;
01194 i = ccn_btree_node_nent(q);
01195 }
01196 *ansp = q;
01197 ans = 1;
01198 break;
01199 }
01200 p = parent;
01201 }
01202 if (ans != 1) {
01203 *ansp = NULL;
01204 ans = 0;
01205 }
01206 Bail:
01207 return(ans);
01208 }
01209
01210 #define CCN_BTREE_MAGIC 0x53ade78
01211 #define CCN_BTREE_VERSION 1
01212
01213
01214
01215
01216
01217
01218
01219
01220 int
01221 ccn_btree_close_node(struct ccn_btree *btree, struct ccn_btree_node *node)
01222 {
01223 int res = 0;
01224 struct ccn_btree_io *io = btree->io;
01225
01226 if (node->corrupt)
01227 res = -1;
01228 else if (node->iodata != NULL && io != NULL) {
01229 res = io->btwrite(io, node);
01230 if (res < 0)
01231 ccn_btree_note_error(btree, __LINE__);
01232 else
01233 node->clean = node->buf->length;
01234 res |= io->btclose(io, node);
01235 if (res < 0)
01236 ccn_btree_note_error(btree, __LINE__);
01237 }
01238 else if (io != NULL && node->clean != node->buf->length) {
01239 res = -1;
01240 ccn_btree_note_error(btree, __LINE__);
01241 }
01242 return(res);
01243 }
01244
01245 static void
01246 finalize_node(struct hashtb_enumerator *e)
01247 {
01248 struct ccn_btree *btree = hashtb_get_param(e->ht, NULL);
01249 struct ccn_btree_node *node = e->data;
01250
01251 if (btree->magic != CCN_BTREE_MAGIC)
01252 abort();
01253 ccn_btree_close_node(btree, node);
01254 ccn_charbuf_destroy(&node->buf);
01255 }
01256
01257
01258
01259
01260
01261
01262 void
01263 ccn_btree_note_error(struct ccn_btree *bt, int info)
01264 {
01265 bt->errors++;
01266 }
01267
01268
01269
01270
01271
01272 struct ccn_btree *
01273 ccn_btree_create(void)
01274 {
01275 struct ccn_btree *ans;
01276 struct hashtb_param param = {0};
01277
01278 ans = calloc(1, sizeof(*ans));
01279 if (ans != NULL) {
01280 ans->magic = CCN_BTREE_MAGIC;
01281 param.finalize_data = ans;
01282 param.finalize = &finalize_node;
01283 ans->resident = hashtb_create(sizeof(struct ccn_btree_node), ¶m);
01284 if (ans->resident == NULL) {
01285 free(ans);
01286 return(NULL);
01287 }
01288 ans->errors = 0;
01289 ans->io = NULL;
01290 ans->nextnodeid = 1;
01291 ans->full = ans->full0 = 19;
01292 }
01293 return(ans);
01294 }
01295
01296
01297
01298
01299
01300 int
01301 ccn_btree_destroy(struct ccn_btree **pbt)
01302 {
01303 struct ccn_btree *bt = *pbt;
01304 int res = 0;
01305
01306 if (bt == NULL)
01307 return(0);
01308 *pbt = NULL;
01309 if (bt->magic != CCN_BTREE_MAGIC)
01310 abort();
01311 hashtb_destroy(&bt->resident);
01312 if (bt->errors != 0)
01313 res = -(bt->errors & 1023);
01314 if (bt->io != NULL)
01315 res |= bt->io->btdestroy(&bt->io);
01316 free(bt);
01317 return(res);
01318 }
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330 int
01331 ccn_btree_init_node(struct ccn_btree_node *node,
01332 int level, unsigned char nodetype, unsigned char extsz)
01333 {
01334 struct ccn_btree_node_header *hdr = NULL;
01335 size_t bytes;
01336
01337 if (node->corrupt)
01338 return(-1);
01339 bytes = sizeof(*hdr) + extsz * CCN_BT_SIZE_UNITS;
01340 node->clean = 0;
01341 node->buf->length = 0;
01342 hdr = (struct ccn_btree_node_header *)ccn_charbuf_reserve(node->buf, bytes);
01343 if (hdr == NULL) return(-1);
01344 memset(hdr, 0, bytes);
01345 MYSTORE(hdr, magic, CCN_BTREE_MAGIC);
01346 MYSTORE(hdr, version, CCN_BTREE_VERSION);
01347 MYSTORE(hdr, nodetype, nodetype);
01348 MYSTORE(hdr, level, level);
01349 MYSTORE(hdr, extsz, extsz);
01350 node->buf->length = bytes;
01351 node->freelow = bytes;
01352 node->parent = 0;
01353 return(0);
01354 }
01355
01356 #define CCN_BTREE_MAX_NODE_BYTES (8U<<20)
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367 struct ccn_btree_node *
01368 ccn_btree_getnode(struct ccn_btree *bt,
01369 ccn_btnodeid nodeid,
01370 ccn_btnodeid parentid)
01371 {
01372 struct hashtb_enumerator ee;
01373 struct hashtb_enumerator *e = ⅇ
01374 struct ccn_btree_node *node = NULL;
01375 int res;
01376
01377 if (bt->magic != CCN_BTREE_MAGIC)
01378 abort();
01379 hashtb_start(bt->resident, e);
01380 res = hashtb_seek(e, &nodeid, sizeof(nodeid), 0);
01381 node = e->data;
01382 if (res == HT_NEW_ENTRY) {
01383 node->nodeid = nodeid;
01384 node->buf = ccn_charbuf_create();
01385 bt->cleanreq++;
01386 if (node->buf == NULL) {
01387 ccn_btree_note_error(bt, __LINE__);
01388 node->corrupt = __LINE__;
01389 }
01390 if (bt->io != NULL) {
01391 res = bt->io->btopen(bt->io, node);
01392 if (res < 0) {
01393 ccn_btree_note_error(bt, __LINE__);
01394 node->corrupt = __LINE__;
01395 }
01396 else {
01397 res = bt->io->btread(bt->io, node, CCN_BTREE_MAX_NODE_BYTES);
01398 if (res < 0)
01399 ccn_btree_note_error(bt, __LINE__);
01400 else {
01401 node->clean = node->buf->length;
01402 if (-1 == ccn_btree_chknode(node))
01403 ccn_btree_note_error(bt, __LINE__);
01404 node->activity = CCN_BT_ACTIVITY_READ_BUMP;
01405 if (bt->io->openfds >= CCN_BT_OPEN_NODES_LIMIT) {
01406
01407 res = bt->io->btclose(bt->io, node);
01408 if (res < 0)
01409 ccn_btree_note_error(bt, __LINE__);
01410 }
01411 }
01412 }
01413 }
01414 }
01415 if (node != NULL && node->nodeid != nodeid)
01416 abort();
01417 hashtb_end(e);
01418 if (node != NULL && node->parent == 0)
01419 node->parent = parentid;
01420 node->activity += CCN_BT_ACTIVITY_REFERENCE_BUMP;
01421 return(node);
01422 }
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435 struct ccn_btree_node *
01436 ccn_btree_rnode(struct ccn_btree *bt, ccn_btnodeid nodeid)
01437 {
01438 return(hashtb_lookup(bt->resident, &nodeid, sizeof(nodeid)));
01439 }
01440
01441
01442
01443
01444
01445
01446
01447
01448
01449 int
01450 ccn_btree_chknode(struct ccn_btree_node *node)
01451 {
01452 unsigned freelow = 0;
01453 unsigned freemax = 0;
01454 unsigned strbase = sizeof(struct ccn_btree_node_header);
01455 struct ccn_btree_node_header *hdr = NULL;
01456 unsigned lev = 0;
01457 unsigned entsz = 0;
01458 unsigned saved_corrupt;
01459 struct ccn_btree_entry_trailer *p = NULL;
01460 int i;
01461 int nent;
01462 unsigned koff;
01463 unsigned ksiz;
01464
01465 if (node == NULL)
01466 return(-1);
01467 saved_corrupt = node->corrupt;
01468 node->corrupt = 0;
01469 if (node->buf == NULL)
01470 return(node->corrupt = __LINE__, -1);
01471 if (node->buf->length == 0)
01472 return(node->freelow = 0, node->corrupt = 0, 0);
01473 if (node->buf->length < sizeof(struct ccn_btree_node_header))
01474 return(node->corrupt = __LINE__, -1);
01475 hdr = (struct ccn_btree_node_header *)node->buf->buf;
01476 if (MYFETCH(hdr, magic) != CCN_BTREE_MAGIC)
01477 return(node->corrupt = __LINE__, -1);
01478 if (MYFETCH(hdr, version) != CCN_BTREE_VERSION)
01479 return(node->corrupt = __LINE__, -1);
01480
01481 lev = MYFETCH(hdr, level);
01482 strbase += MYFETCH(hdr, extsz) * CCN_BT_SIZE_UNITS;
01483 if (strbase > node->buf->length)
01484 return(node->corrupt = __LINE__, -1);
01485 if (strbase == node->buf->length)
01486 return(node->freelow = strbase, saved_corrupt);
01487 nent = ccn_btree_node_nent(node);
01488 for (i = 0; i < nent; i++) {
01489 unsigned e;
01490 p = seek_trailer(node, i);
01491 if (p == NULL)
01492 return(-1);
01493 e = MYFETCH(p, entsz);
01494 if (i == 0) {
01495 freemax = ((unsigned char *)p) - node->buf->buf;
01496 entsz = e;
01497 }
01498 if (e != entsz)
01499 return(node->corrupt = __LINE__, -1);
01500 if (MYFETCH(p, level) != lev)
01501 return(node->corrupt = __LINE__, -1);
01502 koff = MYFETCH(p, koff0);
01503 ksiz = MYFETCH(p, ksiz0);
01504 if (koff < strbase && ksiz != 0)
01505 return(node->corrupt = __LINE__, -1);
01506 if (koff > freemax)
01507 return(node->corrupt = __LINE__, -1);
01508 if (ksiz > freemax - koff)
01509 return(node->corrupt = __LINE__, -1);
01510 if (koff + ksiz > freelow)
01511 freelow = koff + ksiz;
01512 koff = MYFETCH(p, koff1);
01513 ksiz = MYFETCH(p, ksiz1);
01514 if (koff < strbase && ksiz != 0)
01515 return(node->corrupt = __LINE__, -1);
01516 if (koff > freemax)
01517 return(node->corrupt = __LINE__, -1);
01518 if (ksiz > freemax - koff)
01519 return(node->corrupt = __LINE__, -1);
01520 if (koff + ksiz > freelow)
01521 freelow = koff + ksiz;
01522 }
01523 if (node->freelow != freelow)
01524 node->freelow = freelow;
01525 return(saved_corrupt);
01526 }
01527
01528
01529
01530
01531
01532
01533
01534
01535
01536 int
01537 ccn_btree_prepare_for_update(struct ccn_btree *bt, struct ccn_btree_node *node)
01538 {
01539 int res = 0;
01540
01541 if (node->freelow == 0)
01542 ccn_btree_chknode(node);
01543 if (node->corrupt)
01544 return(-1);
01545 if (bt->io != NULL && node->iodata == NULL) {
01546 bt->cleanreq++;
01547 res = bt->io->btopen(bt->io, node);
01548 if (res < 0) {
01549 ccn_btree_note_error(bt, __LINE__);
01550 node->corrupt = __LINE__;
01551 }
01552 }
01553 node->activity += CCN_BT_ACTIVITY_UPDATE_BUMP;
01554 return(res);
01555 }
01556
01557 static int
01558 compare_lexical(struct ccn_charbuf *a, struct ccn_charbuf *b)
01559 {
01560 int al, bl;
01561 int res;
01562
01563 al = a->length;
01564 bl = b->length;
01565 res = memcmp(a->buf, b->buf, al < bl ? al : bl);
01566 if (res == 0)
01567 res = (al - bl);
01568 return(res);
01569 }
01570
01571 static void
01572 ccn_charbuf_append_escaped(struct ccn_charbuf *dst, struct ccn_charbuf *src)
01573 {
01574 size_t i, n;
01575 int c;
01576
01577 n = src->length;
01578 ccn_charbuf_reserve(dst, n);
01579 for (i = 0; i < n; i++) {
01580 c = src->buf[i];
01581 if (c < ' ' || c > '~' || c == '\\' || c == '(' || c == ')' || c == '"')
01582 ccn_charbuf_putf(dst, "\\%03o", c);
01583 else
01584 ccn_charbuf_append_value(dst, c, 1);
01585 }
01586 }
01587
01588 #define MSG(fmt, ...) if (outfp != NULL) fprintf(outfp, fmt "\n", __VA_ARGS__)
01589
01590
01591
01592
01593
01594
01595
01596 int
01597 ccn_btree_check(struct ccn_btree *btree, FILE *outfp) {
01598 struct ccn_btree_node *node;
01599 struct ccn_btree_node *child;
01600 ccn_btnodeid stack[40] = {};
01601 int kstk[40] = {};
01602 int sp = 0;
01603 struct ccn_charbuf *buf[3];
01604 struct ccn_charbuf *q;
01605 int pp = 0;
01606 int res;
01607 int i, k;
01608 struct ccn_btree_internal_payload *e = NULL;
01609 const char *indent = "\t\t\t\t\t\t\t\t";
01610
01611
01612 if (0) return(0);
01613
01614 for (i = 0; i < 3; i++)
01615 buf[i] = ccn_charbuf_create();
01616 q = buf[2];
01617 MSG("%%I start ccn_btree_check %d %u %u %d",
01618 hashtb_n(btree->resident),
01619 (unsigned)btree->nextsplit,
01620 (unsigned)btree->missedsplit,
01621 btree->errors);
01622 if (btree->missedsplit != 0 || btree->errors != 0) {
01623 MSG("%%W %s", "reset error indications");
01624 btree->missedsplit = 0;
01625 btree->errors = 0;
01626 }
01627 node = ccn_btree_getnode(btree, 1, 0);
01628 if (node == NULL) {
01629 MSG("%%E %s", "no root node!");
01630 goto Bail;
01631 }
01632 k = 0;
01633 res = 0;
01634 while (node != NULL && res >= 0) {
01635 int l = ccn_btree_node_level(node);
01636 int n = ccn_btree_node_nent(node);
01637 if (k == 0) {
01638 res = ccn_btree_chknode(node);
01639 if (res < 0) {
01640 MSG("%%E ccn_btree_chknode(%u) error (%d)",
01641 (unsigned)node->nodeid, node->corrupt);
01642 ccn_btree_note_error(btree, __LINE__);
01643 }
01644 else if (res != 0) {
01645 MSG("%%W ccn_btree_chknode(%u) returned %d",
01646 (unsigned)node->nodeid, node->corrupt);
01647 }
01648 }
01649 if (k == n) {
01650
01651 res = ccn_btree_close_node(btree, node);
01652 if (res < 0)
01653 MSG("%%W close of node %u failed", (unsigned)node->nodeid);
01654
01655 if (sp == 0) (k = 0, node = NULL);
01656 else (sp--, k = kstk[sp], node = ccn_btree_getnode(btree, stack[sp], 0));
01657 }
01658 else {
01659 if (k == 0 && l > 0) {
01660
01661 if (ccn_btree_compare(NULL, 0, node, k) != 0) {
01662 ccn_btree_key_fetch(q, node, k);
01663 i = q->length;
01664 ccn_charbuf_append_escaped(q, q);
01665 MSG("%%E Key [%u 0] %d not empty: (%s)",
01666 (unsigned)node->nodeid, l, ccn_charbuf_as_string(q) + i);
01667 ccn_btree_note_error(btree, __LINE__);
01668 }
01669 }
01670 else {
01671 pp ^= 1;
01672 res = ccn_btree_key_fetch(buf[pp], node, k);
01673 if (res < 0) {
01674 MSG("%%E could not fetch key %d of node %u",
01675 k, (unsigned)node->nodeid);
01676 }
01677 else {
01678 res = compare_lexical(buf[pp ^ 1], buf[pp]);
01679 if (res < 0 || (res == 0 && k == 0 && l == 0)) {
01680
01681 res = 0;
01682 }
01683 else {
01684 MSG("%%E Keys are out of order! [%u %d]",
01685 (unsigned)node->nodeid, k);
01686 ccn_btree_note_error(btree, __LINE__);
01687 res = -(btree->errors > 10);
01688 }
01689 q->length = 0;
01690 ccn_charbuf_append_escaped(q, buf[pp]);
01691 MSG("%s(%s) [%u %d] %d %s", indent + 8 - sp % 8,
01692 ccn_charbuf_as_string(q), (unsigned)node->nodeid, k, l,
01693 l == 0 ? "leaf" : "node");
01694 }
01695 }
01696 if (l == 0)
01697 k++;
01698 else {
01699 stack[sp] = node->nodeid;
01700 kstk[sp] = k + 1;
01701 sp++;
01702 if (sp == 40) goto Bail;
01703 e = ccn_btree_node_internal_entry(node, k);
01704 if (e == NULL) goto Bail;
01705 child = ccn_btree_getnode(btree, MYFETCH(e, child), node->nodeid);
01706 if (child == NULL) goto Bail;
01707 if (child->parent != node->nodeid) {
01708
01709 MSG("%%E child->parent != node->nodeid (%u!=%u)",
01710 (unsigned)child->parent, (unsigned)node->nodeid);
01711 ccn_btree_note_error(btree, __LINE__);
01712 child->parent = node->nodeid;
01713 }
01714 node = child;
01715 k = 0;
01716 }
01717 }
01718 }
01719 if (res <= 0 && btree->errors == 0) {
01720 for (i = 0; i < 3; i++)
01721 ccn_charbuf_destroy(&buf[i]);
01722 return(0);
01723 }
01724 Bail:
01725 ccn_btree_note_error(btree, __LINE__);
01726 MSG("%%W finish ccn_btree_check %d %u %u %d",
01727 hashtb_n(btree->resident),
01728 (unsigned)btree->nextsplit,
01729 (unsigned)btree->missedsplit,
01730 btree->errors);
01731 for (i = 0; i < 3; i++)
01732 ccn_charbuf_destroy(&buf[i]);
01733 return(-1);
01734 }
01735 #undef MSG