Пример #1
0
void mastermind_t::data::collect_info_loop_impl() {
	if (m_logger->verbosity() >= cocaine::logging::info) {
		auto current_remote = m_current_remote;
		std::ostringstream oss;
		oss << "libmastermind: collect_info_loop: begin; current host: ";
		if (current_remote.first.empty()) {
			oss << "none";
		} else {
			oss << current_remote.first << ':' << m_current_remote.second;
		}
		COCAINE_LOG_INFO(m_logger, "%s", oss.str().c_str());
	}

	auto beg_time = std::chrono::system_clock::now();

	{
		spent_time_printer_t helper("collect_namespaces_states", m_logger);
		collect_namespaces_states();
	}
#if 0
	{
		spent_time_printer_t helper("collect_cache_groups", m_logger);
		collect_cache_groups();
	}
#endif
	{
		spent_time_printer_t helper("collect_elliptics_remotes", m_logger);
		collect_elliptics_remotes();
	}

	cache_expire();
	generate_fake_caches();
	serialize();

	auto end_time = std::chrono::system_clock::now();

	if (m_logger->verbosity() >= cocaine::logging::info) {
		auto current_remote = m_current_remote;
		std::ostringstream oss;
		oss << "libmastermind: collect_info_loop: end; current host: ";
		if (current_remote.first.empty()) {
			oss << "none";
		} else {
			oss << current_remote.first << ':' << m_current_remote.second;
		}
		oss
			<< "; spent time: "
			<< std::chrono::duration_cast<std::chrono::milliseconds>(end_time - beg_time).count()
			<< " milliseconds";
		COCAINE_LOG_INFO(m_logger, "%s", oss.str().c_str());
	}
}
Пример #2
0
/*
 *	Do caching checks.  Since we can update ANY VP list, we do
 *	exactly the same thing for all sections (autz / auth / etc.)
 *
 *	If you want to cache something different in different sections,
 *	configure another cache module.
 */
