ccnbtreetest.c

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