extern int SyncTreeMarkReachable(struct SyncTreeWorkerHead *head, int minLevel) { int count = 0; while (head->level > minLevel) { struct SyncTreeWorkerEntry *ent = SyncTreeWorkerTop(head); if (ent == NULL) break; struct SyncHashCacheEntry *ce = ent->cacheEntry; if (ce == NULL) break; ce->state |= SyncHashState_marked; count++; struct SyncNodeComposite *nc = ((head->remote > 0) ? ce->ncR : ce->ncL); if (nc == NULL) break; int lim = nc->refLen; if (ent->pos >= lim) { // done with the current level, go back to the previous level ent = SyncTreeWorkerPop(head); if (ent == NULL) break; ent->pos++; } else { struct SyncNodeElem *ep = &nc->refs[ent->pos]; if (ep->kind & SyncElemKind_leaf) { // a leaf, so skip it ent->pos++; } else { // a node, so push into it ent = SyncTreeWorkerPush(head); if (ent == NULL) break; } } } return count; }
extern enum SyncCompareResult SyncTreeLookupName(struct SyncTreeWorkerHead *head, struct ccn_charbuf *name, int minLevel) { enum SyncCompareResult cr = SCR_inside; while (head->level > minLevel) { struct SyncTreeWorkerEntry *ent = SyncTreeWorkerTop(head); if (ent->cacheEntry == NULL) { // probably a real bug! return SCR_error; } struct SyncHashCacheEntry *ce = ent->cacheEntry; struct SyncNodeComposite *nc = ((head->remote > 0) ? ce->ncR : ce->ncL); if (nc == NULL) { // report desired node as missing return SCR_missing; } int lim = nc->refLen; if (ent->pos >= lim) { // done with the current level, go back to the previous level ent = SyncTreeWorkerPop(head); if (ent == NULL) break; ent->pos++; } else { if (ent->pos == 0) { // need to check the min and max of the current node enum SyncCompareResult cr = SyncNodeCompareMinMax(nc, name); if (cr == SCR_after) { // not in this node at all, so pop out ent->pos = lim; } else if (cr != SCR_inside) return cr; } if (ent->pos < lim) { struct SyncNodeElem *ep = &nc->refs[ent->pos]; if (ep->kind & SyncElemKind_leaf) { // a leaf, so the element name is inline cr = SyncNodeCompareLeaf(nc, ep, name); if (cr != SCR_after) return cr; ent->pos++; } else { // a node, so try this recursively ent = SyncTreeWorkerPush(head); if (ent == NULL) { return SCR_error; } } } } } return SCR_after; }
extern enum SyncCompareResult SyncTreeGenerateNames(struct SyncTreeWorkerHead *head, struct SyncNameAccum *accum, int minLevel) { while (head->level > minLevel) { struct SyncTreeWorkerEntry *ent = SyncTreeWorkerTop(head); if (ent->cacheEntry == NULL) { // probably a real bug! return SCR_error; } struct SyncHashCacheEntry *ce = ent->cacheEntry; struct SyncNodeComposite *nc = ((head->remote > 0) ? ce->ncR : ce->ncL); if (nc == NULL) { // TBD: fetch node if not present return SCR_missing; } int lim = nc->refLen; if (ent->pos >= lim) { // done with the current level, go back to the previous level ent = SyncTreeWorkerPop(head); if (ent == NULL) break; ent->pos++; } else { struct SyncNodeElem *ep = &nc->refs[ent->pos]; if (ep->kind & SyncElemKind_leaf) { // a leaf, so the element name is inline struct ccn_buf_decoder bd; struct ccn_buf_decoder *d = SyncInitDecoderFromOffset(&bd, nc, ep->start, ep->stop); struct ccn_charbuf *cb = ccn_charbuf_create(); int res = SyncAppendElementInner(cb, d); if (res < 0) { // that did not work well ccn_charbuf_destroy(&cb); return SCR_error; } SyncNameAccumAppend(accum, cb, 0); ent->pos++; } else { ent = SyncTreeWorkerPush(head); if (ent == NULL) { return SCR_error; } } } } return SCR_after; }
extern struct SyncNodeElem * SyncTreeWorkerGetElem(struct SyncTreeWorkerHead *head) { struct SyncTreeWorkerEntry *ent = SyncTreeWorkerTop(head); if (ent == NULL) return NULL; struct SyncHashCacheEntry *ce = ent->cacheEntry; if (ce == NULL) return NULL; struct SyncNodeComposite *nc = ((head->remote > 0) ? ce->ncR : ce->ncL); if (nc == NULL) return NULL; int pos = ent->pos; if (pos < 0 || pos >= nc->refLen) return NULL; struct SyncNodeElem *ref = &nc->refs[pos]; return ref; }
int BuildTree(struct SyncUpdateData *ud, struct SyncTreeWorkerHead *tw, struct SyncNameAccum *src) { int res = 0; while (res == 0) { struct SyncTreeWorkerEntry *ent = SyncTreeWorkerTop(tw); if (ent == NULL) break; struct SyncHashCacheEntry *ce = ent->cacheEntry; if (ce == NULL) // no cache entry, so bad news return -__LINE__; struct SyncNodeComposite *nc = CacheEntryFetch(ud, ce); if (nc == NULL) { if (ce->state & SyncHashState_fetching) // can't process this node now, it's being fetched return 0; return -__LINE__; } struct ccn_charbuf *name = BestName(ud); enum SyncCompareResult scr = SyncNodeCompareMinMax(nc, name); switch (scr) { case SCR_before: // name < Min(L), so add name, advance names UpdateAddName(ud, name); AdvanceName(ud); break; case SCR_min: // name == Min(L), advance names AdvanceName(ud); break; case SCR_max: // R == Max(L), discard R, advance both ent->pos++; AdvanceName(ud); break; case SCR_after: // R > Max(L), advance L AcceptNode(ud); break; case SCR_inside: // Min(L) < R < Max(L), so dive into L if (SyncTreeWorkerPush(tw) == NULL) return - __LINE__; break; default: // this is really broken return -__LINE__; } } }
extern struct SyncTreeWorkerEntry * SyncTreeWorkerPush(struct SyncTreeWorkerHead *head) { struct SyncNodeElem *ref = SyncTreeWorkerGetElem(head); if (ref == NULL || (ref->kind & SyncElemKind_leaf)) return NULL; struct SyncTreeWorkerEntry *ent = SyncTreeWorkerTop(head); struct SyncHashCacheEntry *ce = ent->cacheEntry; if (ce == NULL) return NULL; struct SyncNodeComposite *nc = ce->ncL; if (nc == NULL) nc = ce->ncR; if (nc == NULL) return NULL; struct ccn_buf_decoder cbd; struct ccn_buf_decoder *cb = SyncInitDecoderFromOffset(&cbd, nc, ref->start, ref->stop); const unsigned char *xp = NULL; ssize_t xs = 0; SyncGetHashPtr(cb, &xp, &xs); ce = SyncHashLookup(head->cache, xp, xs); if (ce == NULL) // no entry? this is not so good return NULL; struct SyncTreeWorkerEntry *stack = head->stack; int level = head->level; int oLim = head->lim; if (level > oLim) { // something bad has happened return NULL; } if (level == oLim) { // first, expand the stack to get enough room int nLim = oLim + oLim / 2 + 4; struct SyncTreeWorkerEntry *nStack = NEW_STRUCT(nLim, SyncTreeWorkerEntry); memcpy(nStack, stack, level*sizeof(struct SyncTreeWorkerEntry)); free(stack); stack = nStack; head->stack = nStack; head->lim = nLim; } // now we can push the node head->level = level+1; ent = &stack[level]; ent->pos = 0; ent->count = 0; ent->cacheEntry = ce; ce->busy++; head->visits++; return ent; }