ccnbtreetest.c

Go to the documentation of this file.
00001 /**
00002  * @file ccnbtreetest.c
00003  * 
00004  * Part of ccnr - CCNx Repository Daemon.
00005  *
00006  */
00007 
00008 /*
00009  * Copyright (C) 2011 Palo Alto Research Center, Inc.
00010  *
00011  * This work is free software; you can redistribute it and/or modify it under
00012  * the terms of the GNU General Public License version 2 as published by the
00013  * Free Software Foundation.
00014  * This work is distributed in the hope that it will be useful, but WITHOUT ANY
00015  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
00016  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
00017  * for more details. You should have received a copy of the GNU General Public
00018  * License along with this program; if not, write to the
00019  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020  * Boston, MA 02110-1301, USA.
00021  */
00022  
00023 #include <errno.h>
00024 #include <fcntl.h>
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <sys/mman.h>
00029 #include <sys/stat.h>
00030 #include <sys/types.h>
00031 #include <unistd.h>
00032 
00033 #include <ccn/btree.h>
00034 #include <ccn/btree_content.h>
00035 #include <ccn/ccn.h>
00036 #include <ccn/charbuf.h>
00037 #include <ccn/indexbuf.h>
00038 #include <ccn/hashtb.h>
00039 #include <ccn/uri.h>
00040 
00041 #define FAILIF(cond) do {} while ((cond) && fatal(__func__, __LINE__))
00042 #define CHKSYS(res) FAILIF((res) == -1)
00043 #define CHKPTR(p)   FAILIF((p) == NULL)
00044 
00045 static int
00046 fatal(const char *fn, int lineno)
00047 {
00048     char buf[80] = {0};
00049     snprintf(buf, sizeof(buf)-1, "OOPS - function %s, line %d", fn, lineno);
00050     perror(buf);
00051     exit(1);
00052     return(0);
00053 }
00054 
00055 /**
00056  * Use standard mkdtemp() to create a subdirectory of the
00057  * current working directory, and set the TEST_DIRECTORY environment
00058  * variable with its name.
00059  */
00060 static int
00061 test_directory_creation(void)
00062 {
00063     int res;
00064     struct ccn_charbuf *dirbuf;
00065     char *temp;
00066     
00067     dirbuf = ccn_charbuf_create();
00068     CHKPTR(dirbuf);
00069     res = ccn_charbuf_putf(dirbuf, "./%s", "_bt_XXXXXX");
00070     CHKSYS(res);
00071     temp = mkdtemp(ccn_charbuf_as_string(dirbuf));
00072     CHKPTR(temp);
00073     res = ccn_charbuf_putf(dirbuf, "/%s", "_test");
00074     CHKSYS(res);
00075     res = mkdir(ccn_charbuf_as_string(dirbuf), 0777);
00076     CHKSYS(res);
00077     printf("Created directory %s\n", ccn_charbuf_as_string(dirbuf));
00078     setenv("TEST_DIRECTORY", ccn_charbuf_as_string(dirbuf), 1);
00079     ccn_charbuf_destroy(&dirbuf);
00080     return(res);
00081 }
00082 
00083 /**
00084  * Basic tests of ccn_btree_io_from_directory() and its methods.
00085  *
00086  * Assumes TEST_DIRECTORY has been set.
00087  */
00088 static int
00089 test_btree_io(void)
00090 {
00091     int res;
00092     struct ccn_btree_node nodespace = {0};
00093     struct ccn_btree_node *node = &nodespace;
00094     struct ccn_btree_io *io = NULL;
00095 
00096     /* Open it up. */
00097     io = ccn_btree_io_from_directory(getenv("TEST_DIRECTORY"), NULL);
00098     CHKPTR(io);
00099     node->buf = ccn_charbuf_create();
00100     CHKPTR(node->buf);
00101     node->nodeid = 12345;
00102     res = io->btopen(io, node);
00103     CHKSYS(res);
00104     FAILIF(node->iodata == NULL);
00105     ccn_charbuf_putf(node->buf, "smoke");
00106     res = io->btwrite(io, node);
00107     CHKSYS(res);
00108     node->buf->length = 0;
00109     ccn_charbuf_putf(node->buf, "garbage");
00110     res = io->btread(io, node, 500000);
00111     CHKSYS(res);
00112     FAILIF(node->buf->length != 5);
00113     FAILIF(node->buf->limit > 10000);
00114     node->clean = 5;
00115     ccn_charbuf_putf(node->buf, "r");
00116     res = io->btwrite(io, node);
00117     CHKSYS(res);
00118     node->buf->length--;
00119     ccn_charbuf_putf(node->buf, "d");
00120     res = io->btread(io, node, 1000);
00121     CHKSYS(res);
00122     FAILIF(0 != strcmp("smoker", ccn_charbuf_as_string(node->buf)));
00123     node->buf->length--;
00124     res = io->btwrite(io, node);
00125     CHKSYS(res);
00126     node->buf->length = 0;
00127     ccn_charbuf_putf(node->buf, "garbage");
00128     node->clean = 0;
00129     res = io->btread(io, node, 1000);
00130     CHKSYS(res);
00131     res = io->btclose(io, node);
00132     CHKSYS(res);
00133     FAILIF(node->iodata != NULL);
00134     FAILIF(0 != strcmp("smoke", ccn_charbuf_as_string(node->buf)));
00135     res = io->btdestroy(&io);
00136     CHKSYS(res);
00137     ccn_charbuf_destroy(&node->buf);
00138     return(res);
00139 }
00140 
00141 /**
00142  * Helper for test_structure_sizes()
00143  *
00144  * Prints out the size of the struct
00145  */
00146 static void
00147 check_structure_size(const char *what, int sz)
00148 {
00149     printf("%s size is %d bytes\n", what, sz);
00150     errno=EINVAL;
00151     FAILIF(sz % CCN_BT_SIZE_UNITS != 0);
00152 }
00153 
00154 /**
00155  * Helper for test_structure_sizes()
00156  *
00157  * Prints the size of important structures, and make sure that
00158  * they are mutiples of CCN_BT_SIZE_UNITS.
00159  */
00160 int
00161 test_structure_sizes(void)
00162 {
00163     check_structure_size("ccn_btree_entry_trailer",
00164             sizeof(struct ccn_btree_entry_trailer));
00165     check_structure_size("ccn_btree_internal_entry",
00166             sizeof(struct ccn_btree_internal_entry));
00167     check_structure_size("ccn_btree_content_entry",
00168             sizeof(struct ccn_btree_content_entry));
00169     return(0);
00170 }
00171 
00172 /**
00173  * Test that the lockfile works.
00174  */
00175 int
00176 test_btree_lockfile(void)
00177 {
00178     int res;
00179     struct ccn_btree_io *io = NULL;
00180     struct ccn_btree_io *io2 = NULL;
00181 
00182     io = ccn_btree_io_from_directory(getenv("TEST_DIRECTORY"), NULL);
00183     CHKPTR(io);
00184     /* Make sure the locking works */
00185     errno = 0;
00186     io2 = ccn_btree_io_from_directory(getenv("TEST_DIRECTORY"), NULL);
00187     FAILIF(io2 != NULL || errno == 0);
00188     errno=EINVAL;
00189     res = io->btdestroy(&io);
00190     CHKSYS(res);
00191     FAILIF(io != NULL);
00192     return(res);
00193 }
00194 
00195 struct entry_example {
00196     unsigned char p[CCN_BT_SIZE_UNITS];
00197     struct ccn_btree_entry_trailer t;
00198 };
00199 
00200 struct node_example {
00201     struct ccn_btree_node_header hdr;
00202     unsigned char ss[64];
00203     struct entry_example e[3];
00204 } ex1 = {
00205     {{0x05, 0x3a, 0xde, 0x78}, {1}},
00206     "goodstuff<------ WASTE---------->d<----><-------------- free -->",
00207     //                                 beauty
00208     {
00209         {.t={.koff0={0,0,0,33+8}, .ksiz0={0,1}, .entdx={0,0}, .entsz={3}}}, // "d"
00210         {.t={.koff0={0,0,0,0+8}, .ksiz0={0,9}, .entdx={0,1}, .entsz={3}}}, // "goodstuff"
00211         {.t={.koff0={0,0,0,2+8}, .ksiz0={0,2}, .entdx={0,2}, .entsz={3},
00212             .koff1={0,0,0,3+8}, .ksiz1={0,1}}}, // "odd"
00213     }
00214 };
00215 
00216 struct node_example ex2 = {
00217     {{0x05, 0x3a, 0xde, 0x78}, {1}},
00218     "struthiomimus",
00219     {
00220         {.t={.koff1={0,0,0,2+8}, .ksiz1={0,3}, .entdx={0,0}, .entsz={3}}}, // "rut"
00221         {.t={.koff0={0,0,0,0+8}, .ksiz0={0,5}, .entdx={0,1}, .entsz={3}}}, // "strut"
00222         {.t={.koff0={0,0,0,1+8}, .ksiz0={0,5}, .entdx={0,2}, .entsz={3}}}, // "truth"
00223     }
00224 };
00225 
00226 struct root_example {
00227     struct ccn_btree_node_header hdr;
00228     unsigned char ss[CCN_BT_SIZE_UNITS];
00229     struct ccn_btree_internal_entry e[2];
00230 } rootex1 = {
00231     {{0x05, 0x3a, 0xde, 0x78}, {1}, {'R'}, {1}},
00232     "ru",
00233     {
00234         {   {.magic={0xcc}, .child={0,0,0,2}}, // ex1 at nodeid 2 as 1st child
00235             {.entdx={0,0}, .level={1}, .entsz={3}}}, 
00236         {   {.magic={0xcc}, .child={0,0,0,3}}, // ex2 at nodeid 3 as 2nd child
00237             {.koff1={0,0,0,0+8}, .ksiz1={0,2}, 
00238                 .entdx={0,1}, .level={1}, .entsz={3}}},
00239     }
00240 };
00241 
00242 int
00243 test_btree_chknode(void)
00244 {
00245     int res;
00246     struct ccn_btree_node *node = NULL;
00247     struct node_example *ex = NULL;
00248     
00249     node = calloc(1, sizeof(*node));
00250     CHKPTR(node);
00251     node->buf = ccn_charbuf_create();
00252     CHKPTR(node->buf);
00253     ccn_charbuf_append(node->buf, &ex1, sizeof(ex1));
00254     res = ccn_btree_chknode(node);
00255     CHKSYS(res);
00256     FAILIF(node->corrupt != 0);
00257     FAILIF(node->freelow != 8 + 34); // header plus goodstuff<- ... ->d
00258     ex = (void *)node->buf->buf;
00259     ex->e[1].t.ksiz0[2] = 100; /* ding the size in entry 1 */
00260     res = ccn_btree_chknode(node);
00261     FAILIF(res != -1);
00262     FAILIF(node->corrupt == 0);
00263     ccn_charbuf_destroy(&node->buf);
00264     free(node);
00265     return(0);
00266 }
00267 
00268 int
00269 test_btree_key_fetch(void)
00270 {
00271     int i;
00272     int res;
00273     struct ccn_charbuf *cb = NULL;
00274     struct ccn_btree_node *node = NULL;
00275     struct node_example ex = ex1;
00276     
00277     const char *expect[3] = { "d", "goodstuff", "odd" };
00278     
00279     node = calloc(1, sizeof(*node));
00280     CHKPTR(node);
00281     node->buf = ccn_charbuf_create();
00282     CHKPTR(node->buf);
00283     ccn_charbuf_append(node->buf, &ex, sizeof(ex));
00284     
00285     cb = ccn_charbuf_create();
00286     
00287     for (i = 0; i < 3; i++) {
00288         res = ccn_btree_key_fetch(cb, node, i);
00289         CHKSYS(res);
00290         FAILIF(cb->length != strlen(expect[i]));
00291         FAILIF(0 != memcmp(cb->buf, expect[i], cb->length));
00292     }
00293     
00294     res = ccn_btree_key_fetch(cb, node, i); /* fetch past end */
00295     FAILIF(res != -1);
00296     res = ccn_btree_key_fetch(cb, node, -1); /* fetch before start */
00297     FAILIF(res != -1);
00298     FAILIF(node->corrupt); /* Those should not have flagged corruption */
00299     
00300     ex.e[1].t.koff0[2] = 1; /* ding the offset in entry 1 */
00301     node->buf->length = 0;
00302     ccn_charbuf_append(node->buf, &ex, sizeof(ex));
00303     
00304     res = ccn_btree_key_append(cb, node, 0); /* Should still be OK */
00305     CHKSYS(res);
00306     
00307     res = ccn_btree_key_append(cb, node, 1); /* Should fail */
00308     FAILIF(res != -1);
00309     FAILIF(!node->corrupt);
00310     printf("line %d code = %d\n", __LINE__, node->corrupt);
00311     
00312     ccn_charbuf_destroy(&cb);
00313     ccn_charbuf_destroy(&node->buf);
00314     free(node);
00315     return(0);
00316 }
00317 
00318 int
00319 test_btree_compare(void)
00320 {
00321     int i, j;
00322     int res;
00323     struct ccn_btree_node *node = NULL;
00324     struct node_example ex = ex1;
00325     
00326     const char *expect[3] = { "d", "goodstuff", "odd" };
00327     
00328     node = calloc(1, sizeof(*node));
00329     CHKPTR(node);
00330     node->buf = ccn_charbuf_create();
00331     CHKPTR(node->buf);
00332     ccn_charbuf_append(node->buf, &ex, sizeof(ex));
00333     
00334     for (i = 0; i < 3; i++) {
00335         for (j = 0; j < 3; j++) {
00336             res = ccn_btree_compare((const void *)expect[i], strlen(expect[i]),
00337                 node, j);
00338             FAILIF( (i < j) != (res < 0));
00339             FAILIF( (i > j) != (res > 0));
00340             FAILIF( (i == j) != (res == 0));
00341         }
00342     }
00343     ccn_charbuf_destroy(&node->buf);
00344     free(node);
00345     return(0);
00346 }
00347 
00348 int
00349 test_btree_searchnode(void)
00350 {
00351     int i;
00352     int res;
00353     struct ccn_btree_node *node = NULL;
00354     struct node_example ex = ex1;
00355     const int yes = 1;
00356     const int no = 0;
00357     
00358     struct {
00359         const char *s;
00360         int expect;
00361     } testvec[] = {
00362         {"", CCN_BT_ENCRES(0, no)},
00363         {"c", CCN_BT_ENCRES(0, no)},
00364         {"d", CCN_BT_ENCRES(0, yes)},
00365         {"d1", CCN_BT_ENCRES(1, no)},
00366         {"goodstuff", CCN_BT_ENCRES(1, yes)},
00367         {"goodstuff1", CCN_BT_ENCRES(2, no)},
00368         {"odc++++++", CCN_BT_ENCRES(2, no)},
00369         {"odd", CCN_BT_ENCRES(2, yes)},
00370         {"odd1", CCN_BT_ENCRES(3, no)},
00371         {"ode", CCN_BT_ENCRES(3, no)}
00372     };
00373     
00374     node = calloc(1, sizeof(*node));
00375     CHKPTR(node);
00376     node->buf = ccn_charbuf_create();
00377     CHKPTR(node->buf);
00378     ccn_charbuf_append(node->buf, &ex, sizeof(ex));
00379     
00380     res = ccn_btree_node_nent(node);
00381     FAILIF(res != 3);
00382     
00383     for (i = 0; i < sizeof(testvec)/sizeof(testvec[0]); i++) {
00384         const char *s = testvec[i].s;
00385         res = ccn_btree_searchnode((const void *)s, strlen(s), node);
00386         printf("search %s => %d, expected %d\n", s, res, testvec[i].expect);
00387         FAILIF(res != testvec[i].expect);
00388     }
00389     ccn_charbuf_destroy(&node->buf);
00390     free(node);
00391     return(0);
00392 }
00393 
00394 int
00395 test_btree_init(void)
00396 {
00397     struct ccn_btree *btree = NULL;
00398     int res;
00399     struct ccn_btree_node *node = NULL;
00400     struct ccn_btree_node *node0 = NULL;
00401     struct ccn_btree_node *node1 = NULL;
00402     
00403     btree = ccn_btree_create();
00404     CHKPTR(btree);
00405     node0 = ccn_btree_getnode(btree, 0, 0);
00406     CHKPTR(node0);
00407     node1 = ccn_btree_getnode(btree, 1, 0);
00408     FAILIF(node0 == node1);
00409     FAILIF(hashtb_n(btree->resident) != 2);
00410     node = ccn_btree_rnode(btree, 0);
00411     FAILIF(node != node0);
00412     node = ccn_btree_rnode(btree, 1);
00413     FAILIF(node != node1);
00414     node = ccn_btree_rnode(btree, 2);
00415     FAILIF(node != NULL);
00416     res = ccn_btree_destroy(&btree);
00417     FAILIF(btree != NULL);
00418     return(res);
00419 }
00420 
00421 struct ccn_btree *
00422 example_btree_small(void)
00423 {
00424     struct ccn_btree *btree = NULL;
00425     struct ccn_btree_node *root = NULL;
00426     struct ccn_btree_node *leaf = NULL;
00427     int res = 0;
00428 
00429     btree = ccn_btree_create();
00430     CHKPTR(btree);
00431     leaf = ccn_btree_getnode(btree, 2, 0);
00432     CHKPTR(leaf);
00433     ccn_charbuf_append(leaf->buf, &ex1, sizeof(ex1));
00434     res = ccn_btree_chknode(leaf);
00435     CHKSYS(res);
00436     leaf = ccn_btree_getnode(btree, 3, 0);
00437     CHKPTR(leaf);
00438     ccn_charbuf_append(leaf->buf, &ex2, sizeof(ex2));
00439     res = ccn_btree_chknode(leaf);
00440     CHKSYS(res);
00441     root = ccn_btree_getnode(btree, 1, 0);
00442     CHKPTR(root);
00443     ccn_charbuf_append(root->buf, &rootex1, sizeof(rootex1));
00444     res = ccn_btree_chknode(root);
00445     CHKSYS(res);
00446     btree->nextnodeid = 4;
00447     return(btree);
00448 }
00449 
00450 int
00451 test_btree_lookup(void)
00452 {
00453     const int yes = 1;
00454     const int no = 0;
00455     struct ccn_btree *btree = NULL;
00456     struct ccn_btree_node *leaf = NULL;
00457     int i;
00458     int res;
00459     struct {
00460         const char *s;
00461         int expectnode;
00462         int expectres;
00463     } testvec[] = {
00464         {"d", 2, CCN_BT_ENCRES(0, yes)},
00465         {"goodstuff", 2, CCN_BT_ENCRES(1, yes)},
00466         {"odd", 2, CCN_BT_ENCRES(2, yes)},
00467         {"truth", 3, CCN_BT_ENCRES(2, yes)},
00468         {"tooth", 3, CCN_BT_ENCRES(2, no)},
00469     };
00470 
00471     btree = example_btree_small();
00472     CHKPTR(btree);
00473     /* Now we should have a 3-node btree, all resident. Do our lookups. */
00474     for (i = 0; i < sizeof(testvec)/sizeof(testvec[0]); i++) {
00475         const char *s = testvec[i].s;
00476         res = ccn_btree_lookup(btree, (const void *)s, strlen(s), &leaf);
00477         printf("lookup %s => %d, %d, expected %d, %d\n", s,
00478             leaf->nodeid,          res,
00479             testvec[i].expectnode, testvec[i].expectres);
00480         FAILIF(res != testvec[i].expectres);
00481         FAILIF(leaf->nodeid != testvec[i].expectnode);
00482         FAILIF(leaf->parent != 1);
00483         res = ccn_btree_node_level(leaf);
00484         FAILIF(res != 0);
00485     }
00486     res = ccn_btree_check(btree, stderr); // see how that works out
00487     res = ccn_btree_destroy(&btree);
00488     FAILIF(btree != NULL);
00489     return(res);
00490 }
00491 
00492 int
00493 test_basic_btree_insert_entry(void)
00494 {
00495     struct ccn_btree *btree = NULL;
00496     struct ccn_btree_node *leaf = NULL;
00497     int res;
00498     int ndx;
00499     const char *s = "";
00500     unsigned char payload[6] = "@12345";
00501     unsigned char *c = NULL;
00502     unsigned char canary = 42;
00503     unsigned cage = 10000;
00504     unsigned perch = 1000;
00505     
00506     btree = example_btree_small();
00507     CHKPTR(btree);
00508     s = "beauty";
00509     res = ccn_btree_lookup(btree, (const void *)s, strlen(s), &leaf);
00510     CHKSYS(res);
00511     FAILIF(CCN_BT_SRCH_FOUND(res));
00512     ndx = CCN_BT_SRCH_INDEX(res);
00513     FAILIF(ndx != 0); // beauty before d
00514     memset(ccn_charbuf_reserve(leaf->buf, cage), canary, cage);
00515     res = ccn_btree_chknode(leaf);
00516     CHKSYS(res);
00517     res = ccn_btree_insert_entry(leaf, ndx,
00518                                  (const void *)s, strlen(s),
00519                                  payload, sizeof(payload));
00520     CHKSYS(res);
00521     res = ccn_btree_chknode(leaf);
00522     CHKSYS(res);
00523     c = &leaf->buf->buf[leaf->buf->length];
00524     FAILIF(c[0] != canary);
00525     FAILIF(0 != memcmp(c, c + 1, perch - 1));
00526     res = ccn_btree_lookup(btree, (const void *)s, strlen(s), &leaf);
00527     FAILIF(res != 1);
00528     res = ccn_btree_lookup(btree, (const void *)"d", 1, &leaf);
00529     FAILIF(res != 3);
00530     s = "age";
00531     payload[0] = 'A';
00532     res = ccn_btree_lookup(btree, (const void *)s, strlen(s), &leaf);
00533     FAILIF(res != 0);
00534     res = ccn_btree_insert_entry(leaf, ndx,
00535                                  (const void *)s, strlen(s),
00536                                  payload, sizeof(payload));
00537     CHKSYS(res);
00538     res = ccn_btree_lookup(btree, (const void *)s, strlen(s), &leaf);
00539     FAILIF(res != 1); // age before beauty
00540     res = ccn_btree_lookup(btree, (const void *)"d", 1, &leaf);
00541     FAILIF(res != 5);
00542     c = &leaf->buf->buf[leaf->buf->length];
00543     FAILIF(c[0] != canary);
00544     FAILIF(0 != memcmp(c, c + 1, perch - 1));
00545     /* Try this out here while we have a handy leaf node. */
00546     btree->nextnodeid = 101;
00547     res = ccn_btree_split(btree, leaf);
00548     CHKSYS(res);
00549     FAILIF(btree->errors != 0);
00550     res = ccn_btree_destroy(&btree);
00551     FAILIF(btree != NULL);
00552     return(res);
00553 }
00554 
00555 int
00556 test_btree_inserts_from_stdin(void)
00557 {
00558     struct ccn_charbuf *c;
00559     char payload[8] = "TestTree";
00560     int res;
00561     int item = 0;
00562     int dups = 0;
00563     int unique = 0;
00564     struct ccn_btree *btree = NULL;
00565     struct ccn_btree_node *node = NULL;
00566     struct ccn_btree_node *leaf = NULL;
00567     
00568     // XXX - need nice way to create a brand-new empty btree
00569     btree = ccn_btree_create();
00570     CHKPTR(btree);
00571     FAILIF(btree->nextnodeid != 1);
00572     node = ccn_btree_getnode(btree, btree->nextnodeid++, 0);
00573     CHKPTR(node);
00574     res = ccn_btree_init_node(node, 0, 'R', 0);
00575     CHKPTR(node);
00576     FAILIF(btree->nextnodeid < 2);
00577     res = ccn_btree_chknode(node);
00578     CHKSYS(res);
00579     btree->full = 5;
00580     
00581     c = ccn_charbuf_create();
00582     CHKPTR(c);
00583     CHKPTR(ccn_charbuf_reserve(c, 8800));
00584     while (fgets((char *)c->buf, c->limit, stdin)) {
00585         item++;
00586         c->length = strlen((char *)c->buf);
00587         if (c->length > 0 && c->buf[c->length - 1] == '\n')
00588             c->length--;
00589         // printf("%9d %s\n", item, ccn_charbuf_as_string(c));
00590         res = ccn_btree_lookup(btree, c->buf, c->length, &leaf);
00591         CHKSYS(res);
00592         if (CCN_BT_SRCH_FOUND(res)) {
00593             dups++;
00594         }
00595         else {
00596             unique++;
00597             res = ccn_btree_insert_entry(leaf, CCN_BT_SRCH_INDEX(res),
00598                                          c->buf, c->length,
00599                                          payload, sizeof(payload));
00600             CHKSYS(res);
00601             if (res > 7) {
00602                 int limit = 20;
00603                 res = ccn_btree_split(btree, leaf);
00604                 CHKSYS(res);
00605                 while (btree->nextsplit != 0) {
00606                     node = ccn_btree_rnode(btree, btree->nextsplit);
00607                     CHKPTR(node);
00608                     res = ccn_btree_split(btree, node);
00609                     CHKSYS(res);
00610                     FAILIF(!--limit);
00611                 }
00612                 FAILIF(btree->missedsplit);
00613             }
00614         }
00615     }
00616     res = ccn_btree_check(btree, stderr);
00617     CHKSYS(res);
00618     printf("%d unique, %d duplicate, %d errors\n", unique, dups, btree->errors);
00619     FAILIF(btree->errors != 0);
00620     res = ccn_btree_lookup(btree, c->buf, 0, &leaf); /* Get the first leaf */
00621     CHKSYS(res);
00622     printf("Leaf nodes:");
00623     while (leaf != NULL) {
00624         printf(" %u", leaf->nodeid);
00625         node = leaf;
00626         res = ccn_btree_next_leaf(btree, leaf, &leaf);
00627         CHKSYS(res);
00628     }
00629     printf("\n");
00630     printf("Reversed leaf nodes:");
00631     for (leaf = node; leaf != NULL;) {
00632         printf(" %u", leaf->nodeid);
00633         res = ccn_btree_prev_leaf(btree, leaf, &leaf);
00634         CHKSYS(res);
00635     }
00636     printf("\n");
00637     res = ccn_btree_destroy(&btree);
00638     FAILIF(btree != NULL);
00639     return(res);
00640 }
00641 
00642 int
00643 test_flatname(void)
00644 {
00645     unsigned char L0[1] = { 0x00 };
00646     unsigned char A[2] = { 0x01, 'A' };
00647     unsigned char C1[128] = { 0x7F, 0xC1, '.', 'x', '~'};
00648     unsigned char XL[130] = { 0x81, 0x00, 0x39, ' ', 'e', 't', 'c' };
00649     struct {unsigned char *x; size_t l;} ex[] = {
00650         {L0, 0},
00651         {L0, sizeof(L0)},
00652         {A, sizeof(A)},
00653         {C1, sizeof(C1)},
00654         {XL, sizeof(XL)},
00655         {0,0}
00656     };
00657     struct ccn_charbuf *flat;
00658     struct ccn_charbuf *flatout;
00659     struct ccn_charbuf *ccnb;
00660     struct ccn_charbuf *uri;
00661     int i;
00662     int res;
00663     const char *expect = NULL;
00664     
00665     flat = ccn_charbuf_create();
00666     flatout = ccn_charbuf_create();
00667     ccnb = ccn_charbuf_create();
00668     uri = ccn_charbuf_create();
00669     
00670     res = ccn_flatname_ncomps(flat->buf, flat->length);
00671     FAILIF(res != 0);
00672     for (i = 0; ex[i].x != NULL; i++) {
00673         res = ccn_name_init(ccnb);
00674         FAILIF(res < 0);
00675         flat->length = 0;
00676         ccn_charbuf_append(flat, ex[i].x, ex[i].l);
00677         res = ccn_flatname_ncomps(flat->buf, flat->length);
00678         FAILIF(res != (i > 0));
00679         res = ccn_name_append_flatname(ccnb, flat->buf, flat->length, 0, -1);
00680         FAILIF(res < 0);
00681         res = ccn_flatname_from_ccnb(flatout, ccnb->buf, ccnb->length);
00682         FAILIF(res < 0);
00683         FAILIF(flatout->length != flat->length);
00684         FAILIF(0 != memcmp(flatout->buf, flat->buf,flat->length));
00685         uri->length = 0;
00686         res = ccn_uri_append(uri, ccnb->buf, ccnb->length, 1);
00687         printf("flatname %d: %s\n", i, ccn_charbuf_as_string(uri));
00688     }
00689     ccnb->length = 0;
00690     res = ccn_name_from_uri(ccnb, "ccnx:/10/9/8/7/6/5/4/3/2/1/...");
00691     FAILIF(res < 0);
00692     flat->length = 0;
00693     for (i = 12; i >= 0; i--) {
00694         res = ccn_flatname_append_from_ccnb(flat, ccnb->buf, ccnb->length, i, 1);
00695         FAILIF(res != (i < 11));
00696     }
00697     res = ccn_flatname_append_from_ccnb(flat, ccnb->buf, ccnb->length, 1, 30);
00698     FAILIF(res != 10);
00699     uri->length = 0;
00700     res = ccn_uri_append_flatname(uri, flat->buf, flat->length, 0);
00701     printf("palindrome: %s\n", ccn_charbuf_as_string(uri));
00702     FAILIF(res < 0);
00703     expect = "/.../1/2/3/4/5/6/7/8/9/10/9/8/7/6/5/4/3/2/1/...";
00704     FAILIF(0 != strcmp(ccn_charbuf_as_string(uri), expect));
00705     res = ccn_flatname_ncomps(flat->buf, flat->length);
00706     FAILIF(res != 21);
00707     res = ccn_flatname_ncomps(flat->buf, flat->length - 2);
00708     FAILIF(res != -1);
00709     ccn_charbuf_reserve(flat, 1)[0] = 0x80;
00710     res = ccn_flatname_ncomps(flat->buf, flat->length + 1);
00711     FAILIF(res != -1);
00712     ccn_charbuf_reserve(flat, 1)[0] = 1;
00713     res = ccn_flatname_ncomps(flat->buf, flat->length + 1);
00714     FAILIF(res != -1);
00715     ccn_charbuf_destroy(&flat);
00716     ccn_charbuf_destroy(&flatout);
00717     ccn_charbuf_destroy(&ccnb);
00718     ccn_charbuf_destroy(&uri);
00719     return(0);
00720 }
00721 
00722 /**
00723  * Given an Interest (or a Name), find the matching objects
00724  *
00725  * @returns count of matches, or -1 for an error.
00726  */
00727 static int
00728 testhelp_count_matches(struct ccn_btree *btree,
00729                        unsigned char *msg, size_t size)
00730 {
00731     struct ccn_btree_node *leaf = NULL;
00732     struct ccn_charbuf *flat = NULL;
00733     struct ccn_charbuf *scratch = NULL;
00734     struct ccn_parsed_interest parsed_interest = {0};
00735     struct ccn_parsed_interest *pi = &parsed_interest;
00736     int cmp;
00737     int i;
00738     int matches;
00739     int n;
00740     int res;
00741     
00742     flat = ccn_charbuf_create();
00743     CHKPTR(flat);
00744     res = ccn_flatname_from_ccnb(flat, msg, size);
00745     if (res < 0)
00746         goto Bail;
00747     res = ccn_parse_interest(msg, size, pi, NULL);
00748     if (res < 0) {
00749         if (flat->length > 0)
00750             pi = NULL; /* do prefix-only match */
00751         else
00752             goto Bail;
00753     }
00754     res = ccn_btree_lookup(btree, flat->buf, flat->length, &leaf);
00755     CHKSYS(res);
00756     matches = 0;
00757     /* Here we only look inside one leaf. Real code has to look beyond. */
00758     scratch = ccn_charbuf_create();
00759     n = ccn_btree_node_nent(leaf);
00760     for (i = CCN_BT_SRCH_INDEX(res); i < n; i++) {
00761         cmp = ccn_btree_compare(flat->buf, flat->length, leaf, i);
00762         if (cmp == 0 || cmp == -9999) {
00763             /* The prefix matches; check the rest. */
00764             if (pi == NULL)
00765                 res = 0;
00766             else
00767                 res = ccn_btree_match_interest(leaf, i, msg, pi, scratch);
00768             CHKSYS(res);
00769             if (res == 1) {
00770                 /* We have a match */
00771                 matches++;
00772             }
00773         }
00774         else if (cmp > 0) {
00775             /* This should never happen; if it does there must be a bug. */
00776             FAILIF(1);
00777         }
00778         else {
00779             /* There is no longer a prefix match with the current object */
00780             break;
00781         }
00782     }
00783     res = matches;
00784 Bail:
00785     ccn_charbuf_destroy(&flat);
00786     return(res);
00787 }
00788 
00789 /**
00790  * Make an index from a file filled ccnb-encoded content objects
00791  *
00792  * Intersprsed interests will be regarded as querys, and matches will be
00793  * found.
00794  *
00795  * The file is named by the environment varible TEST_CONTENT.
00796  */
00797 int
00798 test_insert_content(void)
00799 {
00800     const char *filename = NULL;
00801     unsigned char *cb = NULL;
00802     unsigned char *cob = NULL;
00803     struct stat statbuf;
00804     int dres;
00805     int fd;
00806     int i;
00807     int res;
00808     size_t cob_offset;
00809     size_t cob_size;
00810     size_t size;
00811     struct ccn_skeleton_decoder decoder = {0};
00812     struct ccn_skeleton_decoder *d = &decoder;
00813     struct ccn_parsed_ContentObject pcobject = {0};
00814     struct ccn_parsed_ContentObject *pc = &pcobject;
00815     struct ccn_charbuf *flatname = NULL;
00816     struct ccn_charbuf *temp = NULL;
00817     struct ccn_indexbuf *comps = NULL;
00818     struct ccn_btree *btree = NULL;
00819     struct ccn_btree_node *node = NULL;
00820     struct ccn_btree_node *leaf = NULL;
00821     
00822     filename = getenv("TEST_CONTENT");
00823     if (filename == NULL || filename[0] == 0)
00824         return(1);
00825     printf("Opening %s\n", filename);
00826     fd = open(filename, O_RDONLY, 0);
00827     CHKSYS(fd);
00828     res = fstat(fd, &statbuf);
00829     CHKSYS(res);
00830     size = statbuf.st_size;
00831     printf("Mapping %zd bytes from file %s\n", size, filename);
00832     cb = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
00833     FAILIF(cb == MAP_FAILED && size != 0);
00834 
00835     // XXX - need nice way to create a brand-new empty btree
00836     btree = ccn_btree_create();
00837     CHKPTR(btree);
00838     FAILIF(btree->nextnodeid != 1);
00839     node = ccn_btree_getnode(btree, btree->nextnodeid++, 0);
00840     CHKPTR(node);
00841     res = ccn_btree_init_node(node, 0, 'R', 0);
00842     CHKPTR(node);
00843     FAILIF(btree->nextnodeid < 2);
00844     res = ccn_btree_chknode(node);
00845     CHKSYS(res);
00846     btree->full = 50;
00847 
00848     flatname = ccn_charbuf_create();
00849     CHKPTR(flatname);
00850     temp = ccn_charbuf_create();
00851     CHKPTR(temp);
00852     comps = ccn_indexbuf_create();
00853     CHKPTR(comps);
00854     while (d->index < size) {
00855         dres = ccn_skeleton_decode(d, cb + d->index, size - d->index);
00856         if (!CCN_FINAL_DSTATE(d->state))
00857             break;
00858         cob_offset = d->index - dres;
00859         cob = cb + cob_offset;
00860         cob_size = dres;
00861         printf("offset %zd, size %zd\n", cob_offset, cob_size);
00862         res = ccn_parse_ContentObject(cob, cob_size, pc, comps);
00863         if (res < 0) {
00864             res = testhelp_count_matches(btree, cob, cob_size);
00865             if (res < 0) {
00866                 printf("  . . . skipping non-ContentObject\n");
00867             }
00868             else {
00869                 printf("  . . . interest processing res = %d\n", res);
00870             }
00871         }
00872         else {
00873             res = ccn_flatname_from_ccnb(flatname, cob, cob_size);
00874             FAILIF(res != comps->n - 1);
00875             ccn_digest_ContentObject(cob, pc);
00876             FAILIF(pc->digest_bytes != 32);
00877             res = ccn_flatname_append_component(flatname,
00878                                                 pc->digest, pc->digest_bytes);
00879             CHKSYS(res);
00880             temp->length = 0;
00881             ccn_uri_append_flatname(temp, flatname->buf, flatname->length, 1);
00882             res = ccn_btree_lookup(btree, flatname->buf, flatname->length, &leaf);
00883             CHKSYS(res);
00884             if (CCN_BT_SRCH_FOUND(res)) {
00885                 printf("FOUND %s\n", ccn_charbuf_as_string(temp));
00886             }
00887             else {
00888                 i = CCN_BT_SRCH_INDEX(res);
00889                 res = ccn_btree_insert_content(leaf, i,
00890                                                cob_offset + 1,
00891                                                cob,
00892                                                pc,
00893                                                flatname);
00894                 CHKSYS(res);
00895                 printf("INSERTED %s\n", ccn_charbuf_as_string(temp));
00896                 // don't split yet, see how we cope
00897             }
00898         }
00899     }
00900     FAILIF(d->index != size);
00901     FAILIF(!CCN_FINAL_DSTATE(d->state));
00902     if (cb != MAP_FAILED) {
00903         res = munmap(cb, size);
00904         CHKSYS(res);
00905         cb = NULL;
00906         size = 0;
00907     }
00908     res = close(fd);
00909     CHKSYS(res);
00910     ccn_charbuf_destroy(&flatname);
00911     ccn_charbuf_destroy(&temp);
00912     ccn_indexbuf_destroy(&comps);
00913     return(0);
00914 }
00915 
00916 int
00917 ccnbtreetest_main(int argc, char **argv)
00918 {
00919     int res;
00920 
00921     if (argv[1] && 0 == strcmp(argv[1], "-")) {
00922         res = test_btree_inserts_from_stdin();
00923         CHKSYS(res);
00924         exit(0);
00925     }
00926     res = test_directory_creation();
00927     CHKSYS(res);
00928     res = test_btree_io();
00929     CHKSYS(res);
00930     res = test_btree_lockfile();
00931     CHKSYS(res);
00932     res = test_structure_sizes();
00933     CHKSYS(res);
00934     res = test_btree_chknode();
00935     CHKSYS(res);
00936     res = test_btree_key_fetch();
00937     CHKSYS(res);
00938     res = test_btree_compare();
00939     CHKSYS(res);
00940     res = test_btree_searchnode();
00941     CHKSYS(res);
00942     res = test_btree_init();
00943     CHKSYS(res);
00944     res = test_btree_lookup();
00945     CHKSYS(res);
00946     res = test_basic_btree_insert_entry();
00947     CHKSYS(res);
00948     res = test_flatname();
00949     CHKSYS(res);
00950     res = test_insert_content();
00951     CHKSYS(res);
00952     if (res != 0)
00953         fprintf(stderr, "test_insert_content() => %d\n", res);
00954     return(0);
00955 }

Generated on Thu Feb 16 00:44:00 2012 for Content-Centric Networking in C by  doxygen 1.5.6