00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026 #include <string.h>
00027 #include <sys/time.h>
00028 #include <ccn/ccn.h>
00029 #include <ccn/coding.h>
00030 #include <ccn/digest.h>
00031 #include <ccn/sync.h>
00032 #include <ccn/uri.h>
00033
00034 #include <sync/SyncActions.h>
00035 #include <sync/SyncNode.h>
00036 #include <sync/SyncPrivate.h>
00037 #include <sync/SyncTreeWorker.h>
00038
00039 #define CCNL_NONE 0
00040 #define CCNL_SEVERE 3
00041 #define CCNL_ERROR 5
00042 #define CCNL_WARNING 7
00043 #define CCNL_INFO 9
00044 #define CCNL_FINE 11
00045 #define CCNL_FINER 13
00046 #define CCNL_FINEST 15
00047
00048 #define CACHE_PURGE_TRIGGER 60 // cache entry purge, in seconds
00049 #define CACHE_CLEAN_BATCH 16 // seconds between cleaning batches
00050 #define CACHE_CLEAN_DELTA 8 // cache clean batch size
00051 #define ADVISE_NEED_RESET 1 // reset value for adviseNeed
00052 #define UPDATE_STALL_DELTA 15 // seconds used to determine stalled update
00053 #define UPDATE_NEED_DELTA 6 // seconds for adaptive update
00054 #define SHORT_DELAY_MICROS 500 // short delay for quick reschedule
00055 #define COMPARE_ASSUME_BAD 20 // secs since last fetch OK to assume compare failed
00056 #define NODE_SPLIT_TRIGGER 400 // in bytes, triggers node split
00057 #define EXCLUSION_LIMIT 1000 // in bytes, limits exclusion list size
00058 #define EXCLUSION_TRIG 5 // trigger for including root hashes in excl list (secs)
00059 #define STABLE_TIME_TRIG 10 // trigger for storing stable point (secs)
00060 #define HASH_SPLIT_TRIGGER 17 // trigger for splitting based on hash (n/255)
00061 #define NAMES_YIELD_INC 100 // number of names to inc between yield tests
00062 #define NAMES_YIELD_MICROS 20*1000 // number of micros to use as yield trigger
00063
00064 static ccnr_hwm ccns_hwm_update(struct ccnr_handle *ccnr, ccnr_hwm hwm, ccnr_accession a);
00065 static uintmax_t ccns_accession_encode(struct ccnr_handle *ccnr, ccnr_accession a);
00066
00067 struct ccns_slice {
00068 unsigned version;
00069 unsigned nclauses;
00070 struct ccn_charbuf *topo;
00071 struct ccn_charbuf *prefix;
00072 struct ccn_charbuf **clauses;
00073 };
00074
00075 #define CCNS_FLAGS_SC 1 // start at current root hash.
00076
00077 struct ccns_handle {
00078 struct SyncBaseStruct *base;
00079 struct SyncRootStruct *root;
00080 struct ccn_scheduled_event *ev;
00081 ccns_callback callback;
00082 unsigned flags;
00083 };
00084
00085
00086
00087
00088 struct ccns_slice *
00089 ccns_slice_create()
00090 {
00091 struct ccns_slice *s = calloc(1, sizeof(*s));
00092 if (s == NULL)
00093 return(NULL);
00094 s->version = SLICE_VERSION;
00095 s->topo = ccn_charbuf_create_n(8);
00096 s->prefix = ccn_charbuf_create_n(8);
00097 if (s->topo == NULL || s->prefix == NULL) {
00098 ccn_charbuf_destroy(&s->topo);
00099 ccn_charbuf_destroy(&s->prefix);
00100 free(s);
00101 s = NULL;
00102 } else {
00103 ccn_name_init(s->topo);
00104 ccn_name_init(s->prefix);
00105 }
00106 return(s);
00107 }
00108 void
00109 ccns_slice_destroy(struct ccns_slice **sp)
00110 {
00111 struct ccns_slice *s = *sp;
00112 if (s != NULL) {
00113 ccn_charbuf_destroy(&(s->topo));
00114 ccn_charbuf_destroy(&(s->prefix));
00115 if (s->clauses != NULL) {
00116 while(s->nclauses > 0) {
00117 s->nclauses--;
00118 ccn_charbuf_destroy(&(s->clauses[s->nclauses]));
00119 }
00120 free(s->clauses);
00121 }
00122 free(s);
00123 *sp = NULL;
00124 }
00125 }
00126
00127
00128
00129 int
00130 ccns_slice_add_clause(struct ccns_slice *s, struct ccn_charbuf *c)
00131 {
00132 struct ccn_charbuf **clauses = NULL;
00133 struct ccn_charbuf *clause;
00134 clause = ccn_charbuf_create_n(c->length);
00135 if (clause == NULL)
00136 return(-1);
00137 if (s->clauses == NULL) {
00138 s->clauses = calloc(1, sizeof(s->clauses[0]));
00139 if (s->clauses == NULL)
00140 goto Cleanup;
00141 } else {
00142 clauses = realloc(s->clauses, (s->nclauses + 1) * sizeof(s->clauses[0]));
00143 if (clauses == NULL)
00144 goto Cleanup;
00145 s->clauses = clauses;
00146 }
00147 ccn_charbuf_append_charbuf(clause, c);
00148 s->clauses[s->nclauses++] = clause;
00149 return (0);
00150
00151 Cleanup:
00152 ccn_charbuf_destroy(&clause);
00153 return (-1);
00154 }
00155
00156
00157
00158
00159 int
00160 ccns_slice_set_topo_prefix(struct ccns_slice *s, struct ccn_charbuf *t,
00161 struct ccn_charbuf *p)
00162 {
00163 int res = 0;
00164 if (t != NULL) {
00165 ccn_charbuf_reset(s->topo);
00166 res |= ccn_charbuf_append_charbuf(s->topo, t);
00167 }
00168 if (p != NULL) {
00169 ccn_charbuf_reset(s->prefix);
00170 res |= ccn_charbuf_append_charbuf(s->prefix, p);
00171 }
00172 return(res);
00173 }
00174
00175
00176
00177
00178 static int
00179 append_slice(struct ccn_charbuf *c, struct ccns_slice *s)
00180 {
00181 int res = 0;
00182 int i;
00183
00184 res |= ccnb_element_begin(c, CCN_DTAG_SyncConfigSlice);
00185 res |= ccnb_tagged_putf(c, CCN_DTAG_SyncVersion, "%u", SLICE_VERSION);
00186 res |= ccn_charbuf_append_charbuf(c, s->topo);
00187 res |= ccn_charbuf_append_charbuf(c, s->prefix);
00188 res |= ccnb_element_begin(c, CCN_DTAG_SyncConfigSliceList);
00189 for (i = 0; i < s->nclauses ; i++) {
00190 res |= ccnb_tagged_putf(c, CCN_DTAG_SyncConfigSliceOp, "%u", 0);
00191 res |= ccn_charbuf_append_charbuf(c, s->clauses[i]);
00192 }
00193 res |= ccnb_element_end(c);
00194 res |= ccnb_element_end(c);
00195 return (res);
00196 }
00197
00198
00199
00200
00201 static int
00202 slice_parse(struct ccns_slice *s, const unsigned char *p, size_t size)
00203 {
00204 int res = 0;
00205 struct ccn_buf_decoder decoder;
00206 struct ccn_buf_decoder *d = ccn_buf_decoder_start(&decoder, p, size);
00207 uintmax_t version;
00208 int op;
00209 int start;
00210 struct ccn_charbuf *clause = NULL;
00211
00212 if (!ccn_buf_match_dtag(d, CCN_DTAG_SyncConfigSlice))
00213 return (-1);
00214 ccn_buf_advance(d);
00215 if (!ccn_buf_match_dtag(d, CCN_DTAG_SyncVersion))
00216 return (-1);
00217 ccn_buf_advance(d);
00218 ccn_parse_uintmax(d, &version);
00219 ccn_buf_check_close(d);
00220 if (version != SLICE_VERSION)
00221 return (-1);
00222 start = d->decoder.token_index;
00223 if (ccn_parse_Name(d, NULL) < 0)
00224 return(-1);
00225 ccn_charbuf_reset(s->topo);
00226 res = ccn_charbuf_append(s->topo, p + start, d->decoder.token_index - start);
00227 if (res < 0)
00228 return(-1);
00229 start = d->decoder.token_index;
00230 if (ccn_parse_Name(d, NULL) < 0)
00231 return(-1);
00232 ccn_charbuf_reset(s->prefix);
00233 res = ccn_charbuf_append(s->prefix, p + start, d->decoder.token_index - start);
00234 if (res < 0)
00235 return(-1);
00236 if (!ccn_buf_match_dtag(d, CCN_DTAG_SyncConfigSliceList))
00237 return(-1);
00238 ccn_buf_advance(d);
00239 clause = ccn_charbuf_create();
00240 if (clause == NULL)
00241 return(-1);
00242 while (ccn_buf_match_dtag(d, CCN_DTAG_SyncConfigSliceOp)) {
00243 ccn_buf_advance(d);
00244 op = ccn_parse_nonNegativeInteger(d);
00245 ccn_buf_check_close(d);
00246 if (op != 0)
00247 break;
00248 ccn_charbuf_reset(clause);
00249 start = d->decoder.token_index;
00250 if (ccn_parse_Name(d, NULL) < 0)
00251 break;
00252 res = ccn_charbuf_append(clause, p + start, d->decoder.token_index - start);
00253 ccns_slice_add_clause(s, clause);
00254 }
00255 ccn_charbuf_destroy(&clause);
00256 ccn_buf_check_close(d);
00257 ccn_buf_check_close(d);
00258 if (d->decoder.index != size || !CCN_FINAL_DSTATE(d->decoder.state))
00259 return(-1);
00260 return(0);
00261 }
00262
00263
00264
00265
00266
00267
00268
00269 int
00270 ccns_slice_name(struct ccn_charbuf *nm, struct ccns_slice *s)
00271 {
00272 struct ccn_charbuf *c;
00273 struct ccn_digest *digest = NULL;
00274 struct ccn_charbuf *hash = NULL;
00275 int res = 0;
00276
00277 c = ccn_charbuf_create();
00278 if (c == NULL)
00279 return (-1);
00280 res = append_slice(c, s);
00281 if (res < 0)
00282 goto Cleanup;
00283
00284 digest = ccn_digest_create(CCN_DIGEST_SHA256);
00285 hash = ccn_charbuf_create_n(ccn_digest_size(digest));
00286 if (hash == NULL)
00287 goto Cleanup;
00288 ccn_digest_init(digest);
00289 res |= ccn_digest_update(digest, c->buf, c->length);
00290 res |= ccn_digest_final(digest, hash->buf, hash->limit);
00291 if (res < 0)
00292 goto Cleanup;
00293 hash->length = hash->limit;
00294 if (ccn_name_from_uri(nm, "ccnx:/%C1.M.S.localhost/%C1.S.cs") < 0)
00295 res = -1;
00296 res |= ccn_name_append(nm, hash->buf, hash->length);
00297
00298 Cleanup:
00299 ccn_charbuf_destroy(&c);
00300 ccn_digest_destroy(&digest);
00301 ccn_charbuf_destroy(&hash);
00302 return (res);
00303 }
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313 int
00314 ccns_read_slice(struct ccn *h, struct ccn_charbuf *name,
00315 struct ccns_slice *slice)
00316 {
00317 struct ccn_parsed_ContentObject pco_space = { 0 };
00318 struct ccn_parsed_ContentObject *pco = &pco_space;
00319 struct ccn_charbuf *nc = ccn_charbuf_create_n(name->length);
00320 struct ccn_charbuf *cob = ccn_charbuf_create();
00321 const unsigned char *content;
00322 size_t content_length;
00323 int res = -1;
00324
00325 if (nc == NULL || cob == NULL)
00326 goto Cleanup;
00327
00328 ccn_charbuf_append_charbuf(nc, name);
00329 res = ccn_resolve_version(h, nc, CCN_V_HIGHEST, 100);
00330 if (res < 0)
00331 goto Cleanup;
00332 if (res == 0) {
00333
00334 }
00335 res = ccn_get(h, nc, NULL, 100, cob, pco, NULL, 0);
00336 if (res < 0)
00337 goto Cleanup;
00338 if (pco->type != CCN_CONTENT_DATA) {
00339 res = -1;
00340 goto Cleanup;
00341 }
00342 res = ccn_content_get_value(cob->buf, cob->length, pco,
00343 &content, &content_length);
00344 if (res < 0)
00345 goto Cleanup;
00346 res = slice_parse(slice, content, content_length);
00347
00348 Cleanup:
00349 ccn_charbuf_destroy(&nc);
00350 ccn_charbuf_destroy(&cob);
00351 return (res);
00352 }
00353
00354 struct ccn_charbuf *
00355 make_scope1_template(void)
00356 {
00357 struct ccn_charbuf *templ = NULL;
00358 templ = ccn_charbuf_create_n(16);
00359 ccnb_element_begin(templ, CCN_DTAG_Interest);
00360 ccnb_element_begin(templ, CCN_DTAG_Name);
00361 ccnb_element_end(templ);
00362 ccnb_tagged_putf(templ, CCN_DTAG_Scope, "%u", 1);
00363 ccnb_element_end(templ);
00364 return(templ);
00365 }
00366
00367 static enum ccn_upcall_res
00368 write_interest_handler (struct ccn_closure *selfp,
00369 enum ccn_upcall_kind kind,
00370 struct ccn_upcall_info *info)
00371 {
00372 struct ccn_charbuf *cob = selfp->data;
00373 struct ccn *h = info->h;
00374
00375 if (kind != CCN_UPCALL_INTEREST)
00376 return(CCN_UPCALL_RESULT_OK);
00377 if (ccn_content_matches_interest(cob->buf, cob->length, 1, NULL,
00378 info->interest_ccnb,
00379 info->pi->offset[CCN_PI_E],
00380 info->pi)) {
00381 ccn_put(info->h, cob->buf, cob->length);
00382 selfp->intdata = 1;
00383 ccn_set_run_timeout(h, 0);
00384 return(CCN_UPCALL_RESULT_INTEREST_CONSUMED);
00385 }
00386 return(CCN_UPCALL_RESULT_OK);
00387 }
00388
00389 static int
00390 write_slice(struct ccn *h, struct ccns_slice *slice,
00391 struct ccn_charbuf *name)
00392 {
00393 struct ccn_charbuf *content = NULL;
00394 unsigned char *cbuf = NULL;
00395 size_t clength = 0;
00396 struct ccn_charbuf *sw = NULL;
00397 struct ccn_charbuf *templ = NULL;
00398 struct ccn_charbuf *cob = NULL;
00399 struct ccn_signing_params sparm = CCN_SIGNING_PARAMS_INIT;
00400 struct ccn_closure *wc = NULL;
00401 int res;
00402
00403 sw = ccn_charbuf_create_n(32 + name->length);
00404 if (sw == NULL) {
00405 res = -1;
00406 goto Cleanup;
00407 }
00408 ccn_charbuf_append_charbuf(sw, name);
00409 ccn_name_chop(sw, NULL, -1);
00410 ccn_name_from_uri(sw, "%C1.R.sw");
00411 ccn_name_append_nonce(sw);
00412
00413
00414 cob = ccn_charbuf_create();
00415 if (cob == NULL) {
00416 res = -1;
00417 goto Cleanup;
00418 }
00419 if (slice != NULL) {
00420 content = ccn_charbuf_create();
00421 if (content == NULL) {
00422 res = -1;
00423 goto Cleanup;
00424 }
00425 res = append_slice(content, slice);
00426 if (res < 0)
00427 goto Cleanup;
00428 cbuf = content->buf;
00429 clength = content->length;
00430 } else {
00431 sparm.type = CCN_CONTENT_GONE;
00432 }
00433
00434 sparm.sp_flags = CCN_SP_FINAL_BLOCK;
00435 res = ccn_sign_content(h, cob, name, &sparm, cbuf, clength);
00436 if (res < 0)
00437 goto Cleanup;
00438
00439 wc = calloc(1, sizeof(*wc));
00440 if (wc == NULL) {
00441 res = -1;
00442 goto Cleanup;
00443 }
00444 wc->p = &write_interest_handler;
00445 wc->data = cob;
00446 res = ccn_set_interest_filter(h, name, wc);
00447 if (res < 0)
00448 goto Cleanup;
00449 templ = make_scope1_template();
00450 if (templ == NULL) {
00451 res = -1;
00452 goto Cleanup;
00453 }
00454 res = ccn_get(h, sw, templ, 1000, NULL, NULL, NULL, 0);
00455 if (res < 0)
00456 goto Cleanup;
00457 ccn_run(h, 1000);
00458 if (wc->intdata != 1) {
00459 res = -1;
00460 goto Cleanup;
00461 }
00462 res = 0;
00463 Cleanup:
00464 ccn_set_interest_filter(h, name, NULL);
00465 if (wc != NULL)
00466 free(wc);
00467 ccn_charbuf_destroy(&cob);
00468 ccn_charbuf_destroy(&content);
00469 ccn_charbuf_destroy(&sw);
00470 ccn_charbuf_destroy(&templ);
00471 return (res);
00472 }
00473
00474
00475
00476
00477
00478
00479
00480
00481 int
00482 ccns_write_slice(struct ccn *h, struct ccns_slice *slice,
00483 struct ccn_charbuf *name)
00484 {
00485 struct ccn_charbuf *n = NULL;
00486 int res;
00487
00488 n = ccn_charbuf_create();
00489 if (n == NULL)
00490 return(-1);
00491 res = ccns_slice_name(n, slice);
00492 if (res < 0)
00493 goto Cleanup;
00494 res |= ccn_create_version(h, n, CCN_V_NOW, 0, 0);
00495 if (name != NULL) {
00496 ccn_charbuf_reset(name);
00497 res |= ccn_charbuf_append_charbuf(name, n);
00498 }
00499 res |= ccn_name_append_numeric(n, CCN_MARKER_SEQNUM, 0);
00500 if (res < 0)
00501 goto Cleanup;
00502 res = write_slice(h, slice, n);
00503
00504 Cleanup:
00505 ccn_charbuf_destroy(&n);
00506 return (res);
00507 }
00508
00509
00510
00511
00512
00513
00514 int
00515 ccns_delete_slice(struct ccn *h, struct ccn_charbuf *name)
00516 {
00517 struct ccn_charbuf *n = NULL;
00518 int res;
00519
00520
00521 n = ccn_charbuf_create_n(32 + name->length);
00522 if (n == NULL)
00523 return(-1);
00524 res = ccn_charbuf_append_charbuf(n, name);
00525 res |= ccn_create_version(h, n, CCN_V_NOW | CCN_V_REPLACE, 0, 0);
00526 res |= ccn_name_append_numeric(n, CCN_MARKER_SEQNUM, 0);
00527 if (res < 0)
00528 return(-1);
00529 res = write_slice(h, NULL, n);
00530 ccn_charbuf_destroy(&n);
00531 return (res);
00532 }
00533
00534
00535
00536
00537 static void
00538 gettime(const struct ccn_gettime *self, struct ccn_timeval *result)
00539 {
00540 struct timeval now = {0};
00541 gettimeofday(&now, 0);
00542 result->s = now.tv_sec;
00543 result->micros = now.tv_usec;
00544 }
00545
00546 static int HeartbeatAction(struct ccn_schedule *sched,
00547 void *clienth,
00548 struct ccn_scheduled_event *ev,
00549 int flags);
00550
00551 static int ccns_send_root_advise_interest(struct SyncRootStruct *root);
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570 struct ccns_handle *
00571 ccns_open(struct ccn *h,
00572 struct ccns_slice *slice,
00573 ccns_callback callback,
00574 struct ccn_charbuf *rhash,
00575 struct ccn_charbuf *pname)
00576 {
00577 struct ccn_schedule *schedule;
00578 struct ccn_gettime *timer;
00579 struct ccns_handle *ccns = calloc(1, sizeof(*ccns));
00580 struct SyncHashCacheEntry *ceL = NULL;
00581 if (ccns == NULL)
00582 return(NULL);
00583 schedule = ccn_get_schedule(h);
00584 if (schedule == NULL) {
00585 timer = calloc(1, sizeof(*timer));
00586 timer->descr[0]='S';
00587 timer->micros_per_base = 1000000;
00588 timer->gettime = &gettime;
00589 timer->data = h;
00590 schedule = ccn_schedule_create(h, timer);
00591 ccn_set_schedule(h, schedule);
00592 }
00593 ccns->callback = callback;
00594 ccns->base = SyncNewBase((void *)ccns, h, schedule);
00595 ccns->base->priv->heartbeatMicros = 1000000;
00596 ccns->base->priv->rootAdviseLifetime = 20;
00597 ccns->base->priv->maxComparesBusy = 8;
00598 ccns->base->debug = CCNL_WARNING;
00599 ccns->root = SyncAddRoot(ccns->base, ccns->base->priv->syncScope,
00600 slice->topo, slice->prefix, NULL);
00601
00602
00603
00604
00605 if (rhash != NULL) {
00606 if (rhash->length > 0) {
00607 ccn_charbuf_reset(ccns->root->currentHash);
00608 ccn_charbuf_append_charbuf(ccns->root->currentHash, rhash);
00609 ceL = SyncHashEnter(ccns->root->ch, rhash->buf, rhash->length, 0);
00610 } else {
00611 ccns->flags |= CCNS_FLAGS_SC;
00612 }
00613 }
00614
00615 ccns_send_root_advise_interest(ccns->root);
00616 ccns->ev = ccn_schedule_event(ccns->base->sched,
00617 ccns->base->priv->heartbeatMicros,
00618 &HeartbeatAction,
00619 ccns->base,
00620 0);
00621
00622 return(ccns);
00623 }
00624
00625
00626
00627
00628
00629
00630
00631
00632 void ccns_close(struct ccns_handle **ccnsp, struct ccn_charbuf *rhash, struct ccn_charbuf *pname)
00633 {
00634 struct ccns_handle *ccns = *ccnsp;
00635 ccn_schedule_cancel(ccns->base->sched, ccns->ev);
00636
00637 if (rhash != NULL) {
00638 ccn_charbuf_reset(rhash);
00639 ccn_charbuf_append_charbuf(rhash, ccns->root->currentHash);
00640 }
00641 SyncFreeBase(&(*ccnsp)->base);
00642 free(*ccnsp);
00643 *ccnsp = NULL;
00644 return;
00645 }
00646
00647 void
00648 ccns_msg(struct ccnr_handle *h, const char *fmt, ...)
00649 {
00650 struct timeval t;
00651 va_list ap;
00652 struct ccn_charbuf *b = ccn_charbuf_create();
00653 ccn_charbuf_reserve(b, 1024);
00654 gettimeofday(&t, NULL);
00655 ccn_charbuf_putf(b, "%s\n", fmt);
00656 char *fb = ccn_charbuf_as_string(b);
00657 va_start(ap, fmt);
00658 vfprintf(stdout, fb, ap);
00659 va_end(ap);
00660 fflush(stdout);
00661 ccn_charbuf_destroy(&b);
00662 }
00663
00664 enum SyncCompareState {
00665 SyncCompare_init,
00666 SyncCompare_preload,
00667 SyncCompare_busy,
00668 SyncCompare_waiting,
00669 SyncCompare_done
00670 };
00671
00672 struct SyncCompareData {
00673 struct SyncRootStruct *root;
00674 struct SyncTreeWorkerHead *twL;
00675 struct SyncTreeWorkerHead *twR;
00676 struct ccn_charbuf *hashL;
00677 struct ccn_charbuf *hashR;
00678 struct ccn_charbuf *cbL;
00679 struct ccn_charbuf *cbR;
00680 struct ccn_charbuf *lagL;
00681 int *lagMatch;
00682 struct SyncActionData *errList;
00683 int errsQueued;
00684 int namesAdded;
00685 int nodeFetchBusy;
00686 int nodeFetchFailed;
00687 int contentPos;
00688 int contentFetchBusy;
00689 int contentFetchFailed;
00690 struct ccn_scheduled_event *ev;
00691 enum SyncCompareState state;
00692 int64_t lastFetchOK;
00693 int64_t startTime;
00694 int64_t lastEnter;
00695 int64_t lastMark;
00696 int64_t maxHold;
00697 };
00698
00699 static void
00700 delinkActionData(struct SyncActionData *data) {
00701 if (data == NULL) return;
00702 if (data->state == SyncActionState_sent) {
00703
00704 struct SyncRootStruct *root = data->root;
00705 if (root == NULL) return;
00706 struct SyncActionData *each = root->actions;
00707 struct SyncActionData *lag = NULL;
00708 data->state = SyncActionState_loose;
00709 while (each != NULL) {
00710 struct SyncActionData *next = each->next;
00711 if (data == each) {
00712 data->next = NULL;
00713 if (lag == NULL) root->actions = next;
00714 else lag->next = next;
00715 break;
00716 }
00717 lag = each;
00718 each = next;
00719 }
00720 } else {
00721 if (data->state == SyncActionState_error) {
00722
00723 struct SyncCompareData *comp = data->comp;
00724 if (comp == NULL) return;
00725 struct SyncActionData *each = comp->errList;
00726 struct SyncActionData *lag = NULL;
00727 data->state = SyncActionState_loose;
00728 while (each != NULL) {
00729 struct SyncActionData *next = each->next;
00730 if (data == each) {
00731 data->next = NULL;
00732 if (comp->errsQueued > 0) comp->errsQueued--;
00733 if (lag == NULL) comp->errList = next;
00734 else lag->next = next;
00735 break;
00736 }
00737 lag = each;
00738 each = next;
00739 }
00740 }
00741 }
00742 }
00743
00744 static int
00745 moveActionData(struct SyncActionData *data, enum SyncActionState dstState) {
00746
00747
00748
00749 if (data == NULL) return 0;
00750 if (dstState == SyncActionState_error && data->state != SyncActionState_sent)
00751 return 0;
00752 if (dstState == SyncActionState_sent && data->state != SyncActionState_error)
00753 return 0;
00754 struct SyncRootStruct *root = data->root;
00755 struct SyncCompareData *comp = data->comp;
00756 if (root == NULL || comp == NULL) return 0;
00757 delinkActionData(data);
00758 if (dstState == SyncActionState_sent) {
00759 data->next = root->actions;
00760 root->actions = data;
00761 } else {
00762 data->next = comp->errList;
00763 comp->errList = data;
00764 comp->errsQueued++;
00765 }
00766 data->state = dstState;
00767 return 1;
00768 }
00769
00770 static struct SyncActionData *
00771 destroyActionData(struct SyncActionData *data) {
00772 if (data != NULL) {
00773 delinkActionData(data);
00774
00775 if (data->prefix != NULL)
00776 ccn_charbuf_destroy(&data->prefix);
00777 if (data->hash != NULL)
00778 ccn_charbuf_destroy(&data->hash);
00779 data->next = NULL;
00780 data->root = NULL;
00781 data->comp = NULL;
00782 free(data);
00783 }
00784 return NULL;
00785 }
00786
00787 static struct SyncActionData *
00788 newActionData(enum SyncRegisterActionKind kind) {
00789 struct SyncActionData *data = calloc(1, sizeof(*data));
00790 data->startTime = SyncCurrentTime();
00791 data->kind = kind;
00792 data->state = SyncActionState_init;
00793 return data;
00794 }
00795
00796 static void
00797 linkActionData(struct SyncRootStruct *root, struct SyncActionData *data) {
00798 data->root = root;
00799 data->next = root->actions;
00800 data->client_handle = root->base->client_handle;
00801 data->state = SyncActionState_sent;
00802 root->actions = data;
00803 }
00804
00805 static void
00806 setCovered(struct SyncHashCacheEntry *ce) {
00807 char *here = "Sync.setCovered";
00808 if (ce->state & SyncHashState_covered) {
00809
00810 } else if (ce->state & SyncHashState_remote) {
00811
00812 struct SyncRootStruct *root = ce->head->root;
00813 if (root->base->debug >= CCNL_FINER) {
00814 char *hex = SyncHexStr(ce->hash->buf, ce->hash->length);
00815 SyncNoteSimple(root, here, hex);
00816 free(hex);
00817 }
00818 ce->state |= SyncHashState_covered;
00819 }
00820 }
00821
00822 static int
00823 isCovered(struct SyncHashCacheEntry *ce) {
00824 if (ce->state & SyncHashState_covered) return 1;
00825 if (ce->state & SyncHashState_local) {
00826 setCovered(ce);
00827 return 1;
00828 }
00829 return 0;
00830 }
00831
00832 static int
00833 compareHash(struct ccn_charbuf *hashX, struct ccn_charbuf *hashY) {
00834 if (hashX == hashY) return 0;
00835 if (hashX == NULL) return -1;
00836 if (hashY == NULL) return 1;
00837 size_t lenX = hashX->length;
00838 size_t lenY = hashY->length;
00839 if (lenX < lenY) return -1;
00840 if (lenX > lenY) return 1;
00841 return memcmp(hashX->buf, hashY->buf, lenX);
00842 }
00843
00844 static struct SyncActionData *
00845 SyncFindAction(struct SyncRootStruct *root, enum SyncRegisterActionKind kind) {
00846 struct SyncActionData *each = root->actions;
00847 while (each != NULL) {
00848 if (each->kind == kind) return each;
00849 each = each->next;
00850 }
00851 return NULL;
00852 }
00853
00854 extern int
00855 SyncAddName(struct SyncBaseStruct *base,
00856 struct ccn_charbuf *name,
00857 ccnr_accession item) {
00858 static char *here = "Sync.SyncAddName";
00859 struct SyncPrivate *priv = base->priv;
00860 int debug = base->debug;
00861 struct SyncRootStruct *root = priv->rootHead;
00862 int count = 0;
00863 while (root != NULL) {
00864 if (SyncRootLookupName(root, name) == SyncRootLookupCode_covered) {
00865
00866
00867 struct ccn_charbuf *prev = NULL;
00868 int pos = root->namesToAdd->len;
00869 if (pos > 0) prev = root->namesToAdd->ents[pos-1].name;
00870 if (prev != NULL && SyncCmpNames(name, prev) == 0) {
00871
00872 if (debug >= CCNL_FINE) {
00873 SyncNoteUri(root, here, "ignore dup", name);
00874 }
00875 } else {
00876
00877 uintmax_t itemNum = ccns_accession_encode(base->client_handle, item);
00878 SyncNameAccumAppend(root->namesToAdd, SyncCopyName(name), itemNum);
00879 if (item != CCNR_NULL_ACCESSION)
00880 root->priv->highWater = ccns_hwm_update(base->client_handle,
00881 root->priv->highWater,
00882 item);
00883 count++;
00884 if (debug >= CCNL_FINE) {
00885 char temp[64];
00886
00887 if (item >= CCNR_MIN_ACCESSION && item <= CCNR_MAX_ACCESSION) {
00888 snprintf(temp, sizeof(temp), "added, %ju", itemNum);
00889 } else {
00890 snprintf(temp, sizeof(temp), "no accession");
00891 }
00892 SyncNoteUri(root, here, temp, name);
00893 }
00894 }
00895 }
00896 root = root->next;
00897 }
00898 if (item != CCNR_NULL_ACCESSION)
00899 base->highWater = ccns_hwm_update(base->client_handle, base->highWater, item);
00900 return count;
00901 }
00902
00903 static struct SyncNodeComposite *
00904 extractNode(struct SyncRootStruct *root, struct ccn_upcall_info *info) {
00905
00906 char *here = "Sync.extractNode";
00907 const unsigned char *cp = NULL;
00908 size_t cs = 0;
00909 size_t ccnb_size = info->pco->offset[CCN_PCO_E];
00910 const unsigned char *ccnb = info->content_ccnb;
00911 int res = ccn_content_get_value(ccnb, ccnb_size, info->pco,
00912 &cp, &cs);
00913 if (res < 0 || cs < DEFAULT_HASH_BYTES) {
00914 SyncNoteFailed(root, here, "ccn_content_get_value", __LINE__);
00915 return NULL;
00916 }
00917
00918
00919 struct SyncNodeComposite *nc = SyncAllocComposite(root->base);
00920 struct ccn_buf_decoder ds;
00921 struct ccn_buf_decoder *d = ccn_buf_decoder_start(&ds, cp, cs);
00922 res |= SyncParseComposite(nc, d);
00923 if (res < 0) {
00924
00925 SyncNoteFailed(root, here, "bad parse", -res);
00926 SyncFreeComposite(nc);
00927 nc = NULL;
00928 }
00929 return nc;
00930 }
00931
00932 static int
00933 noteRemoteHash(struct SyncRootStruct *root, struct SyncHashCacheEntry *ce, int add) {
00934 char *here = "Sync.noteRemoteHash";
00935 int debug = root->base->debug;
00936 struct ccnr_handle *ccnr = root->base->client_handle;
00937 struct ccn_charbuf *hash = ce->hash;
00938 int hl = hash->length;
00939 if (hl == 0) return 0;
00940 struct SyncHashInfoList *head = root->priv->remoteSeen;
00941 struct SyncHashInfoList *each = head;
00942 struct SyncHashInfoList *lag = NULL;
00943 int64_t mark = SyncCurrentTime();
00944 ce->lastUsed = mark;
00945 ce->lastRemoteFetch = mark;
00946 if (ce->state & SyncHashState_local)
00947 setCovered(ce);
00948 while (each != NULL) {
00949 if (ce == each->ce) {
00950 if (lag != NULL) {
00951
00952 lag->next = each->next;
00953 each->next = head;
00954 root->priv->remoteSeen = each;
00955 }
00956 break;
00957 }
00958 lag = each;
00959 each = each->next;
00960 }
00961 if (each == NULL && add) {
00962
00963 each = calloc(1, sizeof(*each));
00964 each->next = head;
00965 root->priv->remoteSeen = each;
00966 }
00967 if (debug >= CCNL_FINE) {
00968 char *hex = SyncHexStr(hash->buf, hash->length);
00969 char *extra = "";
00970 if (ce->state & SyncHashState_covered) extra = "covered, ";
00971 ccns_msg(ccnr, "%s, root#%u, %s%s", here, root->rootId, extra, hex);
00972 free(hex);
00973 }
00974 if (each != NULL) {
00975 each->ce = ce;
00976 ce->busy++;
00977 each->lastSeen = mark;
00978 }
00979 return 1;
00980 }
00981
00982 static char *
00983 getCmdStr(enum SyncRegisterActionKind kind) {
00984 switch (kind) {
00985 case SRI_Kind_AdviseInt:
00986 case SRI_Kind_RootAdvise:
00987 return "\xC1.S.ra";
00988 case SRI_Kind_FetchInt:
00989 case SRI_Kind_NodeFetch:
00990 return "\xC1.S.nf";
00991 case SRI_Kind_RootStats:
00992 return "\xC1.S.rs";
00993 default:
00994 return NULL;
00995 }
00996 }
00997
00998
00999
01000 static struct SyncNameAccum *
01001 sortNames(struct SyncRootStruct *root, struct SyncNameAccum *src) {
01002 char *here = "Sync.sortNames";
01003 IndexSorter_Index ixLim = src->len;
01004 IndexSorter_Base ixBase = IndexSorter_New(ixLim, -1);
01005 ixBase->sorter = SyncNameAccumSorter;
01006 ixBase->client = src;
01007 IndexSorter_Index ix = 0;
01008 for (ix = 0; ix < ixLim; ix++) IndexSorter_Add(ixBase, ix);
01009 struct SyncNameAccum *dst = SyncAllocNameAccum(ixLim);
01010 struct ccn_charbuf *lag = NULL;
01011 for (ix = 0; ix < ixLim; ix++) {
01012 IndexSorter_Index j = IndexSorter_Rem(ixBase);
01013 if (j >= ixLim) {
01014 SyncNoteFailed(root, here, "rem failed", __LINE__);
01015 break;
01016 }
01017 struct ccn_charbuf *name = src->ents[j].name;
01018 src->ents[j].name = NULL;
01019 if (name == NULL) {
01020 SyncNoteFailed(root, here, "name == NULL", __LINE__);
01021 break;
01022 }
01023 if (lag == NULL || SyncCmpNames(lag, name) != 0) {
01024
01025 SyncNameAccumAppend(dst, name, src->ents[j].data);
01026 lag = name;
01027 } else {
01028
01029 ccn_charbuf_destroy(&name);
01030 }
01031 }
01032 src->len = 0;
01033 IndexSorter_Free(&ixBase);
01034 return dst;
01035 }
01036
01037 static struct SyncNameAccum *
01038 exclusionsFromHashList(struct SyncRootStruct *root, struct SyncHashInfoList *list) {
01039 struct SyncNameAccum *acc = SyncAllocNameAccum(0);
01040 int count = 0;
01041 int limit = 1000;
01042 int64_t now = SyncCurrentTime();
01043 int64_t limitMicros = 1000000 * 5;
01044
01045 if (root->currentHash->length > 0) {
01046
01047 struct ccn_charbuf *hash = root->currentHash;
01048 struct ccn_charbuf *name = ccn_charbuf_create();
01049 count = count + hash->length + 8;
01050 ccn_name_init(name);
01051 ccn_name_append(name, hash->buf, hash->length);
01052 SyncNameAccumAppend(acc, name, 0);
01053 }
01054
01055 while (list != NULL) {
01056 struct SyncHashCacheEntry *ce = list->ce;
01057 if (ce != NULL && (ce->state & SyncHashState_remote)
01058 && (ce->state & SyncHashState_covered)
01059 && SyncDeltaTime(ce->lastUsed, now) < limitMicros) {
01060
01061 struct ccn_charbuf *hash = ce->hash;
01062 count = count + hash->length + 8;
01063 if (count > limit)
01064
01065 break;
01066 struct ccn_charbuf *name = ccn_charbuf_create();
01067 ccn_name_init(name);
01068 ccn_name_append(name, hash->buf, hash->length);
01069 SyncNameAccumAppend(acc, name, 0);
01070 }
01071 list = list->next;
01072 }
01073 if (acc->len == 0) {
01074 SyncFreeNameAccum(acc);
01075 return NULL;
01076 }
01077 struct SyncNameAccum *lag = acc;
01078 if (acc->len == 0) {
01079
01080 acc = NULL;
01081 } else {
01082
01083 acc = sortNames(root, acc);
01084 }
01085 SyncFreeNameAccum(lag);
01086 return acc;
01087 }
01088
01089 static struct ccn_charbuf *
01090 constructCommandPrefix(struct SyncRootStruct *root,
01091 enum SyncRegisterActionKind kind) {
01092 struct ccn_charbuf *prefix = ccn_charbuf_create();
01093 int res = 0;
01094 ccn_name_init(prefix);
01095 if (root->topoPrefix != NULL && root->topoPrefix->length > 0) {
01096
01097 res |= SyncAppendAllComponents(prefix, root->topoPrefix);
01098 }
01099
01100 ccn_name_append_str(prefix, getCmdStr(kind));
01101 res |= ccn_name_append(prefix, root->sliceHash->buf, root->sliceHash->length);
01102
01103 if (res < 0) {
01104 ccn_charbuf_destroy(&prefix);
01105 }
01106 return prefix;
01107 }
01108
01109
01110 enum ccn_upcall_res
01111 ccns_root_advise_response(struct ccn_closure *selfp,
01112 enum ccn_upcall_kind kind,
01113 struct ccn_upcall_info *info) {
01114 static char *here = "Sync.SyncRootAdviseResponse";
01115 struct SyncActionData *data = selfp->data;
01116 enum ccn_upcall_res ret = CCN_UPCALL_RESULT_OK;
01117 switch (kind) {
01118 case CCN_UPCALL_FINAL:
01119 data = destroyActionData(data);
01120 free(selfp);
01121 break;
01122 case CCN_UPCALL_CONTENT_UNVERIFIED:
01123 ret = CCN_UPCALL_RESULT_VERIFY;
01124 break;
01125 case CCN_UPCALL_CONTENT_KEYMISSING:
01126 ret = CCN_UPCALL_RESULT_FETCHKEY;
01127 break;
01128 case CCN_UPCALL_INTEREST_TIMED_OUT:
01129 if (data == NULL || info == NULL ||
01130 data->root == NULL || data->kind != SRI_Kind_RootAdvise) {
01131
01132 } else {
01133 int64_t now = SyncCurrentTime();
01134 struct SyncRootStruct *root = data->root;
01135 int debug = root->base->debug;
01136
01137 if (debug >= CCNL_INFO) {
01138 char temp[64];
01139 int64_t dt = SyncDeltaTime(data->startTime, now);
01140 dt = (dt + 500) / 1000;
01141 snprintf(temp, sizeof(temp),
01142 "timeout, %d.%03d secs",
01143 (int) (dt / 1000), (int) (dt % 1000));
01144 SyncNoteUri(root, here, temp, data->prefix);
01145 }
01146 data->startTime = now;
01147
01148 ret = CCN_UPCALL_RESULT_REEXPRESS;
01149 }
01150 break;
01151 case CCN_UPCALL_CONTENT_RAW:
01152 case CCN_UPCALL_CONTENT:
01153 if (data == NULL || info == NULL ||
01154 data->root == NULL || data->kind != SRI_Kind_RootAdvise) {
01155
01156 break;
01157 }
01158 struct SyncRootStruct *root = data->root;
01159 int debug = root->base->debug;
01160 if (debug >= CCNL_INFO) {
01161 struct ccn_charbuf *nm = SyncNameForIndexbuf(info->content_ccnb,
01162 info->content_comps);
01163 size_t bytes = info->pco->offset[CCN_PCO_E];
01164 char temp[64];
01165 int64_t dt = SyncDeltaTime(data->startTime, SyncCurrentTime());
01166 dt = (dt + 500) / 1000;
01167 snprintf(temp, sizeof(temp),
01168 "content, %d.%03d secs, %u bytes",
01169 (int) (dt / 1000), (int) (dt % 1000),
01170 (unsigned) bytes);
01171 SyncNoteUri(root, here, temp, nm);
01172 ccn_charbuf_destroy(&nm);
01173 }
01174
01175 const unsigned char *hp = NULL;
01176 size_t hs = 0;
01177 size_t bytes = 0;
01178 int failed = 0;
01179 int cres = ccn_name_comp_get(info->content_ccnb,
01180 info->content_comps,
01181 data->skipToHash, &hp, &hs);
01182 if (cres < 0 || hp == NULL) {
01183
01184 failed++;
01185 SyncNoteFailed(root, here, "bad hash", __LINE__);
01186
01187
01188
01189
01190 } else {
01191 struct SyncHashCacheEntry *ce = SyncHashEnter(root->ch, hp, hs,
01192 SyncHashState_remote);
01193 noteRemoteHash(root, ce, 1);
01194 if (!isCovered(ce)) {
01195
01196 struct SyncNodeComposite *nc = NULL;
01197 char *hex = SyncHexStr(hp, hs);
01198 if (ce != NULL && ce->ncR != NULL) {
01199 nc = ce->ncR;
01200 if (debug >= CCNL_INFO)
01201 SyncNoteSimple2(root, here, "existing but not covered", hex);
01202 } else {
01203 nc = extractNode(root, info);
01204 if (nc == NULL) {
01205
01206 failed++;
01207 if (debug >= CCNL_SEVERE)
01208 SyncNoteSimple2(root, here, "extractNode failed", hex);
01209 } else {
01210
01211 ce->ncR = nc;
01212 SyncNodeIncRC(nc);
01213 bytes = info->pco->offset[CCN_PCO_E];
01214 if (debug >= CCNL_INFO)
01215 SyncNoteSimple2(root, here, "remote entered", hex);
01216 }
01217 }
01218 free(hex);
01219 }
01220 }
01221 if (failed) {
01222 root->priv->stats->rootAdviseFailed++;
01223 } else {
01224 root->priv->stats->rootAdviseReceived++;
01225 root->priv->stats->rootAdviseBytes += bytes;
01226 }
01227 break;
01228 default:
01229
01230 ret = CCN_UPCALL_RESULT_ERR;
01231 break;
01232 }
01233 return ret;
01234 }
01235
01236 static int
01237 ccns_send_root_advise_interest(struct SyncRootStruct *root) {
01238 static char *here = "Sync.SyncSendRootAdviseInterest";
01239 enum SyncRegisterActionKind kind = SRI_Kind_RootAdvise;
01240 int debug = root->base->debug;
01241 struct SyncActionData *data = SyncFindAction(root, kind);
01242 struct SyncHashCacheEntry *ce = NULL;
01243 if (root->currentHash->length > 0) {
01244 ce = SyncHashLookup(root->ch,
01245 root->currentHash->buf,
01246 root->currentHash->length);
01247 }
01248 if (data != NULL) {
01249
01250 if (ce == NULL || ce == root->priv->lastLocalSent)
01251 return 0;
01252
01253 data->kind = SRI_Kind_None;
01254 if (debug >= CCNL_FINE)
01255 SyncNoteSimple(root, here, "marked old interest as inactive");
01256 }
01257 struct ccn_closure *action = calloc(1, sizeof(*action));
01258 struct ccn_charbuf *prefix = constructCommandPrefix(root, kind);
01259 struct ccn_charbuf *hash = ccn_charbuf_create();
01260
01261 ccn_charbuf_append_charbuf(hash, root->currentHash);
01262 ccn_name_append(prefix, hash->buf, hash->length);
01263
01264 data = newActionData(kind);
01265 data->skipToHash = SyncComponentCount(prefix);
01266 data->hash = hash;
01267 data->prefix = prefix;
01268 action->data = data;
01269 action->p = &ccns_root_advise_response;
01270
01271 struct SyncNameAccum *excl = exclusionsFromHashList(root, root->priv->remoteSeen);
01272 struct ccn_charbuf *template = SyncGenInterest(NULL,
01273 1,
01274 root->base->priv->rootAdviseLifetime,
01275 -1, -1,
01276 excl);
01277 int res = ccn_express_interest(root->base->ccn,
01278 prefix,
01279 action,
01280 template);
01281 SyncFreeNameAccumAndNames(excl);
01282 ccn_charbuf_destroy(&template);
01283 if (res >= 0) {
01284
01285 if (root->priv->adviseNeed > 0) root->priv->adviseNeed--;
01286 linkActionData(root, data);
01287 root->priv->lastAdvise = SyncCurrentTime();
01288 root->priv->lastLocalSent = ce;
01289 root->priv->stats->rootAdviseSent++;
01290 if (debug >= CCNL_INFO)
01291 SyncNoteUri(root, here, "sent", prefix);
01292 return 1;
01293 } else {
01294
01295 data = destroyActionData(data);
01296 free(action);
01297 if (debug >= CCNL_ERROR)
01298 SyncNoteSimple(root, here, "ccn_express_interest failed");
01299 return -1;
01300 }
01301 }
01302
01303 static int
01304 CompareAction(struct ccn_schedule *sched,
01305 void *clienth,
01306 struct ccn_scheduled_event *ev,
01307 int flags);
01308
01309 static struct SyncHashInfoList *
01310 chooseRemoteHash(struct SyncRootStruct *root) {
01311 struct SyncHashInfoList *each = root->priv->remoteSeen;
01312 int64_t now = SyncCurrentTime();
01313 int64_t limit = ((int64_t)root->base->priv->rootAdviseLifetime)*3*1000000;
01314 struct SyncHashInfoList *lag = NULL;
01315 while (each != NULL) {
01316 struct SyncHashCacheEntry *ce = each->ce;
01317 struct SyncHashInfoList *next = each->next;
01318 if (ce != NULL
01319 && (ce->state & SyncHashState_remote)
01320 && ((ce->state & SyncHashState_covered) == 0)) {
01321
01322 int64_t dt = SyncDeltaTime(ce->lastUsed, now);
01323 if (dt < limit) return each;
01324 ce = NULL;
01325 }
01326 if (ce == NULL || (ce->state & SyncHashState_covered)) {
01327
01328 if (lag == NULL) root->priv->remoteSeen = next;
01329 else lag->next = next;
01330 free(each);
01331 } else
01332 lag = each;
01333 each = next;
01334 }
01335 return NULL;
01336 }
01337
01338 static void
01339 destroyCompareData(struct SyncCompareData *data) {
01340 if (data == NULL) return;
01341 struct SyncRootStruct *root = data->root;
01342 struct SyncPrivate *priv = root->base->priv;
01343 if (root != NULL) {
01344 while (data->errList != NULL) {
01345 struct SyncActionData *sad = data->errList;
01346 destroyActionData(sad);
01347 }
01348 root->namesToFetch = SyncFreeNameAccumAndNames(root->namesToFetch);
01349 root->compare = NULL;
01350 struct SyncActionData *each = root->actions;
01351
01352 while (each != NULL) {
01353 if (each->comp == data) each->comp = NULL;
01354 each = each->next;
01355 }
01356 }
01357 if (priv->comparesBusy > 0) priv->comparesBusy--;
01358 ccn_charbuf_destroy(&data->hashL);
01359 ccn_charbuf_destroy(&data->hashR);
01360 ccn_charbuf_destroy(&data->cbL);
01361 ccn_charbuf_destroy(&data->cbR);
01362 data->twL = SyncTreeWorkerFree(data->twL);
01363 data->twR = SyncTreeWorkerFree(data->twR);
01364 if (data->ev != NULL && root != NULL) {
01365 data->ev->evdata = NULL;
01366 ccn_schedule_cancel(root->base->sched, data->ev);
01367 }
01368 free(data);
01369 }
01370
01371
01372 static void
01373 abortCompare(struct SyncCompareData *data, char *why) {
01374
01375
01376
01377 if (data == NULL) return;
01378 struct SyncRootStruct *root = data->root;
01379 if (root != NULL) {
01380 char *here = "Sync.abortCompare";
01381 struct SyncBaseStruct *base = root->base;
01382 struct SyncRootPrivate *priv = root->priv;
01383 struct SyncHashInfoList *list = priv->remoteSeen;
01384 struct SyncHashInfoList *lag = NULL;
01385 struct ccn_charbuf *hash = data->hashR;
01386 while (list != NULL) {
01387 struct SyncHashInfoList *next = list->next;
01388 struct SyncHashCacheEntry *ce = list->ce;
01389 if (ce != NULL && compareHash(ce->hash, hash) == 0) {
01390
01391
01392 if (base->debug >= CCNL_INFO) {
01393
01394 char *hex = SyncHexStr(hash->buf, hash->length);
01395 ccns_msg(root->base->client_handle,
01396 "%s, root#%u, remove remote hash %s",
01397 here, root->rootId, hex);
01398 free(hex);
01399 }
01400 list->next = NULL;
01401 list->ce = NULL;
01402 if (ce->busy > 0) ce->busy--;
01403 if (lag == NULL) priv->remoteSeen = next;
01404 else lag->next = next;
01405 free(list);
01406 break;
01407 }
01408 lag = list;
01409 list = next;
01410 }
01411 if (root->base->debug >= CCNL_WARNING)
01412 SyncNoteSimple(root, here, why);
01413 }
01414 destroyCompareData(data);
01415 }
01416
01417 static int
01418 comparisonFailed(struct SyncCompareData *data, char *why, int line) {
01419 SyncNoteFailed(data->root, "Sync.CompareAction", why, line);
01420 data->state = SyncCompare_waiting;
01421 return -1;
01422 }
01423
01424 static int
01425 extractBuf(struct ccn_charbuf *cb, struct SyncNodeComposite *nc, struct SyncNodeElem *ne) {
01426 struct ccn_buf_decoder ds;
01427 struct ccn_buf_decoder *d = SyncInitDecoderFromElem(&ds, nc, ne);
01428 ccn_charbuf_reset(cb);
01429 int res = SyncAppendElementInner(cb, d);
01430 return res;
01431 }
01432
01433 static struct SyncHashCacheEntry *
01434 ensureRemoteEntry(struct SyncCompareData *data,
01435 const unsigned char * xp,
01436 ssize_t xs) {
01437 char *here = "Sync.ensureRemoteEntry";
01438 struct SyncRootStruct *root = data->root;
01439 struct SyncHashCacheEntry *ce = SyncHashEnter(root->ch, xp, xs, SyncHashState_remote);
01440 if (ce == NULL) {
01441
01442 SyncNoteFailed(root, here, "bad enter", __LINE__);
01443 return ce;
01444 }
01445 if (ce->state & SyncHashState_local) setCovered(ce);
01446 return ce;
01447 }
01448
01449 static struct SyncHashCacheEntry *
01450 cacheEntryForElem(struct SyncCompareData *data,
01451 struct SyncNodeComposite *nc,
01452 struct SyncNodeElem *ne,
01453 int remote) {
01454 char *here = "Sync.cacheEntryForElem";
01455 struct SyncRootStruct *root = data->root;
01456 struct ccn_buf_decoder ds;
01457 struct ccn_buf_decoder *d = SyncInitDecoderFromOffset(&ds, nc,
01458 ne->start,
01459 ne->stop);
01460 const unsigned char * xp = NULL;
01461 ssize_t xs = 0;
01462 SyncGetHashPtr(d, &xp, &xs);
01463 if (xs == 0 || xp == NULL) {
01464
01465 SyncNoteFailed(root, here, "no hash", __LINE__);
01466 return NULL;
01467 }
01468 struct SyncHashCacheEntry *ce = NULL;
01469 if (remote > 0) {
01470
01471 ce = ensureRemoteEntry(data, xp, xs);
01472 } else {
01473
01474 ce = SyncHashLookup(root->ch, xp, xs);
01475 if (SyncCacheEntryFetch(ce) < 0) {
01476 SyncNoteFailed(root, here, "bad fetch", __LINE__);
01477 return NULL;
01478 }
01479 }
01480 if (ce == NULL) {
01481
01482 SyncNoteFailed(root, here, "bad lookup", __LINE__);
01483 return ce;
01484 }
01485 ce->lastUsed = data->lastEnter;
01486 return ce;
01487 }
01488
01489 static void
01490 kickCompare(struct SyncCompareData *scd, struct SyncActionData *action) {
01491
01492
01493 if (scd != NULL && scd->ev == NULL) {
01494 struct ccn_scheduled_event *ev = ccn_schedule_event(scd->root->base->sched,
01495 2000,
01496 CompareAction,
01497 scd,
01498 0);
01499 scd->ev = ev;
01500 }
01501 }
01502
01503
01504
01505
01506 extern enum ccn_upcall_res
01507 SyncRemoteFetchResponse(struct ccn_closure *selfp,
01508 enum ccn_upcall_kind kind,
01509 struct ccn_upcall_info *info) {
01510 static char *here = "Sync.SyncRemoteFetchResponse";
01511 struct SyncActionData *data = selfp->data;
01512 enum ccn_upcall_res ret = CCN_UPCALL_RESULT_OK;
01513 switch (kind) {
01514 case CCN_UPCALL_FINAL:
01515 selfp->data = destroyActionData(data);
01516 free(selfp);
01517 break;
01518 case CCN_UPCALL_CONTENT_UNVERIFIED:
01519
01520
01521 #if (CCN_API_VERSION >= 4004)
01522 case CCN_UPCALL_CONTENT_RAW:
01523 case CCN_UPCALL_CONTENT_KEYMISSING:
01524 #endif
01525 case CCN_UPCALL_INTEREST_TIMED_OUT:
01526 case CCN_UPCALL_CONTENT: {
01527 if (data == NULL) break;
01528 struct ccnr_handle *ccnr = data->client_handle;
01529 struct SyncRootStruct *root = data->root;
01530 struct SyncCompareData *comp = data->comp;
01531 if (root == NULL) break;
01532 int debug = root->base->debug;
01533 struct SyncRootStats *stats = root->priv->stats;
01534 size_t bytes = 0;
01535 int64_t now = SyncCurrentTime();
01536 if (ccnr != NULL && info != NULL && info->pco != NULL
01537 && kind != CCN_UPCALL_INTEREST_TIMED_OUT)
01538 bytes = info->pco->offset[CCN_PCO_E];
01539 if (debug >= CCNL_INFO) {
01540 char temp[64];
01541 char *ns = "node";
01542 char *ks = "ok";
01543 if (data->kind == SRI_Kind_Content) ns = "content";
01544 if (kind == CCN_UPCALL_INTEREST_TIMED_OUT) ks = "timeout!";
01545 int64_t dt = SyncDeltaTime(data->startTime, now);
01546 dt = (dt + 500) / 1000;
01547 if (bytes > 0)
01548 snprintf(temp, sizeof(temp),
01549 "%s, %s, %d.%03d secs, %u bytes",
01550 ns, ks, (int) (dt / 1000), (int) (dt % 1000),
01551 (unsigned) bytes);
01552 else
01553 snprintf(temp, sizeof(temp),
01554 "%s, %s, %d.%03d secs",
01555 ns, ks, (int) (dt / 1000), (int) (dt % 1000));
01556 SyncNoteUri(root, here, temp, data->prefix);
01557 }
01558
01559 switch (data->kind) {
01560 case SRI_Kind_NodeFetch: {
01561
01562 const unsigned char *xp = data->hash->buf;
01563 ssize_t xs = data->hash->length;
01564 char *hex = SyncHexStr(xp, xs);
01565 struct SyncHashCacheEntry *ce = SyncHashLookup(root->ch, xp, xs);
01566 if (bytes <= 0) {
01567
01568 } else if (ce != NULL && (isCovered(ce) || ce->ncR != NULL)) {
01569
01570
01571 if (debug >= CCNL_FINE) {
01572 SyncNoteSimple2(root, here, "remote node covered", hex);
01573 }
01574 } else {
01575
01576 struct SyncNodeComposite *ncR = extractNode(root, info);
01577 if (ncR == NULL) {
01578
01579 if (debug >= CCNL_SEVERE)
01580 SyncNoteSimple2(root, here, "extractNode failed", hex);
01581 bytes = 0;
01582 } else {
01583
01584 ce = SyncHashEnter(root->ch, xp, xs, SyncHashState_remote);
01585 ce->ncR = ncR;
01586 SyncNodeIncRC(ncR);
01587
01588 if (ce->ncL == NULL) {
01589 ce->ncL = ncR;
01590 SyncNodeIncRC(ncR);
01591 }
01592
01593 if (debug >= CCNL_INFO) {
01594 SyncNoteSimple2(root, here, "remote node entered", hex);
01595 }
01596 if (comp == NULL) {
01597 if (debug >= CCNL_ERROR)
01598 SyncNoteSimple(root, here, "remote node comp == NULL");
01599 }
01600 }
01601 }
01602 if (comp != NULL && comp->nodeFetchBusy > 0)
01603 comp->nodeFetchBusy--;
01604 if (bytes > 0) {
01605
01606 stats->nodeFetchReceived++;
01607 stats->nodeFetchBytes += bytes;
01608 if (comp != NULL)
01609 comp->lastFetchOK = now;
01610 } else {
01611
01612 if (kind == CCN_UPCALL_INTEREST_TIMED_OUT)
01613 stats->nodeFetchTimeout++;
01614 else stats->nodeFetchFailed++;
01615 if (comp != NULL) {
01616
01617 if (!moveActionData(data, SyncActionState_error))
01618 SyncNoteFailed(root, here, "moveActionData", __LINE__);
01619 comp->nodeFetchFailed++;
01620 selfp->data = NULL;
01621 }
01622 }
01623 if (ce != NULL && (ce->state & SyncHashState_fetching))
01624
01625 ce->state -= SyncHashState_fetching;
01626 kickCompare(comp, data);
01627 free(hex);
01628 break;
01629 }
01630 default:
01631
01632 ret = CCN_UPCALL_RESULT_ERR;
01633 break;
01634 }
01635 break;
01636 }
01637 default:
01638
01639 ret = CCN_UPCALL_RESULT_ERR;
01640 break;
01641 }
01642 return ret;
01643 }
01644
01645 extern int
01646 SyncStartNodeFetch(struct SyncRootStruct *root,
01647 struct SyncHashCacheEntry *ce,
01648 struct SyncCompareData *comp) {
01649 static char *here = "Sync.SyncStartNodeFetch";
01650 enum SyncRegisterActionKind kind = SRI_Kind_NodeFetch;
01651 struct SyncBaseStruct *base = root->base;
01652 int debug = base->debug;
01653 struct ccn *ccn = base->ccn;
01654 if (ccn == NULL)
01655 return SyncNoteFailed(root, here, "bad ccn handle", __LINE__);
01656
01657 struct ccn_charbuf *hash = ce->hash;
01658 struct SyncActionData *data = root->actions;
01659 if (ce->state & SyncHashState_fetching)
01660
01661 return 0;
01662 while (data != NULL) {
01663 if (data->kind == kind && compareHash(data->hash, hash) == 0)
01664 return 0;
01665 data = data->next;
01666 }
01667
01668 struct ccn_closure *action = calloc(1, sizeof(*action));
01669 data = newActionData(kind);
01670 struct ccn_charbuf *name = constructCommandPrefix(root, kind);
01671 int res = -1;
01672 char *why = "constructCommandPrefix";
01673 if (name != NULL) {
01674 data->skipToHash = SyncComponentCount(name);
01675 ccn_name_append(name, hash->buf, hash->length);
01676 data->prefix = name;
01677 data->hash = ccn_charbuf_create();
01678 ccn_charbuf_append_charbuf(data->hash, hash);
01679 data->comp = comp;
01680 action->data = data;
01681 action->p = &SyncRemoteFetchResponse;
01682
01683 struct ccn_charbuf *template = SyncGenInterest(NULL,
01684 1,
01685 base->priv->fetchLifetime,
01686 -1, 1, NULL);
01687 res = ccn_express_interest(ccn, name, action, template);
01688 if (res < 0) {
01689 why = "ccn_express_interest";
01690 if (debug >= CCNL_SEVERE) {
01691 char *hex = SyncHexStr(hash->buf, hash->length);
01692 SyncNoteSimple2(root, here, "failed to express interest", hex);
01693 free(hex);
01694 }
01695 } else {
01696 root->priv->stats->nodeFetchSent++;
01697 if (debug >= CCNL_INFO) {
01698 char *hex = SyncHexStr(hash->buf, hash->length);
01699 SyncNoteSimple2(root, here, "fetching", hex);
01700 free(hex);
01701 }
01702 }
01703 ccn_charbuf_destroy(&template);
01704 }
01705 if (res >= 0) {
01706
01707 linkActionData(root, data);
01708 comp->nodeFetchBusy++;
01709 ce->state |= SyncHashState_fetching;
01710 res = 1;
01711 } else {
01712
01713 comp->nodeFetchFailed++;
01714 data = destroyActionData(data);
01715 free(action);
01716 if (debug >= CCNL_SEVERE)
01717 SyncNoteFailed(root, here, why, __LINE__);
01718 }
01719 return res;
01720 }
01721
01722
01723
01724
01725
01726
01727
01728 static int
01729 doPreload(struct SyncCompareData *data, struct SyncTreeWorkerHead *twHead) {
01730 struct SyncRootStruct *root = data->root;
01731 int busyLim = root->base->priv->maxFetchBusy;
01732 for (;;) {
01733 if (data->nodeFetchBusy > busyLim) return 0;
01734 if (twHead->level <= 0) break;
01735 struct SyncTreeWorkerEntry *ent = SyncTreeWorkerTop(twHead);
01736 if (ent->cacheEntry == NULL)
01737 return -1;
01738 struct SyncHashCacheEntry *ceR = ent->cacheEntry;
01739 if (ceR == NULL
01740 || ceR->state & SyncHashState_fetching
01741 || ceR->state & SyncHashState_covered
01742 || ceR->state & SyncHashState_local) {
01743
01744 } else if (ceR->ncR != NULL) {
01745
01746 struct SyncNodeComposite *ncR = ceR->ncR;
01747 int lim = ncR->refLen;
01748 while (ent->pos < lim) {
01749 struct SyncNodeElem *ep = &ncR->refs[ent->pos];
01750 if ((ep->kind & SyncElemKind_leaf) == 0)
01751 break;
01752 ent->pos++;
01753 }
01754 if (ent->pos < lim) {
01755 struct SyncNodeElem *ep = &ncR->refs[ent->pos];
01756 struct SyncHashCacheEntry *sub = cacheEntryForElem(data, ncR, ep, 1);
01757 if (sub == NULL)
01758 return -1;
01759 ent = SyncTreeWorkerPush(twHead);
01760 if (ent == NULL)
01761 return -1;
01762 continue;
01763 }
01764 } else {
01765
01766 SyncStartNodeFetch(root, ceR, data);
01767 }
01768
01769 ent = SyncTreeWorkerPop(twHead);
01770 if (ent != NULL) ent->pos++;
01771 }
01772 while (data->nodeFetchBusy < busyLim) {
01773
01774 struct SyncActionData *sad = data->errList;
01775 if (sad == NULL) break;
01776 struct SyncHashCacheEntry *ceR = SyncHashLookup(root->ch,
01777 sad->hash->buf,
01778 sad->hash->length);
01779 SyncStartNodeFetch(root, ceR, data);
01780 destroyActionData(sad);
01781 }
01782
01783 if (data->nodeFetchBusy > 0) return 0;
01784 if (data->errList != NULL) return 0;
01785 if (twHead->level > 0) return 0;
01786 return 1;
01787 }
01788
01789 static int
01790 addNameFromCompare(struct SyncCompareData *data) {
01791 char *here = "Sync.addNameFromCompare";
01792 struct SyncRootStruct *root = data->root;
01793 struct ccns_handle *ccns = (struct ccns_handle *)root->base->client_handle;
01794 int debug = root->base->debug;
01795 struct ccn_charbuf *name = data->cbR;
01796 int res;
01797
01798 struct SyncTreeWorkerEntry *tweR = SyncTreeWorkerTop(data->twR);
01799 tweR->pos++;
01800 tweR->count++;
01801 data->namesAdded++;
01802 res = ccns->callback(ccns, root->currentHash, data->hashR, name);
01803 if (debug >= CCNL_FINE) {
01804 SyncNoteUri(root, here, "added", name);
01805 }
01806 return 0;
01807 }
01808
01809
01810
01811
01812
01813
01814
01815
01816
01817
01818
01819
01820 static int
01821 doComparison(struct SyncCompareData *data) {
01822 struct SyncRootStruct *root = data->root;
01823 struct SyncTreeWorkerHead *twL = data->twL;
01824 struct SyncTreeWorkerHead *twR = data->twR;
01825
01826 for (;;) {
01827 struct SyncTreeWorkerEntry *tweR = SyncTreeWorkerTop(twR);
01828 if (tweR == NULL) {
01829
01830 return 1;
01831 }
01832 struct SyncHashCacheEntry *ceR = tweR->cacheEntry;
01833 if (ceR == NULL)
01834 return comparisonFailed(data, "bad cache entry for R", __LINE__);
01835 ceR->lastUsed = data->lastEnter;
01836 if (tweR->pos == 0 && isCovered(ceR)) {
01837
01838 size_t c = tweR->count;
01839 tweR = SyncTreeWorkerPop(twR);
01840 if (tweR != NULL) {
01841 tweR->pos++;
01842 tweR->count += c;
01843 }
01844 continue;
01845 }
01846 struct SyncNodeComposite *ncR = ceR->ncR;
01847 if (ncR == NULL) {
01848
01849 int nf = SyncStartNodeFetch(root, ceR, data);
01850 if (nf == 0) {
01851
01852
01853 return comparisonFailed(data, "node fetch duplicate?", __LINE__);
01854 } else if (nf > 0) {
01855
01856 } else {
01857
01858 return comparisonFailed(data, "bad node fetch for R", __LINE__);
01859 }
01860 return 0;
01861 }
01862 if (tweR->pos >= ncR->refLen) {
01863
01864
01865 size_t c = tweR->count;
01866 if (c == 0) {
01867
01868 setCovered(ceR);
01869 }
01870 tweR = SyncTreeWorkerPop(twR);
01871 if (tweR != NULL) {
01872 tweR->pos++;
01873 tweR->count += c;
01874 }
01875 continue;
01876 }
01877 struct SyncNodeElem *neR = SyncTreeWorkerGetElem(twR);
01878 if (neR == NULL)
01879 return comparisonFailed(data, "bad element for R", __LINE__);
01880
01881 if (extractBuf(data->cbR, ncR, neR) < 0)
01882
01883 return comparisonFailed(data, "bad extract for R", __LINE__);
01884
01885 struct SyncTreeWorkerEntry *tweL = SyncTreeWorkerTop(twL);
01886 if (tweL == NULL) {
01887
01888 if (neR->kind == SyncElemKind_node) {
01889
01890 struct SyncHashCacheEntry *subR = cacheEntryForElem(data, ncR, neR, 1);
01891 if (subR == NULL || SyncTreeWorkerPush(twR) == NULL)
01892 return comparisonFailed(data, "bad cache entry for R", __LINE__);
01893 } else {
01894
01895 addNameFromCompare(data);
01896 }
01897 } else {
01898 struct SyncHashCacheEntry *ceL = tweL->cacheEntry;
01899
01900 struct SyncNodeComposite *ncL = ceL->ncL;
01901 if (ncL == NULL) {
01902
01903 int nf = SyncStartNodeFetch(root, ceL, data);
01904 if (nf == 0) {
01905
01906
01907 return comparisonFailed(data, "node fetch duplicate?", __LINE__);
01908 } else if (nf > 0) {
01909
01910 } else {
01911
01912 return comparisonFailed(data, "bad node fetch for R", __LINE__);
01913 }
01914 return 0;
01915 }
01916
01917 ceL->lastUsed = data->lastEnter;
01918 if (tweL->pos >= ncL->refLen) {
01919
01920 tweL = SyncTreeWorkerPop(twL);
01921 if (tweL != NULL) tweL->pos++;
01922 continue;
01923 }
01924 struct SyncNodeElem *neL = SyncTreeWorkerGetElem(twL);
01925 if (neL == NULL || extractBuf(data->cbL, ncL, neL) < 0) {
01926
01927 return comparisonFailed(data, "bad extract for L", __LINE__);
01928 }
01929 if (neR->kind == SyncElemKind_node) {
01930
01931 struct SyncHashCacheEntry *subR = cacheEntryForElem(data, ncR, neR, 1);
01932 if (subR == NULL)
01933 return comparisonFailed(data, "bad element for R", __LINE__);
01934 if (isCovered(subR)) {
01935
01936
01937 tweR->pos++;
01938 continue;
01939 }
01940 if (subR->ncR == NULL) {
01941
01942
01943 if (SyncTreeWorkerPush(twR) == NULL)
01944 return comparisonFailed(data, "bad push for R", __LINE__);
01945 continue;
01946 }
01947
01948 if (neL->kind == SyncElemKind_leaf) {
01949
01950 enum SyncCompareResult scr = SyncNodeCompareMinMax(subR->ncR, data->cbL);
01951 switch (scr) {
01952 case SCR_before:
01953
01954 tweL->pos++;
01955 break;
01956 case SCR_max:
01957
01958 tweL->pos++;
01959 tweR->pos++;
01960 break;
01961 default:
01962
01963 if (SyncTreeWorkerPush(twR) == NULL)
01964 return comparisonFailed(data, "bad push for R", __LINE__);
01965 break;
01966 }
01967
01968 } else {
01969
01970 struct SyncHashCacheEntry *subL = cacheEntryForElem(data, ncL, neL, 1);
01971 if (subL == NULL || subL->ncL == NULL)
01972 return comparisonFailed(data, "bad cache entry for L", __LINE__);
01973
01974 struct SyncNodeComposite *ncL = subL->ncL;
01975 struct SyncNodeComposite *ncR = subR->ncR;
01976 int cmp = SyncCmpNames(ncR->minName, ncL->maxName);
01977 if (cmp > 0) {
01978
01979 tweL->pos++;
01980 } else {
01981
01982 if (SyncTreeWorkerPush(twL) == NULL)
01983 return comparisonFailed(data, "bad push for L", __LINE__);
01984 if (SyncTreeWorkerPush(twR) == NULL)
01985 return comparisonFailed(data, "bad push for R", __LINE__);
01986 }
01987 }
01988 } else {
01989
01990 if (neL->kind == SyncElemKind_leaf) {
01991
01992 int cmp = SyncCmpNames(data->cbL, data->cbR);
01993 if (cmp == 0) {
01994
01995 tweL->pos++;
01996 tweR->pos++;
01997 } else if (cmp < 0) {
01998
01999 tweL->pos++;
02000 } else {
02001
02002 addNameFromCompare(data);
02003 }
02004 } else {
02005
02006 struct SyncHashCacheEntry *subL = cacheEntryForElem(data, ncL, neL, 1);
02007 if (subL == NULL || subL->ncL == NULL)
02008 return comparisonFailed(data, "bad cache entry for L", __LINE__);
02009 enum SyncCompareResult scr = SyncNodeCompareMinMax(subL->ncL, data->cbR);
02010 switch (scr) {
02011 case SCR_before:
02012
02013 addNameFromCompare(data);
02014 break;
02015 case SCR_max:
02016
02017 tweL->pos++;
02018 tweR->pos++;
02019 break;
02020 case SCR_min:
02021
02022 tweR->pos++;
02023 break;
02024 case SCR_after:
02025
02026 tweL->pos++;
02027 break;
02028 case SCR_inside:
02029
02030 if (SyncTreeWorkerPush(twL) == NULL)
02031 return comparisonFailed(data, "bad push for L", __LINE__);
02032 break;
02033 default:
02034
02035 return comparisonFailed(data, "bad min/max compare", __LINE__);
02036 }
02037
02038 }
02039 }
02040 }
02041 }
02042 }
02043
02044 static int
02045 CompareAction(struct ccn_schedule *sched,
02046 void *clienth,
02047 struct ccn_scheduled_event *ev,
02048 int flags) {
02049 char *here = "Sync.CompareAction";
02050 struct SyncCompareData *data = (struct SyncCompareData *) ev->evdata;
02051 int res;
02052
02053 if (data == NULL || data->root == NULL) {
02054
02055 return -1;
02056 }
02057 data->lastEnter = SyncCurrentTime();
02058 struct SyncRootStruct *root = data->root;
02059 struct ccns_handle *ccns = (struct ccns_handle *)root->base->client_handle;
02060 int debug = root->base->debug;
02061 if (data->ev != ev || flags & CCN_SCHEDULE_CANCEL) {
02062
02063 if (debug >= CCNL_FINE)
02064 SyncNoteSimple(root, here, "orphan?");
02065 data->ev = NULL;
02066 return -1;
02067 }
02068
02069 int delay = 2000;
02070 switch (data->state) {
02071 case SyncCompare_init:
02072
02073 if (debug >= CCNL_FINE)
02074 SyncNoteSimple(root, here, "init");
02075 data->state = SyncCompare_preload;
02076 case SyncCompare_preload:
02077
02078 if (debug >= CCNL_FINE)
02079 SyncNoteSimple(root, here, "preload");
02080
02081 struct SyncHashCacheEntry *ceL = SyncHashLookup(root->ch,
02082 data->hashL->buf,
02083 data->hashL->length);
02084 if (ceL != NULL) {
02085 SyncTreeWorkerInit(data->twL, ceL, 1);
02086 res = doPreload(data, data->twL);
02087 if (res < 0) {
02088 abortCompare(data, "doPreloadL failed");
02089 return -1;
02090 }
02091 if (res == 0) {
02092
02093 if (data->nodeFetchBusy > 0) {
02094
02095 data->ev = NULL;
02096 delay = -1;
02097 }
02098 break;
02099 }
02100
02101 SyncTreeWorkerInit(data->twL, ceL, 1);
02102 }
02103 struct SyncHashCacheEntry *ceR = SyncHashLookup(root->ch,
02104 data->hashR->buf,
02105 data->hashR->length);
02106 SyncTreeWorkerInit(data->twR, ceR, 1);
02107 res = doPreload(data, data->twR);
02108 if (res < 0) {
02109 abortCompare(data, "doPreloadR failed");
02110 return -1;
02111 }
02112 if (res == 0) {
02113
02114 if (data->nodeFetchBusy > 0) {
02115
02116 data->ev = NULL;
02117 delay = -1;
02118 }
02119 break;
02120 }
02121
02122 SyncTreeWorkerInit(data->twR, ceR, 1);
02123
02124
02125 if (ccns->flags & CCNS_FLAGS_SC) {
02126 ccns->flags &= ~CCNS_FLAGS_SC;
02127 data->state = SyncCompare_done;
02128 delay = 20;
02129 break;
02130 }
02131 data->state = SyncCompare_busy;
02132 case SyncCompare_busy:
02133
02134 if (debug >= CCNL_FINE)
02135 SyncNoteSimple(root, here, "busy");
02136 res = doComparison(data);
02137 if (res < 0) {
02138 abortCompare(data, "doComparison failed");
02139 return -1;
02140 }
02141 if (data->errList != NULL) {
02142
02143 data->state = SyncCompare_preload;
02144 if (debug >= CCNL_WARNING)
02145 SyncNoteSimple(root, here, "retreat one state");
02146 break;
02147 }
02148 if (res == 0)
02149
02150 break;
02151
02152 data->state = SyncCompare_waiting;
02153 case SyncCompare_waiting:
02154 if (debug >= CCNL_FINE)
02155 SyncNoteSimple(root, here, "waiting");
02156 data->state = SyncCompare_done;
02157 case SyncCompare_done: {
02158
02159 struct SyncHashCacheEntry *ce = SyncHashLookup(root->ch,
02160 data->hashR->buf,
02161 data->hashR->length);
02162 ccn_charbuf_reset(root->currentHash);
02163 ccn_charbuf_append_charbuf(root->currentHash, data->hashR);
02164 SyncNodeIncRC(ce->ncR);
02165 if (ce->ncL != NULL)
02166 SyncNodeDecRC(ce->ncL);
02167 ce->ncL = ce->ncR;
02168
02169 int64_t now = SyncCurrentTime();
02170 int64_t mh = SyncDeltaTime(data->lastEnter, now);
02171 int64_t dt = SyncDeltaTime(data->startTime, now);
02172 root->priv->stats->comparesDone++;
02173 root->priv->stats->lastCompareMicros = dt;
02174 if (mh > data->maxHold) data->maxHold = mh;
02175 mh = (mh + 500) / 1000;
02176 dt = (dt + 500) / 1000;
02177
02178 if (debug >= CCNL_INFO) {
02179 int reportStats = 1;
02180 char temp[64];
02181 snprintf(temp, sizeof(temp)-2,
02182 "%d.%03d secs [%d.%03d], %d names added",
02183 (int) (dt / 1000), (int) (dt % 1000),
02184 (int) (mh / 1000), (int) (mh % 1000),
02185 (int) data->namesAdded);
02186 SyncNoteSimple2(root, here, "done", temp);
02187 if (reportStats) {
02188 struct ccn_charbuf *cb = ccn_charbuf_create();
02189
02190 char *str = ccn_charbuf_as_string(cb);
02191 ccns_msg(root->base->client_handle, "%s, %s", here, str);
02192 ccn_charbuf_destroy(&cb);
02193 }
02194 }
02195 destroyCompareData(data);
02196 return -1;
02197 }
02198 default: break;
02199 }
02200 int64_t mh = SyncDeltaTime(data->lastEnter, SyncCurrentTime());
02201 if (mh > data->maxHold) data->maxHold = mh;
02202 return delay;
02203 }
02204
02205 int
02206 SyncStartCompareAction(struct SyncRootStruct *root, struct ccn_charbuf *hashR) {
02207 char *here = "Sync.SyncStartCompareAction";
02208 struct SyncPrivate *priv = root->base->priv;
02209 if (root->compare != NULL
02210 || priv->comparesBusy >= priv->maxComparesBusy)
02211 return 0;
02212
02213 struct ccn_charbuf *hashL = root->currentHash;
02214 struct SyncHashCacheEntry *ceL = NULL;
02215
02216 if (hashL->length > 0) {
02217
02218 ceL = SyncHashLookup(root->ch, hashL->buf, hashL->length);
02219 if (ceL == NULL)
02220 return SyncNoteFailed(root, here, "bad lookup for L", __LINE__);
02221 }
02222 struct SyncHashCacheEntry *ceR = SyncHashEnter(root->ch,
02223 hashR->buf,
02224 hashR->length,
02225 SyncHashState_remote);
02226 if (ceR == NULL)
02227 return SyncNoteFailed(root, here, "bad lookup for R", __LINE__);
02228
02229 int debug = root->base->debug;
02230 struct ccnr_handle *ccnr = root->base->client_handle;
02231 struct SyncCompareData *data = calloc(1, sizeof(*data));
02232 int64_t mark = SyncCurrentTime();
02233 data->startTime = mark;
02234 data->lastEnter = mark;
02235 data->lastMark = mark;
02236 data->lastFetchOK = mark;
02237 data->root = root;
02238 root->compare = data;
02239 root->namesToFetch = SyncFreeNameAccumAndNames(root->namesToFetch);
02240 data->twL = SyncTreeWorkerCreate(root->ch, ceL, 0);
02241 if (ceL != NULL) ceL->lastUsed = mark;
02242 data->twR = SyncTreeWorkerCreate(root->ch, ceR, 1);
02243 ceR->lastUsed = mark;
02244 data->hashL = ccn_charbuf_create();
02245 ccn_charbuf_append_charbuf(data->hashL, hashL);
02246 data->hashR = ccn_charbuf_create();
02247 ccn_charbuf_append_charbuf(data->hashR, hashR);
02248
02249 data->cbL = ccn_charbuf_create();
02250 data->cbR = ccn_charbuf_create();
02251
02252 data->state = SyncCompare_init;
02253 priv->comparesBusy++;
02254
02255 kickCompare(data, NULL);
02256
02257 if (debug >= CCNL_INFO) {
02258 char *hexL = SyncHexStr(hashL->buf, hashL->length);
02259 char *msgL = ((hashL->length > 0) ? hexL : "empty");
02260 char *hexR = SyncHexStr(hashR->buf, hashR->length);
02261 char *msgR = ((hashR->length > 0) ? hexR : "empty");
02262 ccns_msg(ccnr, "%s, root#%u, L %s, R %s",
02263 here, root->rootId, msgL, msgR);
02264 free(hexL);
02265 free(hexR);
02266 }
02267
02268 return 1;
02269 }
02270
02271 static int
02272 HeartbeatAction(struct ccn_schedule *sched,
02273 void *clienth,
02274 struct ccn_scheduled_event *ev,
02275 int flags) {
02276 char *here = "Sync.HeartbeatAction";
02277 struct SyncBaseStruct *base = (struct SyncBaseStruct *) ev->evdata;
02278 if (base == NULL || base->priv == NULL || (flags & CCN_SCHEDULE_CANCEL)) {
02279
02280 return -1;
02281 }
02282
02283 struct SyncPrivate *priv = base->priv;
02284 int64_t now = SyncCurrentTime();
02285 struct SyncRootStruct *root = priv->rootHead;
02286
02287 while (root != NULL) {
02288 struct SyncCompareData *comp = root->compare;
02289 if (comp == NULL) {
02290
02291 struct SyncHashInfoList *x = chooseRemoteHash(root);
02292 if (x != NULL) {
02293 SyncStartCompareAction(root, x->ce->hash);
02294 }
02295 } else {
02296
02297 int64_t dt = SyncDeltaTime(comp->lastMark, now);
02298 if (dt > 15*1000000) {
02299
02300 if (base->debug >= CCNL_WARNING)
02301 SyncNoteSimple(root, here, "compare stalled?");
02302 comp->lastMark = now;
02303 }
02304
02305 dt = SyncDeltaTime(comp->lastFetchOK, now);
02306 if (dt > 20*1000000) {
02307 abortCompare(comp, "no progress");
02308 }
02309 }
02310
02311
02312 root = root->next;
02313 }
02314 return priv->heartbeatMicros;
02315 }
02316 extern enum ccn_upcall_res
02317 SyncInterestArrived(struct ccn_closure *selfp,
02318 enum ccn_upcall_kind kind,
02319 struct ccn_upcall_info *info) {
02320 static char *here = "Sync.SyncInterestArrived";
02321 struct SyncActionData *data = selfp->data;
02322 enum ccn_upcall_res ret = CCN_UPCALL_RESULT_OK;
02323 switch (kind) {
02324 case CCN_UPCALL_FINAL:
02325 data = destroyActionData(data);
02326 free(selfp);
02327 break;
02328 case CCN_UPCALL_INTEREST: {
02329 struct SyncRootStruct *root = data->root;
02330 if (root == NULL) break;
02331 struct SyncRootPrivate *rp = root->priv;
02332 struct SyncBaseStruct *base = root->base;
02333 int debug = base->debug;
02334 int skipToHash = data->skipToHash;
02335 const unsigned char *buf = info->interest_ccnb;
02336 struct ccn_indexbuf *comps = info->interest_comps;
02337 char *hexL = NULL;
02338 char *hexR = NULL;
02339 if ((info->pi->answerfrom & CCN_AOK_NEW) == 0) {
02340
02341 if (debug >= CCNL_INFO)
02342 SyncNoteUri(root, here, "CCN_AOK_NEW = 0", data->prefix);
02343 break;
02344 }
02345 switch (data->kind) {
02346 case SRI_Kind_None:
02347
02348 break;
02349 case SRI_Kind_AdviseInt: {
02350 const unsigned char *bufR = NULL;
02351 size_t lenR = 0;
02352 struct SyncHashCacheEntry *ceR = NULL;
02353 const unsigned char *bufL = root->currentHash->buf;
02354 char *who = "RootAdvise";
02355 size_t lenL = root->currentHash->length;
02356 ccn_name_comp_get(buf, comps, skipToHash, &bufR, &lenR);
02357 if (bufR == NULL || lenR == 0) {
02358 if (data->kind == SRI_Kind_FetchInt) {
02359
02360 if (debug >= CCNL_SEVERE)
02361 SyncNoteSimple2(root, here, who, "failed, no remote hash");
02362 return ret;
02363 }
02364 } else hexR = SyncHexStr(bufR, lenR);
02365
02366 if (debug >= CCNL_INFO) {
02367 if (hexR == NULL)
02368 SyncNoteSimple2(root, here, who, "empty remote hash");
02369 else SyncNoteSimple3(root, here, who, "remote hash", hexR);
02370 }
02371 if (data->kind == SRI_Kind_AdviseInt) {
02372
02373
02374
02375
02376
02377
02378
02379
02380
02381
02382
02383
02384
02385 if (lenR != 0) {
02386 ceR = SyncHashEnter(root->ch, bufR, lenR, SyncHashState_remote);
02387 int64_t lastMark = ceR->lastRemoteFetch;
02388 noteRemoteHash(root, ceR, 1);
02389 rp->adviseNeed = ADVISE_NEED_RESET;
02390
02391 if (lastMark == 0) {
02392
02393 struct SyncActionData *data = SyncFindAction(root, SRI_Kind_RootAdvise);
02394 if (data != NULL) data->kind = SRI_Kind_None;
02395 }
02396 }
02397 rp->stats->rootAdviseSeen++;
02398 } else {
02399 rp->stats->nodeFetchSeen++;
02400 }
02401
02402 if (lenL == 0) {
02403 if (debug >= CCNL_INFO)
02404 SyncNoteSimple2(root, here, who, "ignored (empty local root)");
02405 if (lenR == 0) {
02406
02407 rp->adviseNeed = 0;
02408 } else if (root->namesToAdd->len > 0) {
02409 if (debug >= CCNL_FINE)
02410 SyncNoteSimple2(root, here, who, "new tree needed");
02411 }
02412 break;
02413 }
02414
02415 break;
02416
02417 if (data->kind == SRI_Kind_AdviseInt
02418 && lenR == lenL && memcmp(bufL, bufR, lenR) == 0) {
02419
02420 if (debug >= CCNL_INFO)
02421 SyncNoteSimple2(root, here, who, "ignored (same hash)");
02422
02423 break;
02424 }
02425 break;
02426 }
02427 default:
02428
02429 ret = CCN_UPCALL_RESULT_ERR;
02430 break;
02431 }
02432 if (hexL != NULL) free(hexL);
02433 if (hexR != NULL) free(hexR);
02434 break;
02435 }
02436 default:
02437
02438 ret = CCN_UPCALL_RESULT_ERR;
02439 break;
02440 }
02441 return ret;
02442 }
02443
02444 int
02445 SyncRegisterInterests(struct SyncRootStruct *root) {
02446 char *here = "Sync.SyncRegisterInterests";
02447 struct SyncBaseStruct *base = root->base;
02448 struct ccn *ccn = base->ccn;
02449 struct ccn_charbuf *prefix;
02450 struct ccn_closure *action;
02451 struct SyncActionData *data;
02452
02453 if (ccn == NULL) return -1;
02454 int res = 0;
02455
02456 prefix = constructCommandPrefix(root, SRI_Kind_AdviseInt);
02457 if (prefix == NULL) {
02458 res = SyncNoteFailed(root, here, "bad prefix", __LINE__);
02459 return(res);
02460 }
02461 action = calloc(1, sizeof(*action));
02462 data = newActionData(SRI_Kind_AdviseInt);
02463 data->prefix = prefix;
02464 data->skipToHash = SyncComponentCount(prefix);
02465 action->data = data;
02466 action->p = &SyncInterestArrived;
02467 res |= ccn_set_interest_filter(root->base->ccn, prefix, action);
02468 if (res < 0) {
02469 if (base->debug >= CCNL_SEVERE)
02470 SyncNoteUri(root, here, "ccn_set_interest_filter failed", prefix);
02471 data = destroyActionData(data);
02472 } else {
02473 linkActionData(root, data);
02474 if (base->debug >= CCNL_INFO)
02475 SyncNoteUri(root, here, "RootAdvise", prefix);
02476 }
02477 return(res);
02478 }
02479
02480 int
02481 SyncHandleSlice(struct SyncBaseStruct *base, struct ccn_charbuf *name) {
02482 return(0);
02483 }
02484
02485 int
02486 SyncStartSliceEnum(struct SyncRootStruct *root) {
02487 return(0);
02488 }
02489
02490 int
02491 SyncStartHeartbeat(struct SyncBaseStruct *base) {
02492 return(0);
02493 }
02494
02495
02496
02497
02498
02499 static int
02500 r_sync_lookup(struct ccnr_handle *ccnr,
02501 struct ccn_charbuf *interest,
02502 struct ccn_charbuf *content_ccnb)
02503 {
02504 int ans = -1;
02505 ccns_msg(ccnr, "WARNING: r_sync_lookup should not be called in sync library");
02506 return(ans);
02507 }
02508
02509
02510
02511
02512
02513
02514
02515 static int
02516 r_sync_local_store(struct ccnr_handle *ccnr,
02517 struct ccn_charbuf *content)
02518 {
02519 int ans = -1;
02520 ccns_msg(ccnr, "WARNING: r_sync_local_store should not be called in sync library");
02521 return(ans);
02522 }
02523
02524 static uintmax_t
02525 ccns_accession_encode(struct ccnr_handle *ccnr, ccnr_accession a)
02526 {
02527 return(a);
02528 }
02529
02530 static ccnr_hwm
02531 ccns_hwm_update(struct ccnr_handle *ccnr, ccnr_hwm hwm, ccnr_accession a)
02532 {
02533 return(a <= hwm ? hwm : a);
02534 }
02535 #define extern
02536 #define SYNCLIBRARY
02537 #define ccnr_msg ccns_msg
02538 #define ccnr_hwm_update ccns_hwm_update
02539 #include <sync/IndexSorter.c>
02540 #include <sync/SyncBase.c>
02541 #include <sync/SyncHashCache.c>
02542 #include <sync/SyncNode.c>
02543 #include <sync/SyncRoot.c>
02544 #include <sync/SyncTreeWorker.c>
02545 #include <sync/SyncUtil.c>
02546 #undef extern