Ejemplo n.º 1
0
/**
 * DBMW foreach iterator to reload keyinfo.
 *
 * @return TRUE if persisted entry can be deleted.
 */
static G_GNUC_COLD bool
reload_ki(void *key, void *value, size_t u_len, void *data)
{
	struct keys_create_context *ctx = data;
	const struct keydata *kd = value;
	const kuid_t *id = key;
	struct keyinfo *ki;
	size_t common;
	time_t next_expire = TIME_T_MAX, last_expire = 0, now = tm_time();
	unsigned i;

	(void) u_len;

	if (0 == kd->values)
		return TRUE;

	/*
	 * Check whether key has expired: if all the values associated with it
	 * have expired, there will be no need to recreate the keyinfo and
	 * retrieve the associated value data.
	 */

	for (i = 0; i < kd->values; i++) {
		last_expire = MAX(last_expire, kd->expire[i]);
	}

	if (delta_time(now, last_expire) >= 0)
		return TRUE;

	/*
	 * We're going to keep at least one of the values, prepare keyinfo.
	 */

	common = kuid_common_prefix(ctx->our_kuid, id);
	ki = allocate_keyinfo(id, common);
	hikset_insert_key(keys, &ki->kuid);

	/*
	 * Values will be inserted later, just prepare the DB keys we need to
	 * load to restore them.
	 */

	for (i = 0; i < kd->values; i++) {
		uint64 dbkey = kd->dbkeys[i];

		if (delta_time(now, kd->expire[i]) >= 0)
			continue;		/* This value has already expired */

		next_expire = MIN(next_expire, kd->expire[i]);

		if (!hset_contains(ctx->dbkeys, &dbkey)) {
			const uint64 *dbatom = atom_uint64_get(&dbkey);
			hset_insert(ctx->dbkeys, dbatom);
		}
	}

	ki->next_expire = next_expire;

	return FALSE;		/* Keep keydata */
}
Ejemplo n.º 2
0
/**
 * Record a SHA1 for publishing.
 */
void
publisher_add(const sha1_t *sha1)
{
	struct publisher_entry *pe;
	struct pubdata *pd;

	g_assert(sha1 != NULL);

	if (NULL == db_pubdata)
		return;					/* Shutdowning */

	/*
	 * If already known, ignore silently.
	 */

	if (hikset_lookup(publisher_sha1, sha1))
		return;

	/*
	 * Create persistent publishing data if none known already.
	 */

	pd = get_pubdata(sha1);
	if (NULL == pd) {
		struct pubdata new_pd;

		new_pd.next_enqueue = 0;
		new_pd.expiration = 0;

		dbmw_write(db_pubdata, sha1, &new_pd, sizeof new_pd);

		if (GNET_PROPERTY(publisher_debug) > 2) {
			g_debug("PUBLISHER allocating new SHA-1 %s",
				sha1_to_string(sha1));
		}
	} else {
		if (GNET_PROPERTY(publisher_debug) > 2) {
			time_delta_t enqueue = delta_time(pd->next_enqueue, tm_time());
			time_delta_t expires = delta_time(pd->expiration, tm_time());

			g_debug("PUBLISHER existing SHA-1 %s, next enqueue %s%s, %s%s",
				sha1_to_string(sha1),
				enqueue > 0 ? "in " : "",
				enqueue > 0 ? compact_time(enqueue) : "now",
				pd->expiration ?
					(expires > 0 ? "expires in " : "expired") : "not published",
				expires > 0 ? compact_time2(expires) : "");
		}
	}

	/*
	 * New entry will be processed immediately.
	 */

	pe = publisher_entry_alloc(sha1);
	hikset_insert_key(publisher_sha1, &pe->sha1);

	publisher_handle(pe);
}
Ejemplo n.º 3
0
/**
 * Add a new entry to the in-memory cache.
 */
