Classes for data strage, flooding
This commit is contained in:
parent
143cff86f5
commit
c0f1c55e03
4 changed files with 311 additions and 0 deletions
110
dataStore.cpp
Normal file
110
dataStore.cpp
Normal file
|
@ -0,0 +1,110 @@
|
|||
/***************************************************************************
|
||||
* By Théophile Bastian, 2017
|
||||
* M1 Network course project at ENS Cachan, Juliusz Chroboczek.
|
||||
* License: WTFPL v2 <http://www.wtfpl.net/>
|
||||
**************************************************************************/
|
||||
|
||||
#include "dataStore.h"
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
DataStore::DataStore(Protocol* proto) : proto(proto)
|
||||
{}
|
||||
|
||||
DataStore::~DataStore() {
|
||||
}
|
||||
|
||||
void DataStore::update() {
|
||||
while(!timeEvents.empty()) {
|
||||
const TimeEvent& evt = timeEvents.top();
|
||||
if(evt.time > time(NULL)) // We're done for now.
|
||||
break;
|
||||
|
||||
timeEvents.pop();
|
||||
switch(evt.type) {
|
||||
case EV_REPUBLISH:
|
||||
handleRepublish(evt.id);
|
||||
break;
|
||||
|
||||
case EV_EXPIRES:
|
||||
handleExpire(evt.id, evt.seqno);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DataStore::addData(Bytes pck, u32 seqno, u64 id, bool mine) {
|
||||
if(curSeqno.find(id) != curSeqno.end() && curSeqno[id] >= seqno)
|
||||
return;
|
||||
|
||||
data[id] = Data(pck, mine);
|
||||
curSeqno[id] = seqno;
|
||||
|
||||
if(mine) {
|
||||
timeEvents.push(TimeEvent(
|
||||
time(NULL) + csts::TIME_REPUBLISH_DATA,
|
||||
seqno, id, EV_REPUBLISH));
|
||||
|
||||
}
|
||||
else {
|
||||
timeEvents.push(TimeEvent(
|
||||
time(NULL) + csts::TIMEOUT_DATA,
|
||||
seqno, id, EV_EXPIRES));
|
||||
// If it is not renewed, it will expire.
|
||||
}
|
||||
|
||||
recvTime[id] = time(NULL);
|
||||
fprintf(stderr, "[INFO] Storing data %lX (%u)\n", id, seqno);
|
||||
|
||||
handleFlood(id);
|
||||
}
|
||||
|
||||
ssize_t DataStore::dataSize(u64 id) {
|
||||
if(data.find(id) == data.end())
|
||||
return -1;
|
||||
return data[id].data.size();
|
||||
}
|
||||
|
||||
ssize_t DataStore::readData(u64 id, char* buffer, size_t size) {
|
||||
if(data.find(id) == data.end())
|
||||
return -1;
|
||||
ssize_t len = min((ssize_t)size, dataSize(id));
|
||||
data[id].data.writeToBuffer(buffer, size);
|
||||
return len;
|
||||
}
|
||||
|
||||
void DataStore::ids(std::vector<u64>& out) {
|
||||
for(auto& dat : data)
|
||||
out.push_back(dat.first);
|
||||
}
|
||||
|
||||
void DataStore::setFlooded(u64 id) {
|
||||
toFlood_.erase(id);
|
||||
}
|
||||
|
||||
void DataStore::handleExpire(u64 id, u32 seqno) {
|
||||
if(seqno < curSeqno[id])
|
||||
return; // Was updated in time
|
||||
|
||||
cleanData(id);
|
||||
}
|
||||
|
||||
void DataStore::handleRepublish(u64 id) {
|
||||
if(data.find(id) == data.end() || !data[id].isMine)
|
||||
return;
|
||||
|
||||
curSeqno[id] = time(NULL);
|
||||
handleFlood(id);
|
||||
}
|
||||
|
||||
void DataStore::handleFlood(u64 id) {
|
||||
toFlood_.insert(id);
|
||||
}
|
||||
|
||||
void DataStore::cleanData(u64 id) {
|
||||
curSeqno.erase(id);
|
||||
recvTime.erase(id);
|
||||
data.erase(id); // Deletes the Bytes as well
|
||||
}
|
||||
|
98
dataStore.h
Normal file
98
dataStore.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
/***************************************************************************
|
||||
* By Théophile Bastian, 2017
|
||||
* M1 Network course project at ENS Cachan, Juliusz Chroboczek.
|
||||
* License: WTFPL v2 <http://www.wtfpl.net/>
|
||||
**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
#include "data.h"
|
||||
#include "nw_constants.h"
|
||||
#include "protocol.h"
|
||||
#include "Bytes.h"
|
||||
|
||||
class DataStore {
|
||||
public:
|
||||
DataStore(Protocol* proto);
|
||||
~DataStore();
|
||||
|
||||
void update();
|
||||
/** Performs bookkeeping actions. Sends packets. This function should
|
||||
* be called often enough.
|
||||
*/
|
||||
|
||||
void addData(Bytes pck, u32 seqno, u64 id, bool mine=false);
|
||||
/** Adds a data in the data storage. If `mine` is `true`, the current
|
||||
* node considers itself responsible for the data and will republish
|
||||
* it when needed.
|
||||
*/
|
||||
|
||||
ssize_t dataSize(u64 id);
|
||||
/** Gets the size of the data with id `id`. Returns -1 if there is no
|
||||
* such data stored.
|
||||
*/
|
||||
|
||||
ssize_t readData(u64 id, char* buffer, size_t size);
|
||||
/** Fills `buffer` with the data of the given `id`.
|
||||
* If the data does not exist, returs -1; else, returns the length of
|
||||
* data actually retrieved.
|
||||
*/
|
||||
|
||||
const Bytes& operator[](u64 id) {
|
||||
return data[id].data;
|
||||
}
|
||||
|
||||
u32 getSeqno(u64 id) const { return curSeqno.at(id); }
|
||||
|
||||
void ids(std::vector<u64>& out);
|
||||
/** Fills `out` with the IDs of the stored data. */
|
||||
|
||||
const std::set<u64> toFlood() const { return toFlood_; }
|
||||
/** Returns a list of data IDs that should be flooded. */
|
||||
|
||||
void setFlooded(u64 id);
|
||||
/** Marks a data as flooded */
|
||||
|
||||
private: //meth
|
||||
void handleExpire(u64 id, u32 seqno);
|
||||
void handleRepublish(u64 id);
|
||||
void handleFlood(u64 id);
|
||||
|
||||
void cleanData(u64 id);
|
||||
|
||||
private:
|
||||
enum EvType {
|
||||
EV_REPUBLISH, EV_EXPIRES
|
||||
};
|
||||
struct TimeEvent {
|
||||
TimeEvent(time_t time, u32 seqno, u64 id, EvType type) :
|
||||
time(time), seqno(seqno), id(id), type(type) {}
|
||||
time_t time;
|
||||
u32 seqno;
|
||||
u64 id;
|
||||
EvType type;
|
||||
|
||||
bool operator<(const TimeEvent& e) const {
|
||||
return time > e.time; // Max-priority queue
|
||||
}
|
||||
};
|
||||
|
||||
struct Data {
|
||||
Data() : data(), isMine(false) {}
|
||||
Data(Bytes b) : data(b), isMine(false) {}
|
||||
Data(Bytes b, bool mine) : data(b), isMine(mine) {}
|
||||
Bytes data;
|
||||
bool isMine;
|
||||
};
|
||||
|
||||
std::priority_queue<TimeEvent> timeEvents;
|
||||
Protocol* proto;
|
||||
std::unordered_map<u64, Data> data;
|
||||
std::unordered_map<u64, u32> curSeqno;
|
||||
std::unordered_map<u64, time_t> recvTime;
|
||||
|
||||
std::set<u64> toFlood_;
|
||||
};
|
||||
|
54
flooder.cpp
Normal file
54
flooder.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
/***************************************************************************
|
||||
* By Théophile Bastian, 2017
|
||||
* M1 Network course project at ENS Cachan, Juliusz Chroboczek.
|
||||
* License: WTFPL v2 <http://www.wtfpl.net/>
|
||||
**************************************************************************/
|
||||
|
||||
#include "flooder.h"
|
||||
|
||||
Flooder::Flooder(const Bytes& data, u64 datId, u32 seqno, Protocol* proto,
|
||||
const std::list<Neighbour>& peers) :
|
||||
data(data), datId(datId), seqno(seqno), proto(proto)
|
||||
{
|
||||
fprintf(stderr, "[DBG] Created flooder for %lX (%u)\n", datId, seqno);
|
||||
for(auto it=peers.begin(); it != peers.end(); ++it) {
|
||||
triesCount[it->id] = 0;
|
||||
toFlood.push(FloodEvt(time(NULL), it->id));
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void Flooder::update() {
|
||||
while(!toFlood.empty()) {
|
||||
const FloodEvt& evt = toFlood.top();
|
||||
if(evt.time > time(NULL))
|
||||
break;
|
||||
toFlood.pop();
|
||||
|
||||
if(triesCount[evt.id] > csts::FLOOD_RETRIES) {
|
||||
fprintf(stderr, "[WARNING] Could not flood to %lX: no IHave.\n",
|
||||
evt.id);
|
||||
continue;
|
||||
}
|
||||
else if(triesCount[evt.id] < 0) {
|
||||
fprintf(stderr, "[DBG] Got your IHave, %lX!\n", evt.id);
|
||||
continue; // IHave received
|
||||
}
|
||||
|
||||
sendTo(evt.id);
|
||||
triesCount[evt.id]++;
|
||||
toFlood.push(FloodEvt(time(NULL) + csts::TIME_RESEND_FLOOD, evt.id));
|
||||
}
|
||||
}
|
||||
|
||||
void Flooder::gotIHave(u64 id, u32 withSeqno) {
|
||||
if(seqno > withSeqno)
|
||||
return;
|
||||
|
||||
triesCount[id] = -1;
|
||||
}
|
||||
|
||||
void Flooder::sendTo(u64 id) {
|
||||
proto->sendData(id, data, seqno, datId);
|
||||
}
|
||||
|
49
flooder.h
Normal file
49
flooder.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/***************************************************************************
|
||||
* By Théophile Bastian, 2017
|
||||
* M1 Network course project at ENS Cachan, Juliusz Chroboczek.
|
||||
* License: WTFPL v2 <http://www.wtfpl.net/>
|
||||
**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ctime>
|
||||
#include <queue>
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
#include "data.h"
|
||||
#include "nw_constants.h"
|
||||
#include "protocol.h"
|
||||
|
||||
class Flooder {
|
||||
public:
|
||||
Flooder(const Bytes& data, u64 datId, u32 seqno, Protocol* proto,
|
||||
const std::list<Neighbour>& peers);
|
||||
|
||||
void update();
|
||||
/** Call often enough (ie ~1s) */
|
||||
|
||||
void gotIHave(u64 id, u32 withSeqno);
|
||||
/** Acknoledges the reception of the resource by peer `id`. */
|
||||
|
||||
bool done() const { return toFlood.empty(); }
|
||||
|
||||
private: //meth
|
||||
void sendTo(u64 id);
|
||||
|
||||
private:
|
||||
struct FloodEvt {
|
||||
FloodEvt(time_t time, u64 id) : time(time), id(id) {}
|
||||
time_t time;
|
||||
u64 id;
|
||||
bool operator<(const FloodEvt& e) const {
|
||||
return time > e.time; // Max priority queue.
|
||||
}
|
||||
};
|
||||
std::unordered_map<u64, int> triesCount;
|
||||
std::priority_queue<FloodEvt> toFlood;
|
||||
Bytes data;
|
||||
u64 datId;
|
||||
u32 seqno;
|
||||
Protocol* proto;
|
||||
};
|
||||
|
Loading…
Reference in a new issue