chunk picker strategies

This commit is contained in:
Green Sky 2024-07-07 16:49:31 +02:00
parent 11dee5870c
commit bf1fa64973
No known key found for this signature in database
2 changed files with 113 additions and 14 deletions

View File

@ -8,6 +8,104 @@
#include <iostream> #include <iostream>
// TODO: move ps to own file
// picker strategies are generators
// gen returns true if a valid chunk was picked
// ps should be light weight and no persistant state
// ps produce an index only once
// simply scans from the beginning, requesting chunks in that order
struct PickerStrategySimpleFirst {
const BitSet& chunk_candidates;
const size_t total_chunks;
// TODO: optimize simple and start at first chunk we dont have
size_t i {0u};
PickerStrategySimpleFirst(
const BitSet& chunk_candidates_,
const size_t total_chunks_
) :
chunk_candidates(chunk_candidates_),
total_chunks(total_chunks_)
{}
bool gen(size_t& out_chunk_idx) {
for (; i < total_chunks && i < chunk_candidates.size_bits(); i++) {
if (chunk_candidates[i]) {
out_chunk_idx = i;
i++;
return true;
}
}
return false;
}
};
// chooses a random start position and then requests linearly from there
struct PickerStrategyRandom {
const BitSet& chunk_candidates;
const size_t total_chunks;
std::default_random_engine& rng;
size_t count {0u};
size_t i {rng()%total_chunks};
PickerStrategyRandom(
const BitSet& chunk_candidates_,
const size_t total_chunks_,
std::default_random_engine& rng_
) :
chunk_candidates(chunk_candidates_),
total_chunks(total_chunks_),
rng(rng_)
{}
bool gen(size_t& out_chunk_idx) {
for (; count < total_chunks; count++, i++) {
// wrap around
if (i >= total_chunks) {
i = i%total_chunks;
}
if (chunk_candidates[i]) {
out_chunk_idx = i;
count++;
i++;
return true;
}
}
return false;
}
};
// switches randomly between random and simple first
struct PickerStrategyRandomFirst {
PickerStrategyRandom psr;
PickerStrategySimpleFirst pssf;
std::bernoulli_distribution d{0.5f};
PickerStrategyRandomFirst(
const BitSet& chunk_candidates_,
const size_t total_chunks_,
std::default_random_engine& rng_
) :
psr(chunk_candidates_, total_chunks_, rng_),
pssf(chunk_candidates_, total_chunks_)
{}
bool gen(size_t& out_chunk_idx) {
if (d(psr.rng)) {
return psr.gen(out_chunk_idx);
} else {
return pssf.gen(out_chunk_idx);
}
}
};
void ChunkPicker::updateParticipation( void ChunkPicker::updateParticipation(
Contact3Handle c, Contact3Handle c,
@ -126,7 +224,6 @@ std::vector<ChunkPicker::ContentChunkR> ChunkPicker::updateChunkRequests(
// TODO: trim off round up to 8, since they are now always set // TODO: trim off round up to 8, since they are now always set
// now select (globaly) unrequested other have // now select (globaly) unrequested other have
// TODO: pick strategies
// TODO: how do we prioratize within a file? // TODO: how do we prioratize within a file?
// - first (walk from start (or readhead?)) // - first (walk from start (or readhead?))
// - random (choose random start pos and walk) // - random (choose random start pos and walk)
@ -135,18 +232,17 @@ std::vector<ChunkPicker::ContentChunkR> ChunkPicker::updateChunkRequests(
// maybe look into libtorrens deadline stuff // maybe look into libtorrens deadline stuff
// - arbitrary priority maps/functions (and combine with above in rations) // - arbitrary priority maps/functions (and combine with above in rations)
// simple, we use first //PickerStrategySimpleFirst ps(chunk_candidates, total_chunks);
// TODO: optimize simple and start at first chunk we dont have //PickerStrategyRandom ps(chunk_candidates, total_chunks, _rng);
for (size_t i = 0; i < total_chunks && req_ret.size() < num_requests && i < chunk_candidates.size_bits(); i++) { // TODO: configurable
if (!chunk_candidates[i]) { PickerStrategyRandomFirst ps(chunk_candidates, total_chunks, _rng);
continue; size_t out_chunk_idx {0};
} while (ps.gen(out_chunk_idx) && req_ret.size() < num_requests) {
// out_chunk_idx is a potential candidate we can request form peer
// i is a potential candidate we can request form peer
// - check against double requests // - check against double requests
if (std::find_if(req_ret.cbegin(), req_ret.cend(), [&](const ContentChunkR& x) -> bool { if (std::find_if(req_ret.cbegin(), req_ret.cend(), [&](const ContentChunkR& x) -> bool {
return x.object == o && x.chunk_index == i; return x.object == o && x.chunk_index == out_chunk_idx;
}) != req_ret.cend()) { }) != req_ret.cend()) {
// already in return array // already in return array
// how did we get here? should we fast exit? if simple-first strat, we would want to // how did we get here? should we fast exit? if simple-first strat, we would want to
@ -154,21 +250,21 @@ std::vector<ChunkPicker::ContentChunkR> ChunkPicker::updateChunkRequests(
} }
// - check against global requests (this might differ based on strat) // - check against global requests (this might differ based on strat)
if (requested_chunks.count(i) != 0) { if (requested_chunks.count(out_chunk_idx) != 0) {
continue; continue;
} }
// - we check against globally running transfers (this might differ based on strat) // - we check against globally running transfers (this might differ based on strat)
if (rt.containsChunk(o, i)) { if (rt.containsChunk(o, out_chunk_idx)) {
continue; continue;
} }
// if nothing else blocks this, add to ret // if nothing else blocks this, add to ret
req_ret.push_back(ContentChunkR{o, i}); req_ret.push_back(ContentChunkR{o, out_chunk_idx});
// TODO: move this after packet was sent successfully // TODO: move this after packet was sent successfully
// (move net in? hmm) // (move net in? hmm)
requested_chunks[i] = Components::FT1ChunkSHA1Requested::Entry{0.f, c}; requested_chunks[out_chunk_idx] = Components::FT1ChunkSHA1Requested::Entry{0.f, c};
} }
} }

View File

@ -12,6 +12,7 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <random>
//#include <solanaceae/ngc_ft1/ngcft1.hpp> //#include <solanaceae/ngc_ft1/ngcft1.hpp>
@ -24,6 +25,8 @@ struct ChunkPicker {
static constexpr size_t max_tf_info_requests {1}; static constexpr size_t max_tf_info_requests {1};
static constexpr size_t max_tf_chunk_requests {3}; static constexpr size_t max_tf_chunk_requests {3};
std::default_random_engine _rng{1337*17};
//// max outstanding requests //// max outstanding requests
//// TODO: should this include transfers? //// TODO: should this include transfers?
//static constexpr size_t max_open_info_requests {1}; //static constexpr size_t max_open_info_requests {1};