static void
add_volatile_cache_entry(const char *filename, filesize_t size, time_t mtime,
	const struct sha1 *sha1, const struct tth *tth, bool known_to_be_shared)
{
	struct sha1_cache_entry *item;
   
	WALLOC(item);
	item->file_name = atom_str_get(filename);
	item->size = size;
	item->mtime = mtime;
	item->sha1 = atom_sha1_get(sha1);
	item->tth = tth ? atom_tth_get(tth) : NULL;
	item->shared = known_to_be_shared;
	hikset_insert_key(sha1_cache, &item->file_name);
}
Ejemplo n.º 4
0
/**
 * Register new file to be monitored.
 *
 * If the file was already monitored, cancel the previous monitoring action
 * and replace it with this one.
 *
 * @param filename the file to monitor (string duplicated)
 * @param cb the callback to invoke when the file changes
 * @param udata extra data to pass to the callback, along with filename
 */
void
watcher_register(const char *filename, watcher_cb_t cb, void *udata)
{
	struct monitored *m;

	WALLOC0(m);
	m->filename = atom_str_get(filename);
	m->cb = cb;
	m->udata = udata;
	m->mtime = watcher_mtime(filename);

	if (hikset_contains(monitored, filename))
		watcher_unregister(filename);

	hikset_insert_key(monitored, &m->filename);
}
Ejemplo n.º 5
0
static void
hash_list_insert_item(hash_list_t *hl, struct hash_list_item *item)
{
	g_assert(!hikset_contains(hl->ht, item->key));
	hikset_insert_key(hl->ht, &item->key);

	/*
	 * Insertion in the list is "safe" with respect to iterators.
	 *
	 * Although there is no guarantee the inserted item will be iterated
	 * over (if it lies before the iterating point), there is no invalidation
	 * of the "next" and "prev" entries that we can have pre-computed in the
	 * iterator, nor is there the risk that we would iterate forever.  All
	 * existing references to linkable cells will remain valid after the
	 * insertion took place.
	 *
	 * Therefore, do not update the hl->stamp value.
	 */

	hash_list_regression(hl);
}
Ejemplo n.º 6
0
/**
 * Adds ``hostname'' and ``addr'' to the cache. The cache is implemented
 * as a wrap-around FIFO. In case it's full, the oldest entry will be
 * overwritten.
 */
static void
adns_cache_add(adns_cache_t *cache, time_t now,
	const char *hostname, const host_addr_t *addrs, size_t n)
{
	adns_cache_entry_t *entry;
	size_t i;
	
	g_assert(NULL != addrs);
	g_assert(NULL != cache);
	g_assert(NULL != hostname);
	g_assert(n > 0);

	g_assert(!hikset_contains(cache->ht, hostname));
	g_assert(cache->pos < G_N_ELEMENTS(cache->entries));
	
	entry = adns_cache_get_entry(cache, cache->pos);
	if (entry) {
		g_assert(entry->hostname);
		g_assert(entry == hikset_lookup(cache->ht, entry->hostname));

		hikset_remove(cache->ht, entry->hostname);
		adns_cache_free_entry(cache, cache->pos);
		entry = NULL;
	}

	entry = walloc(adns_cache_entry_size(n));
	entry->n = n;
	entry->hostname = atom_str_get(hostname);
	entry->timestamp = now;
	entry->id = cache->pos;
	for (i = 0; i < entry->n; i++) {
		entry->addrs[i] = addrs[i];
	}
	hikset_insert_key(cache->ht, &entry->hostname);
	cache->entries[cache->pos++] = entry;
	cache->pos %= G_N_ELEMENTS(cache->entries);
}
Ejemplo n.º 7
0
/**
 * Add value to a key, recording the new association between the KUID of the
 * creator (secondary key) and the 64-bit DB key under which the value is
 * stored.
 *
 * @param id		the primary key (may not exist yet)
 * @param cid		the secondary key (creator's ID)
 * @param dbkey		the 64-bit DB key
 * @param expire	expiration time for the value
 */
