diff --git a/CMakeLists.txt b/CMakeLists.txt index e7d9a01..278ec5c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,9 @@ add_library(solanaceae_sha1_ngcft1 ./solanaceae/ngc_ft1_sha1/participation.hpp ./solanaceae/ngc_ft1_sha1/participation.cpp + ./solanaceae/ngc_ft1_sha1/re_announce_systems.hpp + ./solanaceae/ngc_ft1_sha1/re_announce_systems.cpp + ./solanaceae/ngc_ft1_sha1/chunk_picker_systems.hpp ./solanaceae/ngc_ft1_sha1/chunk_picker_systems.cpp diff --git a/solanaceae/ngc_ft1_sha1/components.cpp b/solanaceae/ngc_ft1_sha1/components.cpp index ba31d3a..26c6e82 100644 --- a/solanaceae/ngc_ft1_sha1/components.cpp +++ b/solanaceae/ngc_ft1_sha1/components.cpp @@ -25,6 +25,25 @@ bool FT1ChunkSHA1Cache::haveChunk(const SHA1Digest& hash) const { return false; } +void ReAnnounceTimer::set(const float new_timer) { + timer = new_timer; + last_max = new_timer; +} + +void ReAnnounceTimer::reset(void) { + if (last_max <= 0.01f) { + last_max = 1.f; + } + + last_max *= 2.f; + timer = last_max; +} + +void ReAnnounceTimer::lower(void) { + timer *= 0.1f; + last_max *= 0.1f; +} + void TransferStatsTally::Peer::trimSent(const float time_now) { while (recently_sent.size() > 4 && time_now - recently_sent.front().time_point > 1.f) { recently_sent.pop_front(); diff --git a/solanaceae/ngc_ft1_sha1/components.hpp b/solanaceae/ngc_ft1_sha1/components.hpp index ca81241..740a46c 100644 --- a/solanaceae/ngc_ft1_sha1/components.hpp +++ b/solanaceae/ngc_ft1_sha1/components.hpp @@ -75,6 +75,23 @@ namespace Components { float timer {0.f}; }; + struct AnnounceTargets { + entt::dense_set targets; + }; + + struct ReAnnounceTimer { + float timer {0.f}; + float last_max {0.f}; + + void set(const float new_timer); + + // exponential back-off + void reset(void); + + // on peer join to group + void lower(void); + }; + struct DownloadPriority { // download/retreival priority in comparison to other objects // not all backends implement this diff --git a/solanaceae/ngc_ft1_sha1/re_announce_systems.cpp b/solanaceae/ngc_ft1_sha1/re_announce_systems.cpp new file mode 100644 index 0000000..124baa0 --- /dev/null +++ b/solanaceae/ngc_ft1_sha1/re_announce_systems.cpp @@ -0,0 +1,83 @@ +#include "./re_announce_systems.hpp" + +#include "./components.hpp" +#include +#include +#include +#include +#include + +namespace Systems { + +void re_announce( + ObjectRegistry& os_reg, + Contact3Registry& cr, + NGCEXTEventProvider& neep, + const float delta +) { + std::vector to_remove; + os_reg.view().each([&os_reg, &cr, &neep, &to_remove, delta](Object ov, Components::ReAnnounceTimer& rat) { + ObjectHandle o{os_reg, ov}; + // if paused -> remove + if (o.all_of()) { + to_remove.push_back(ov); + return; + } + + // if not downloading or info incomplete -> remove + if (!o.all_of()) { + to_remove.push_back(ov); + assert(false && "transfer in broken state"); + return; + } + + if (o.get().have_all) { + // transfer done, we stop announcing + to_remove.push_back(ov); + return; + } + + + // update all timers + rat.timer -= delta; + + // send announces + if (rat.timer <= 0.f) { + rat.reset(); // exponential back-off + + std::vector announce_id; + const uint32_t file_kind = static_cast(NGCFT1_file_kind::HASH_SHA1_INFO); + for (size_t i = 0; i < sizeof(file_kind); i++) { + announce_id.push_back((file_kind>>(i*8)) & 0xff); + } + assert(o.all_of()); + const auto& info_hash = o.get().hash; + announce_id.insert(announce_id.cend(), info_hash.cbegin(), info_hash.cend()); + + for (const auto cv : o.get().targets) { + if (cr.all_of(cv)) { + // private ? + const auto [group_number, peer_number] = cr.get(cv); + neep.send_pc1_announce(group_number, peer_number, announce_id.data(), announce_id.size()); + } else if (cr.all_of(cv)) { + // public + const auto group_number = cr.get(cv).group_number; + neep.send_all_pc1_announce(group_number, announce_id.data(), announce_id.size()); + } else { + assert(false && "we dont know how to announce to this target"); + } + } + } + }); + + for (const auto ov : to_remove) { + os_reg.remove(ov); + // we keep the annouce target list around (if it exists) + // TODO: should we make the target list more generic? + } + + // TODO: how to handle unpause? +} + +} // Systems + diff --git a/solanaceae/ngc_ft1_sha1/re_announce_systems.hpp b/solanaceae/ngc_ft1_sha1/re_announce_systems.hpp new file mode 100644 index 0000000..46847f3 --- /dev/null +++ b/solanaceae/ngc_ft1_sha1/re_announce_systems.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include + +namespace Systems { + +void re_announce( + ObjectRegistry& os_reg, + Contact3Registry& cr, + NGCEXTEventProvider& neep, + const float delta +); + +} // Systems + diff --git a/solanaceae/ngc_ft1_sha1/sha1_ngcft1.cpp b/solanaceae/ngc_ft1_sha1/sha1_ngcft1.cpp index ab146f1..d4c0074 100644 --- a/solanaceae/ngc_ft1_sha1/sha1_ngcft1.cpp +++ b/solanaceae/ngc_ft1_sha1/sha1_ngcft1.cpp @@ -23,6 +23,7 @@ #include "./chunk_picker.hpp" #include "./participation.hpp" +#include "./re_announce_systems.hpp" #include "./chunk_picker_systems.hpp" #include "./transfer_stats_systems.hpp" @@ -289,6 +290,8 @@ float SHA1_NGCFT1::iterate(float delta) { } } + Systems::re_announce(_os.registry(), _cr, _neep, delta); + { // send out bitsets // currently 1 per tick if (!_queue_send_bitset.empty()) { @@ -531,33 +534,21 @@ bool SHA1_NGCFT1::onEvent(const Message::Events::MessageUpdated& e) { ce.emplace(std::move(file_impl)); - // announce we are participating + // queue announce we are participating // since this is the first time, we publicly announce to all if (e.e.all_of()) { const auto c_f = e.e.get().c; const auto c_t = e.e.get().c; - std::vector announce_id; - const uint32_t file_kind = static_cast(NGCFT1_file_kind::HASH_SHA1_INFO); - for (size_t i = 0; i < sizeof(file_kind); i++) { - announce_id.push_back((file_kind>>(i*8)) & 0xff); - } - assert(ce.all_of()); - const auto& info_hash = ce.get().hash; - announce_id.insert(announce_id.cend(), info_hash.cbegin(), info_hash.cend()); - if (_cr.all_of(c_t)) { // public - const auto group_number = _cr.get(c_t).group_number; - - _neep.send_all_pc1_announce(group_number, announce_id.data(), announce_id.size()); + ce.get_or_emplace().targets.emplace(c_t); } else if (_cr.all_of(c_f)) { // private ? - const auto [group_number, peer_number] = _cr.get(c_f); - - _neep.send_pc1_announce(group_number, peer_number, announce_id.data(), announce_id.size()); + ce.get_or_emplace().targets.emplace(c_f); } } + ce.get_or_emplace(0.1f, 60.f*(_rng()%5120) / 1024.f).timer = (_rng()%512) / 1024.f; ce.remove();