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