void
keys_add_value(const kuid_t *id, const kuid_t *cid,
	uint64 dbkey, time_t expire)
{
	struct keyinfo *ki;
	struct keydata *kd;
	struct keydata new_kd;

	ki = hikset_lookup(keys, id);

	/*
	 * If we're storing the first value under a key, we do not have any
	 * keyinfo structure yet.
	 */

	if (NULL == ki) {
		size_t common;
		bool in_kball;

		common = kuid_common_prefix(get_our_kuid(), id);
		in_kball = bits_within_kball(common);

		if (GNET_PROPERTY(dht_storage_debug) > 5)
			g_debug("DHT STORE new %s %s (%zu common bit%s) with creator %s",
				in_kball ? "key" : "cached key",
				kuid_to_hex_string(id), common, plural(common),
				kuid_to_hex_string2(cid));

		ki = allocate_keyinfo(id, common);
		ki->next_expire = expire;
		ki->flags = in_kball ? 0 : DHT_KEY_F_CACHED;

		hikset_insert_key(keys, &ki->kuid);

		kd = &new_kd;
		kd->values = 0;						/* will be incremented below */
		kd->creators[0] = *cid;				/* struct copy */
		kd->dbkeys[0] = dbkey;
		kd->expire[0] = expire;

		gnet_stats_inc_general(GNR_DHT_KEYS_HELD);
		if (!in_kball)
			gnet_stats_inc_general(GNR_DHT_CACHED_KEYS_HELD);
	} else {
		int low = 0;
		int high = ki->values - 1;

		kd = get_keydata(id);

		if (NULL == kd)
			return;

		g_assert(kd->values == ki->values);
		g_assert(kd->values < MAX_VALUES);

		if (GNET_PROPERTY(dht_storage_debug) > 5)
			g_debug("DHT STORE existing key %s (%u common bit%s) "
				"has new creator %s",
				kuid_to_hex_string(id), ki->common_bits,
				plural(ki->common_bits), kuid_to_hex_string2(cid));

		/*
		 * Keys are collected asynchronously, so it is possible that
		 * the key structure still exists, yet holds no values.  If this
		 * happens, then we win because we spared the useless deletion of
		 * the key structure to recreate it a little bit later.
		 */

		if (0 == kd->values)
			goto empty;

		/*
		 * Insert KUID of creator in array, which must be kept sorted.
		 * We perform a binary insertion.
		 */

		while (low <= high) {
			int mid = low + (high - low) / 2;
			int c;

			g_assert(mid >= 0 && mid < ki->values);

			c = kuid_cmp(&kd->creators[mid], cid);

			if (0 == c)
				g_error("new creator KUID %s must not already be present",
					kuid_to_hex_string(cid));
			else if (c < 0)
				low = mid + 1;
			else
				high = mid - 1;
		}

		/* Make room for inserting new item at `low' */

		ARRAY_FIXED_MAKEROOM(kd->creators, low, kd->values);
		ARRAY_FIXED_MAKEROOM(kd->dbkeys,   low, kd->values);
		ARRAY_FIXED_MAKEROOM(kd->expire,   low, kd->values);

		/* FALL THROUGH */

	empty:
		/* Insert new item at `low' */

		kd->creators[low] = *cid;			/* struct copy */
		kd->dbkeys[low] = dbkey;
		kd->expire[low] = expire;

		ki->next_expire = MIN(ki->next_expire, expire);
	}

	kd->values++;
	ki->values++;

	dbmw_write(db_keydata, id, kd, sizeof *kd);

	if (GNET_PROPERTY(dht_storage_debug) > 2)
		g_debug("DHT STORE %s key %s now holds %d/%d value%s",
			&new_kd == kd ? "new" : "existing",
			kuid_to_hex_string(id), ki->values, MAX_VALUES, plural(ki->values));
}