static rlm_rcode_t CC_HINT(nonnull) mod_cache_it(void *instance, REQUEST *request)
{
	rlm_cache_entry_t *c;
	rlm_cache_t *inst = instance;

	rlm_cache_handle_t *handle;

	vp_cursor_t cursor;
	VALUE_PAIR *vp;
	char buffer[1024];
	rlm_rcode_t rcode;

	int ttl = inst->ttl;

	if (radius_xlat(buffer, sizeof(buffer), request, inst->key, NULL, NULL) < 0) return RLM_MODULE_FAIL;

	if (buffer[0] == '\0') {
		REDEBUG("Zero length key string is invalid");
		return RLM_MODULE_INVALID;
	}

	if (cache_acquire(&handle, inst, request) < 0) return RLM_MODULE_FAIL;

	rcode = cache_find(&c, inst, request, &handle, buffer);
	if (rcode == RLM_MODULE_FAIL) goto finish;
	rad_assert(handle);

	/*
	 *	If Cache-Status-Only == yes, only return whether we found a
	 *	valid cache entry
	 */
	vp = pairfind(request->config_items, PW_CACHE_STATUS_ONLY, 0, TAG_ANY);
	if (vp && vp->vp_integer) {
		rcode = c ? RLM_MODULE_OK:
			    RLM_MODULE_NOTFOUND;
		goto finish;
	}

	/*
	 *	Update the expiry time based on the TTL.
	 *	A TTL of 0 means "delete from the cache".
	 *	A TTL < 0 means "delete from the cache and recreate the entry".
	 */
	vp = pairfind(request->config_items, PW_CACHE_TTL, 0, TAG_ANY);
	if (vp) ttl = vp->vp_signed;

	/*
	 *	If there's no existing cache entry, go and create a new one.
	 */
	if (!c) {
		if (ttl <= 0) ttl = inst->ttl;
		goto insert;
	}

	/*
	 *	Expire the entry if requested to do so
	 */
	if (vp) {
		if (ttl == 0) {
			cache_expire(inst, request, &handle, &c);
			RDEBUG("Forcing expiry of entry");
			rcode = RLM_MODULE_OK;
			goto finish;
		}

		if (ttl < 0) {
			RDEBUG("Forcing expiry of existing entry");
			cache_expire(inst, request, &handle, &c);
			ttl *= -1;
			goto insert;
		}
		c->expires = request->timestamp + ttl;
		RDEBUG("Setting TTL to %d", ttl);
	}

	/*
	 *	Cache entry was still valid, so we merge it into the request
	 *	and return. No need to add a new entry.
	 */
	cache_merge(inst, request, c);
	rcode = RLM_MODULE_UPDATED;

	goto finish;

insert:
	/*
	 *	If Cache-Read-Only == yes, then we only allow already cached entries
	 *	to be merged into the request
	 */
	vp = pairfind(request->config_items, PW_CACHE_READ_ONLY, 0, TAG_ANY);
	if (vp && vp->vp_integer) {
		rcode = RLM_MODULE_NOTFOUND;
		goto finish;
	}

	/*
	 *	Create a new entry.
	 */
	rcode = cache_insert(inst, request, &handle, buffer, ttl);
	rad_assert(handle);

finish:
	cache_free(inst, &c);
	cache_release(inst, request, &handle);

	/*
	 *	Clear control attributes
	 */
	for (vp = fr_cursor_init(&cursor, &request->config_items);
	     vp;
	     vp = fr_cursor_next(&cursor)) {
		if (vp->da->vendor == 0) switch (vp->da->attr) {
		case PW_CACHE_TTL:
		case PW_CACHE_STATUS_ONLY:
		case PW_CACHE_READ_ONLY:
		case PW_CACHE_MERGE:
			vp = fr_cursor_remove(&cursor);
			talloc_free(vp);
			break;
		}
	}

	return rcode;
}
Пример #3
0
static rlm_rcode_t mod_cache_it(void *instance, UNUSED void *thread, REQUEST *request)
{
	rlm_cache_entry_t	*c = NULL;
	rlm_cache_t const	*inst = instance;

	rlm_cache_handle_t	*handle;

	fr_cursor_t		cursor;
	VALUE_PAIR		*vp;

	bool			merge = true, insert = true, expire = false, set_ttl = false;
	int			exists = -1;

	uint8_t			buffer[1024];
	uint8_t const		*key;
	ssize_t			key_len;
	rlm_rcode_t		rcode = RLM_MODULE_NOOP;

	int			ttl = inst->config.ttl;

	key_len = tmpl_expand((char const **)&key, (char *)buffer, sizeof(buffer),
			      request, inst->config.key, NULL, NULL);
	if (key_len < 0) return RLM_MODULE_FAIL;

	if (key_len == 0) {
		REDEBUG("Zero length key string is invalid");
		return RLM_MODULE_INVALID;
	}

	/*
	 *	If Cache-Status-Only == yes, only return whether we found a
	 *	valid cache entry
	 */
	vp = fr_pair_find_by_da(request->control, attr_cache_status_only, TAG_ANY);
	if (vp && vp->vp_bool) {
		RINDENT();
		RDEBUG3("status-only: yes");
		REXDENT();

		if (cache_acquire(&handle, inst, request) < 0) return RLM_MODULE_FAIL;

		rcode = cache_find(&c, inst, request, &handle, key, key_len);
		if (rcode == RLM_MODULE_FAIL) goto finish;
		rad_assert(!inst->driver->acquire || handle);

		rcode = c ? RLM_MODULE_OK:
			    RLM_MODULE_NOTFOUND;
		goto finish;
	}

	/*
	 *	Figure out what operation we're doing
	 */
	vp = fr_pair_find_by_da(request->control, attr_cache_allow_merge, TAG_ANY);
	if (vp) merge = vp->vp_bool;

	vp = fr_pair_find_by_da(request->control, attr_cache_allow_insert, TAG_ANY);
	if (vp) insert = vp->vp_bool;

	vp = fr_pair_find_by_da(request->control, attr_cache_ttl, TAG_ANY);
	if (vp) {
		if (vp->vp_int32 == 0) {
			expire = true;
		} else if (vp->vp_int32 < 0) {
			expire = true;
			ttl = -(vp->vp_int32);
		/* Updating the TTL */
		} else {
			set_ttl = true;
			ttl = vp->vp_int32;
		}
	}

	RINDENT();
	RDEBUG3("merge  : %s", merge ? "yes" : "no");
	RDEBUG3("insert : %s", insert ? "yes" : "no");
	RDEBUG3("expire : %s", expire ? "yes" : "no");
	RDEBUG3("ttl    : %i", ttl);
	REXDENT();
	if (cache_acquire(&handle, inst, request) < 0) return RLM_MODULE_FAIL;

	/*
	 *	Retrieve the cache entry and merge it with the current request
	 *	recording whether the entry existed.
	 */
	if (merge) {
		rcode = cache_find(&c, inst, request, &handle, key, key_len);
		switch (rcode) {
		case RLM_MODULE_FAIL:
			goto finish;

		case RLM_MODULE_OK:
			rcode = cache_merge(inst, request, c);
			exists = 1;
			break;

		case RLM_MODULE_NOTFOUND:
			rcode = RLM_MODULE_NOTFOUND;
			exists = 0;
			break;

		default:
			rad_assert(0);
		}
		rad_assert(!inst->driver->acquire || handle);
	}

	/*
	 *	Expire the entry if told to, and we either don't know whether
	 *	it exists, or we know it does.
	 *
	 *	We only expire if we're not inserting, as driver insert methods
	 *	should perform upserts.
	 */
	if (expire && ((exists == -1) || (exists == 1))) {
		if (!insert) {
			rad_assert(!set_ttl);
			switch (cache_expire(inst, request, &handle, key, key_len)) {
			case RLM_MODULE_FAIL:
				rcode = RLM_MODULE_FAIL;
				goto finish;

			case RLM_MODULE_OK:
				if (rcode == RLM_MODULE_NOOP) rcode = RLM_MODULE_OK;
				break;

			case RLM_MODULE_NOTFOUND:
				if (rcode == RLM_MODULE_NOOP) rcode = RLM_MODULE_NOTFOUND;
				break;

			default:
				rad_assert(0);
				break;
			}
			/* If it previously existed, it doesn't now */
		}
		/* Otherwise use insert to overwrite */
		exists = 0;
	}

	/*
	 *	If we still don't know whether it exists or not
	 *	and we need to do an insert or set_ttl operation
	 *	determine that now.
	 */
	if ((exists < 0) && (insert || set_ttl)) {
		switch (cache_find(&c, inst, request, &handle, key, key_len)) {
		case RLM_MODULE_FAIL:
			rcode = RLM_MODULE_FAIL;
			goto finish;

		case RLM_MODULE_OK:
			exists = 1;
			if (rcode != RLM_MODULE_UPDATED) rcode = RLM_MODULE_OK;
			break;

		case RLM_MODULE_NOTFOUND:
			exists = 0;
			break;

		default:
			rad_assert(0);
		}
		rad_assert(!inst->driver->acquire || handle);
	}

	/*
	 *	We can only alter the TTL on an entry if it exists.
	 */
	if (set_ttl && (exists == 1)) {
		rad_assert(c);

		c->expires = request->packet->timestamp.tv_sec + ttl;

		switch (cache_set_ttl(inst, request, &handle, c)) {
		case RLM_MODULE_FAIL:
			rcode = RLM_MODULE_FAIL;
			goto finish;

		case RLM_MODULE_NOTFOUND:
		case RLM_MODULE_OK:
			if (rcode != RLM_MODULE_UPDATED) rcode = RLM_MODULE_OK;
			goto finish;

		default:
			rad_assert(0);
		}
	}

	/*
	 *	Inserts are upserts, so we don't care about the
	 *	entry state, just that we're not meant to be
	 *	setting the TTL, which precludes performing an
	 *	insert.
	 */
	if (insert && (exists == 0)) {
		switch (cache_insert(inst, request, &handle, key, key_len, ttl)) {
		case RLM_MODULE_FAIL:
			rcode = RLM_MODULE_FAIL;
			goto finish;

		case RLM_MODULE_OK:
			if (rcode != RLM_MODULE_UPDATED) rcode = RLM_MODULE_OK;
			break;

		case RLM_MODULE_UPDATED:
			rcode = RLM_MODULE_UPDATED;
			break;

		default:
			rad_assert(0);
		}
		rad_assert(!inst->driver->acquire || handle);
		goto finish;
	}


finish:
	cache_free(inst, &c);
	cache_release(inst, request, &handle);

	/*
	 *	Clear control attributes
	 */
	for (vp = fr_cursor_init(&cursor, &request->control);
	     vp;
	     vp = fr_cursor_next(&cursor)) {
	     again:
		if (!fr_dict_attr_is_top_level(vp->da)) continue;

		switch (vp->da->attr) {
		case FR_CACHE_TTL:
		case FR_CACHE_STATUS_ONLY:
		case FR_CACHE_ALLOW_MERGE:
		case FR_CACHE_ALLOW_INSERT:
		case FR_CACHE_MERGE_NEW:
			RDEBUG2("Removing &control:%s", vp->da->name);
			vp = fr_cursor_remove(&cursor);
			talloc_free(vp);
			vp = fr_cursor_current(&cursor);
			if (!vp) break;
			goto again;
		}
	}

	return rcode;
}
Пример #4
0
void p2p_cron(void)
{
	/* Tick Tock */
	gettimeofday(&_main->p2p->time_now, NULL);

	if (nbhd_is_empty()) {

		/* Bootstrap PING */
		if (_main->p2p->time_now.tv_sec > _main->p2p->time_restart) {
			p2p_bootstrap();
			time_add_1_min_approx(&_main->p2p->time_restart);
		}

	} else {

		/* Create a new token every ~5 minutes */
		if (_main->p2p->time_now.tv_sec > _main->p2p->time_token) {
			tkn_put();
			time_add_5_min_approx(&_main->p2p->time_token);
		}

		/* Expire objects. Run once a minute. */
		if (_main->p2p->time_now.tv_sec > _main->p2p->time_expire) {
			tdb_expire(_main->p2p->time_now.tv_sec);
			nbhd_expire(_main->p2p->time_now.tv_sec);
			val_expire(_main->p2p->time_now.tv_sec);
			tkn_expire(_main->p2p->time_now.tv_sec);
			cache_expire(_main->p2p->time_now.tv_sec);
			time_add_1_min_approx(&_main->p2p->time_expire);
		}

		/* Split buckets. Evolve neighbourhood. Run often to evolve
		 * neighbourhood fast. */
		if (_main->p2p->time_now.tv_sec > _main->p2p->time_split) {
			nbhd_split(_main->conf->node_id, TRUE);
			time_add_5_sec_approx(&_main->p2p->time_split);
		}

		/* Find nodes every ~5 minutes. */
		if (_main->p2p->time_now.tv_sec > _main->p2p->time_find) {
			p2p_cron_find_myself();
			time_add_5_sec_approx(&_main->p2p->time_find);
		}

		/* Find random node every ~5 minutes for maintainance reasons. */
		if (_main->p2p->time_now.tv_sec > _main->p2p->time_maintainance) {
			p2p_cron_find_random();
			time_add_5_sec_approx(&_main->p2p->time_maintainance);
		}

		/* Announce my hostname every ~5 minutes. This includes a full search
		 * to get the needed tokens first. */
		if (_main->p2p->time_now.tv_sec >
		    _main->p2p->time_announce_host) {
			p2p_cron_lookup_all();
			time_add_5_sec_approx(&_main->p2p->time_announce_host);
		}

		/* Ping all nodes every ~5 minutes. */
		if (_main->p2p->time_now.tv_sec > _main->p2p->time_ping) {
			p2p_cron_ping();
			time_add_5_sec_approx(&_main->p2p->time_ping);
		}

		/* Renew cached requests */
		if (_main->p2p->time_now.tv_sec > _main->p2p->time_cache) {
			cache_renew(_main->p2p->time_now.tv_sec);
			time_add_5_sec_approx(&_main->p2p->time_cache);
		}
	}

	/* Try to register multicast address until it works. */
	if (_main->udp->multicast == FALSE) {
		if (_main->p2p->time_now.tv_sec > _main->p2p->time_multicast) {
			udp_multicast(_main->udp, multicast_enabled,
				      multicast_start);
			time_add_5_min_approx(&_main->p2p->time_multicast);
		}
	}
}
Пример #5
0
void mastermind_t::data::deserialize() {
	std::string file;
	{
		std::ifstream input(m_cache_path.c_str());
		if (input.is_open() == false) {
			return;
		}
		typedef std::istreambuf_iterator<char> it_t;
		file.assign(it_t(input), it_t());
	}

	try {
		msgpack::unpacked msg;
		msgpack::unpack(&msg, file.data(), file.size());
		msgpack::object object = msg.get();

		kora::dynamic_t raw_cache;

		cocaine::io::type_traits<kora::dynamic_t>::unpack(object, raw_cache);

		auto &raw_cache_object = raw_cache.as_object();

#define TRY_UNPACK_CACHE(cache) \
		do { \
			try { \
				cache.set(cache##_t::cache_type(raw_cache_object[#cache].as_object() \
							, std::bind(&data::create_##cache, this \
								, std::placeholders::_1, std::placeholders::_2) \
							, #cache)); \
			} catch (const std::exception &ex) { \
				COCAINE_LOG_ERROR(m_logger, "libmastermind: cannot deserialize cache %s: %s" \
						, #cache, ex.what()); \
			} \
		} while (false)

#if 0
		TRY_UNPACK_CACHE(cache_groups);
#endif
		TRY_UNPACK_CACHE(elliptics_remotes);

#undef TRY_UNPACK_CACHE

		{
			const auto &raw_namespaces_states = raw_cache_object["namespaces_states"];
			const auto &raw_namespaces_states_object = raw_namespaces_states.as_object();

			for (auto it = raw_namespaces_states_object.begin()
					, end = raw_namespaces_states_object.end();
					it != end; ++it) {
				const auto &name = it->first;

				try {
					namespaces_states.set(name, namespaces_states_t::cache_type(
								it->second.as_object()
								, std::bind(&data::create_namespaces_states, this
									, std::placeholders::_1, std::placeholders::_2)
								, name));
				} catch (const std::exception &ex) {
					COCAINE_LOG_ERROR(m_logger
							, "libmastermind: cannot update namespace_state for %s: %s"
							, name.c_str(), ex.what());
				}
			}
		}

		cache_expire();
		generate_fake_caches();
	} catch (const std::exception &ex) {
		COCAINE_LOG_WARNING(m_logger
				, "libmastermind: cannot deserialize libmastermind cache: %s"
				, ex.what());
	} catch (...) {
		COCAINE_LOG_WARNING(m_logger
				, "libmastermind: cannot deserialize libmastermind cache");
	}
}