SyncActions.c

Go to the documentation of this file.
00001 /**
00002  * @file sync/SyncActions.c
00003  *  
00004  * Part of CCNx Sync.
00005  *
00006  * This library is free software; you can redistribute it and/or modify it
00007  * under the terms of the GNU Lesser General Public License version 2.1
00008  * as published by the Free Software Foundation.
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00012  * Lesser General Public License for more details. You should have received
00013  * a copy of the GNU Lesser General Public License along with this library;
00014  * if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
00015  * Fifth Floor, Boston, MA 02110-1301 USA.
00016  */
00017 
00018 #include <stdlib.h>
00019 #include <string.h>
00020 #include <strings.h>
00021 #include <sys/resource.h>
00022 #include <sys/time.h>
00023 
00024 #include "SyncActions.h"
00025 #include "SyncNode.h"
00026 #include "SyncPrivate.h"
00027 #include "SyncRoot.h"
00028 #include "SyncTreeWorker.h"
00029 #include "SyncUtil.h"
00030 
00031 #include <ccn/ccn.h>
00032 #include <ccn/charbuf.h>
00033 #include <ccn/coding.h>
00034 #include <ccn/indexbuf.h>
00035 #include <ccn/schedule.h>
00036 
00037 #include <ccnr/ccnr_msg.h>
00038 #include <ccnr/ccnr_sync.h>
00039 #include <ccnr/ccnr_private.h>
00040 
00041 #define M 1000000
00042 // various configuration parameters
00043 // TBD: get them from an external source?
00044 static int cachePurgeTrigger = 60;      // cache entry purge, in seconds
00045 static int cacheCleanBatch = 16;        // seconds between cleaning batches
00046 static int cacheCleanDelta = 8;         // cache clean batch size
00047 static int adviseNeedReset = 1;         // reset value for adviseNeed
00048 static int updateStallDelta = 15;       // seconds used to determine stalled update
00049 static int updateNeedDelta = 6;         // seconds for adaptive update
00050 static int shortDelayMicros = 1000;     // short delay for quick reschedule
00051 static int compareAssumeBad = 20;       // secs since last fetch OK to assume compare failed
00052 static int nodeSplitTrigger = 4000;     // in bytes, triggers node split
00053 static int exclusionLimit = 1000;       // in bytes, limits exclusion list size
00054 static int stableTimeTrig = 10;         // trigger for storing stable point (secs)
00055 static int hashSplitTrigger = 17;       // trigger for splitting based on hash (n/255)
00056 static int namesYieldInc = 100;         // number of names to inc between yield tests
00057 static int namesYieldMicros = 20*1000;  // number of micros to use as yield trigger
00058 static char *syncStableSuffix = "SyncStable";
00059 
00060 static int syncScope = 2;
00061 
00062 enum SyncCompareState {
00063     SyncCompare_init,
00064     SyncCompare_preload,
00065     SyncCompare_busy,
00066     SyncCompare_waiting,
00067     SyncCompare_done
00068 };
00069 
00070 struct SyncCompareData {
00071     struct SyncRootStruct *root;    /**< parent root for this comparison */
00072     struct SyncTreeWorkerHead *twL; /**< local tree walker state */
00073     struct SyncTreeWorkerHead *twR; /**< remote tree walker state */
00074     struct ccn_charbuf *hashL;      /**< hash for root of local sync tree */
00075     struct ccn_charbuf *hashR;      /**< hash for root of remote sync tree */
00076     struct ccn_charbuf *cbL;        /**< local tree scratch */
00077     struct ccn_charbuf *cbR;        /**< remote tree scratch */
00078     struct ccn_charbuf *lagL;       /**< local lag name */
00079     int *lagMatch;                  /**< lagging # of matching components */
00080     struct SyncActionData *errList; /**< actions that had errors for this compare */
00081     int errsQueued;                 /**< names added during this comparison */
00082     int namesAdded;                 /**< names added during this comparison */
00083     int nodeFetchBusy;              /**< number of busy remote node fetches */
00084     int nodeFetchFailed;            /**< number of failed remote node fetches */
00085     int contentPos;                 /**< position of next content to fetch */
00086     int contentFetchBusy;           /**< number of busy content fetches */
00087     int contentFetchFailed;         /**< number of failed content fetches */
00088     struct ccn_scheduled_event *ev; /**< progress event */
00089     enum SyncCompareState state;    /**< summary state of comparison */
00090     sync_time lastFetchOK;          /**< time marker for last successul node/content fetch */
00091     sync_time startTime;            /**< time marker for compare data creation */
00092     sync_time lastEnter;            /**< time marker for last compare step entry */
00093     sync_time lastMark;             /**< time marker for stall determination */
00094     int64_t maxHold;                /**< max time thread was held by compare */
00095 };
00096 
00097 enum SyncUpdateState {
00098     SyncUpdate_init,
00099     SyncUpdate_inserted,
00100     SyncUpdate_busy,
00101     SyncUpdate_error,
00102     SyncUpdate_done
00103 };
00104 
00105 struct SyncUpdateData {
00106     struct SyncRootStruct *root;
00107     enum SyncUpdateState state;
00108     struct SyncNameAccum *sort;
00109     struct SyncNodeAccum *nodes;
00110     struct SyncTreeWorkerHead *tw;
00111     struct ccn_charbuf *cb;
00112     IndexSorter_Base ixBase;
00113     IndexSorter_Index ixPos;
00114     int nameLenAccum;
00115     int namesAdded;
00116     int initLen;
00117     sync_time startTime;
00118     sync_time entryTime;
00119     int64_t maxHold;
00120     int preSortCount;
00121     int postSortCount;
00122 };
00123 
00124 
00125 ///////////////////////////////////////////////////////////////////////////
00126 ///// General internal routines
00127 ///////////////////////////////////////////////////////////////////////////
00128 
00129 static struct SyncActionData *
00130 newActionData(enum SyncRegisterActionKind kind) {
00131     struct SyncActionData *data = NEW_STRUCT(1, SyncActionData);
00132     data->startTime = SyncCurrentTime();
00133     data->kind = kind;
00134     data->state = SyncActionState_init;
00135     return data;
00136 }
00137 
00138 static void
00139 linkActionData(struct SyncRootStruct *root, struct SyncActionData *data) {
00140     data->root = root;
00141     data->next = root->actions;
00142     data->ccnr = root->base->ccnr;
00143     data->state = SyncActionState_sent;
00144     root->actions = data;
00145 }
00146 
00147 static void
00148 delinkActionData(struct SyncActionData *data) {
00149     if (data == NULL) return;
00150     if (data->state == SyncActionState_sent) {
00151         // remove from the action chain in the root
00152         struct SyncRootStruct *root = data->root;
00153         if (root == NULL) return;
00154         struct SyncActionData *each = root->actions;
00155         struct SyncActionData *lag = NULL;
00156         data->state = SyncActionState_loose;
00157         while (each != NULL) {
00158             struct SyncActionData *next = each->next;
00159             if (data == each) {
00160                 data->next = NULL;
00161                 if (lag == NULL) root->actions = next;
00162                 else lag->next = next;
00163                 break;
00164             }
00165             lag = each;
00166             each = next;
00167         }
00168     } else {
00169         if (data->state == SyncActionState_error) {
00170             // remove from the errList chain in the comparison
00171             struct SyncCompareData *comp = data->comp;
00172             if (comp == NULL) return;
00173             struct SyncActionData *each = comp->errList;
00174             struct SyncActionData *lag = NULL;
00175             data->state = SyncActionState_loose;
00176             while (each != NULL) {
00177                 struct SyncActionData *next = each->next;
00178                 if (data == each) {
00179                     data->next = NULL;
00180                     if (comp->errsQueued > 0) comp->errsQueued--;
00181                     if (lag == NULL) comp->errList = next;
00182                     else lag->next = next;
00183                     break;
00184                 }
00185                 lag = each;
00186                 each = next;
00187             }
00188         }
00189     }
00190 }
00191 
00192 static int
00193 moveActionData(struct SyncActionData *data, enum SyncActionState dstState) {
00194     // moves the action data to the given state queue
00195     // (must be SyncActionState_sent or SyncActionState_error)
00196     // returns 1 for success, 0 for not possible
00197     if (data == NULL) return 0;
00198     if (dstState == SyncActionState_error && data->state != SyncActionState_sent)
00199         return 0;
00200     if (dstState == SyncActionState_sent && data->state != SyncActionState_error)
00201         return 0;
00202     struct SyncRootStruct *root = data->root;
00203     struct SyncCompareData *comp = data->comp;
00204     if (root == NULL || comp == NULL) return 0;
00205     delinkActionData(data);
00206     if (dstState == SyncActionState_sent) {
00207         data->next = root->actions;
00208         root->actions = data;
00209     } else {
00210         data->next = comp->errList;
00211         comp->errList = data;
00212         comp->errsQueued++;
00213     }
00214     data->state = dstState;
00215     return 1;
00216 }
00217 
00218 static struct SyncActionData *
00219 destroyActionData(struct SyncActionData *data) {
00220     if (data != NULL) {
00221         delinkActionData(data);
00222         // remove any resources
00223         if (data->prefix != NULL)
00224             ccn_charbuf_destroy(&data->prefix);
00225         if (data->hash != NULL)
00226             ccn_charbuf_destroy(&data->hash);
00227         data->next = NULL;
00228         data->root = NULL;
00229         data->comp = NULL;
00230         free(data);
00231     }
00232     return NULL;
00233 }
00234 
00235 static char *
00236 getCmdStr(enum SyncRegisterActionKind kind) {
00237     switch (kind) {
00238         case SRI_Kind_AdviseInt:
00239         case SRI_Kind_RootAdvise:
00240             return "\xC1.S.ra";
00241         case SRI_Kind_FetchInt:
00242         case SRI_Kind_NodeFetch:
00243             return "\xC1.S.nf";
00244         case SRI_Kind_RootStats:
00245             return "\xC1.S.rs";
00246         default:
00247             return NULL;
00248     }
00249 }
00250 
00251 static char *
00252 getKindStr(enum SyncRegisterActionKind kind) {
00253     switch (kind) {
00254         case SRI_Kind_None:
00255             return "None";
00256         case SRI_Kind_AdviseInt:
00257         case SRI_Kind_RootAdvise:
00258             return "RootAdvise";
00259         case SRI_Kind_FetchInt:
00260         case SRI_Kind_NodeFetch:
00261             return "NodeFetch";
00262         case SRI_Kind_RootStats:
00263             return "RootStats";
00264         case SRI_Kind_Content:
00265             return "Content";
00266         default:
00267             return NULL;
00268     }
00269 }
00270 
00271 static void
00272 setCovered(struct SyncHashCacheEntry *ce) {
00273     char *here = "Sync.setCovered";
00274     if (ce->state & SyncHashState_covered) {
00275         // nothing to do, already covered
00276     } else if (ce->state & SyncHashState_remote) {
00277         // only set this bit if a remote hash has been entered
00278         struct SyncRootStruct *root = ce->head->root;
00279         if (root->base->debug >= CCNL_FINER) {
00280             char *hex = SyncHexStr(ce->hash->buf, ce->hash->length);
00281             SyncNoteSimple(root, here, hex);
00282             free(hex);
00283         }
00284         ce->state |= SyncHashState_covered;
00285     }
00286 }
00287 
00288 static int
00289 isCovered(struct SyncHashCacheEntry *ce) {
00290     if (ce->state & SyncHashState_covered) return 1;
00291     if (ce->state & SyncHashState_local) {
00292         setCovered(ce);
00293         return 1;
00294     }
00295     return 0;
00296 }
00297 
00298 static int
00299 compareHash(struct ccn_charbuf *hashX, struct ccn_charbuf *hashY) {
00300     if (hashX == hashY) return 0;
00301     if (hashX == NULL) return -1;
00302     if (hashY == NULL) return 1;
00303     size_t lenX = hashX->length;
00304     size_t lenY = hashY->length;
00305     if (lenX < lenY) return -1;
00306     if (lenX > lenY) return 1;
00307     return memcmp(hashX->buf, hashY->buf, lenX);
00308 }
00309 
00310 // take a list of names and sort them, removing duplicates!
00311 // should leave src empty  
00312 static struct SyncNameAccum *
00313 sortNames(struct SyncRootStruct *root, struct SyncNameAccum *src) {
00314     char *here = "Sync.sortNames";
00315     IndexSorter_Index ixLim = src->len;
00316     IndexSorter_Base ixBase = IndexSorter_New(ixLim, -1);
00317     ixBase->sorter = SyncNameAccumSorter;
00318     ixBase->client = src;
00319     IndexSorter_Index ix = 0;
00320     for (ix = 0; ix < ixLim; ix++) IndexSorter_Add(ixBase, ix);
00321     struct SyncNameAccum *dst = SyncAllocNameAccum(ixLim);
00322     struct ccn_charbuf *lag = NULL;
00323     for (ix = 0; ix < ixLim; ix++) {
00324         IndexSorter_Index j = IndexSorter_Rem(ixBase);
00325         if (j >= ixLim) {
00326             SyncNoteFailed(root, here, "rem failed", __LINE__);
00327             break;
00328         }
00329         struct ccn_charbuf *name = src->ents[j].name;
00330         src->ents[j].name = NULL;
00331         if (name == NULL) {
00332             SyncNoteFailed(root, here, "name == NULL", __LINE__);
00333             break;
00334         }
00335         if (lag == NULL || SyncCmpNames(lag, name) != 0) {
00336             // only append the name if it is not a duplicate
00337             SyncNameAccumAppend(dst, name, src->ents[j].data); // XXXXXX
00338             lag = name;
00339         } else {
00340             // this name needs to be destroyed
00341             ccn_charbuf_destroy(&name);
00342         }
00343     }    
00344     src->len = 0;
00345     IndexSorter_Free(&ixBase);
00346     return dst;
00347 }
00348 
00349 int
00350 reportExclude(struct SyncRootStruct *root, struct ccn_buf_decoder *d) {
00351     char *here = "Sync.reportExclude";
00352     int res = -1;
00353     if (ccn_buf_match_dtag(d, CCN_DTAG_Exclude)) {
00354         res = d->decoder.element_index;
00355         ccn_buf_advance(d);
00356         // optional Any | Bloom not present
00357         while (ccn_buf_match_dtag(d, CCN_DTAG_Component)) {
00358             size_t cs = 0;
00359             const unsigned char *cp = NULL;
00360             ccn_buf_advance(d);
00361             if (ccn_buf_match_blob(d, &cp, &cs)) {
00362                 ccn_buf_advance(d);
00363                 char *hex = SyncHexStr(cp, cs);
00364                 SyncNoteSimple(root, here, hex);
00365                 free(hex);
00366                 ccn_buf_check_close(d);
00367             }
00368         }
00369         ccn_buf_check_close(d);
00370     }
00371     if (d->decoder.state < 0)
00372         res = d->decoder.state;
00373     if (res < 0)
00374         SyncNoteSimple(root, here, "parse failed");
00375     return res;
00376 }
00377 
00378 #define StatsLine(XXX) \
00379 if (stats->XXX) \
00380 pos += snprintf(s+pos, lim-pos, ", %s %ju", #XXX, (uintmax_t) stats->XXX);
00381 
00382 static struct ccn_charbuf *
00383 formatStats(struct SyncRootStruct *root, struct ccn_charbuf *cb) {
00384     struct SyncRootStats *stats = root->priv->stats;
00385     const unsigned char *bufL = root->currentHash->buf;
00386     int lenL = root->currentHash->length;
00387     struct SyncNodeComposite *ncL = NULL;
00388     char s[2000];
00389     int lim = sizeof(s);
00390     int pos = 0;
00391     sync_time now = SyncCurrentTime();
00392     int ru_ok = -1;
00393 #ifdef RUSAGE_SELF
00394     struct rusage ru;
00395     ru_ok = getrusage(RUSAGE_SELF, &ru);
00396 #endif
00397     struct ccn_charbuf *hash = root->currentHash;
00398     struct SyncCompareData *comp = root->compare;
00399     struct SyncUpdateData *update = root->update;
00400     if (lenL > 0) {
00401         struct SyncHashCacheEntry *ceL = SyncHashLookup(root->ch, bufL, lenL);
00402         if (ceL != NULL) {
00403             SyncCacheEntryFetch(ceL);
00404             ncL = ceL->ncL;
00405         }
00406     }
00407     
00408     pos += snprintf(s+pos, lim-pos, "stats for root#%u", root->rootId);
00409     if (hash->length > 0) {
00410         // show the current hash
00411         char *hex = SyncHexStr(hash->buf, hash->length);
00412         pos += snprintf(s+pos, lim-pos, ", currentHash %s", hex);
00413         free(hex);
00414     }
00415     if (comp != NULL) {
00416         struct ccn_charbuf *hashR = comp->hashR;
00417         if (hashR != NULL && hashR->length > 0) {
00418             char *hex = SyncHexStr(hashR->buf, hashR->length);
00419             pos += snprintf(s+pos, lim-pos, ", remoteHash %s", hex);
00420             free(hex);
00421         }
00422         intmax_t dt = SyncDeltaTime(comp->startTime, now);
00423         pos += snprintf(s+pos, lim-pos, ", compareBusy %jd", dt);
00424     }
00425     if (update != NULL) {
00426         intmax_t dt = SyncDeltaTime(update->startTime, now);
00427         pos += snprintf(s+pos, lim-pos, ", updateBusy %jd", dt);
00428     }
00429     
00430     if (root->priv->lastHashChange != 0) {
00431         uintmax_t x = root->priv->lastHashChange;
00432         pos += snprintf(s+pos, lim-pos, ", lastHashChange %ju.%06u",
00433                         x / M, (unsigned) (x % M));
00434     }
00435     
00436     if (root->namesToAdd != NULL) {
00437         intmax_t rem = root->namesToAdd->len;
00438         if (rem > 0)
00439             pos += snprintf(s+pos, lim-pos, ", namesToAdd %jd", rem);
00440     }
00441     if (root->namesToFetch != NULL) {
00442         intmax_t rem = root->namesToFetch->len;
00443         if (comp != NULL) rem = rem - comp->contentPos;
00444         if (rem > 0)
00445             pos += snprintf(s+pos, lim-pos, ", namesToFetch %jd", rem);
00446     }
00447     if (ncL != NULL) {
00448         pos += snprintf(s+pos, lim-pos, ", treeDepth %ju", (uintmax_t) 
00449                         ncL->treeDepth);
00450         pos += snprintf(s+pos, lim-pos, ", treeNames %ju", (uintmax_t) 
00451                         ncL->leafCount);
00452         pos += snprintf(s+pos, lim-pos, ", treeBytes %ju", (uintmax_t) 
00453                         ncL->byteCount + ncL->cb->length);
00454     }
00455     
00456     StatsLine(comparesDone);
00457     StatsLine(lastCompareMicros);
00458     StatsLine(updatesDone);
00459     StatsLine(lastUpdateMicros);
00460     StatsLine(nodesCreated);
00461     StatsLine(nodesShared);
00462     StatsLine(rootAdviseSent);
00463     StatsLine(rootAdviseSeen);
00464     StatsLine(rootAdviseReceived);
00465     StatsLine(rootAdviseTimeout);
00466     StatsLine(rootAdviseFailed);
00467     StatsLine(nodeFetchSent);
00468     StatsLine(nodeFetchSeen);
00469     StatsLine(nodeFetchReceived);
00470     StatsLine(nodeFetchTimeout);
00471     StatsLine(nodeFetchFailed);
00472     StatsLine(nodeFetchBytes);
00473     StatsLine(contentFetchSent);
00474     StatsLine(contentFetchReceived);
00475     StatsLine(contentFetchTimeout);
00476     StatsLine(contentFetchFailed);
00477     StatsLine(contentFetchBytes);
00478     
00479 #ifdef RUSAGE_SELF
00480     if (ru_ok >= 0) {
00481         pos += snprintf(s+pos, lim-pos, ", maxrss %ju",
00482                         (uintmax_t) ru.ru_maxrss);
00483         pos += snprintf(s+pos, lim-pos, ", utime %ju.%06u",
00484                         (uintmax_t) ru.ru_utime.tv_sec,
00485                         (unsigned) ru.ru_utime.tv_usec);
00486         pos += snprintf(s+pos, lim-pos, ", stime %ju.%06u",
00487                         (uintmax_t) ru.ru_stime.tv_sec,
00488                         (unsigned) ru.ru_stime.tv_usec);
00489     }
00490 #endif   
00491     ccn_charbuf_append(cb, s, pos);
00492     return cb;
00493 }
00494 
00495 #undef StatsLine
00496 
00497 static struct SyncNameAccum *
00498 exclusionsFromHashList(struct SyncRootStruct *root, struct SyncHashInfoList *list) {
00499     struct SyncNameAccum *acc = SyncAllocNameAccum(0);
00500     int count = 0;
00501     int limit = exclusionLimit;
00502     
00503     if (root->currentHash->length > 0) {
00504         // if the current hash is not empty, start there
00505         struct ccn_charbuf *hash = root->currentHash;
00506         struct ccn_charbuf *name = ccn_charbuf_create();
00507         count = count + hash->length + 8;
00508         ccn_name_init(name);
00509         ccn_name_append(name, hash->buf, hash->length);
00510         SyncNameAccumAppend(acc, name, 0);
00511     }
00512     
00513     while (list != NULL) {
00514         struct SyncHashCacheEntry *ce = list->ce;
00515         if (ce != NULL && (ce->state & SyncHashState_remote)
00516             && (ce->state & SyncHashState_covered)) {
00517             // any remote root known to be covered is excluded
00518             struct ccn_charbuf *hash = ce->hash;
00519             count = count + hash->length + 8;
00520             if (count > limit)
00521                 // exclusion list is getting too long, so ignore earlier roots
00522                 break;
00523             struct ccn_charbuf *name = ccn_charbuf_create();
00524             ccn_name_init(name);
00525             ccn_name_append(name, hash->buf, hash->length);
00526             SyncNameAccumAppend(acc, name, 0);
00527         }
00528         list = list->next;
00529     }
00530     if (acc->len == 0) {
00531         SyncFreeNameAccum(acc);
00532         return NULL;
00533     }
00534     struct SyncNameAccum *lag = acc;
00535     if (acc->len == 0) {
00536         // empty liust convention is NULL
00537         acc = NULL;
00538     } else {
00539         // exclusion list must be sorted
00540         acc = sortNames(root, acc);
00541     }
00542     SyncFreeNameAccum(lag);
00543     return acc;
00544 }
00545 
00546 static struct ccn_charbuf *
00547 constructCommandPrefix(struct SyncRootStruct *root,
00548                        enum SyncRegisterActionKind kind) {
00549     struct ccn_charbuf *prefix = ccn_charbuf_create();
00550     int res = 0;
00551     ccn_name_init(prefix);
00552     if (root->topoPrefix != NULL && root->topoPrefix->length > 0) {
00553         // the topo (if any) always comes first
00554         res |= SyncAppendAllComponents(prefix, root->topoPrefix);
00555     }
00556     // the command comes after the topo
00557     ccn_name_append_str(prefix, getCmdStr(kind));
00558     res |= ccn_name_append(prefix, root->sliceHash->buf, root->sliceHash->length);
00559     
00560     if (res < 0) {
00561         ccn_charbuf_destroy(&prefix);
00562     }
00563     return prefix;
00564 }
00565 
00566 static struct SyncNodeComposite *
00567 extractNode(struct SyncRootStruct *root, struct ccn_upcall_info *info) {
00568     // first, find the content
00569     char *here = "Sync.extractNode";
00570     const unsigned char *cp = NULL;
00571     size_t cs = 0;
00572     size_t ccnb_size = info->pco->offset[CCN_PCO_E];
00573     const unsigned char *ccnb = info->content_ccnb;
00574     int res = ccn_content_get_value(ccnb, ccnb_size, info->pco,
00575                                     &cp, &cs);
00576     if (res < 0 || cs < DEFAULT_HASH_BYTES) {
00577         SyncNoteFailed(root, here, "ccn_content_get_value", __LINE__);
00578         return NULL;
00579     }
00580     
00581     // second, parse the object
00582     struct SyncNodeComposite *nc = SyncAllocComposite(root->base);
00583     struct ccn_buf_decoder ds;
00584     struct ccn_buf_decoder *d = ccn_buf_decoder_start(&ds, cp, cs);
00585     res |= SyncParseComposite(nc, d);
00586     if (res < 0) {
00587         // failed, so back out of the allocations
00588         SyncNoteFailed(root, here, "bad parse", -res);
00589         SyncFreeComposite(nc);
00590         nc = NULL;
00591     }
00592     return nc;
00593 }
00594 
00595 static int
00596 noteRemoteHash(struct SyncRootStruct *root, struct SyncHashCacheEntry *ce, int add) {
00597     char *here = "Sync.noteRemoteHash";
00598     int debug = root->base->debug;
00599     struct ccnr_handle *ccnr = root->base->ccnr;
00600     struct ccn_charbuf *hash = ce->hash;
00601     int hl = hash->length;
00602     if (hl == 0) return 0;
00603     struct SyncHashInfoList *head = root->priv->remoteSeen;
00604     struct SyncHashInfoList *each = head;
00605     struct SyncHashInfoList *lag = NULL;
00606     sync_time mark = SyncCurrentTime();
00607     ce->lastUsed = mark;
00608     ce->lastRemoteFetch = mark;
00609     if (ce->state & SyncHashState_local)
00610         setCovered(ce);
00611     while (each != NULL) {
00612         if (ce == each->ce) {
00613             if (lag != NULL) {
00614                 // move it to the front
00615                 lag->next = each->next;
00616                 each->next = head;
00617                 root->priv->remoteSeen = each;
00618             }
00619             break;
00620         }
00621         lag = each;
00622         each = each->next;
00623     }
00624     if (each == NULL && add) {
00625         // need a new entry
00626         each = NEW_STRUCT(1, SyncHashInfoList);
00627         each->next = head;
00628         root->priv->remoteSeen = each;
00629     }
00630     if (debug >= CCNL_FINE) {
00631         char *hex = SyncHexStr(hash->buf, hash->length);
00632         char *extra = "";
00633         if (ce->state & SyncHashState_covered) extra = "covered, ";
00634         ccnr_msg(ccnr, "%s, root#%u, %s%s", here, root->rootId, extra, hex);
00635         free(hex);
00636     }
00637     if (each != NULL) {
00638         each->ce = ce;
00639         ce->busy++;
00640         each->lastSeen = mark;
00641     }
00642     return 1;
00643 }
00644 
00645 static struct SyncHashInfoList *
00646 chooseRemoteHash(struct SyncRootStruct *root) {
00647     struct SyncHashInfoList *each = root->priv->remoteSeen;
00648     sync_time now = SyncCurrentTime();
00649     int64_t limit = ((int64_t)root->base->priv->rootAdviseLifetime)*3*M;
00650     struct SyncHashInfoList *lag = NULL;
00651     while (each != NULL) {
00652         struct SyncHashCacheEntry *ce = each->ce;
00653         struct SyncHashInfoList *next = each->next;
00654         if (ce != NULL
00655             && (ce->state & SyncHashState_remote)
00656             && ((ce->state & SyncHashState_covered) == 0)) {
00657             // choose the first entry that is remote and not covered
00658             int64_t dt = SyncDeltaTime(ce->lastUsed, now);
00659             if (dt < limit) return each;
00660             ce = NULL;
00661         }
00662         if (ce == NULL || (ce->state & SyncHashState_covered)) {
00663             // prune this entry
00664             if (lag == NULL) root->priv->remoteSeen = next;
00665             else lag->next = next;
00666             free(each);
00667         } else
00668             lag = each;
00669         each = next;
00670     }
00671     return NULL;
00672 }
00673 
00674 static int
00675 fauxError(struct SyncBaseStruct *base) {
00676     // returns 1 with probability fauxErrorTrigger percent [roughly]
00677     if (base != NULL && base->priv->fauxErrorTrigger > 0) {
00678         int fet = base->priv->fauxErrorTrigger;
00679         if (fet > 0) {
00680             int r = random() % 100;
00681             if (r < fet) return 1;
00682         }
00683     }
00684     return 0;
00685 }
00686 
00687 ///////////////////////////////////////////////////////////////////////////
00688 ///// Comparison internal routines
00689 ///////////////////////////////////////////////////////////////////////////
00690 
00691 static void
00692 destroyCompareData(struct SyncCompareData *data) {
00693     if (data == NULL) return;
00694     struct SyncRootStruct *root = data->root;
00695     struct SyncPrivate *priv = root->base->priv;
00696     if (root != NULL) {
00697         while (data->errList != NULL) {
00698             struct SyncActionData *sad = data->errList;
00699             destroyActionData(sad);
00700         }
00701         root->namesToFetch = SyncFreeNameAccumAndNames(root->namesToFetch);
00702         root->compare = NULL;
00703         struct SyncActionData *each = root->actions;
00704         // break the link from the action to the compare
00705         while (each != NULL) {
00706             if (each->comp == data) each->comp = NULL;
00707             each = each->next;
00708         }
00709     }
00710     if (priv->comparesBusy > 0) priv->comparesBusy--;
00711     ccn_charbuf_destroy(&data->hashL);
00712     ccn_charbuf_destroy(&data->hashR);
00713     ccn_charbuf_destroy(&data->cbL);
00714     ccn_charbuf_destroy(&data->cbR);
00715     data->twL = SyncTreeWorkerFree(data->twL);
00716     data->twR = SyncTreeWorkerFree(data->twR);
00717     if (data->ev != NULL && root != NULL) {
00718         data->ev->evdata = NULL;
00719         ccn_schedule_cancel(root->base->sched, data->ev);
00720     }
00721     free(data);
00722 }
00723 
00724 static void
00725 abortCompare(struct SyncCompareData *data, char *why) {
00726     // this compare failed due to a node fetch or content fetch failure
00727     // we could get repeated failures if we try the same remote node,
00728     // so remove it from the seen remote nodes, then destroy the compare data
00729     if (data == NULL) return;
00730     struct SyncRootStruct *root = data->root;
00731     if (root != NULL) {
00732         char *here = "Sync.abortCompare";
00733         struct SyncBaseStruct *base = root->base;
00734         struct SyncRootPrivate *priv = root->priv;
00735         struct SyncHashInfoList *list = priv->remoteSeen;
00736         struct SyncHashInfoList *lag = NULL;
00737         struct ccn_charbuf *hash = data->hashR;
00738         while (list != NULL) {
00739             struct SyncHashInfoList *next = list->next;
00740             struct SyncHashCacheEntry *ce = list->ce;
00741             if (ce != NULL && compareHash(ce->hash, hash) == 0) {
00742                 // found the failed root, so remove the remote entry
00743                 // if we really needed it it will come back via root advise
00744                 if (base->debug >= CCNL_INFO) {
00745                     // maybe this should be a warning?
00746                     char *hex = SyncHexStr(hash->buf, hash->length);
00747                     ccnr_msg(root->base->ccnr,
00748                              "%s, root#%u, remove remote hash %s",
00749                              here, root->rootId, hex);
00750                     free(hex);
00751                 }
00752                 list->next = NULL;
00753                 list->ce = NULL;
00754                 if (ce->busy > 0) ce->busy--;
00755                 if (lag == NULL) priv->remoteSeen = next;
00756                 else lag->next = next;
00757                 free(list);
00758                 break;
00759             }
00760             lag = list;
00761             list = next;
00762         }
00763         if (root->base->debug >= CCNL_WARNING)
00764             SyncNoteSimple(root, here, why);
00765     }
00766     destroyCompareData(data);
00767 }
00768 
00769 static int
00770 extractBuf(struct ccn_charbuf *cb, struct SyncNodeComposite *nc, struct SyncNodeElem *ne) {
00771     struct ccn_buf_decoder ds;
00772     struct ccn_buf_decoder *d = SyncInitDecoderFromElem(&ds, nc, ne);
00773     ccn_charbuf_reset(cb);
00774     int res = SyncAppendElementInner(cb, d);
00775     return res;    
00776 }
00777 
00778 static struct SyncHashCacheEntry *
00779 ensureRemoteEntry(struct SyncCompareData *data,
00780                   const unsigned char * xp,
00781                   ssize_t xs) {
00782     char *here = "Sync.ensureRemoteEntry";
00783     struct SyncRootStruct *root = data->root;
00784     struct SyncHashCacheEntry *ce = SyncHashEnter(root->ch, xp, xs, SyncHashState_remote);
00785     if (ce == NULL) {
00786         // and why did this fail?
00787         SyncNoteFailed(root, here, "bad enter", __LINE__);
00788         return ce;
00789     }
00790     if (ce->state & SyncHashState_local) setCovered(ce);
00791     return ce;
00792 }
00793 
00794 static struct SyncHashCacheEntry *
00795 cacheEntryForElem(struct SyncCompareData *data,
00796                   struct SyncNodeComposite *nc,
00797                   struct SyncNodeElem *ne,
00798                   int remote) {
00799     char *here = "Sync.cacheEntryForElem";
00800     struct SyncRootStruct *root = data->root;
00801     struct ccn_buf_decoder ds;
00802     struct ccn_buf_decoder *d = SyncInitDecoderFromOffset(&ds, nc,
00803                                                           ne->start,
00804                                                           ne->stop);
00805     const unsigned char * xp = NULL;
00806     ssize_t xs = 0;
00807     SyncGetHashPtr(d, &xp, &xs);
00808     if (xs == 0 || xp == NULL) {
00809         // no hash?  this could be a problem
00810         SyncNoteFailed(root, here, "no hash", __LINE__);
00811         return NULL;
00812     }
00813     struct SyncHashCacheEntry *ce = NULL;
00814     if (remote > 0) {
00815         // the entry should be remote
00816         ce = ensureRemoteEntry(data, xp, xs);
00817     } else {
00818         // local entry, fetch it if missing
00819         ce = SyncHashLookup(root->ch, xp, xs);
00820         if (SyncCacheEntryFetch(ce) < 0) {
00821             SyncNoteFailed(root, here, "bad fetch", __LINE__);
00822             return NULL;
00823         }
00824     }
00825     if (ce == NULL) {
00826         // this entry should already exist
00827         SyncNoteFailed(root, here, "bad lookup", __LINE__);
00828         return ce;
00829     }
00830     ce->lastUsed = data->lastEnter;
00831     return ce;
00832 }
00833 
00834 static int
00835 comparisonFailed(struct SyncCompareData *data, char *why, int line) {
00836     SyncNoteFailed(data->root, "Sync.CompareAction", why, line);
00837     data->state = SyncCompare_waiting;
00838     return -1;
00839 }
00840 
00841 static int
00842 addNameFromCompare(struct SyncCompareData *data) {
00843     char *here = "Sync.addNameFromCompare";
00844     struct SyncRootStruct *root = data->root;
00845     int debug = root->base->debug;
00846     struct ccn_charbuf *name = data->cbR;
00847     if (root->namesToFetch == NULL)
00848         root->namesToFetch = SyncAllocNameAccum(0);
00849     SyncNameAccumAppend(root->namesToFetch, SyncCopyName(name), 0);
00850     struct SyncTreeWorkerEntry *tweR = SyncTreeWorkerTop(data->twR);
00851     tweR->pos++;
00852     tweR->count++;
00853     data->namesAdded++;
00854     if (debug >= CCNL_FINE) {
00855         SyncNoteUri(root, here, "added", name);
00856     }
00857     return 0;
00858 }
00859 
00860 /*
00861  * doPreload(data) walks the remote tree, and requests a fetch for every remote
00862  * node that is not covered locally and has not been fetched,
00863  * and is not being fetched.  This allows large trees to be fetched in parallel,
00864  * speeding up the load process.
00865  */
00866 static int
00867 doPreload(struct SyncCompareData *data) {
00868     struct SyncRootStruct *root = data->root;
00869     struct SyncTreeWorkerHead *twR = data->twR;
00870     int busyLim = root->base->priv->maxFetchBusy;
00871     for (;;) {
00872         if (data->nodeFetchBusy > busyLim) return 0;
00873         if (twR->level <= 0) break;
00874         struct SyncTreeWorkerEntry *ent = SyncTreeWorkerTop(twR);
00875         if (ent->cacheEntry == NULL)
00876             return -1;
00877         struct SyncHashCacheEntry *ceR = ent->cacheEntry;
00878         if (ceR == NULL
00879             || ceR->state & SyncHashState_fetching
00880             || ceR->state & SyncHashState_covered
00881             || ceR->state & SyncHashState_local) {
00882             // not a needed node, so pop it
00883         } else if (ceR->ncR != NULL) {
00884             // visit the children
00885             struct SyncNodeComposite *ncR = ceR->ncR;
00886             int lim = ncR->refLen;
00887             while (ent->pos < lim) {
00888                 struct SyncNodeElem *ep = &ncR->refs[ent->pos];
00889                 if ((ep->kind & SyncElemKind_leaf) == 0)
00890                     break;
00891                 ent->pos++;
00892             }
00893             if (ent->pos < lim) {
00894                 struct SyncNodeElem *ep = &ncR->refs[ent->pos];
00895                 struct SyncHashCacheEntry *sub = cacheEntryForElem(data, ncR, ep, 1);
00896                 if (sub == NULL)
00897                     return -1;
00898                 ent = SyncTreeWorkerPush(twR);
00899                 if (ent == NULL)
00900                     return -1;
00901                 continue;
00902             }
00903         } else {
00904             // init the fetch, then pop
00905             SyncStartNodeFetch(root, ceR, data);
00906         }
00907         // common exit to pop and iterate
00908         ent = SyncTreeWorkerPop(twR);
00909         if (ent != NULL) ent->pos++;
00910     }
00911     while (data->nodeFetchBusy < busyLim) {
00912         // restart the failed node fetches (while we can)
00913         struct SyncActionData *sad = data->errList;
00914         if (sad == NULL) break;
00915         struct SyncHashCacheEntry *ceR = SyncHashLookup(root->ch,
00916                                                         sad->hash->buf,
00917                                                         sad->hash->length);
00918         SyncStartNodeFetch(root, ceR, data);
00919         destroyActionData(sad);
00920     }
00921     
00922     if (data->nodeFetchBusy > 0) return 0;
00923     if (data->errList != NULL) return 0;
00924     if (twR->level > 0) return 0;
00925     return 1;
00926 }
00927 
00928 /*
00929  * doComparison(data) is a key routine, because it determines what is
00930  * present in data->twR that is not present in data->twL.  It does so by
00931  * walking the two trees, L and R, in increasing name order.  To gain efficiency
00932  * doComparison avoids examining nodes in R that are already covered, and nodes
00933  * in L that have been bypassed in the walk of R.
00934  *
00935  * Ideally doComparison allows determination of k differences in O(k*log(N))
00936  * steps, where N is the number of names in the union of L and R.  However, if
00937  * the tree structures differ significantly the cost can be as high as O(N).
00938  */
00939 static int
00940 doComparison(struct SyncCompareData *data) {
00941     struct SyncRootStruct *root = data->root;
00942     struct SyncTreeWorkerHead *twL = data->twL;
00943     struct SyncTreeWorkerHead *twR = data->twR;
00944     
00945     for (;;) {
00946         struct SyncTreeWorkerEntry *tweR = SyncTreeWorkerTop(twR);
00947         if (tweR == NULL) {
00948             // the remote is done, so no more names to add
00949             return 1;
00950         }
00951         struct SyncHashCacheEntry *ceR = tweR->cacheEntry;
00952         if (ceR == NULL)
00953             return comparisonFailed(data, "bad cache entry for R", __LINE__);
00954         ceR->lastUsed = data->lastEnter;
00955         if (tweR->pos == 0 && isCovered(ceR)) {
00956             // short cut, nothing in R we don't have
00957             size_t c = tweR->count;
00958             tweR = SyncTreeWorkerPop(twR);
00959             if (tweR != NULL) {
00960                 tweR->pos++;
00961                 tweR->count += c;
00962             }
00963             continue;
00964         }
00965         struct SyncNodeComposite *ncR = ceR->ncR;
00966         if (ncR == NULL) {
00967             // top remote node not present, so go get it
00968             int nf = SyncStartNodeFetch(root, ceR, data);
00969             if (nf == 0) {
00970                 // TBD: duplicate, so ignore the fetch?
00971                 // for now, this is an error!
00972                 return comparisonFailed(data, "node fetch duplicate?", __LINE__);
00973             } else if (nf > 0) {
00974                 // node fetch started OK
00975             } else {
00976                 // node fetch failed to initiate
00977                 return comparisonFailed(data, "bad node fetch for R", __LINE__);
00978             }
00979             return 0;
00980         }
00981         if (tweR->pos >= ncR->refLen) {
00982             // we just went off the end of the current remote node, so pop it
00983             // skip over the processed element if we still have a node
00984             size_t c = tweR->count;
00985             if (c == 0) {
00986                 // nothing was added, so this node must be covered
00987                 setCovered(ceR);
00988             }
00989             tweR = SyncTreeWorkerPop(twR);
00990             if (tweR != NULL) {
00991                 tweR->pos++;
00992                 tweR->count += c;
00993             }
00994             continue;
00995         }
00996         struct SyncNodeElem *neR = SyncTreeWorkerGetElem(twR);
00997         if (neR == NULL)
00998             return comparisonFailed(data, "bad element for R", __LINE__);
00999         
01000         if (extractBuf(data->cbR, ncR, neR) < 0)
01001             // the remote name/hash extract failed
01002             return comparisonFailed(data, "bad extract for R", __LINE__);
01003         
01004         struct SyncTreeWorkerEntry *tweL = SyncTreeWorkerTop(twL);
01005         if (tweL == NULL) {
01006             // L is now empty, so add R
01007             if (neR->kind == SyncElemKind_node) {
01008                 // to add a node R, push into it
01009                 struct SyncHashCacheEntry *subR = cacheEntryForElem(data, ncR, neR, 1);
01010                 if (subR == NULL || SyncTreeWorkerPush(twR) == NULL)
01011                     return comparisonFailed(data, "bad cache entry for R", __LINE__);
01012             } else {
01013                 // R is a leaf
01014                 addNameFromCompare(data);
01015             }
01016         } else {
01017             struct SyncHashCacheEntry *ceL = tweL->cacheEntry;
01018             if (SyncCacheEntryFetch(ceL) < 0)
01019                 return comparisonFailed(data, "bad cache entry for L", __LINE__);
01020             struct SyncNodeComposite *ncL = ceL->ncL;
01021             ceL->lastUsed = data->lastEnter;
01022             if (tweL->pos >= ncL->refLen) {
01023                 // we just went off the end of the current local node, so pop it
01024                 tweL = SyncTreeWorkerPop(twL);
01025                 if (tweL != NULL) tweL->pos++;
01026                 continue;
01027             }
01028             struct SyncNodeElem *neL = SyncTreeWorkerGetElem(twL);
01029             if (neL == NULL || extractBuf(data->cbL, ncL, neL) < 0) {
01030                 // the local name/hash extract failed
01031                 return comparisonFailed(data, "bad extract for L", __LINE__);
01032             }
01033             if (neR->kind == SyncElemKind_node) {
01034                 // quick kill for a remote node?
01035                 struct SyncHashCacheEntry *subR = cacheEntryForElem(data, ncR, neR, 1);
01036                 if (subR == NULL)
01037                     return comparisonFailed(data, "bad element for R", __LINE__);
01038                 if (isCovered(subR)) {
01039                     // nothing to add, this node is already covered
01040                     // note: this works even if the remote node is not present!
01041                     tweR->pos++;
01042                     continue;
01043                 }
01044                 if (subR->ncR == NULL) {
01045                     // there is a remote hash, but no node present,
01046                     // so push into it to force the fetch
01047                     if (SyncTreeWorkerPush(twR) == NULL)
01048                         return comparisonFailed(data, "bad push for R", __LINE__);
01049                     continue;
01050                 }
01051                 
01052                 if (neL->kind == SyncElemKind_leaf) {
01053                     // L is a leaf, R is a node that is present
01054                     enum SyncCompareResult scr = SyncNodeCompareMinMax(subR->ncR, data->cbL);
01055                     switch (scr) {
01056                         case SCR_before:
01057                             // L < Min(R), so advance L
01058                             tweL->pos++;
01059                             break;
01060                         case SCR_max:
01061                             // L == Max(R), advance both
01062                             tweL->pos++;
01063                             tweR->pos++;
01064                             break;
01065                         default:
01066                             // in all other cases, dive into R
01067                             if (SyncTreeWorkerPush(twR) == NULL)
01068                                 return comparisonFailed(data, "bad push for R", __LINE__);
01069                             break;
01070                     }
01071                     
01072                 } else {
01073                     // both L and R are nodes, test for L being present
01074                     struct SyncHashCacheEntry *subL = cacheEntryForElem(data, ncL, neL, 0);
01075                     if (subL == NULL || subL->ncL == NULL)
01076                         return comparisonFailed(data, "bad cache entry for L", __LINE__);
01077                     // both L and R are nodes, and both are present
01078                     struct SyncNodeComposite *ncL = subL->ncL;
01079                     struct SyncNodeComposite *ncR = subR->ncR;
01080                     int cmp = SyncCmpNames(ncR->minName, ncL->maxName);
01081                     if (cmp > 0) {
01082                         // Min(R) > Max(L), so advance L
01083                         tweL->pos++;
01084                     } else {
01085                         // dive into both nodes
01086                         if (SyncTreeWorkerPush(twL) == NULL)
01087                             return comparisonFailed(data, "bad push for L", __LINE__);
01088                         if (SyncTreeWorkerPush(twR) == NULL)
01089                             return comparisonFailed(data, "bad push for R", __LINE__);
01090                     }
01091                 }
01092             } else {
01093                 // R is a leaf
01094                 if (neL->kind == SyncElemKind_leaf) {
01095                     // both L and R are names, so the compare is simple
01096                     int cmp = SyncCmpNames(data->cbL, data->cbR);
01097                     if (cmp == 0) {
01098                         // L == R, so advance both
01099                         tweL->pos++;
01100                         tweR->pos++;
01101                     } else if (cmp < 0) {
01102                         // L < R, advance L 
01103                         tweL->pos++;
01104                     } else {
01105                         // L > R, so add R
01106                         addNameFromCompare(data);
01107                     }
01108                 } else {
01109                     // R is a leaf, but L is a node
01110                     struct SyncHashCacheEntry *subL = cacheEntryForElem(data, ncL, neL, 0);
01111                     if (subL == NULL || subL->ncL == NULL)
01112                         return comparisonFailed(data, "bad cache entry for L", __LINE__);
01113                     enum SyncCompareResult scr = SyncNodeCompareMinMax(subL->ncL, data->cbR);
01114                     switch (scr) {
01115                         case SCR_before:
01116                             // R < Min(L), so add R
01117                             addNameFromCompare(data);
01118                             break;
01119                         case SCR_max:
01120                             // R == Max(L), advance both
01121                             tweL->pos++;
01122                             tweR->pos++;
01123                             break;
01124                         case SCR_min:
01125                             // R == Min(L), advance R
01126                             tweR->pos++;
01127                             break;
01128                         case SCR_after:
01129                             // R > Max(L), advance L
01130                             tweL->pos++;
01131                             break;
01132                         case SCR_inside:
01133                             // Min(L) < R < Max(L), so dive into L
01134                             if (SyncTreeWorkerPush(twL) == NULL)
01135                                 return comparisonFailed(data, "bad push for L", __LINE__);
01136                             break;
01137                         default:
01138                             // this is really broken
01139                             return comparisonFailed(data, "bad min/max compare", __LINE__);
01140                     }
01141                     
01142                 }
01143             }
01144         }
01145     }
01146 }
01147 
01148 static int
01149 fetchStablePoint(struct SyncBaseStruct *base, ccnr_hwm *ptr) {
01150     int res = 0;
01151     struct ccn_charbuf *cb = ccn_charbuf_create();
01152     struct ccn_charbuf *name = SyncCopyName(base->priv->localHostPrefix);
01153     res |= ccn_name_append_str(name, syncStableSuffix);
01154     struct ccn_charbuf *interest = SyncGenInterest(name, 1, 0, -1, 1, NULL);
01155     if (interest == NULL) return -__LINE__;
01156     // TBD: check the signature!
01157     res |= r_sync_lookup(base->ccnr, interest, cb);
01158     if (res >= 0) {
01159         // parse the object
01160         const unsigned char *xp = NULL;
01161         size_t xs = 0;
01162         res |= SyncPointerToContent(cb, NULL, &xp, &xs);
01163         if (res >= 0) {
01164             // extract the value
01165             uintmax_t val = 0;
01166             static char *key = "stable ";
01167             struct ccn_buf_decoder ds;
01168             struct ccn_buf_decoder *d = ccn_buf_decoder_start(&ds, xp, xs);
01169             res = -__LINE__;
01170             if (ccn_buf_match_dtag(d, CCN_DTAG_StringValue)) {
01171                 ccn_buf_advance(d);
01172                 res = -__LINE__;
01173                 if (ccn_buf_match_blob(d, &xp, &xs)) {
01174                     int ks = strlen(key);
01175                     ccn_buf_advance(d);
01176                     res = -__LINE__;
01177                     if (xs > ks && strncmp(key, (char *) xp, ks) == 0) {
01178                         xp = xp + ks;
01179                         for (;;) {
01180                             unsigned char c = *xp;
01181                             if (c < '0' || c > '9') break;
01182                             val = val * 10 + (c - '0');
01183                             xp++;
01184                             res = 0;
01185                         }
01186                         if (ptr != NULL && res == 0)
01187                             *ptr = ccnr_hwm_decode(base->ccnr, val);
01188                     }
01189                 }
01190             }
01191         }
01192     }
01193     
01194     ccn_charbuf_destroy(&cb);
01195     ccn_charbuf_destroy(&name);
01196     ccn_charbuf_destroy(&interest);
01197     return res;
01198 }
01199 
01200 static int
01201 storeStablePoint(struct SyncBaseStruct *base, ccnr_hwm point) {
01202     struct ccn_charbuf *x = ccn_charbuf_create();
01203     struct ccn_charbuf *name = SyncCopyName(base->priv->localHostPrefix);
01204     int res = 0;
01205     char temp[32];
01206     int nc = snprintf(temp, sizeof(temp), "stable %ju",
01207                       ccnr_hwm_encode(base->ccnr, point));
01208     // TBD: find a better encoding & use better tags?
01209     res |= ccnb_append_tagged_blob(x, CCN_DTAG_StringValue, temp, nc);
01210     res |= ccn_name_append_str(name, syncStableSuffix);
01211     res |= ccn_create_version(base->ccn, name, CCN_V_NOW, 0, 0);
01212     res |= ccn_name_append_numeric(name, CCN_MARKER_SEQNUM, 0);
01213     if (res >= 0) {
01214         // sign and store the buffer
01215         // freshness need not be long at all
01216         struct ccn_charbuf *cob = SyncSignBuf(base, x, name,
01217                                               1, CCN_SP_FINAL_BLOCK);
01218         if (cob != NULL) {
01219             res |= r_sync_local_store(base->ccnr, cob);
01220             ccn_charbuf_destroy(&cob);
01221         }
01222     }
01223     ccn_charbuf_destroy(&name);
01224     ccn_charbuf_destroy(&x);
01225     return res;
01226 }
01227 
01228 static int
01229 isRootStableEnough(struct SyncRootStruct *root, ccnr_hwm target) {
01230     if (root->namesToAdd->len == 0) return 1;
01231     return 0;
01232 }
01233 
01234 // purge the nodes associated with cache entries that have not been
01235 // recently used, provided that the nodes are not reachable from the current
01236 // sync tree root
01237 static void
01238 purgeOldEntries(struct SyncRootStruct *root) {
01239     char *here = "Sync.purgeOldEntries";
01240     struct SyncHashCacheHead *ch = root->ch;
01241     struct ccn_charbuf *hashL = root->currentHash;
01242     if (hashL == NULL || hashL->length == 0) return;
01243     struct SyncHashCacheEntry *ceL = SyncHashLookup(ch,
01244                                                     hashL->buf,
01245                                                     hashL->length);
01246     if (ceL == NULL) return;
01247     struct SyncTreeWorkerHead *twL = SyncTreeWorkerCreate(ch, ceL, 0);
01248     sync_time now = SyncCurrentTime();
01249     int64_t trigger = cachePurgeTrigger*M;
01250     SyncHashClearMarks(ch);
01251     SyncTreeMarkReachable(twL, 0);
01252     int hx = 0;
01253     for (hx = 0; hx < ch->mod; hx++) {
01254         struct SyncHashCacheEntry *ce = ch->ents[hx];
01255         while (ce != NULL) {
01256             if ((ce->state & SyncHashState_marked) == 0
01257                 && ce->state & SyncHashState_stored) {
01258                 // stable, but not reachable using current tree
01259                 struct SyncNodeComposite *ncL = ce->ncL;
01260                 if (ncL != NULL) {
01261                     int64_t dt = SyncDeltaTime(ce->lastUsed, now);
01262                     if (dt > trigger) {
01263                         // old enough to know better
01264                         ce->ncL = NULL;
01265                         ncL = SyncNodeDecRC(ncL);
01266                         if (root->base->debug >= CCNL_FINE) {
01267                             char *hex = SyncHexStr(ce->hash->buf, ce->hash->length);
01268                             SyncNoteSimple(root, here, hex);
01269                             free(hex);
01270                         }
01271                     }
01272                 }
01273             }
01274             ce = ce->next;
01275         }
01276     }
01277     SyncTreeWorkerFree(twL);
01278 }
01279 
01280 static int
01281 CompareAction(struct ccn_schedule *sched,
01282               void *clienth,
01283               struct ccn_scheduled_event *ev,
01284               int flags) {
01285     char *here = "Sync.CompareAction";
01286     struct SyncCompareData *data = (struct SyncCompareData *) ev->evdata;
01287     if (data == NULL || data->root == NULL) {
01288         // invalid, not sure how we got here
01289         return -1;
01290     }
01291     data->lastEnter = SyncCurrentTime();
01292     struct SyncRootStruct *root = data->root;
01293     struct ccnr_handle *ccnr = root->base->ccnr;
01294     int debug = root->base->debug;
01295     if (data->ev != ev || flags & CCN_SCHEDULE_CANCEL) {
01296         // orphaned or cancelled
01297         if (debug >= CCNL_FINE)
01298             SyncNoteSimple(root, here, "orphan?");
01299         data->ev = NULL;
01300         return -1;
01301     }
01302     
01303     int delay = shortDelayMicros;
01304     switch (data->state) {
01305         case SyncCompare_init:
01306             // nothing to do, flow into next state
01307             if (debug >= CCNL_FINE)
01308                 SyncNoteSimple(root, here, "init");
01309             data->state = SyncCompare_preload;
01310         case SyncCompare_preload: {
01311             // nothing to do (yet), flow into next state
01312             if (debug >= CCNL_FINE)
01313                 SyncNoteSimple(root, here, "preload");
01314             struct SyncHashCacheEntry *ceR = SyncHashLookup(root->ch,
01315                                                             data->hashR->buf,
01316                                                             data->hashR->length);
01317             SyncTreeWorkerInit(data->twR, ceR, 1);
01318             int res = doPreload(data);
01319             if (res < 0) {
01320                 abortCompare(data, "doPreload failed");
01321                 return -1;
01322             }
01323             if (res == 0) {
01324                 // not yet preloaded
01325                 if (data->nodeFetchBusy > 0) {
01326                     // rely on SyncRemoteFetchResponse to restart us
01327                     data->ev = NULL;
01328                     delay = -1;
01329                 }
01330                 break;
01331             }
01332             // before switch to busy, reset the remote tree walker
01333             SyncTreeWorkerInit(data->twR, ceR, 1);
01334             data->state = SyncCompare_busy;
01335         }
01336         case SyncCompare_busy: {
01337             // come here when we are comparing the trees
01338             if (debug >= CCNL_FINE)
01339                 SyncNoteSimple(root, here, "busy");
01340             int res = doComparison(data);
01341             if (res < 0) {
01342                 abortCompare(data, "doComparison failed");
01343                 return -1;
01344             }
01345             if (data->errList != NULL) {
01346                 // we had a load started during compare, so retreat a state
01347                 data->state = SyncCompare_preload;
01348                 if (debug >= CCNL_WARNING)
01349                     SyncNoteSimple(root, here, "retreat one state");
01350                 break;
01351             }
01352             if (res == 0)
01353                 // comparison not yet complete
01354                 break;
01355             // either full success or failure gets here
01356             data->state = SyncCompare_waiting;
01357         }
01358         case SyncCompare_waiting: {
01359             if (debug >= CCNL_FINE)
01360                 SyncNoteSimple(root, here, "waiting");
01361             struct SyncNameAccum *namesToFetch = root->namesToFetch;
01362             int busyLim = root->base->priv->maxFetchBusy;
01363             int len = ((namesToFetch != NULL) ? namesToFetch->len : 0);
01364             if (debug >= CCNL_FINE) {
01365                 int pos = data->contentPos;
01366                 ccnr_msg(ccnr, "%s, root#%u, pos %d, names %d",
01367                          here, root->rootId, pos, len);
01368             }
01369             while (data->contentFetchBusy < busyLim
01370                    && data->contentPos < len) {
01371                 // initiate the content fetches
01372                 int pos = data->contentPos;
01373                 struct ccn_charbuf *name = namesToFetch->ents[pos].name;
01374                 SyncStartContentFetch(root, name, data);
01375                 data->contentPos = pos + 1;
01376             }
01377             while (data->contentFetchBusy < busyLim) {
01378                 // restart the failed fetches
01379                 struct SyncActionData *sad = data->errList;
01380                 if (sad == NULL) break;
01381                 SyncStartContentFetch(root, sad->prefix, data);
01382                 destroyActionData(sad);
01383             }
01384             if (data->contentFetchBusy > 0) {
01385                 // rely on SyncRemoteFetchResponse to restart us
01386                 data->ev = NULL;
01387                 delay = -1;
01388                 break;
01389             }
01390             data->state = SyncCompare_done;
01391         }
01392         case SyncCompare_done: {
01393             // cleanup
01394             sync_time now = SyncCurrentTime();
01395             int64_t mh = SyncDeltaTime(data->lastEnter, now);
01396             int64_t dt = SyncDeltaTime(data->startTime, now);
01397             root->priv->stats->comparesDone++;
01398             root->priv->stats->lastCompareMicros = dt;
01399             if (mh > data->maxHold) data->maxHold = mh;
01400             mh = (mh + 500) / 1000;
01401             dt = (dt + 500) / 1000;
01402 
01403             if (debug >= CCNL_INFO) {
01404                 int reportStats = root->base->priv->syncActionsPrivate & 4;
01405                 char temp[64];
01406                 snprintf(temp, sizeof(temp)-2,
01407                          "%d.%03d secs [%d.%03d], %d names added",
01408                          (int) (dt / 1000), (int) (dt % 1000),
01409                          (int) (mh / 1000), (int) (mh % 1000),
01410                          (int) data->namesAdded);
01411                 SyncNoteSimple2(root, here, "done", temp);
01412                 if (reportStats) {
01413                     struct ccn_charbuf *cb = ccn_charbuf_create();
01414                     formatStats(root, cb);
01415                     char *str = ccn_charbuf_as_string(cb);
01416                     ccnr_msg(root->base->ccnr, "%s, %s", here, str);
01417                     ccn_charbuf_destroy(&cb);
01418                 }
01419             }
01420             destroyCompareData(data);
01421             return -1;
01422         }
01423         default: break;
01424     }
01425     int64_t mh = SyncDeltaTime(data->lastEnter, SyncCurrentTime());
01426     if (mh > data->maxHold) data->maxHold = mh;
01427     return delay;
01428 }
01429 
01430 static void
01431 kickCompare(struct SyncCompareData *scd, struct SyncActionData *action) {
01432     // we just got content for a particular action
01433     // may need to restart CompareAction
01434     if (scd != NULL && scd->ev == NULL) {
01435         struct ccn_scheduled_event *ev = ccn_schedule_event(scd->root->base->sched,
01436                                                             shortDelayMicros,
01437                                                             CompareAction,
01438                                                             scd,
01439                                                             0);
01440         scd->ev = ev;
01441     }
01442 }
01443 
01444 ///////////////////////////////////////////////////////////////////////////
01445 ///// Tree building internal routines
01446 ///////////////////////////////////////////////////////////////////////////
01447 
01448 static struct SyncHashCacheEntry *
01449 newNodeCommon(struct SyncRootStruct *root,
01450               struct SyncNodeAccum *nodes,
01451               struct SyncNodeComposite *nc) {
01452     // finish building and inserting a local node
01453     char *here = "Sync.newNodeCommon";
01454     int debug = root->base->debug;
01455     struct ccnr_handle *ccnr = root->base->ccnr;
01456     if (nc == NULL || nc->hash == NULL) {
01457         SyncNoteFailed(root, here, "bad node", __LINE__);
01458         return NULL;
01459     }
01460     struct SyncHashCacheHead *ch = root->ch;
01461     struct ccn_charbuf *hash = nc->hash;
01462     struct SyncHashCacheEntry *ce = SyncHashLookup(ch, hash->buf, hash->length);
01463     SyncCacheEntryFetch(ce);
01464     if (ce != NULL && ce->ncL != NULL) {
01465         // and equivalent local node is already in the cache
01466         // so get rid of the new node and return the existing entry
01467         if (debug >= CCNL_FINE) {
01468             char *hex = SyncHexStr(hash->buf, hash->length);
01469             SyncNoteSimple2(root, here, "suppressed duplicate", hex);
01470             free(hex);
01471         }
01472         SyncFreeComposite(nc);
01473         nc = ce->ncL;
01474         root->priv->stats->nodesShared++;
01475     } else {
01476         struct SyncPrivate *priv = root->base->priv;
01477         // must ensure that there is a local cache entry
01478         ce = SyncHashEnter(ch, hash->buf, hash->length, SyncHashState_local);
01479         if (ce == NULL) {
01480             // this should not have happened!
01481             SyncNoteFailed(root, here, "bad enter", __LINE__);
01482             SyncNodeDecRC(nc);
01483             return NULL;
01484         }
01485         ce->ncL = nc;
01486         if (ce->state & SyncHashState_remote)
01487             setCovered(ce);
01488         // queue this cache entry for storing
01489         ce->state |= SyncHashState_storing;
01490         if (priv->storingTail == NULL) {
01491             // storing queue is empty
01492             priv->storingHead = ce;
01493         } else {
01494             // append to the tail
01495             priv->storingTail->storing = ce;
01496         }
01497         priv->storingTail = ce;
01498         priv->nStoring++;
01499         root->priv->stats->nodesCreated++;
01500         if (nc->cb->length >= nodeSplitTrigger) {
01501             // if this happens then our split estimate was wrong!
01502             if (debug >= CCNL_INFO)
01503                 ccnr_msg(ccnr,
01504                          "%s, root#%u, cb->length (%d) >= nodeSplitTrigger (%d)",
01505                          here, root->rootId,
01506                          (int) nc->cb->length, (int) nodeSplitTrigger);
01507         }
01508     }
01509     SyncNodeIncRC(nc);
01510     SyncAccumNode(nodes, nc);
01511     return ce;
01512 }
01513 
01514 static struct SyncHashCacheEntry *
01515 nodeFromNodes(struct SyncRootStruct *root, struct SyncNodeAccum *na) {
01516     char *here = "Sync.nodeFromNodes";
01517     struct SyncHashCacheHead *ch = root->ch;
01518     struct SyncBaseStruct *base = root->base;
01519     struct ccnr_handle *ccnr = base->ccnr;
01520     int debug = base->debug;
01521     int lim = na->len;
01522     if (lim == 0) {
01523         SyncNoteFailed(root, here, "empty", __LINE__);
01524         return NULL;
01525     }
01526     if (lim == 1) {
01527         // just return the singleton node
01528         struct SyncNodeComposite *nc = na->ents[0];
01529         if (nc == NULL || nc->hash == NULL) {
01530             SyncNoteFailed(root, here, "bad node", __LINE__);
01531             return NULL;
01532         }
01533         struct SyncHashCacheEntry *ce = SyncHashLookup(ch,
01534                                                        nc->hash->buf,
01535                                                        nc->hash->length);
01536         if (ce == NULL)
01537             SyncNoteFailed(root, here, "bad lookup", __LINE__);
01538         return ce;
01539     }
01540     
01541     int accLim = nodeSplitTrigger - nodeSplitTrigger/8;
01542     struct SyncNodeAccum *nodes = SyncAllocNodeAccum(0);
01543     struct SyncHashCacheEntry *ce = NULL;
01544     int j = 0;
01545     while (j < lim) {
01546         int maxLen = 0;
01547         int i = j;
01548         struct SyncNodeComposite *nc = SyncAllocComposite(base);
01549         int accLen = nc->cb->length;
01550         // first, loop to find the run length
01551         while (i < lim && accLen < accLim) {
01552             struct SyncNodeComposite *elem = na->ents[i];
01553             i++;
01554             int nodeLen = elem->hash->length + 8;
01555             if (nodeLen > maxLen) maxLen = nodeLen;
01556             accLen = accLen + nodeLen + (maxLen - nodeLen) * 2;
01557         }
01558         
01559         // append the references in the run
01560         while (j < i) {
01561             struct SyncNodeComposite *elem = na->ents[j];
01562             j++;
01563             SyncNodeAddNode(nc, elem);
01564         }
01565         SyncEndComposite(nc); // finish the node
01566         ce = newNodeCommon(root, nodes, nc);
01567     }
01568     // go recursive just in case we need the extra levels
01569     ce = nodeFromNodes(root, nodes);
01570     nodes = SyncFreeNodeAccum(nodes);
01571     if (debug >= CCNL_FINE) {
01572         ccnr_msg(ccnr, "%s, root#%u, %d refs", here, root->rootId, lim);
01573     }
01574     return ce;
01575 }
01576 
01577 extern int
01578 SyncStartSliceEnum(struct SyncRootStruct *root) {
01579     char *here = "Sync.SyncStartSliceEnum";
01580     struct SyncBaseStruct *base = root->base;
01581     if (base->priv->sliceBusy == 0) {
01582         int debug = root->base->debug;
01583         struct ccn_charbuf *name = root->namingPrefix;
01584         struct ccn_charbuf *nin = SyncGenInterest(name,
01585                                                   -1, -1, -1, -1,
01586                                                   NULL);
01587         int res = r_sync_enumerate(base->ccnr, nin);
01588         
01589         ccn_charbuf_destroy(&nin);
01590         if (res > 0) {
01591             if (debug >= CCNL_INFO)
01592                 SyncNoteUri(root, here, "slice enum start", name);
01593             base->priv->sliceBusy = res;
01594             root->priv->sliceBusy = res;
01595             return 1;
01596         } else if (debug >= CCNL_SEVERE) {
01597             SyncNoteUri(root, here, "slice enum failed", name);
01598             return -1;
01599         }
01600     }
01601     return 0;
01602 }
01603 
01604 ///////////////////////////////////////////////////////////////////////////
01605 ///// Main dispatching routine, the heart beat
01606 ///////////////////////////////////////////////////////////////////////////
01607 
01608 static int
01609 HeartbeatAction(struct ccn_schedule *sched,
01610                 void *clienth,
01611                 struct ccn_scheduled_event *ev,
01612                 int flags) {
01613     char *here = "Sync.HeartbeatAction";
01614     struct SyncBaseStruct *base = (struct SyncBaseStruct *) ev->evdata;
01615     if (base == NULL || base->priv == NULL || (flags & CCN_SCHEDULE_CANCEL)) {
01616         // TBD: and why did this happen? (can't report it, though)
01617         return -1;
01618     }
01619     
01620     struct SyncPrivate *priv = base->priv;
01621     if (priv->sliceEnum > 0) {
01622         // we are still busy enumerating the slices, so reschedule
01623         return shortDelayMicros;
01624     }
01625     
01626     // check for first root that needs a slice enumeration
01627     struct SyncRootStruct *root = priv->rootHead;
01628     while (root != NULL) {
01629         if (root->priv->sliceBusy < 0 && priv->sliceBusy == 0) {
01630             // this root needs an enumeration
01631             if (SyncStartSliceEnum(root) < 0)
01632                 return priv->heartbeatMicros;
01633             return shortDelayMicros;
01634         }
01635         root = root->next;
01636     }
01637     sync_time now = SyncCurrentTime();
01638     root = priv->rootHead;
01639     int64_t lifeMicros = ((int64_t) priv->rootAdviseLifetime)*M;
01640     int64_t needMicros = ((int64_t) updateNeedDelta)*M;
01641         
01642     while (root != NULL) {
01643         struct SyncRootPrivate *rp = root->priv;
01644         struct SyncCompareData *comp = root->compare;
01645         if (rp->sliceBusy < 0 && priv->sliceBusy == 0) {
01646             // this root needs an enumeration
01647             if (SyncStartSliceEnum(root) < 0)
01648                 return priv->heartbeatMicros;
01649         } else if (priv->sliceBusy > 0) {
01650             // this root is busy enumerating
01651         } else if (root->update != NULL) {
01652             // update is busy, so don't process this root
01653         } else if (comp == NULL) {
01654             // only run the update when not comparing
01655             size_t addLen = root->namesToAdd->len;
01656             int64_t deltaAdvise = SyncDeltaTime(rp->lastAdvise, now);
01657             int64_t deltaUpdate = SyncDeltaTime(rp->lastUpdate, now);
01658             int64_t needUpdate = needMicros;
01659             if (addLen == rp->prevAddLen)
01660                 // no change recently, so 
01661                 needUpdate = rp->stats->lastUpdateMicros * 2;
01662             if (rp->adviseNeed <= 0 && deltaAdvise > lifeMicros)
01663                 // it's been a while since the last RootAdvise
01664                 rp->adviseNeed = adviseNeedReset;
01665             if (deltaUpdate >= needUpdate) {
01666                 // TBD: determine if this is a good algorithm for adaptive update  
01667                 if (addLen > 0) {
01668                     // need to update the root
01669                     SyncUpdateRoot(root);
01670                 }
01671                 if (root->currentHash->length > 0) {
01672                     struct SyncHashCacheEntry *ce = SyncHashLookup(root->ch,
01673                                                                    root->currentHash->buf,
01674                                                                    root->currentHash->length);
01675                     if (ce != NULL && (ce->state & SyncHashState_local)) {
01676                         if (rp->adviseNeed > 0
01677                             || ce != rp->lastLocalSent) {
01678                             SyncSendRootAdviseInterest(root);
01679                         }
01680                     }
01681                 } else
01682                     // empty hash, so try for a starting response
01683                     SyncSendRootAdviseInterest(root);
01684                 if (root->update == NULL) {
01685                     struct SyncHashInfoList *x = chooseRemoteHash(root);
01686                     if (x != NULL) {
01687                         SyncStartCompareAction(root, x->ce->hash);
01688                     }
01689                 }
01690             }
01691             rp->prevAddLen = root->namesToAdd->len;
01692         } else {
01693             // running a compare, check for stall or excessive time since last fetch
01694             int64_t dt = SyncDeltaTime(comp->lastMark, now);
01695             if (dt > updateStallDelta*M) {
01696                 // periodic stall warning
01697                 if (base->debug >= CCNL_WARNING)
01698                     SyncNoteSimple(root, here, "compare stalled?");
01699                 comp->lastMark = now;
01700             }
01701             // test for fatal stall (based on last fetch time)
01702             dt = SyncDeltaTime(comp->lastFetchOK, now);
01703             if (dt > compareAssumeBad*M) {
01704                 abortCompare(comp, "no progress");
01705             }
01706         }
01707         // TBD: prune eldest remote roots from list
01708         // TBD: prune old remote node entries from cache
01709         root = root->next;
01710     }
01711     int64_t deltaClean = SyncDeltaTime(priv->lastCacheClean, now);
01712     if (priv->useRepoStore && deltaClean >= cacheCleanDelta*M) {
01713         // time to try to clean a batch of cache entries
01714         // TBD: reclaim local nodes when not used for a while?
01715         int cleanRem = cacheCleanBatch;
01716         while (cleanRem > 0) {
01717             struct SyncHashCacheEntry *ce = priv->storingHead;
01718             if (ce == NULL) break;
01719             struct SyncHashCacheEntry *ceN = ce->storing;
01720             SyncCacheEntryStore(ce);
01721             priv->storingHead = ceN;
01722             if (ceN == NULL) priv->storingTail = ceN;
01723             if (priv->nStoring > 0) priv->nStoring--;
01724             root = ce->head->root;
01725             ccnr_hwm chw = ce->stablePoint;
01726             if (ccnr_hwm_compare(base->ccnr, chw, root->priv->stablePoint) > 0) {
01727                 // the node that just got stored had a better stablePoint for the node
01728                 root->priv->stablePoint = chw;
01729                 root->priv->lastStable = now;
01730                 if (ccnr_hwm_compare(base->ccnr, chw, priv->stableTarget) > 0)
01731                     priv->stableTarget = chw;
01732                 if (base->debug >= CCNL_INFO) {
01733                     char temp[64];
01734                     snprintf(temp, sizeof(temp),
01735                              "newly stable at %ju",
01736                              ccnr_hwm_encode(base->ccnr, chw));
01737                     SyncNoteSimple(root, here, temp);
01738                 }
01739             }
01740             cleanRem--;
01741         }
01742         priv->lastCacheClean = now;
01743     }
01744     if (priv->stableEnabled && priv->useRepoStore
01745         && priv->nStoring == 0
01746         && ccnr_hwm_compare(base->ccnr, priv->stableTarget, priv->stableStored) > 0) {
01747         // test for stability
01748         int unstable = 1;
01749         int64_t dt = SyncDeltaTime(priv->lastStable, now);
01750         if (dt > stableTimeTrig*M) {
01751             // worth examining the roots for stability
01752             unstable = 0;
01753             root = priv->rootHead;
01754             while (root != NULL) {
01755                 if (!isRootStableEnough(root, priv->stableTarget)) {
01756                     unstable++;
01757                     break;
01758                 }
01759                 root = root->next;
01760             }
01761         }
01762         if (unstable == 0) {
01763             // can store out the stable target
01764             if (base->debug >= CCNL_INFO) {
01765                 char temp[64];
01766                 snprintf(temp, sizeof(temp),
01767                          "stable target reached at %ju",
01768                          ccnr_hwm_encode(base->ccnr, priv->stableTarget));
01769                 ccnr_msg(base->ccnr, "%s, %s", here, temp);
01770             }
01771             int spRes = storeStablePoint(base, priv->stableTarget);
01772             if (spRes < 0 && base->debug >= CCNL_WARNING) {
01773                 ccnr_msg(base->ccnr, "%s, warning: stable target not stored", here);
01774             }
01775             priv->lastStable = now;
01776             priv->stableStored = priv->stableTarget;
01777         }
01778     }
01779     return priv->heartbeatMicros;
01780 }
01781 
01782 
01783 ///////////////////////////////////////////////////////////////////////////
01784 ///// External routines
01785 ///////////////////////////////////////////////////////////////////////////
01786 
01787 extern int
01788 SyncStartHeartbeat(struct SyncBaseStruct *base) {
01789     static char *here = "Sync.SyncStartHeartbeat";
01790     int res = -1;
01791     if (base != NULL && base->sched != NULL) {
01792         int debug = base->debug;
01793         struct ccnr_handle *ccnr = base->ccnr;
01794         struct SyncPrivate *priv = base->priv;
01795         struct ccn_charbuf *nin = SyncGenInterest(priv->sliceCmdPrefix,
01796                                                   -1, -1, -1, -1,
01797                                                   NULL);
01798         
01799         // once the slices are started we try to restart at the last commit point
01800         // (there may be none for a fresh repo, or if this feature is disabled)
01801         ccnr_hwm commitPoint = CCNR_NULL_HWM;
01802         if (priv->stableEnabled && priv->useRepoStore) {
01803             res = fetchStablePoint(base, &commitPoint);
01804             if (res < 0 && base->debug >= CCNL_WARNING) 
01805                 ccnr_msg(base->ccnr, "%s, no stable recovery point", here);
01806         }
01807         r_sync_notify_after(base->ccnr, commitPoint);
01808 
01809         // at startup we ask for all of the existing slices
01810         res = r_sync_enumerate(ccnr, nin);
01811         ccn_charbuf_destroy(&nin);
01812         if (res > 0) {
01813             priv->sliceEnum = res;
01814             if (debug >= CCNL_INFO)
01815                 ccnr_msg(ccnr, "%s, slice enumerate started, %d", here, res);
01816             res = 0;
01817         } else if (debug >= CCNL_WARNING) {
01818             // it is OK to fail here, since 
01819             ccnr_msg(ccnr, "%s, no slices found", here);
01820         }
01821         
01822         // next we schedule the heartbeat itself
01823         struct ccn_scheduled_event *ev = ccn_schedule_event(base->sched,
01824                                                             priv->heartbeatMicros,
01825                                                             HeartbeatAction,
01826                                                             base,
01827                                                             0);
01828         
01829         res = 0;
01830         if (ev == NULL) {
01831             if (debug >= CCNL_SEVERE)
01832                 ccnr_msg(ccnr, "%s, initial schedule failed!", here);
01833             res = -1;
01834         }
01835     }
01836     return res;
01837 }
01838 
01839 // callback for when an interest gets a response
01840 // used when fetching a remote content object by explicit name
01841 // or when fetching a remote node
01842 extern enum ccn_upcall_res
01843 SyncRemoteFetchResponse(struct ccn_closure *selfp,
01844                         enum ccn_upcall_kind kind,
01845                         struct ccn_upcall_info *info) {
01846     static char *here = "Sync.SyncRemoteFetchResponse";
01847     struct SyncActionData *data = selfp->data;
01848     enum ccn_upcall_res ret = CCN_UPCALL_RESULT_OK;
01849     switch (kind) {
01850         case CCN_UPCALL_FINAL:
01851             selfp->data = destroyActionData(data);
01852             free(selfp);
01853             break;
01854         case CCN_UPCALL_CONTENT_UNVERIFIED:
01855             // TBD: fix this when we can actually verify
01856             // return CCN_UPCALL_RESULT_VERIFY;
01857 #if (CCN_API_VERSION >= 4004)
01858         case CCN_UPCALL_CONTENT_RAW:
01859         case CCN_UPCALL_CONTENT_KEYMISSING:
01860 #endif
01861         case CCN_UPCALL_INTEREST_TIMED_OUT:
01862         case CCN_UPCALL_CONTENT: {
01863             if (data == NULL) break;
01864             struct ccnr_handle *ccnr = data->ccnr;
01865             struct SyncRootStruct *root = data->root;
01866             struct SyncCompareData *comp = data->comp;
01867             if (root == NULL) break;
01868             int debug = root->base->debug;
01869             struct SyncRootStats *stats = root->priv->stats;
01870             size_t bytes = 0;
01871             int faux = fauxError(root->base);
01872             sync_time now = SyncCurrentTime();
01873             if (ccnr != NULL && info != NULL && info->pco != NULL && faux == 0
01874                 && kind != CCN_UPCALL_INTEREST_TIMED_OUT)
01875                 bytes = info->pco->offset[CCN_PCO_E];
01876             if (debug >= CCNL_INFO) {
01877                 char temp[64];
01878                 char *ns = "node";
01879                 char *ks = "ok";
01880                 if (faux) ks = "faux error";
01881                 if (data->kind == SRI_Kind_Content) ns = "content";
01882                 if (kind == CCN_UPCALL_INTEREST_TIMED_OUT) ks = "timeout!";
01883                 int64_t dt = SyncDeltaTime(data->startTime, now);
01884                 dt = (dt + 500) / 1000;
01885                 if (bytes > 0) 
01886                     snprintf(temp, sizeof(temp),
01887                              "%s, %s, %d.%03d secs, %u bytes",
01888                              ns, ks, (int) (dt / 1000), (int) (dt % 1000),
01889                              (unsigned) bytes);
01890                 else
01891                     snprintf(temp, sizeof(temp),
01892                              "%s, %s, %d.%03d secs",
01893                              ns, ks, (int) (dt / 1000), (int) (dt % 1000));
01894                 SyncNoteUri(root, here, temp, data->prefix);
01895             }
01896             
01897             switch (data->kind) {
01898                 case SRI_Kind_Content: {
01899                     if (bytes > 0) {
01900                         // we fetched the content, so store it to the repo
01901                         ret = r_sync_upcall_store(ccnr, CCN_UPCALL_CONTENT, info);
01902                         if (ret < 0) {
01903                             // note this specific failure cause
01904                             bytes = 0;
01905                             if (debug >= CCNL_SEVERE)
01906                                 SyncNoteFailed(root, here, "content store", __LINE__);
01907                         } else {
01908                             // we need to update the tree, too
01909                             if (debug >= CCNL_FINE)
01910                                 SyncNoteSimple(root, here, "content stored");
01911                         }
01912                     }
01913                     if (comp != NULL && comp->contentFetchBusy > 0)
01914                         comp->contentFetchBusy--;
01915                     if (bytes > 0) {
01916                         // content fetch wins
01917                         stats->contentFetchReceived++;
01918                         stats->contentFetchBytes += bytes;
01919                         if (comp != NULL)
01920                             comp->lastFetchOK = now;
01921                     } else {
01922                         // content fetch failed
01923                         if (kind == CCN_UPCALL_INTEREST_TIMED_OUT)
01924                             stats->contentFetchTimeout++;
01925                         stats->contentFetchFailed++;
01926                         if (comp != NULL) {
01927                             // remember that this one failed
01928                             comp->contentFetchFailed++;
01929                             if (!moveActionData(data, SyncActionState_error))
01930                                 SyncNoteFailed(root, here, "moveActionData", __LINE__);
01931                             selfp->data = NULL;
01932                         }
01933                     }
01934                     // wake up CompareAction to handle more content
01935                     kickCompare(comp, data);
01936                     break;
01937                 }
01938                 case SRI_Kind_NodeFetch: {
01939                     // node fetch response
01940                     const unsigned char *xp = data->hash->buf;
01941                     ssize_t xs = data->hash->length;
01942                     char *hex = SyncHexStr(xp, xs);
01943                     struct SyncHashCacheEntry *ce = SyncHashLookup(root->ch, xp, xs);
01944                     if (bytes <= 0) {
01945                         // did not get the node at all
01946                     } else if (ce != NULL && (isCovered(ce) || ce->ncR != NULL)) {
01947                         // there was a race, and we no longer need this
01948                         // for stats, count this as a success
01949                         if (debug >= CCNL_FINE) {
01950                             SyncNoteSimple2(root, here, "remote node covered", hex);
01951                         }
01952                     } else {
01953                         // we actually need the node that arrived
01954                         struct SyncNodeComposite *ncR = extractNode(root, info);
01955                         if (ncR == NULL) {
01956                             // decoding error, so can't use
01957                             if (debug >= CCNL_SEVERE)
01958                                 SyncNoteSimple2(root, here, "extractNode failed", hex);
01959                             bytes = 0;
01960                         } else {
01961                             // the entry can now be completed
01962                             ce = SyncHashEnter(root->ch, xp, xs, SyncHashState_remote);
01963                             ce->ncR = ncR;
01964                             SyncNodeIncRC(ncR);
01965                             if (debug >= CCNL_INFO) {
01966                                 SyncNoteSimple2(root, here, "remote node entered", hex);
01967                             }
01968                             if (comp == NULL) {
01969                                 if (debug >= CCNL_ERROR)
01970                                     SyncNoteSimple(root, here, "remote node comp == NULL");
01971                             }
01972                         }
01973                     }
01974                     if (comp != NULL && comp->nodeFetchBusy > 0)
01975                         comp->nodeFetchBusy--;
01976                     if (bytes > 0) {
01977                         // node fetch wins
01978                         stats->nodeFetchReceived++;
01979                         stats->nodeFetchBytes += bytes;
01980                         if (comp != NULL)
01981                             comp->lastFetchOK = now;
01982                     } else {
01983                         // node fetch fails
01984                         if (kind == CCN_UPCALL_INTEREST_TIMED_OUT)
01985                             stats->nodeFetchTimeout++;
01986                         else stats->nodeFetchFailed++;
01987                         if (comp != NULL) {
01988                             // remember that this one failed
01989                             if (!moveActionData(data, SyncActionState_error))
01990                                 SyncNoteFailed(root, here, "moveActionData", __LINE__);
01991                             comp->nodeFetchFailed++;
01992                             selfp->data = NULL;
01993                         }
01994                     }
01995                     if (ce != NULL && (ce->state & SyncHashState_fetching))
01996                         // we are no longer fetching this node
01997                         ce->state -= SyncHashState_fetching;
01998                     kickCompare(comp, data);
01999                     free(hex);
02000                     break;
02001                 }
02002                 default:
02003                     // SHOULD NOT HAPPEN
02004                     ret = CCN_UPCALL_RESULT_ERR;
02005                     break;
02006             }
02007             break;
02008         }
02009         default:
02010             // SHOULD NOT HAPPEN
02011             ret = CCN_UPCALL_RESULT_ERR;
02012             break;
02013     }
02014     return ret;
02015 }
02016 
02017 extern int
02018 SyncStartNodeFetch(struct SyncRootStruct *root,
02019                    struct SyncHashCacheEntry *ce,
02020                    struct SyncCompareData *comp) {
02021     static char *here = "Sync.SyncStartNodeFetch";
02022     enum SyncRegisterActionKind kind = SRI_Kind_NodeFetch;
02023     struct SyncBaseStruct *base = root->base;
02024     int debug = base->debug;
02025     struct ccn *ccn = base->ccn;
02026     if (ccn == NULL)
02027         return SyncNoteFailed(root, here, "bad ccn handle", __LINE__);
02028     // first, check for existing fetch of same hash
02029     struct ccn_charbuf *hash = ce->hash;
02030     struct SyncActionData *data = root->actions;
02031     if (ce->state & SyncHashState_fetching)
02032         // already busy
02033         return 0;
02034     while (data != NULL) {
02035         if (data->kind == kind && compareHash(data->hash, hash) == 0)
02036             return 0;
02037         data = data->next;
02038     }
02039     
02040     struct ccn_closure *action = NEW_STRUCT(1, ccn_closure);
02041     data = newActionData(kind);
02042     struct ccn_charbuf *name = constructCommandPrefix(root, kind);
02043     int res = -1;
02044     char *why = "constructCommandPrefix";
02045     if (name != NULL) {
02046         data->skipToHash = SyncComponentCount(name);
02047         ccn_name_append(name, hash->buf, hash->length);
02048         data->prefix = name;
02049         data->hash = ccn_charbuf_create();
02050         ccn_charbuf_append_charbuf(data->hash, hash);
02051         data->comp = comp;
02052         action->data = data;
02053         action->p = &SyncRemoteFetchResponse;
02054         
02055         struct ccn_charbuf *template = SyncGenInterest(NULL,
02056                                                        syncScope,
02057                                                        base->priv->fetchLifetime,
02058                                                        -1, 1, NULL);
02059         res = ccn_express_interest(ccn, name, action, template);
02060         if (res < 0) {
02061             why = "ccn_express_interest";
02062             if (debug >= CCNL_SEVERE) {
02063                 char *hex = SyncHexStr(hash->buf, hash->length);
02064                 SyncNoteSimple2(root, here, "failed to express interest", hex);
02065                 free(hex);
02066             }
02067         } else {
02068             root->priv->stats->nodeFetchSent++;
02069             if (debug >= CCNL_INFO) {
02070                 char *hex = SyncHexStr(hash->buf, hash->length);
02071                 SyncNoteSimple2(root, here, "fetching", hex);
02072                 free(hex);
02073             }
02074         }
02075         ccn_charbuf_destroy(&template);
02076     }
02077     if (res >= 0) {
02078         // link the request into the root
02079         linkActionData(root, data);
02080         comp->nodeFetchBusy++;
02081         ce->state |= SyncHashState_fetching;
02082         res = 1;
02083     } else {
02084         // return the storage
02085         comp->nodeFetchFailed++;
02086         data = destroyActionData(data);
02087         free(action);
02088         if (debug >= CCNL_SEVERE)
02089             SyncNoteFailed(root, here, why, __LINE__);
02090     }
02091     return res;
02092 }
02093 
02094 extern int
02095 SyncStartContentFetch(struct SyncRootStruct *root,
02096                       struct ccn_charbuf *name,
02097                       struct SyncCompareData *comp) {
02098     static char *here = "Sync.SyncStartContentFetch";
02099     struct SyncBaseStruct *base = root->base;
02100     int debug = base->debug;
02101     struct ccn *ccn = base->ccn;
02102     if (ccn == NULL || name == NULL)
02103         return SyncNoteFailed(root, here, "bad ccnr handle", __LINE__);
02104     
02105     // first, test to see if the content is already in the repo (yes, it happens)
02106     struct ccn_charbuf *interest = SyncGenInterest(name, 1, 0, 0, -1, NULL); 
02107     int res = r_sync_lookup(base->ccnr, interest, NULL);
02108     ccn_charbuf_destroy(&interest);
02109     
02110     if (res >= 0) {
02111         // this name is already in the Repo, no need to fetch
02112         // (ignore the accession number through this path)
02113         if (debug >= CCNL_INFO)
02114             SyncNoteUri(root, here, "ignored, already present", name);
02115         SyncAddName(root->base, name, 0);
02116         res = 0;
02117     } else {
02118         struct ccn_closure *action = NEW_STRUCT(1, ccn_closure);
02119         struct SyncActionData *data = newActionData(SRI_Kind_Content);
02120         data->prefix = ccn_charbuf_create();
02121         ccn_charbuf_append_charbuf(data->prefix, name);
02122         data->comp = comp;
02123         action->data = data;
02124         action->p = &SyncRemoteFetchResponse;
02125         data->skipToHash = -1;  // no hash here
02126         struct ccn_charbuf *template = SyncGenInterest(NULL,
02127                                                        syncScope,
02128                                                        base->priv->fetchLifetime,
02129                                                        0, -1, NULL);
02130         res = ccn_express_interest(ccn, name, action, template);
02131         ccn_charbuf_destroy(&template);
02132         if (res >= 0) {
02133             // link the request into the root
02134             root->priv->stats->contentFetchSent++;
02135             linkActionData(root, data);
02136             res = 1;
02137             if (debug >= CCNL_INFO)
02138                 SyncNoteUri(root, here, "fetching", name);
02139             comp->contentFetchBusy++;
02140         } else {
02141             // return the storage
02142             if (debug >= CCNL_SEVERE)
02143                 SyncNoteUri(root, here, "failed", name);
02144             data = destroyActionData(data);
02145             free(action);
02146             comp->contentFetchFailed++;
02147         }
02148     }
02149     return res;
02150 }
02151 
02152 static struct SyncActionData *
02153 SyncFindAction(struct SyncRootStruct *root, enum SyncRegisterActionKind kind) {
02154     struct SyncActionData *each = root->actions;
02155     while (each != NULL) {
02156         if (each->kind == kind) return each;
02157         each = each->next;
02158     }
02159     return NULL;
02160 }
02161 
02162 extern int
02163 SyncAddName(struct SyncBaseStruct *base,
02164             struct ccn_charbuf *name,
02165             ccnr_accession item) {
02166     static char *here = "Sync.SyncAddName";
02167     struct SyncPrivate *priv = base->priv;
02168     int debug = base->debug;
02169     struct SyncRootStruct *root = priv->rootHead;
02170     int count = 0;
02171     while (root != NULL) {
02172         if (SyncRootLookupName(root, name) == SyncRootLookupCode_covered) {
02173             // ANY matching root gets an addition
02174             // add the name for later processing
02175             struct ccn_charbuf *prev = NULL;
02176             int pos = root->namesToAdd->len;
02177             if (pos > 0) prev = root->namesToAdd->ents[pos-1].name;
02178             if (prev != NULL && SyncCmpNames(name, prev) == 0) {
02179                 // this is a duplicate, so forget it!
02180                 if (debug >= CCNL_FINE) {
02181                     SyncNoteUri(root, here, "ignore dup", name);
02182                 }
02183             } else {
02184                 // not obviously a duplicate
02185                 uintmax_t itemNum = ccnr_accession_encode(base->ccnr, item);
02186                 SyncNameAccumAppend(root->namesToAdd, SyncCopyName(name), itemNum);
02187                 if (item != CCNR_NULL_ACCESSION)
02188                     root->priv->highWater = ccnr_hwm_update(base->ccnr,
02189                                                             root->priv->highWater,
02190                                                             item);
02191                 count++;
02192                 if (debug >= CCNL_FINE) {
02193                     char temp[64];
02194                     // TBD: improve item reporting?
02195                     if (item >= CCNR_MIN_ACCESSION && item <= CCNR_MAX_ACCESSION) {
02196                         snprintf(temp, sizeof(temp), "added, %ju", itemNum);
02197                     } else {
02198                         snprintf(temp, sizeof(temp), "no accession");
02199                     }
02200                     SyncNoteUri(root, here, temp, name);
02201                 }
02202             }
02203         }
02204         root = root->next;
02205     }
02206     if (item != CCNR_NULL_ACCESSION)
02207         base->highWater = ccnr_hwm_update(base->ccnr, base->highWater, item);
02208     return count;
02209 }
02210 
02211 static int
02212 findAndDeleteRoot(struct SyncBaseStruct *base, char *here,
02213                   const unsigned char *hp, ssize_t hs) {
02214     struct SyncRootStruct *root = base->priv->rootHead;
02215     int debug = base->debug;
02216     while (root != NULL) {
02217         struct ccn_charbuf *sh = root->sliceHash;
02218         if (sh->length == hs && memcmp(sh->buf, hp, hs) == 0) {
02219             // matching an existing root, so delete it
02220             if (debug >= CCNL_INFO) {
02221                 char *hex = SyncHexStr(hp, hs);
02222                 ccnr_msg(base->ccnr,
02223                          "%s, root#%u, deleted, %s",
02224                          here, root->rootId, hex);
02225                 free(hex);
02226             }
02227             // need to remove any pending stores for deleted roots
02228             struct SyncPrivate *priv = base->priv;
02229             struct SyncHashCacheEntry *ce = priv->storingHead;
02230             struct SyncHashCacheEntry *lag = NULL;
02231             while (ce != NULL) {
02232                 struct SyncHashCacheEntry *ceN = ce->storing;
02233                 if (ce->head->root == root) {
02234                     // this root is going away, so delink the pending store
02235                     if (lag == NULL) priv->storingHead = ceN;
02236                     else lag->storing = ceN;
02237                     if (priv->nStoring > 0) priv->nStoring--;
02238                 } else lag = ce;
02239                 if (ceN == NULL) priv->storingTail = lag;
02240                 ce = ceN;
02241             }
02242             SyncRemRoot(root);
02243             return 1;
02244         }
02245         root = root->next;
02246     }
02247     if (debug >= CCNL_FINE) {
02248         char *hex = SyncHexStr(hp, hs);
02249         ccnr_msg(base->ccnr,
02250                  "%s, root not found, %s",
02251                  here, hex);
02252         free(hex);
02253     }
02254     return 0;
02255 }
02256 
02257 extern int
02258 SyncHandleSlice(struct SyncBaseStruct *base, struct ccn_charbuf *name) {
02259     char *here = "Sync.SyncHandleSlice";
02260     char *why = NULL;
02261     struct ccnr_handle *ccnr = base->ccnr;
02262     int debug = base->debug;
02263     const unsigned char *hp = NULL;
02264     ssize_t hs = 0;
02265     int match = SyncPrefixMatch(base->priv->sliceCmdPrefix, name, 0);
02266     if (match < 0) return match;
02267     // the component after the prefix should be the hash
02268     SyncGetComponentPtr(name, match, &hp, &hs);
02269     why = "invalid hash";
02270     if (hs > 0 && hs < MAX_HASH_BYTES) {
02271         // we pass the first smoke test
02272         struct ccn_charbuf *content = ccn_charbuf_create();
02273         struct ccn_charbuf *interest = SyncGenInterest(name, 1, 0, -1, 1, NULL);
02274         int lookupRes = -__LINE__;
02275         if (interest != NULL) {
02276             lookupRes = r_sync_lookup(ccnr, interest, content);
02277             ccn_charbuf_destroy(&interest);
02278         }
02279         why = "bad fetch";
02280         if (lookupRes >= 0 && content->length > 0) {
02281             // we got the content
02282             struct ccn_parsed_ContentObject pcos;
02283             struct ccn_parsed_ContentObject *pco = &pcos;
02284             int parseRes = ccn_parse_ContentObject(content->buf,
02285                                                    content->length,
02286                                                    pco, NULL);
02287             const unsigned char *xp = NULL;
02288             size_t xs = 0;
02289             why = "bad content object";
02290             if (parseRes >= 0) {
02291                 if (pco->type == CCN_CONTENT_GONE) {
02292                     findAndDeleteRoot(base, here, hp, hs);
02293                     ccn_charbuf_destroy(&content);
02294                     return 0;
02295                 } else {
02296                     why = "bad content start";
02297                     parseRes = SyncPointerToContent(content, pco, &xp, &xs);
02298                     if (debug >= CCNL_SEVERE && (xs <= 0 || parseRes < 0)) {
02299                         // we can't get the pointer, so somebody is wrong
02300                         ssize_t start = pco->offset[CCN_PCO_B_Content];
02301                         ssize_t stop = pco->offset[CCN_PCO_E_Content];
02302                         int len = stop-start;
02303                         char *hex = SyncHexStr(content->buf+start, len);
02304                         ccnr_msg(ccnr,
02305                                  "%s, invalid content start, line %d, len %d, %s",
02306                                  here, -parseRes, len, hex);
02307                         free(hex);
02308                     }
02309                 }
02310             }
02311             if (parseRes >= 0) {
02312                 struct SyncRootStruct *root = base->priv->rootHead;
02313                 while (root != NULL) {
02314                     struct ccn_charbuf *sh = root->sliceHash;
02315                     if (sh->length == hs && memcmp(sh->buf, hp, hs) == 0) {
02316                         // we already have this slice (or at least the hash matches)
02317                         // ignore anything else (first arrival wins)
02318                         if (debug >= CCNL_FINE) {
02319                             char *hex = SyncHexStr(hp, hs);
02320                             ccnr_msg(ccnr,
02321                                      "%s, new root ignored for slice %s",
02322                                      here, hex);
02323                             free(hex);
02324                         }
02325                         ccn_charbuf_destroy(&content);
02326                         return 0;
02327                     }
02328                     root = root->next;
02329                 }
02330                 why = "no content tag";
02331                 struct ccn_buf_decoder rds;
02332                 struct ccn_buf_decoder *rd = NULL;
02333                 rd = ccn_buf_decoder_start(&rds, xp, xs);
02334                 root = SyncRootDecodeAndAdd(base, rd);
02335                 why = "slice decode";
02336                 if (root != NULL) {
02337                     struct ccn_charbuf *sh = root->sliceHash;
02338                     if (sh->length == hs && memcmp(sh->buf, hp, hs) == 0) {
02339                         // this slice is new
02340                         if (debug >= CCNL_INFO) {
02341                             char *hex = SyncHexStr(hp, hs);
02342                             SyncNoteSimple2(root, here, "new root for slice", hex);
02343                             free(hex);
02344                         }
02345                         ccn_charbuf_destroy(&content);
02346                         return 1;
02347                     } else {
02348                         // hashes don't match, so whoever wrote the slice is at fault
02349                         // destroy the root, since it may well be bogus
02350                         // (we could have checked earlier, but the end-to-end check is better)
02351                         if (debug >= CCNL_WARNING) {
02352                             char *hexL = SyncHexStr(sh->buf, sh->length);
02353                             char *hexR = SyncHexStr(hp, hs);
02354                             ccnr_msg(ccnr, "%s, failed, hashes not equal, L %s, R %s",
02355                                      here, hexL, hexR);
02356                             free(hexL);
02357                             free(hexR);
02358                         }
02359                         root = SyncRemRoot(root);
02360                         if (root != NULL) {
02361                             // failed to remove the root, this could be nasty
02362                             SyncNoteFailed(root, here, "root not removed", __LINE__);
02363                         }
02364                     }
02365                 }
02366                 
02367             }
02368         }
02369         if (debug >= CCNL_SEVERE)
02370             ccnr_msg(ccnr, "%s, failed! (%s)", here, why);
02371         ccn_charbuf_destroy(&content);
02372     }
02373     return -1;
02374 }
02375 
02376 extern enum ccn_upcall_res
02377 SyncInterestArrived(struct ccn_closure *selfp,
02378                     enum ccn_upcall_kind kind,
02379                     struct ccn_upcall_info *info) {
02380     static char *here = "Sync.SyncInterestArrived";
02381     struct SyncActionData *data = selfp->data;
02382     enum ccn_upcall_res ret = CCN_UPCALL_RESULT_OK;
02383     switch (kind) {
02384         case CCN_UPCALL_FINAL:
02385             data = destroyActionData(data);
02386             free(selfp);
02387             break;
02388         case CCN_UPCALL_INTEREST: {
02389             struct SyncRootStruct *root = data->root;
02390             if (root == NULL) break;
02391             struct SyncRootPrivate *rp = root->priv;
02392             struct SyncBaseStruct *base = root->base;
02393             int debug = base->debug;
02394             int skipToHash = data->skipToHash;
02395             const unsigned char *buf = info->interest_ccnb;
02396             struct ccn_indexbuf *comps = info->interest_comps;
02397             char *hexL = NULL;
02398             char *hexR = NULL;
02399             if ((info->pi->answerfrom & CCN_AOK_NEW) == 0) {
02400                 // TBD: is this the right thing to do?
02401                 if (debug >= CCNL_INFO)
02402                     SyncNoteUri(root, here, "CCN_AOK_NEW = 0", data->prefix);
02403                 break;
02404             }
02405             switch (data->kind) {
02406                 case SRI_Kind_None:
02407                     // not an active request, so ignore
02408                     break;
02409                 case SRI_Kind_RootStats: {
02410                     char *who = getKindStr(data->kind);
02411                     struct ccn_charbuf *name = SyncCopyName(data->prefix);
02412                     ccn_create_version(info->h, name, CCN_V_NOW, 0, 0);
02413                     ccn_name_append_numeric(name, CCN_MARKER_SEQNUM, 0);
02414                     if (debug >= CCNL_FINE)
02415                         SyncNoteUri(root, here, who, name);
02416                     struct ccn_charbuf *cb = ccn_charbuf_create();
02417                     struct timeval tv = {0};
02418                     gettimeofday(&tv, 0);
02419                     char temp[128];
02420                     int pos = snprintf(temp, sizeof(temp),
02421                                        "%ju.%06u: ", 
02422                                        (uintmax_t) tv.tv_sec,
02423                                        (unsigned) tv.tv_usec);
02424                     ccn_charbuf_append(cb, temp, pos);
02425                     formatStats(root, cb);
02426                     struct ccn_charbuf *cob = SyncSignBuf(base, cb, name,
02427                                                           1, CCN_SP_FINAL_BLOCK);
02428                     int res = ccn_put(info->h, cob->buf, cob->length);
02429                     if (res >= 0) {
02430                         // we have success!
02431                         if (debug >= CCNL_INFO)
02432                             SyncNoteUri(root, here, "response sent", name);
02433                     } else {
02434                         if (debug >= CCNL_SEVERE)
02435                             SyncNoteUri(root, here, "response failed", name);
02436                     }
02437                     ccn_charbuf_destroy(&name);
02438                     ccn_charbuf_destroy(&cb);
02439                     ccn_charbuf_destroy(&cob);
02440                     ret = CCN_UPCALL_RESULT_INTEREST_CONSUMED;
02441                     break;
02442                 }
02443                 case SRI_Kind_AdviseInt:
02444                 case SRI_Kind_FetchInt: {
02445                     const unsigned char *bufR = NULL;
02446                     size_t lenR = 0;
02447                     struct SyncHashCacheEntry *ceL = NULL;
02448                     struct SyncHashCacheEntry *ceR = NULL;
02449                     const unsigned char *bufL = root->currentHash->buf;
02450                     char *who = getKindStr(data->kind);
02451                     size_t lenL = root->currentHash->length;
02452                     ccn_name_comp_get(buf, comps, skipToHash, &bufR, &lenR);
02453                     if (bufR == NULL || lenR == 0) {
02454                         if (data->kind == SRI_Kind_FetchInt) {
02455                             // not well-formed, so ignore it
02456                             if (debug >= CCNL_SEVERE)
02457                                 SyncNoteSimple2(root, here, who, "failed, no remote hash");
02458                             return ret;
02459                         }
02460                     } else hexR = SyncHexStr(bufR, lenR);
02461                     
02462                     if (debug >= CCNL_INFO) {
02463                         if (hexR == NULL)
02464                             SyncNoteSimple2(root, here, who, "empty remote hash");
02465                         else SyncNoteSimple3(root, here, who, "remote hash", hexR);
02466                     }
02467                     if (data->kind == SRI_Kind_AdviseInt) {
02468                         // worth noting the remote root
02469                         if (debug >= CCNL_FINER) {
02470                             ssize_t start = info->pi->offset[CCN_PI_B_Exclude];
02471                             ssize_t stop = info->pi->offset[CCN_PI_E_Exclude];
02472                             if (stop > start) {
02473                                 // we appear to have an exclusion
02474                                 struct ccn_buf_decoder ds;
02475                                 struct ccn_buf_decoder *d = &ds;
02476                                 ccn_buf_decoder_start(d, buf+start, stop - start);
02477                                 reportExclude(root, d);
02478                             }
02479                         }
02480                         if (lenR != 0) {
02481                             ceR = SyncHashEnter(root->ch, bufR, lenR, SyncHashState_remote);
02482                             sync_time lastMark = ceR->lastRemoteFetch;
02483                             noteRemoteHash(root, ceR, 1);
02484                             rp->adviseNeed = adviseNeedReset;
02485                             // force any old interest to be inactive
02486                             if (lastMark == 0) {
02487                                 // not entered, so we need to do a RootAdvise
02488                                 struct SyncActionData *data = SyncFindAction(root, SRI_Kind_RootAdvise);
02489                                 if (data != NULL) data->kind = SRI_Kind_None;
02490                             }
02491                         }
02492                         rp->stats->rootAdviseSeen++;
02493                     } else {
02494                         rp->stats->nodeFetchSeen++;
02495                     }
02496                     
02497                     if (lenL == 0) {
02498                         if (debug >= CCNL_INFO)
02499                             SyncNoteSimple2(root, here, who, "ignored (empty local root)");
02500                         if (lenR == 0) {
02501                             // both L and R are empty, so suppress short-term thrashing
02502                             rp->adviseNeed = 0;
02503                         } else if (root->namesToAdd->len > 0) {
02504                             if (debug >= CCNL_FINE)
02505                                 SyncNoteSimple2(root, here, who, "new tree needed");
02506                         }
02507                         break;
02508                     }
02509                     if (data->kind == SRI_Kind_AdviseInt
02510                         && lenR == lenL && memcmp(bufL, bufR, lenR) == 0) {
02511                         // hash given is same as our root hash, so ignore the request
02512                         if (debug >= CCNL_INFO)
02513                             SyncNoteSimple2(root, here, who, "ignored (same hash)");
02514                         purgeOldEntries(root);
02515                         break;
02516                     }
02517                     
02518                     long fresh = base->priv->rootAdviseFresh;
02519                     // excessive freshness may be a problem when there is an A-B-C
02520                     // routing, and a node shows up in B's cache that mentions
02521                     // subnodes that C cannot reach
02522                     // TBD: come up with a better solution!
02523                     
02524                     hexL = SyncHexStr(bufL, lenL);
02525                     
02526                     rp->adviseNeed = adviseNeedReset;
02527                     
02528                     // we need to respond with our local root node
02529                     
02530                     if (data->kind == SRI_Kind_AdviseInt) {
02531                         // get the entry for the local root node
02532                         // should expire fairly quickly
02533                         ceL = SyncHashLookup(root->ch, bufL, lenL);
02534                         if (debug >= CCNL_INFO) {
02535                             SyncNoteSimple3(root, here, who, "local hash", hexL);
02536                         }
02537                     } else {
02538                         // get the entry for the requested local tree node
02539                         ceL = SyncHashLookup(root->ch, bufR, lenR);
02540                     }
02541                     // test for local root node being present
02542                     if (SyncCacheEntryFetch(ceL) < 0) {
02543                         // requested local node is probably not ours
02544                         if (debug >= CCNL_FINE) {
02545                             SyncNoteSimple3(root, here, who, "no local node", hexL);
02546                         }
02547                         break;
02548                     }
02549                     struct SyncNodeComposite *ncL = ceL->ncL;
02550                     
02551                     // root advise: name is prefix + hashIn + hashOut
02552                     // node fetch: name is prefix + hashIn
02553                     // empty hashes are OK, but must be encoded
02554                     struct ccn_charbuf *name = SyncCopyName(data->prefix);
02555                     ccn_name_append(name, bufR, lenR);
02556                     if (data->kind == SRI_Kind_AdviseInt)
02557                         // respond with the current local hash
02558                         ccn_name_append(name, bufL, lenL);
02559                     
02560                     // the content object is based on the node
02561                     struct ccn_charbuf *cob = NULL;
02562                     if (data->kind == SRI_Kind_FetchInt) {
02563                         // node fetch results need not expire
02564                         cob = ncL->content;
02565                     }
02566                     if (cob == NULL)
02567                         // don't already have it, so make it
02568                         cob = SyncSignBuf(base, ncL->cb, name,
02569                                           fresh, CCN_SP_FINAL_BLOCK);
02570                     
02571                     if (cob != NULL) {
02572                         // we have a response encoded
02573                         if (ccn_content_matches_interest(cob->buf, cob->length,
02574                                                          1, NULL,
02575                                                          info->interest_ccnb,
02576                                                          info->pi->offset[CCN_PI_E],
02577                                                          info->pi)) {
02578                             // we match the interest
02579                             int res = ccn_put(info->h, cob->buf, cob->length);
02580                             if (res >= 0) {
02581                                 // we have success!
02582                                 if (debug >= CCNL_INFO)
02583                                     SyncNoteUri(root, here, "response sent", name);
02584                             } else {
02585                                 if (debug >= CCNL_SEVERE)
02586                                     SyncNoteUri(root, here, "response failed", name);
02587                             }
02588                             ret = CCN_UPCALL_RESULT_INTEREST_CONSUMED;
02589                         } else {
02590                             // the exclusion filter disallows it
02591                             if (debug >= CCNL_FINE)
02592                                 SyncNoteUri(root, here, "no match", name);
02593                         }
02594                         if (data->kind == SRI_Kind_FetchInt) {
02595                             // ownership of the encoding transfers to the node
02596                             ncL->content = cob;
02597                         } else {
02598                             // for root advise, don't hold on to the encoding
02599                             // (it's not signed right for Node Fetch)
02600                             ccn_charbuf_destroy(&cob);
02601                         }
02602                     }
02603                     ccn_charbuf_destroy(&name);
02604                     break;
02605                 }
02606                 default:
02607                     // SHOULD NOT HAPPEN
02608                     ret = CCN_UPCALL_RESULT_ERR;
02609                     break;
02610             }
02611             if (hexL != NULL) free(hexL);
02612             if (hexR != NULL) free(hexR);
02613             break;
02614         }
02615         default:
02616             // SHOULD NOT HAPPEN
02617             ret = CCN_UPCALL_RESULT_ERR;
02618             break;
02619     }
02620     return ret;
02621     
02622 }
02623 
02624 static int
02625 SyncRegisterInterest(struct SyncRootStruct *root,
02626                      enum SyncRegisterActionKind kind) {
02627     static char *here = "Sync.SyncRegisterInterest";
02628     int res = 0;
02629     struct SyncBaseStruct *base = root->base;
02630     int debug = base->debug;
02631     if (base->ccn == NULL)
02632         return -__LINE__;
02633     struct ccn_charbuf *prefix = constructCommandPrefix(root, kind);
02634     if (prefix != NULL) {
02635         // so far we have built the full prefix for the interest
02636         struct ccn_closure *action = NEW_STRUCT(1, ccn_closure);
02637         struct SyncActionData *data = newActionData(kind);
02638         data->prefix = prefix;
02639         data->skipToHash = SyncComponentCount(prefix);
02640         action->data = data;
02641         action->p = &SyncInterestArrived;
02642         
02643         // we can register the prefix
02644         res |= ccn_set_interest_filter(root->base->ccn, prefix, action);
02645         if (res < 0) {
02646             if (debug >= CCNL_SEVERE)
02647                 SyncNoteUri(root, here, "ccn_set_interest_filter failed", prefix);
02648             data = destroyActionData(data);
02649         } else {
02650             linkActionData(root, data);
02651             if (debug >= CCNL_INFO)
02652                 SyncNoteUri(root, here, getKindStr(kind), prefix);
02653         }
02654     } else {
02655         // bad input, so delete the prefix
02656         res = SyncNoteFailed(root, here, "bad prefix", __LINE__);
02657     }
02658     return res;
02659 }
02660 
02661 extern int
02662 SyncRegisterInterests(struct SyncRootStruct *root) {
02663     char *here = "Sync.SyncRegisterInterests";
02664     struct SyncBaseStruct *base = root->base;
02665     struct ccn *ccn = base->ccn;
02666     if (ccn == NULL) return -1;
02667     int res = 0;
02668     if (base->debug >= CCNL_INFO) {
02669         // report the root registration and the hex values
02670         char *hex = SyncHexStr(root->sliceHash->buf, root->sliceHash->length);
02671         struct ccn_charbuf *uriTopo = NULL;
02672         char *msgTopo = "??";
02673         struct ccn_charbuf *topoPrefix = root->topoPrefix;
02674         if (topoPrefix != NULL && topoPrefix->length > 0) {
02675             uriTopo = SyncUriForName(topoPrefix);
02676             msgTopo = ccn_charbuf_as_string(uriTopo);
02677         }
02678         struct ccn_charbuf *uriPrefix = NULL;
02679         char *msgPrefix = "??";
02680         struct ccn_charbuf *namingPrefix = root->namingPrefix;
02681         if (namingPrefix != NULL && namingPrefix->length > 0) {
02682             uriPrefix = SyncUriForName(namingPrefix);
02683             msgPrefix = ccn_charbuf_as_string(uriPrefix);
02684         }
02685         
02686         ccnr_msg(root->base->ccnr,
02687                  "%s, root#%u, topo %s, prefix %s, hash %s",
02688                  here, root->rootId, msgTopo, msgPrefix, hex);
02689         
02690         struct SyncNameAccum *filter = root->filter;
02691         if (filter != NULL) {
02692             int i = 0;
02693             for (i = 0; i < filter->len; i++) {
02694                 struct ccn_charbuf *uri = SyncUriForName(filter->ents[i].name);
02695                 ccnr_msg(root->base->ccnr,
02696                          "%s, root#%u, op %d, pattern %s",
02697                          here, root->rootId,
02698                          (int) filter->ents[i].data,
02699                          ccn_charbuf_as_string(uri));
02700                 ccn_charbuf_destroy(&uri);
02701             }
02702         }
02703         if (uriTopo != NULL) ccn_charbuf_destroy(&uriTopo);
02704         if (uriPrefix != NULL) ccn_charbuf_destroy(&uriPrefix);
02705         free(hex);
02706     }
02707     res |= SyncRegisterInterest(root, SRI_Kind_AdviseInt);
02708     res |= SyncRegisterInterest(root, SRI_Kind_FetchInt);
02709     res |= SyncRegisterInterest(root, SRI_Kind_RootStats);
02710     root->priv->adviseNeed = adviseNeedReset;
02711     return res;
02712 }
02713 
02714 // callback for when a root advise interest gets a response
02715 extern enum ccn_upcall_res
02716 SyncRootAdviseResponse(struct ccn_closure *selfp,
02717                        enum ccn_upcall_kind kind,
02718                        struct ccn_upcall_info *info) {
02719     static char *here = "Sync.SyncRootAdviseResponse";
02720     struct SyncActionData *data = selfp->data;
02721     enum ccn_upcall_res ret = CCN_UPCALL_RESULT_OK;
02722     switch (kind) {
02723         case CCN_UPCALL_FINAL:
02724             data = destroyActionData(data);
02725             free(selfp);
02726             break;
02727         case CCN_UPCALL_CONTENT_UNVERIFIED:
02728             ret = CCN_UPCALL_RESULT_VERIFY;
02729             break;
02730 #if (CCN_API_VERSION >= 4004)
02731         case CCN_UPCALL_CONTENT_KEYMISSING:
02732             ret = CCN_UPCALL_RESULT_FETCHKEY;
02733             break;
02734 #endif
02735         case CCN_UPCALL_INTEREST_TIMED_OUT: {
02736             if (data == NULL || info == NULL ||
02737                 data->root == NULL || data->kind != SRI_Kind_RootAdvise) {
02738                 // not active, no useful info
02739             } else {
02740                 sync_time now = SyncCurrentTime();
02741                 struct SyncRootStruct *root = data->root;
02742                 int debug = root->base->debug;
02743                 root->priv->stats->rootAdviseTimeout++;
02744                 if (debug >= CCNL_INFO) {
02745                     char temp[64];
02746                     int64_t dt = SyncDeltaTime(data->startTime, now);
02747                     dt = (dt + 500) / 1000;
02748                     snprintf(temp, sizeof(temp),
02749                              "timeout, %d.%03d secs",
02750                              (int) (dt / 1000), (int) (dt % 1000));
02751                     SyncNoteUri(root, here, temp, data->prefix);
02752                 }
02753                 data->startTime = now;
02754                 // as long as we need a response, keep expressing it
02755                 ret = CCN_UPCALL_RESULT_REEXPRESS;
02756             }
02757             break;
02758         }
02759 #if (CCN_API_VERSION >= 4004)
02760         case CCN_UPCALL_CONTENT_RAW:
02761 #endif
02762         case CCN_UPCALL_CONTENT: {
02763             if (data == NULL || info == NULL ||
02764                 data->root == NULL || data->kind != SRI_Kind_RootAdvise) {
02765                 // not active, no useful info
02766                 break;
02767             }
02768             struct SyncRootStruct *root = data->root;
02769             int debug = root->base->debug;
02770             if (debug >= CCNL_INFO) {
02771                 struct ccn_charbuf *nm = SyncNameForIndexbuf(info->content_ccnb,
02772                                                              info->content_comps);
02773                 size_t bytes = info->pco->offset[CCN_PCO_E];
02774                 char temp[64];
02775                 int64_t dt = SyncDeltaTime(data->startTime, SyncCurrentTime());
02776                 dt = (dt + 500) / 1000;
02777                 snprintf(temp, sizeof(temp),
02778                          "content, %d.%03d secs, %u bytes",
02779                          (int) (dt / 1000), (int) (dt % 1000),
02780                          (unsigned) bytes);
02781                 SyncNoteUri(root, here, temp, nm);
02782                 ccn_charbuf_destroy(&nm);
02783             }
02784             
02785             const unsigned char *hp = NULL;
02786             size_t hs = 0;
02787             size_t bytes = 0;
02788             int failed = 0;
02789             int cres = ccn_name_comp_get(info->content_ccnb,
02790                                          info->content_comps,
02791                                          data->skipToHash, &hp, &hs);
02792             if (cres < 0 || hp == NULL) {
02793                 // bad hash, so complain
02794                 failed++;
02795                 SyncNoteFailed(root, here, "bad hash", __LINE__);
02796             } else if (fauxError(root->base)) {
02797                 failed++;
02798                 if (debug >= CCNL_WARNING)
02799                     SyncNoteSimple(root, here, "faux error");
02800             } else {
02801                 struct SyncHashCacheEntry *ce = SyncHashEnter(root->ch, hp, hs,
02802                                                               SyncHashState_remote);
02803                 noteRemoteHash(root, ce, 1);
02804                 if (!isCovered(ce)) {
02805                     // may need to make an entry
02806                     struct SyncNodeComposite *nc = NULL;
02807                     char *hex = SyncHexStr(hp, hs);
02808                     if (ce != NULL && ce->ncR != NULL) {
02809                         nc = ce->ncR;
02810                         if (debug >= CCNL_INFO)
02811                             SyncNoteSimple2(root, here, "existing but not covered", hex);
02812                     } else {
02813                         nc = extractNode(root, info);
02814                         if (nc == NULL) {
02815                             // this is bad news, the parsing failed
02816                             failed++;
02817                             if (debug >= CCNL_SEVERE)
02818                                 SyncNoteSimple2(root, here, "extractNode failed", hex);
02819                         } else {
02820                             // new entry
02821                             ce->ncR = nc;
02822                             SyncNodeIncRC(nc);
02823                             bytes = info->pco->offset[CCN_PCO_E];
02824                             if (debug >= CCNL_INFO)
02825                                 SyncNoteSimple2(root, here, "remote entered", hex);
02826                         }
02827                     }
02828                     free(hex);
02829                 }
02830             }
02831             if (failed) {
02832                 root->priv->stats->rootAdviseFailed++;
02833             } else {
02834                 root->priv->stats->rootAdviseReceived++;
02835                 root->priv->stats->rootAdviseBytes += bytes;
02836             }
02837             break;
02838         }
02839         default:
02840             // SHOULD NOT HAPPEN
02841             ret = CCN_UPCALL_RESULT_ERR;
02842             break;
02843     }
02844     return ret;
02845 }
02846 
02847 extern int
02848 SyncSendRootAdviseInterest(struct SyncRootStruct *root) {
02849     static char *here = "Sync.SyncSendRootAdviseInterest";
02850     enum SyncRegisterActionKind kind = SRI_Kind_RootAdvise;
02851     int debug = root->base->debug;
02852     struct SyncActionData *data = SyncFindAction(root, kind);
02853     struct SyncHashCacheEntry *ce = NULL;
02854     if (root->currentHash->length > 0) {
02855         ce = SyncHashLookup(root->ch,
02856                             root->currentHash->buf,
02857                             root->currentHash->length);
02858     }
02859     if (data != NULL) {
02860         // don't override exiting interest for this root unless the root has changed
02861         if (ce == NULL || ce == root->priv->lastLocalSent)
02862             return 0;
02863         // mark this as inactive, response to be ignored
02864         data->kind = SRI_Kind_None;
02865         if (debug >= CCNL_FINE)
02866             SyncNoteSimple(root, here, "marked old interest as inactive");
02867     }
02868     struct ccn_closure *action = NEW_STRUCT(1, ccn_closure);
02869     struct ccn_charbuf *prefix = constructCommandPrefix(root, kind);
02870     struct ccn_charbuf *hash = ccn_charbuf_create();
02871     
02872     ccn_charbuf_append_charbuf(hash, root->currentHash);
02873     ccn_name_append(prefix, hash->buf, hash->length);
02874     
02875     data = newActionData(kind);
02876     data->skipToHash = SyncComponentCount(prefix);
02877     data->hash = hash;
02878     data->prefix = prefix;
02879     action->data = data;
02880     action->p = &SyncRootAdviseResponse;
02881     
02882     struct SyncNameAccum *excl = exclusionsFromHashList(root, root->priv->remoteSeen);
02883     struct ccn_charbuf *template = SyncGenInterest(NULL,
02884                                                    syncScope,
02885                                                    root->base->priv->rootAdviseLifetime,
02886                                                    -1, -1,
02887                                                    excl);
02888     int res = ccn_express_interest(root->base->ccn,
02889                                    prefix,
02890                                    action,
02891                                    template);
02892     SyncFreeNameAccumAndNames(excl);
02893     ccn_charbuf_destroy(&template);
02894     if (res >= 0) {
02895         // link the request into the root
02896         if (root->priv->adviseNeed > 0) root->priv->adviseNeed--;
02897         linkActionData(root, data);
02898         root->priv->lastAdvise = SyncCurrentTime();
02899         root->priv->lastLocalSent = ce;
02900         root->priv->stats->rootAdviseSent++;
02901         if (debug >= CCNL_INFO)
02902             SyncNoteUri(root, here, "sent", prefix);
02903         return 1;
02904     } else {
02905         // failed, so return the storage
02906         data = destroyActionData(data);
02907         free(action);
02908         if (debug >= CCNL_ERROR)
02909             SyncNoteSimple(root, here, "ccn_express_interest failed");
02910         return -1;
02911     }
02912 }
02913 
02914 static int
02915 MakeNodeFromNames(struct SyncUpdateData *ud, int split) {
02916     char *here = "Sync.MakeNodeFromNames";
02917     struct SyncRootStruct *root = ud->root;
02918     int debug = root->base->debug;
02919     struct SyncNameAccum *na = ud->sort;
02920     int lim = na->len;
02921     if (lim == 0)
02922         // should not have been called, but no harm done
02923         return 0;
02924     int i = 0;
02925     if (split == 0) split = lim;
02926     if (debug >= CCNL_FINE) {
02927         char tmp[64];
02928         snprintf(tmp, sizeof(tmp),
02929                  "split %d, lim %d",
02930                  split, lim);
02931         SyncNoteSimple(root, here, tmp);
02932     }
02933     
02934     // accum the hash for the node, and see if it exists
02935     struct SyncLongHashStruct longHash;
02936     memset(&longHash, 0, sizeof(struct SyncLongHashStruct));
02937     longHash.pos = MAX_HASH_BYTES;
02938     for (i = 0; i < split; i++) {
02939         struct ccn_charbuf *name = na->ents[i].name;
02940         SyncAccumHash(&longHash, name);
02941     }
02942     ssize_t hs = MAX_HASH_BYTES-longHash.pos;
02943     unsigned char *hp = longHash.bytes+longHash.pos;
02944     struct SyncHashCacheEntry *ce = SyncHashLookup(root->ch, hp, hs);
02945     if (ce != NULL && ce->ncL != NULL) {
02946         // node already exists
02947         struct SyncNodeComposite *nc = ce->ncL;
02948         SyncNodeIncRC(nc);
02949         SyncAccumNode(ud->nodes, nc);
02950         root->priv->stats->nodesShared++;
02951         if (debug >= CCNL_FINE) {
02952             char *hex = SyncHexStr(hp, hs);
02953             SyncNoteSimple2(root, here, "existing local node", hex);
02954             free(hex);
02955         }
02956     } else {
02957         // need to create a new node
02958         if (debug >= CCNL_FINE) {
02959             char *hex = SyncHexStr(hp, hs);
02960             SyncNoteSimple2(root, here, "need new local node", hex);
02961             free(hex);
02962         }
02963         struct SyncNodeComposite *nc = SyncAllocComposite(root->base);
02964         for (i = 0; i < split; i++) {
02965             struct ccn_charbuf *name = na->ents[i].name;
02966             SyncNodeAddName(nc, name);
02967             ccn_charbuf_destroy(&name);
02968             na->ents[i].name = NULL;
02969         }
02970         SyncEndComposite(nc);
02971         newNodeCommon(root, ud->nodes, nc);
02972     }
02973     // shift remaining elements down in the name accum
02974     ud->nameLenAccum = 0;
02975     i = 0;
02976     while (split < lim) {
02977         struct ccn_charbuf *name = na->ents[split].name;
02978         ud->nameLenAccum += name->length;
02979         na->ents[i] = na->ents[split];
02980         na->ents[split].name = NULL;
02981         i++;
02982         split++;
02983     }
02984     na->len = i;
02985     return i;
02986 }
02987 
02988 static int
02989 TryNodeSplit(struct SyncUpdateData *ud) {
02990     char *here = "Sync.TryNodeSplit";
02991     struct SyncNameAccum *na = ud->sort;
02992     int lim = na->len;
02993     if (lim == 0)
02994         // should not have been called, but no harm done
02995         return 0;
02996     struct SyncRootStruct *root = ud->root;
02997     int debug = root->base->debug;
02998     struct ccn_charbuf *prev = NULL;
02999     int accLim = nodeSplitTrigger - nodeSplitTrigger/8;
03000     int accMin = nodeSplitTrigger/2;
03001     int res = 0;
03002     int splitMethod = 3;  // was variable, now is constantly enabled
03003     int maxLen = 0;
03004     int accLen = 0;
03005     int prevMatch = 0;
03006     int split = 0;
03007     if (debug >= CCNL_FINE) {
03008         char tmp[64];
03009         snprintf(tmp, sizeof(tmp),
03010                  "entered, %d names",
03011                  lim);
03012         SyncNoteSimple(root, here, tmp);
03013     }
03014     for (split = 0; split < lim; split++) {
03015         struct ccn_charbuf *name = na->ents[split].name;
03016         int nameLen = name->length + 8;
03017         if (nameLen > maxLen) maxLen = nameLen;
03018         accLen = accLen + nameLen + (maxLen - nameLen) * 2;
03019         prev = name;
03020         if (split+1 < lim) {
03021             if (splitMethod & 1) {
03022                 // use level shift to split
03023                 struct ccn_charbuf *next = na->ents[split+1].name;
03024                 int match = SyncComponentMatch(name, next);
03025                 if (accLen >= accMin
03026                     && (match < prevMatch || (match > prevMatch+1))) {
03027                     // force a break due to level changes
03028                     if (debug >= CCNL_FINE) {
03029                         char tmp[64];
03030                         snprintf(tmp, sizeof(tmp),
03031                                  "split %d, lim %d, match %d, prev %d, accLen %d",
03032                                  split, lim, match, prevMatch, accLen);
03033                         SyncNoteSimple2(root, here, "level split found", tmp);
03034                     }
03035                     break;
03036                 }
03037                 prevMatch = match;
03038             }
03039             if (splitMethod & 2) {
03040                 // use bits of hash to split
03041                 int pos = name->length - 9;
03042                 if (pos > 0 && accLen >= accMin) {
03043                     unsigned c = name->buf[pos] & 255;
03044                     if (c < hashSplitTrigger) {
03045                         if (debug >= CCNL_FINE) {
03046                             char tmp[64];
03047                             snprintf(tmp, sizeof(tmp),
03048                                      "split %d, lim %d, x %u, accLen %d",
03049                                      split, lim, c, accLen);
03050                             SyncNoteSimple2(root, here, "hash split found", tmp);
03051                         }
03052                         break;
03053                     }
03054                 }
03055             }
03056         }
03057         if (accLen >= accLim) {
03058             break;
03059         }
03060     }
03061     // at this point we take the first "split" elements into a node
03062     res = MakeNodeFromNames(ud, split);
03063     return res;
03064 }
03065     
03066 static int
03067 AddUpdateName(struct SyncUpdateData *ud, struct ccn_charbuf *name) {
03068     struct SyncNameAccum *dst = ud->sort;
03069     int nameLen = name->length;
03070     int accLim = nodeSplitTrigger - nodeSplitTrigger/8;
03071     int res = 0;
03072     name = SyncCopyName(name);
03073     SyncNameAccumAppend(dst, name, 0);
03074     ud->nameLenAccum += nameLen;
03075     ud->namesAdded++;
03076     if (ud->nameLenAccum >= accLim) {
03077         // we should split, if it is possible
03078         res = TryNodeSplit(ud);
03079     }
03080     return res;
03081 }
03082 
03083 // merge the semi-sorted names and the old sync tree
03084 // returns -1 for failure, 0 for incomplete, 1 for complete
03085 static int
03086 SyncTreeMergeNames(struct SyncTreeWorkerHead *head,
03087                    struct SyncUpdateData *ud) {
03088     char *here = "Sync.SyncTreeMergeNames";
03089     struct SyncRootStruct *root = ud->root;
03090     int debug = root->base->debug;
03091     IndexSorter_Base ixBase = ud->ixBase;
03092     struct SyncNameAccum *src = (struct SyncNameAccum *) ixBase->client;
03093     IndexSorter_Index srcPos = 0;
03094     struct ccn_charbuf *cb = ud->cb;
03095     int res = 0;
03096     int namesLim = ud->namesAdded+namesYieldInc;
03097     if (head != NULL) {
03098         while (res == 0) {
03099             struct SyncTreeWorkerEntry *ent = SyncTreeWorkerTop(head);
03100             if (ent == NULL) break;
03101             if (ent->cacheEntry == NULL) {
03102                 // probably a real bug!
03103                 res = -__LINE__;
03104                 break;
03105             }
03106             struct SyncHashCacheEntry *ce = ent->cacheEntry;
03107             if (head->remote <= 0) SyncCacheEntryFetch(ce);
03108             struct SyncNodeComposite *nc = ((head->remote > 0) ? ce->ncR : ce->ncL);
03109             if (nc == NULL) {
03110                 // should not happen
03111                 res = -__LINE__;
03112                 break;
03113             }
03114             int lim = nc->refLen;
03115             if (ent->pos >= lim) {
03116                 // done with the current level, go back to the previous level
03117                 ent = SyncTreeWorkerPop(head);
03118                 if (ent == NULL) break;
03119                 ent->pos++;
03120             } else {
03121                 struct SyncNodeElem *ep = &nc->refs[ent->pos];
03122                 if (ep->kind & SyncElemKind_leaf) {
03123                     // a leaf, so the element name is inline
03124                     enum SyncCompareResult cmp = SCR_after;
03125                     struct ccn_charbuf *name = NULL;
03126                     
03127                     if (ud->ixBase->len > 0) {
03128                         srcPos = IndexSorter_Best(ud->ixBase);
03129                         name = src->ents[srcPos].name;
03130                         if (name != NULL)
03131                             cmp = SyncNodeCompareLeaf(nc, ep, name);
03132                     }
03133                     switch (cmp) {
03134                         case SCR_before:
03135                             // add the name from src
03136                             AddUpdateName(ud, name);
03137                         case SCR_min:
03138                             // advance the src, remove duplicates
03139                             if (cmp == SCR_min) {
03140                                 if (debug >= CCNL_FINE) {
03141                                     SyncNoteUri(root, here, "skip", name);
03142                                 }
03143                             }
03144                             for (;;) {
03145                                 IndexSorter_Rem(ud->ixBase);
03146                                 if (ud->ixBase->len <= 0) break;
03147                                 srcPos = IndexSorter_Best(ud->ixBase);
03148                                 struct ccn_charbuf *next = src->ents[srcPos].name;
03149                                 if (SyncCmpNames(name, next) != 0) break;
03150                                 if (debug >= CCNL_FINE) {
03151                                     SyncNoteUri(root, here, "skip dup", next);
03152                                 }
03153                             }
03154                             break;
03155                         case SCR_after:
03156                             // add the name from the tree
03157                             extractBuf(cb, nc, ep);
03158                             AddUpdateName(ud, cb);
03159                             ent->pos++;
03160                             break;
03161                         default:
03162                             // this is not kosher
03163                             res = -__LINE__;
03164                             break;
03165                     }
03166                     if (ud->namesAdded >= namesLim) {
03167                         int64_t dt = SyncDeltaTime(ud->entryTime, SyncCurrentTime());
03168                         if (dt >= namesYieldMicros) {
03169                             // need to yield
03170                             if (debug >= CCNL_FINE)
03171                                 SyncNoteSimple(root, here, "yield");
03172                             return 0;
03173                         }
03174                         namesLim += namesYieldInc;
03175                     }
03176                 } else {
03177                     // a node, so push into it
03178                     ent = SyncTreeWorkerPush(head);
03179                     if (ent == NULL) {
03180                         res = -__LINE__;
03181                         break;
03182                     }                
03183                 }
03184             }
03185         }
03186     }
03187     if (res == 0) {
03188         // done with the tree, move items from the src
03189         while (ud->ixBase->len > 0) {
03190             srcPos = IndexSorter_Best(ud->ixBase);
03191             struct ccn_charbuf *name = src->ents[srcPos].name;
03192             AddUpdateName(ud, name);
03193             for (;;) {
03194                 IndexSorter_Rem(ud->ixBase);
03195                 if (ud->ixBase->len <= 0) break;
03196                 srcPos = IndexSorter_Best(ud->ixBase);
03197                 struct ccn_charbuf *next = src->ents[srcPos].name;
03198                 if (SyncCmpNames(name, next) != 0) break;
03199             }
03200             if (ud->namesAdded >= namesLim) {
03201                 int64_t dt = SyncDeltaTime(ud->entryTime, SyncCurrentTime());
03202                 if (dt >= namesYieldMicros) {
03203                     // need to yield
03204                     if (debug >= CCNL_FINE)
03205                         SyncNoteSimple(root, here, "yield");
03206                     return 0;
03207                 }
03208                 namesLim += namesYieldInc;
03209             }
03210         }
03211         res = 1;
03212     }
03213     return res;
03214 }
03215 
03216 static int
03217 UpdateAction(struct ccn_schedule *sched,
03218              void *clienth,
03219              struct ccn_scheduled_event *ev,
03220              int flags) {
03221     char *here = "Sync.UpdateAction";
03222     sync_time now = SyncCurrentTime();
03223     struct SyncUpdateData *ud = (struct SyncUpdateData *) ev->evdata;
03224     struct SyncRootStruct *root = ud->root;
03225     struct SyncBaseStruct *base = root->base;
03226     int debug = base->debug;
03227     struct ccnr_handle *ccnr = base->ccnr;
03228     int showEntry = base->priv->syncActionsPrivate & 8;
03229     // sync_time prevTime = ud->entryTime;
03230     ud->entryTime = now;
03231     switch (ud->state) {
03232         case SyncUpdate_init: {
03233             // we are initialized, and need to insert root->namesToAdd
03234             // only process a bounded number of names each time
03235             if (showEntry && debug >= CCNL_INFO) {
03236                 SyncNoteSimple(root, here, "SyncUpdate_init");
03237             }
03238             struct SyncNameAccum *src = (struct SyncNameAccum *) ud->ixBase->client;
03239             IndexSorter_Index srcLen = src->len;
03240             IndexSorter_Index ix = ud->ixPos;
03241             IndexSorter_Index ixLim = ix+namesYieldInc;
03242             if (srcLen < ixLim) ixLim = srcLen;
03243             
03244             
03245             while (ix < srcLen) {
03246                 if (ix > ixLim) {
03247                     int64_t dt = SyncDeltaTime(ud->entryTime, SyncCurrentTime());
03248                     if (dt >= namesYieldMicros) {
03249                         // need to yield
03250                         if (debug >= CCNL_FINE)
03251                             SyncNoteSimple(root, here, "yield");
03252                         break;
03253                     }
03254                     ixLim += namesYieldInc;
03255                 }
03256                 if (debug >= CCNL_FINE) {
03257                     struct ccn_charbuf *name = src->ents[ix].name;
03258                     SyncNoteUri(root, here, "insert", name);
03259                 }
03260                 IndexSorter_Add(ud->ixBase, ix);
03261                 ix++;
03262             }
03263             ud->ixPos = ix;
03264             if (ix < srcLen)
03265                 // not done yet, so take a break
03266                 return shortDelayMicros;
03267             
03268             ud->state = SyncUpdate_inserted;
03269             struct SyncHashCacheEntry *ent = SyncRootTopEntry(root);
03270             if (ent != NULL && ud->tw == NULL) {
03271                 SyncCacheEntryFetch(ent);
03272                 ud->tw = SyncTreeWorkerCreate(root->ch, ent, 0);
03273             }
03274             ud->sort = SyncAllocNameAccum(0);
03275             ud->cb = ccn_charbuf_create();
03276             ud->nodes = SyncAllocNodeAccum(0);
03277             break;
03278         }
03279         case SyncUpdate_inserted: {
03280             // all names to be added are now in ud->ixBase
03281             // the old sync tree has not been changed
03282             if (showEntry && debug >= CCNL_INFO) {
03283                 SyncNoteSimple(root, here, "SyncUpdate_inserted");
03284             }
03285             
03286             int res = SyncTreeMergeNames(ud->tw, ud);
03287             if (res == 0) break;
03288                 // not done yet, pause requested
03289             res = MakeNodeFromNames(ud, 0);
03290             // done, either normally or with error
03291             // free the resources
03292             struct SyncNameAccum *src = (struct SyncNameAccum *) ud->ixBase->client;
03293             ud->tw = SyncTreeWorkerFree(ud->tw);
03294             src = SyncFreeNameAccumAndNames(src);
03295             IndexSorter_Free(&ud->ixBase);
03296             ccn_charbuf_destroy(&ud->cb);
03297             if (res < 0) {
03298                 // this is bad news!
03299                 ud->sort = SyncFreeNameAccumAndNames(ud->sort);
03300                 SyncNoteFailed(root, here, "merge names", __LINE__);
03301                 return res;
03302             }
03303             ud->state = SyncUpdate_busy;
03304             break;
03305         }
03306         case SyncUpdate_busy: {
03307             // ud->nodes has the noes created from the names
03308             // the last step is to make up the node superstructure
03309             if (showEntry && debug >= CCNL_INFO) {
03310                 SyncNoteSimple(root, here, "SyncUpdate_busy");
03311             }
03312             int initCount = root->priv->currentSize;
03313             struct SyncHashCacheEntry *ce = nodeFromNodes(root, ud->nodes);
03314             int count = ud->namesAdded;
03315             if (ce == NULL) {
03316                 count = SyncNoteFailed(root, here, "bad nodeFromNames()", __LINE__);
03317             } else {
03318                 SyncCacheEntryFetch(ce);
03319                 struct SyncNodeComposite *nc = ce->ncL;
03320                 if (nc != NULL) {
03321                     struct ccn_charbuf *old = root->currentHash;
03322                     struct ccn_charbuf *hash = SyncLongHashToBuf(&nc->longHash);
03323                     char *hex = SyncHexStr(hash->buf, hash->length);
03324                     root->currentHash = hash;
03325                     root->priv->currentSize = count;
03326                     now = SyncCurrentTime();
03327                     if (compareHash(old, hash) != 0) {
03328                         // note the time of the last hash change
03329                         root->priv->lastHashChange = now;
03330                     }
03331                     int64_t dt = SyncDeltaTime(ud->startTime, now);
03332                     root->priv->stats->updatesDone++;
03333                     root->priv->stats->lastUpdateMicros = dt;
03334                     dt = (dt + 500) / 1000;
03335                     int64_t mh = SyncDeltaTime(ud->entryTime, now);
03336                     if (mh < ud->maxHold) mh = ud->maxHold;
03337                     mh = (mh + 500) / 1000;
03338                     if (debug >= CCNL_INFO) {
03339                         int reportStats = base->priv->syncActionsPrivate & 4;
03340                         char temp[256];
03341                         snprintf(temp, sizeof(temp)-2,
03342                                  "%d.%03d secs [%d.%03d], %d names, depth %d, hash %s",
03343                                  (int) (dt / 1000), (int) (dt % 1000),
03344                                  (int) (mh / 1000), (int) (mh % 1000),
03345                                  (int) count, (int) nc->treeDepth, hex);
03346                         SyncNoteSimple2(root, here, "done", temp);
03347                         if (reportStats) {
03348                             struct ccn_charbuf *cb = ccn_charbuf_create();
03349                             formatStats(root, cb);
03350                             char *str = ccn_charbuf_as_string(cb);
03351                             ccnr_msg(root->base->ccnr, "%s, %s", here, str);
03352                             ccn_charbuf_destroy(&cb);
03353                         }
03354                     }
03355                     struct SyncHashCacheEntry *chk = SyncRootTopEntry(root);
03356                     if (chk != ce)
03357                         count = SyncNoteFailed(root, here, "bad top entry", __LINE__);
03358                     else if (root->base->ccn != NULL)
03359                         // only do this if it is not the test code
03360                         SyncSendRootAdviseInterest(root);
03361                     if (old != NULL) ccn_charbuf_destroy(&old);
03362                     free(hex);
03363                     // when this root node is stored we will need to know the stable point
03364                     ccnr_hwm hwm = root->priv->highWater;
03365                     ce->stablePoint = hwm;
03366                     if (debug >= CCNL_INFO) {
03367                         char temp[64];
03368                         if (hwm != CCNR_NULL_HWM) {
03369                             snprintf(temp, sizeof(temp),
03370                                      "new stable point at %ju",
03371                                      ccnr_hwm_encode(root->base->ccnr, hwm));
03372                         } else {
03373                             snprintf(temp, sizeof(temp), "high water?");
03374                         }
03375                         SyncNoteSimple(root, here, temp);
03376                     }
03377                 } else {
03378                     count = SyncNoteFailed(root, here, "bad node", __LINE__);
03379                 }
03380             }
03381             root->priv->adviseNeed = adviseNeedReset;
03382             ud->sort = SyncFreeNameAccumAndNames(ud->sort);
03383             ud->nodes = SyncFreeNodeAccum(ud->nodes);
03384             if (count <= initCount) {
03385                 // we were supposed to add something?
03386                 if (debug >= CCNL_INFO) {
03387                     struct ccn_charbuf *hash = root->currentHash;
03388                     char *hex = SyncHexStr(hash->buf, hash->length);
03389                     ccnr_msg(ccnr,
03390                              "%s, root#%u, note, count %d, initCount %d, hash %s",
03391                              here, root->rootId, count, initCount, hex);
03392                     free(hex);
03393                 }
03394             }
03395             root->update = NULL;
03396             free(ud);
03397             ev->evdata = NULL;
03398             return -1;
03399         }
03400         default: {
03401             // show that we are no longer updating
03402             return -1;
03403         }
03404     }
03405     int64_t edt = SyncDeltaTime(ud->entryTime, SyncCurrentTime());
03406     if (edt > ud->maxHold) ud->maxHold = edt;
03407     return shortDelayMicros;
03408 }
03409 
03410 extern int
03411 SyncUpdateRoot(struct SyncRootStruct *root) {
03412     char *here = "Sync.UpdateAction";
03413     struct SyncNameAccum *acc = root->namesToAdd;
03414     if (acc->len == 0) return 0;
03415     sync_time now = SyncCurrentTime();
03416     struct SyncBaseStruct *base = root->base;
03417     struct ccnr_handle *ccnr = base->ccnr;
03418     struct SyncUpdateData *ud = NEW_STRUCT(1, SyncUpdateData);
03419     ud->root = root;
03420     ud->state = SyncUpdate_init;
03421     ud->startTime = now;
03422     ud->entryTime = now;
03423     ud->ixBase = IndexSorter_New(acc->len, -1);
03424     ud->ixBase->sorter = SyncNameAccumSorter;
03425     ud->ixBase->client = acc;
03426     ud->ixPos = 0;
03427     ud->initLen = root->priv->currentSize;
03428     struct ccn_scheduled_event *ev = ccn_schedule_event(base->sched,
03429                                                         0,
03430                                                         UpdateAction,
03431                                                         ud,
03432                                                         0);
03433     if (ev == NULL) {
03434         if (base->debug >= CCNL_SEVERE)
03435             ccnr_msg(ccnr, "%s, initial schedule failed!", here);
03436         free(ud);
03437         return -1;
03438     }
03439     root->priv->lastUpdate = now;
03440     root->update = ud;
03441     root->namesToAdd = SyncAllocNameAccum(0);
03442     if (base->debug >= CCNL_INFO) {
03443         struct ccn_charbuf *hash = root->currentHash;
03444         char *hex = SyncHexStr(hash->buf, hash->length);
03445         ccnr_msg(ccnr,
03446                  "%s, root#%u, start, toAdd %d, current %d, hash %s",
03447                  here, root->rootId,
03448                  (int) acc->len, (int) ud->initLen, hex);
03449         free(hex);
03450     }
03451     return 1;
03452 }
03453 
03454 extern int
03455 SyncStartCompareAction(struct SyncRootStruct *root, struct ccn_charbuf *hashR) {
03456     char *here = "Sync.SyncStartCompareAction";
03457     struct SyncPrivate *priv = root->base->priv;
03458     if (root->compare != NULL
03459         || priv->comparesBusy >= priv->maxComparesBusy)
03460         return 0;
03461     
03462     struct ccn_charbuf *hashL = root->currentHash;
03463     struct SyncHashCacheEntry *ceL = NULL;
03464     
03465     if (hashL->length > 0) {
03466         // if L is not empty, check the cache entry
03467         ceL = SyncHashLookup(root->ch, hashL->buf, hashL->length);
03468         if (ceL == NULL)
03469             return SyncNoteFailed(root, here, "bad lookup for L", __LINE__);
03470     }
03471     struct SyncHashCacheEntry *ceR = SyncHashEnter(root->ch,
03472                                                    hashR->buf,
03473                                                    hashR->length,
03474                                                    SyncHashState_remote);
03475     if (ceR == NULL)
03476         return SyncNoteFailed(root, here, "bad lookup for R", __LINE__);
03477     
03478     int debug = root->base->debug;
03479     struct ccnr_handle *ccnr = root->base->ccnr;
03480     struct SyncCompareData *data = NEW_STRUCT(1, SyncCompareData);
03481     sync_time mark = SyncCurrentTime();
03482     data->startTime = mark;
03483     data->lastEnter = mark;
03484     data->lastMark = mark;
03485     data->lastFetchOK = mark;
03486     data->root = root;
03487     root->compare = data;
03488     root->namesToFetch = SyncFreeNameAccumAndNames(root->namesToFetch);
03489     data->twL = SyncTreeWorkerCreate(root->ch, ceL, 0);
03490     if (ceL != NULL) ceL->lastUsed = mark;
03491     data->twR = SyncTreeWorkerCreate(root->ch, ceR, 1);
03492     ceR->lastUsed = mark;
03493     data->hashL = ccn_charbuf_create();
03494     ccn_charbuf_append_charbuf(data->hashL, hashL);
03495     data->hashR = ccn_charbuf_create();
03496     ccn_charbuf_append_charbuf(data->hashR, hashR);
03497     
03498     data->cbL = ccn_charbuf_create();
03499     data->cbR = ccn_charbuf_create();
03500     
03501     data->state = SyncCompare_init;
03502     priv->comparesBusy++;
03503     
03504     kickCompare(data, NULL);
03505     
03506     if (debug >= CCNL_INFO) {
03507         char *hexL = SyncHexStr(hashL->buf, hashL->length);
03508         char *msgL = ((hashL->length > 0) ? hexL : "empty");
03509         char *hexR = SyncHexStr(hashR->buf, hashR->length);
03510         char *msgR = ((hashR->length > 0) ? hexR : "empty");
03511         ccnr_msg(ccnr, "%s, root#%u, L %s, R %s",
03512                  here, root->rootId, msgL, msgR);
03513         free(hexL);
03514         free(hexR);
03515     }
03516     
03517     return 1;
03518 }
03519 
03520 #undef M

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