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()); } }
/* * 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; }
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; }
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); } } }
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"); } }