/** * Record activity on the node. */ void stable_record_activity(const knode_t *kn) { struct lifedata *ld; struct lifedata new_ld; knode_check(kn); g_assert(kn->flags & KNODE_F_ALIVE); ld = get_lifedata(kn->id); if (NULL == ld) { ld = &new_ld; new_ld.version = LIFEDATA_STRUCT_VERSION; new_ld.first_seen = kn->first_seen; new_ld.last_seen = kn->last_seen; gnet_stats_count_general(GNR_DHT_STABLE_NODES_HELD, +1); } else { if (kn->last_seen <= ld->last_seen) return; ld->last_seen = kn->last_seen; } dbmw_write(db_lifedata, kn->id->v, ld, sizeof *ld); }
/** * The KUID of the node has changed: remove its entry if it had one and make * sure we have an entry for the new KUID. * * @param kn the old node * @param rn the replacing node */ void stable_replace(const knode_t *kn, const knode_t *rn) { struct lifedata *ld; knode_check(kn); knode_check(rn); g_assert(rn->flags & KNODE_F_ALIVE); ld = get_lifedata(kn->id); if (NULL == ld) return; /* Node was not recorded in the "stable" set */ if (GNET_PROPERTY(dht_stable_debug)) { g_debug("DHT STABLE removing obsolete %s, now at %s", knode_to_string(kn), knode_to_string2(rn)); } /* * Remove the old node and create an entry for the new one. */ dbmw_delete(db_lifedata, kn->id->v); gnet_stats_dec_general(GNR_DHT_STABLE_NODES_HELD); stable_record_activity(rn); }
/** * Estimate probability of presence for a value published to some roots in * a given time frame. * * @param d how many seconds in the future? * @param rs the STORE lookup path, giving root candidates * @param status the array of STORE status for each entry in the path * * @return an estimated probability of presence of the value in the network. */ double stable_store_presence(time_delta_t d, const lookup_rs_t *rs, const guint16 *status) { double q = 1.0; size_t i; size_t count = lookup_result_path_length(rs); /* * We may be called by publish callbacks invoked to clean up because * the operation was cancelled. Maybe the DHT was disabled during the * operation, meaning our data structures have been cleaned up? In that * case, abort immediately. * * NOTE: this is not an assertion, it can happen in practice and needs to * be explicitly checked for. */ if (NULL == db_lifedata) /* DHT disabled dynamically */ return 0.0; /* * The probability of presence is (1 - q) where q is the probability * that the value be lost by all the nodes, i.e. that all the nodes * to which the value was published to be gone in "d" seconds. */ for (i = 0; i < count; i++) { if (status[i] == STORE_SC_OK) { const knode_t *kn = lookup_result_nth_node(rs, i); struct lifedata *ld = get_lifedata(kn->id); if (NULL == ld) { return 0.0; /* Cannot compute a suitable probability */ } else { time_delta_t alive = delta_time(ld->last_seen, ld->first_seen); double p = stable_alive_probability(alive, d); q *= (1.0 - p); /* (1 - p) is proba this node will be gone */ } } } return 1.0 - q; }