mirror of https://github.com/BOINC/boinc.git
- client: on network_available() GUI RPC,
clear project-level upload and download backoffs, as well as RPC and individual xfer backoffs. This was an oversight. svn path=/trunk/boinc/; revision=24621
This commit is contained in:
parent
b7962e25b0
commit
5e671e4230
|
@ -8546,3 +8546,16 @@ Charlie 19 Nov 2011
|
||||||
|
|
||||||
clientgui/
|
clientgui/
|
||||||
sg_ProjectPanel.cpp
|
sg_ProjectPanel.cpp
|
||||||
|
|
||||||
|
David 20 Nov 2011
|
||||||
|
- client: on network_available() GUI RPC,
|
||||||
|
clear project-level upload and download backoffs,
|
||||||
|
as well as RPC and individual xfer backoffs.
|
||||||
|
This was an oversight.
|
||||||
|
|
||||||
|
client/
|
||||||
|
client_types.h
|
||||||
|
net_stats.cpp
|
||||||
|
ssim/
|
||||||
|
ssim.cpp
|
||||||
|
makefile
|
||||||
|
|
|
@ -198,6 +198,13 @@ struct FILE_XFER_BACKOFF {
|
||||||
file_xfer_failures = 0;
|
file_xfer_failures = 0;
|
||||||
next_xfer_time = 0;
|
next_xfer_time = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clear backoff but maintain failure count;
|
||||||
|
// called when network becomes available
|
||||||
|
//
|
||||||
|
void clear_temporary() {
|
||||||
|
next_xfer_time = 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// statistics at a specific day
|
// statistics at a specific day
|
||||||
|
|
|
@ -172,6 +172,8 @@ void NET_STATUS::network_available() {
|
||||||
for (i=0; i<gstate.projects.size(); i++) {
|
for (i=0; i<gstate.projects.size(); i++) {
|
||||||
PROJECT* p = gstate.projects[i];
|
PROJECT* p = gstate.projects[i];
|
||||||
p->min_rpc_time = 0;
|
p->min_rpc_time = 0;
|
||||||
|
p->upload_backoff.clear_temporary();
|
||||||
|
p->download_backoff.clear_temporary();
|
||||||
}
|
}
|
||||||
|
|
||||||
// tell active tasks that network is available (for Folding@home)
|
// tell active tasks that network is available (for Folding@home)
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
ssim: ssim.cpp des.h
|
ssim: ssim.cpp des.h
|
||||||
g++ -g -o ssim ssim.cpp
|
g++ -g -Wall -o ssim ssim.cpp
|
||||||
|
|
206
ssim/ssim.cpp
206
ssim/ssim.cpp
|
@ -44,17 +44,17 @@
|
||||||
// The bottom-level data units ("chunks") are stored on hosts,
|
// The bottom-level data units ("chunks") are stored on hosts,
|
||||||
// with R-fold replication
|
// with R-fold replication
|
||||||
|
|
||||||
#define ENCODING_N 10
|
#define ENCODING_N 4
|
||||||
#define ENCODING_K 5
|
#define ENCODING_K 2
|
||||||
#define ENCODING_M 15
|
#define ENCODING_M 6
|
||||||
#define ENCODING_LEVELS 1
|
#define ENCODING_LEVELS 1
|
||||||
#define REPLICATION_LEVEL 2
|
#define REPLICATION_LEVEL 1
|
||||||
|
|
||||||
// When we need to reconstruct an encoded unit on the server,
|
// When we need to reconstruct an encoded unit on the server,
|
||||||
// we try to upload N_UPLOAD subunits,
|
// we try to upload N_UPLOAD subunits,
|
||||||
// where N <= N_UPLOAD <= M
|
// where N <= N_UPLOAD <= M
|
||||||
|
|
||||||
#define N_UPLOAD 12
|
#define N_UPLOAD 5
|
||||||
|
|
||||||
// Terminology:
|
// Terminology:
|
||||||
//
|
//
|
||||||
|
@ -62,7 +62,10 @@
|
||||||
// An encoded data unit is "present_on_server" if at least N
|
// An encoded data unit is "present_on_server" if at least N
|
||||||
// of its subunits are present_on_server (recursive definition).
|
// of its subunits are present_on_server (recursive definition).
|
||||||
|
|
||||||
// A chunk is "recoverable" if it is present on at least 1 host.
|
// A data unit is "recoverable" if it can be reconstruct on the server,
|
||||||
|
// based on current state.
|
||||||
|
// A chunk is "recoverable" if it is assigned at least 1 host.
|
||||||
|
// (if it is downloading, it's still present on the server)
|
||||||
// An encoded data unit is "recoverable" if at least N
|
// An encoded data unit is "recoverable" if at least N
|
||||||
// of its subunits are recoverable.
|
// of its subunits are recoverable.
|
||||||
|
|
||||||
|
@ -110,28 +113,32 @@ struct CHUNK;
|
||||||
struct META_CHUNK;
|
struct META_CHUNK;
|
||||||
struct DFILE;
|
struct DFILE;
|
||||||
struct HOST;
|
struct HOST;
|
||||||
|
set<HOST*> hosts;
|
||||||
|
|
||||||
struct CHUNK_ON_HOST : public EVENT {
|
struct CHUNK_ON_HOST : public EVENT {
|
||||||
HOST* host;
|
HOST* host;
|
||||||
CHUNK* chunk;
|
CHUNK* chunk;
|
||||||
|
char name[256];
|
||||||
bool present_on_host;
|
bool present_on_host;
|
||||||
bool transfer_in_progress; // upload if present_on_host, else download
|
bool transfer_in_progress; // upload if present_on_host, else download
|
||||||
virtual void handle();
|
virtual void handle();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int next_host_id=0;
|
||||||
struct HOST : public EVENT {
|
struct HOST : public EVENT {
|
||||||
|
int id;
|
||||||
set<CHUNK_ON_HOST*> chunks;
|
set<CHUNK_ON_HOST*> chunks;
|
||||||
virtual void handle();
|
virtual void handle();
|
||||||
|
HOST() {
|
||||||
|
t = sim.now + ran_exp(HOST_LIFE_MEAN);
|
||||||
|
id = next_host_id++;
|
||||||
|
hosts.insert(this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
set<HOST*> hosts;
|
|
||||||
|
|
||||||
struct HOST_ARRIVAL : public EVENT {
|
struct HOST_ARRIVAL : public EVENT {
|
||||||
virtual void handle() {
|
virtual void handle() {
|
||||||
HOST* h = new HOST;
|
sim.insert(new HOST);
|
||||||
h->t = t + ran_exp(HOST_LIFE_MEAN);
|
|
||||||
hosts.insert(h);
|
|
||||||
sim.insert(h);
|
|
||||||
t += ran_exp(86400./HOSTS_PER_DAY);
|
t += ran_exp(86400./HOSTS_PER_DAY);
|
||||||
sim.insert(this);
|
sim.insert(this);
|
||||||
}
|
}
|
||||||
|
@ -139,22 +146,28 @@ struct HOST_ARRIVAL : public EVENT {
|
||||||
|
|
||||||
struct REPORT_STATS : public EVENT {
|
struct REPORT_STATS : public EVENT {
|
||||||
virtual void handle() {
|
virtual void handle() {
|
||||||
printf("%f: %d hosts\n", t, hosts.size());
|
printf("%f: %lu hosts\n", t, hosts.size());
|
||||||
t += 86400;
|
t += 86400;
|
||||||
sim.insert(this);
|
sim.insert(this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void die(const char* msg) {
|
||||||
|
printf("%.0f: %s\n", sim.now, msg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
// base class for chunks and meta-chunks
|
// base class for chunks and meta-chunks
|
||||||
//
|
//
|
||||||
struct DATA_UNIT {
|
struct DATA_UNIT {
|
||||||
virtual bool recoverable(){};
|
virtual bool recoverable(){die("recoverable undef"); return false;};
|
||||||
// can be reconstructed w/o reconstructing parent,
|
// can be reconstructed w/o reconstructing parent,
|
||||||
// assuming that current downloads succeed
|
// assuming that current downloads succeed
|
||||||
virtual void start_upload(){};
|
virtual void start_upload(){die("start_upload undef"); };
|
||||||
virtual void assign(){};
|
virtual void assign(){die("assign undef"); };
|
||||||
bool present_on_server;
|
bool present_on_server;
|
||||||
bool is_uploading;
|
bool is_uploading;
|
||||||
|
char name[64];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CHUNK : DATA_UNIT {
|
struct CHUNK : DATA_UNIT {
|
||||||
|
@ -162,14 +175,40 @@ struct CHUNK : DATA_UNIT {
|
||||||
META_CHUNK* parent;
|
META_CHUNK* parent;
|
||||||
double size;
|
double size;
|
||||||
|
|
||||||
CHUNK(META_CHUNK* mc, double s) {
|
CHUNK(META_CHUNK* mc, double s, int index);
|
||||||
parent = mc;
|
|
||||||
size = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void assign();
|
virtual void assign();
|
||||||
void host_failed(CHUNK_ON_HOST* p);
|
void host_failed(CHUNK_ON_HOST* p);
|
||||||
void upload_complete();
|
void upload_complete();
|
||||||
|
virtual bool recoverable() {
|
||||||
|
return (!hosts.empty());
|
||||||
|
}
|
||||||
|
virtual void start_upload() {
|
||||||
|
// if there's another replica, start upload of 1st instance
|
||||||
|
// NOTE: all instances are inherently present_on_host
|
||||||
|
//
|
||||||
|
CHUNK_ON_HOST *c = *(hosts.begin());
|
||||||
|
c->transfer_in_progress = true;
|
||||||
|
c->t = sim.now + size/UPLOAD_BYTES_SEC;
|
||||||
|
printf("%.0f: starting upload of %s\n", sim.now, c->name);
|
||||||
|
sim.insert(c);
|
||||||
|
}
|
||||||
|
void download_complete() {
|
||||||
|
// see if we can remove chunk from server
|
||||||
|
//
|
||||||
|
int n=0;
|
||||||
|
for (unsigned int i=0; i<hosts.size(); i++) {
|
||||||
|
CHUNK_ON_HOST* c = hosts[i];
|
||||||
|
if (c->present_on_host) {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n >= REPLICATION_LEVEL) {
|
||||||
|
printf("%.0f: %s replicated, removing from server\n", sim.now, name);
|
||||||
|
present_on_server = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct META_CHUNK : DATA_UNIT {
|
struct META_CHUNK : DATA_UNIT {
|
||||||
|
@ -179,25 +218,9 @@ struct META_CHUNK : DATA_UNIT {
|
||||||
DFILE* dfile;
|
DFILE* dfile;
|
||||||
bool uploading;
|
bool uploading;
|
||||||
|
|
||||||
META_CHUNK(DFILE* d, META_CHUNK* par, double size, int encoding_level) {
|
META_CHUNK(
|
||||||
dfile = d;
|
DFILE* d, META_CHUNK* par, double size, int encoding_level, int index
|
||||||
parent = par;
|
);
|
||||||
if (encoding_level) {
|
|
||||||
for (int j=0; j<ENCODING_M; j++) {
|
|
||||||
children.push_back(new META_CHUNK(
|
|
||||||
d,
|
|
||||||
this,
|
|
||||||
size/ENCODING_N,
|
|
||||||
encoding_level-1
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (int j=0; j<ENCODING_M; j++) {
|
|
||||||
children.push_back(new CHUNK(this, size/ENCODING_N));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int n_recoverable_children() {
|
int n_recoverable_children() {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
for (int i=0; i<ENCODING_N; i++) {
|
for (int i=0; i<ENCODING_N; i++) {
|
||||||
|
@ -205,19 +228,25 @@ struct META_CHUNK : DATA_UNIT {
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
// a child has become unrecoverable.
|
// a child has become unrecoverable.
|
||||||
// reconstruct this data unit if we still can.
|
// reconstruct this data unit if we still can.
|
||||||
//
|
//
|
||||||
void child_unrecoverable() {
|
void child_unrecoverable() {
|
||||||
if (n_recoverable_children() >= ENCODING_N) {
|
int n = n_recoverable_children();
|
||||||
for (int i=0; i<ENCODING_N; i++) {
|
printf("%.0f: a child of %s has become unrecoverable\n", sim.now, name);
|
||||||
|
if (n >= ENCODING_N) {
|
||||||
|
uploading = true;
|
||||||
|
for (unsigned int i=0; i<children.size(); i++) {
|
||||||
DATA_UNIT* c = children[i];
|
DATA_UNIT* c = children[i];
|
||||||
if (c->recoverable()) {
|
if (c->recoverable()) {
|
||||||
c->start_upload();
|
c->start_upload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
printf("%.0f: only %d recoverable children\n", sim.now, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,23 +256,46 @@ struct META_CHUNK : DATA_UNIT {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is called only if we're uploading
|
||||||
|
//
|
||||||
void child_upload_complete() {
|
void child_upload_complete() {
|
||||||
}
|
int n = 0;
|
||||||
|
for (unsigned int i=0; i<children.size(); i++) {
|
||||||
void upload_complete() {
|
DATA_UNIT* c = children[i];
|
||||||
|
if (c->present_on_server) {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n >= ENCODING_N) {
|
||||||
|
present_on_server = true;
|
||||||
|
}
|
||||||
|
assign();
|
||||||
|
if (parent && parent->uploading) {
|
||||||
|
parent->child_upload_complete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int next_file_id=0;
|
||||||
|
|
||||||
struct DFILE : EVENT {
|
struct DFILE : EVENT {
|
||||||
META_CHUNK* meta_chunk;
|
META_CHUNK* meta_chunk;
|
||||||
double size;
|
double size;
|
||||||
|
int id;
|
||||||
set<HOST*> unused_hosts;
|
set<HOST*> unused_hosts;
|
||||||
// hosts that don't have any packets of this file
|
// hosts that don't have any packets of this file
|
||||||
|
|
||||||
|
DFILE(double s) {
|
||||||
|
id = next_file_id++;
|
||||||
|
unused_hosts = hosts;
|
||||||
|
size = s;
|
||||||
|
}
|
||||||
|
|
||||||
// the creation of a file
|
// the creation of a file
|
||||||
//
|
//
|
||||||
virtual void handle() {
|
virtual void handle() {
|
||||||
meta_chunk = new META_CHUNK(this, NULL, size, ENCODING_LEVELS);
|
printf("creating file %d\n", id);
|
||||||
|
meta_chunk = new META_CHUNK(this, NULL, size, ENCODING_LEVELS, id);
|
||||||
meta_chunk->assign();
|
meta_chunk->assign();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -257,17 +309,21 @@ void CHUNK_ON_HOST::handle() {
|
||||||
if (present_on_host) {
|
if (present_on_host) {
|
||||||
// it was an upload
|
// it was an upload
|
||||||
chunk->upload_complete(); // create new replicas if needed
|
chunk->upload_complete(); // create new replicas if needed
|
||||||
|
printf("%.f: upload of %s completed\n", sim.now, name);
|
||||||
} else {
|
} else {
|
||||||
present_on_host = true;
|
present_on_host = true;
|
||||||
|
printf("%.f: download of %s completed\n", sim.now, name);
|
||||||
|
chunk->download_complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// the host has departed
|
// the host has departed
|
||||||
//
|
//
|
||||||
void HOST:: handle() {
|
void HOST::handle() {
|
||||||
set<HOST*>::iterator i = hosts.find(this);
|
set<HOST*>::iterator i = hosts.find(this);
|
||||||
hosts.erase(i);
|
hosts.erase(i);
|
||||||
|
|
||||||
|
printf("%.0f: host %d failed\n", sim.now, id);
|
||||||
set<CHUNK_ON_HOST*>::iterator p;
|
set<CHUNK_ON_HOST*>::iterator p;
|
||||||
for (p = chunks.begin(); p != chunks.end(); p++) {
|
for (p = chunks.begin(); p != chunks.end(); p++) {
|
||||||
CHUNK_ON_HOST* c = *p;
|
CHUNK_ON_HOST* c = *p;
|
||||||
|
@ -276,27 +332,30 @@ void HOST:: handle() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CHUNK::CHUNK(META_CHUNK* mc, double s, int index) {
|
||||||
|
parent = mc;
|
||||||
|
present_on_server = true;
|
||||||
|
size = s;
|
||||||
|
sprintf(name, "%s.%d", parent->name, index);
|
||||||
|
}
|
||||||
|
|
||||||
void CHUNK::host_failed(CHUNK_ON_HOST* p) {
|
void CHUNK::host_failed(CHUNK_ON_HOST* p) {
|
||||||
set<CHUNK_ON_HOST*>::iterator i = hosts.find(p);
|
set<CHUNK_ON_HOST*>::iterator i = hosts.find(p);
|
||||||
hosts.erase(i);
|
hosts.erase(i);
|
||||||
|
printf("%.0f: handling loss of %s\n", sim.now, p->name);
|
||||||
if (present_on_server) {
|
if (present_on_server) {
|
||||||
// if data is on server, make a new replica
|
// if data is on server, make a new replica
|
||||||
//
|
//
|
||||||
assign();
|
assign();
|
||||||
} else if (!hosts.empty()) {
|
} else if (!hosts.empty()) {
|
||||||
// if there's another replica, start upload of 1st instance
|
start_upload();
|
||||||
// NOTE: all instances are inherently present_on_host
|
|
||||||
//
|
|
||||||
CHUNK_ON_HOST *c = *(hosts.begin());
|
|
||||||
c->transfer_in_progress = true;
|
|
||||||
c->t = sim.now + size/UPLOAD_BYTES_SEC;
|
|
||||||
sim.insert(c);
|
|
||||||
} else {
|
} else {
|
||||||
parent->child_unrecoverable();
|
parent->child_unrecoverable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHUNK::upload_complete() {
|
void CHUNK::upload_complete() {
|
||||||
|
present_on_server = true;
|
||||||
assign();
|
assign();
|
||||||
if (parent->uploading) {
|
if (parent->uploading) {
|
||||||
parent->child_upload_complete();
|
parent->child_upload_complete();
|
||||||
|
@ -305,26 +364,67 @@ void CHUNK::upload_complete() {
|
||||||
|
|
||||||
void CHUNK::assign() {
|
void CHUNK::assign() {
|
||||||
while (hosts.size() < REPLICATION_LEVEL) {
|
while (hosts.size() < REPLICATION_LEVEL) {
|
||||||
|
if (parent->dfile->unused_hosts.size() == 0) {
|
||||||
|
die("no more hosts!\n");
|
||||||
|
}
|
||||||
set<HOST*>::iterator i = parent->dfile->unused_hosts.begin();
|
set<HOST*>::iterator i = parent->dfile->unused_hosts.begin();
|
||||||
HOST* h = *i;
|
HOST* h = *i;
|
||||||
parent->dfile->unused_hosts.erase(i);
|
parent->dfile->unused_hosts.erase(i);
|
||||||
CHUNK_ON_HOST *c = new CHUNK_ON_HOST();
|
CHUNK_ON_HOST *c = new CHUNK_ON_HOST();
|
||||||
|
sprintf(c->name, "chunk %s on host %d", name, h->id);
|
||||||
|
printf("%.0f: assigning chunk %s to host %d\n", sim.now, name, h->id);
|
||||||
c->host = h;
|
c->host = h;
|
||||||
c->chunk = this;
|
c->chunk = this;
|
||||||
c->t = sim.now + size/DOWNLOAD_BYTES_SEC;
|
c->t = sim.now + size/DOWNLOAD_BYTES_SEC;
|
||||||
|
hosts.insert(c);
|
||||||
|
h->chunks.insert(c);
|
||||||
sim.insert(c);
|
sim.insert(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
META_CHUNK::META_CHUNK(
|
||||||
|
DFILE* d, META_CHUNK* par, double size, int encoding_level, int index
|
||||||
|
) {
|
||||||
|
dfile = d;
|
||||||
|
parent = par;
|
||||||
|
if (parent) {
|
||||||
|
sprintf(name, "%s.%d", parent->name, index);
|
||||||
|
} else {
|
||||||
|
sprintf(name, "%d", index);
|
||||||
|
}
|
||||||
|
if (encoding_level) {
|
||||||
|
for (int j=0; j<ENCODING_M; j++) {
|
||||||
|
children.push_back(new META_CHUNK(
|
||||||
|
d,
|
||||||
|
this,
|
||||||
|
size/ENCODING_N,
|
||||||
|
encoding_level-1,
|
||||||
|
j
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int j=0; j<ENCODING_M; j++) {
|
||||||
|
children.push_back(new CHUNK(this, size/ENCODING_N, j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
set<DFILE*> dfiles;
|
set<DFILE*> dfiles;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
#if 0
|
||||||
HOST_ARRIVAL *h = new HOST_ARRIVAL;
|
HOST_ARRIVAL *h = new HOST_ARRIVAL;
|
||||||
h->t = 0;
|
h->t = 0;
|
||||||
sim.insert(h);
|
sim.insert(h);
|
||||||
REPORT_STATS* r = new REPORT_STATS;
|
REPORT_STATS* r = new REPORT_STATS;
|
||||||
r->t = 0;
|
r->t = 0;
|
||||||
sim.insert(r);
|
sim.insert(r);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (int i=0; i<100; i++) {
|
||||||
|
sim.insert(new HOST);
|
||||||
|
}
|
||||||
|
sim.insert(new DFILE(1e12));
|
||||||
|
|
||||||
sim.simulate(200*86400);
|
sim.simulate(200*86400);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue