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