svn path=/trunk/boinc/; revision=20269

This commit is contained in:
David Anderson 2010-01-27 03:55:46 +00:00
parent 904137dfd6
commit 42683a8a31
8 changed files with 109 additions and 45 deletions

View File

@ -667,3 +667,27 @@ David 25 Jan 2010
client/ client/
app_start.cpp app_start.cpp
David 26 Jan 2010
- client/manager: eliminate duplicate notices.
When appending a new notice, we check whether one with
the same title and description is present already.
If so we remove one or the other, depending on the situation.
This introduces the possibility of "holes" in the seqno space.
In order that the manager learns of these deletions,
we use the following mechanism:
whenever a notice is removed (because it's a dup or too old)
a flag is set in each GUI_RPC_CONN.
On the next get_notice() RPC, the client returns the entire
list of notices, preceded by a dummy notice with seqno=-1;
this tells the RPC stub function to replace the current list
rather than appending to it.
client/
client_msgs.cpp
cs_notice.cpp,h
gui_rpc_server.h
gui_rpc_server_ops.cpp
samples/multi_thread/
multi_thread.cpp

View File

@ -88,7 +88,7 @@ void MESSAGE_DESCS::insert(PROJECT* p, int priority, int now, char* message) {
} }
n.create_time = n.arrival_time = gstate.now; n.create_time = n.arrival_time = gstate.now;
strcpy(n.category, "client"); strcpy(n.category, "client");
notices.append(n); notices.append(n, false, false);
} }
#endif #endif
} }

View File

@ -31,6 +31,7 @@
using std::vector; using std::vector;
using std::string; using std::string;
using std::set; using std::set;
using std::deque;
NOTICES notices; NOTICES notices;
RSS_FEEDS rss_feeds; RSS_FEEDS rss_feeds;
@ -230,6 +231,7 @@ void NOTICES::init() {
if (log_flags.notice_debug) { if (log_flags.notice_debug) {
msg_printf(0, MSG_INFO, "read %d BOINC notices", (int)notices.size()); msg_printf(0, MSG_INFO, "read %d BOINC notices", (int)notices.size());
} }
write_archive(NULL);
} }
void NOTICES::init_rss() { void NOTICES::init_rss() {
@ -247,35 +249,63 @@ void NOTICES::init_rss() {
} }
} }
void NOTICES::append(NOTICE& n) { static inline bool equivalent(NOTICE& n1, NOTICE& n2) {
if (strcmp(n1.title, n2.title)) return false;
if (n1.description != n2.description) return false;
return true;
}
// we're considering adding a notice n.
// See if an equivalent notice n2 is already there; if so:
// keep_old: return false
// !keep_old: delete n2
//
bool NOTICES::remove_dups(NOTICE& n, bool keep_old) {
deque<NOTICE>::iterator i = notices.begin();
bool removed_something = false;
while (i != notices.end()) {
NOTICE& n2 = *i;
if (equivalent(n, n2) || (n2.arrival_time < gstate.now - 30*86400)) {
if (keep_old) {
return false;
}
i = notices.erase(i);
removed_something = true;
} else {
++i;
}
}
if (removed_something) {
gstate.gui_rpcs.set_notice_refresh();
}
return true;
}
bool NOTICES::append(NOTICE& n, bool keep_old, bool archive) {
if (notices.empty()) { if (notices.empty()) {
n.seqno = 1; n.seqno = 1;
} else { } else {
if (!remove_dups(n, keep_old)) {
return false;
}
n.seqno = notices.front().seqno + 1; n.seqno = notices.front().seqno + 1;
} }
notices.push_front(n);
prune();
if (!strlen(n.feed_url)) {
write_archive(NULL);
}
}
bool NOTICES::append_unique(NOTICE& n) {
for (unsigned int i=0; i<notices.size(); i++) {
NOTICE& n2 = notices[i];
if (!strcmp(n.guid, n2.guid)) return false;
}
if (log_flags.notice_debug) { if (log_flags.notice_debug) {
msg_printf(0, MSG_INFO, msg_printf(0, MSG_INFO,
"[notice_debug] appending notice: %s", "[notice_debug] appending notice: %s",
n.title n.title
); );
} }
append(n); notices.push_front(n);
if (archive && !strlen(n.feed_url)) {
write_archive(NULL);
}
return true; return true;
} }
// read and parse the contents of an archive file;
// read and parse the contents of an archive file.
// If feed_url is empty it's a system msg, else a feed msg.
// insert items in NOTICES // insert items in NOTICES
// //
int NOTICES::read_archive_file(char* path, char* feed_url) { int NOTICES::read_archive_file(char* path, char* feed_url) {
@ -313,7 +343,7 @@ int NOTICES::read_archive_file(char* path, char* feed_url) {
if (feed_url) { if (feed_url) {
strcpy(n.feed_url, feed_url); strcpy(n.feed_url, feed_url);
} }
notices.push_front(n); append(n, false, false);
} }
} }
} }
@ -324,17 +354,6 @@ int NOTICES::read_archive_file(char* path, char* feed_url) {
return ERR_XML_PARSE; return ERR_XML_PARSE;
} }
// get rid of old notices
//
void NOTICES::prune() {
for (;;) {
if (!notices.size()) break;
NOTICE& n = notices.back();
if (n.arrival_time > gstate.now - 30*86400) break;
notices.pop_back();
}
}
// write archive file for the given RSS feed // write archive file for the given RSS feed
// (or, if NULL, non-RSS notices) // (or, if NULL, non-RSS notices)
// //
@ -368,12 +387,19 @@ void NOTICES::write_archive(RSS_FEED* rfp) {
// write notices newer than seqno as XML (for GUI RPC). // write notices newer than seqno as XML (for GUI RPC).
// Write them in order of increasing seqno // Write them in order of increasing seqno
// //
void NOTICES::write(int seqno, MIOFILE& fout, bool public_only) { void NOTICES::write(int seqno, MIOFILE& fout, bool public_only, bool notice_refresh) {
unsigned int i; unsigned int i;
fout.printf("<notices>\n"); fout.printf("<notices>\n");
for (i=0; i<notices.size(); i++) { if (notice_refresh) {
NOTICE& n = notices[i]; NOTICE n;
if (n.seqno <= seqno) break; n.seqno = -1;
seqno = -1;
i = notices.size();
} else {
for (i=0; i<notices.size(); i++) {
NOTICE& n = notices[i];
if (n.seqno <= seqno) break;
}
} }
for (; i>0; i--) { for (; i>0; i--) {
NOTICE& n = notices[i-1]; NOTICE& n = notices[i-1];
@ -485,7 +511,7 @@ int RSS_FEED::parse_items(XML_PARSER& xp, int& nitems) {
} else { } else {
n.arrival_time = gstate.now; n.arrival_time = gstate.now;
strcpy(n.feed_url, url); strcpy(n.feed_url, url);
if (notices.append_unique(n)) { if (notices.append(n, true, false)) {
nitems++; nitems++;
} }
} }

View File

@ -67,14 +67,13 @@
struct NOTICES { struct NOTICES {
std::deque<NOTICE> notices; std::deque<NOTICE> notices;
void write(int seqno, MIOFILE&, bool public_only); void write(int seqno, MIOFILE&, bool public_only, bool notice_refresh);
void append(NOTICE&); bool append(NOTICE&, bool keep_old, bool archive);
bool append_unique(NOTICE&);
void init(); void init();
void init_rss(); void init_rss();
int read_archive_file(char* file, char* feed_url); int read_archive_file(char* file, char* feed_url);
void write_archive(struct RSS_FEED*); void write_archive(struct RSS_FEED*);
void prune(); bool remove_dups(NOTICE&, bool keep_old);
}; };
extern NOTICES notices; extern NOTICES notices;

View File

@ -79,6 +79,7 @@ GUI_RPC_CONN::GUI_RPC_CONN(int s):
got_auth1 = false; got_auth1 = false;
got_auth2 = false; got_auth2 = false;
sent_unauthorized = false; sent_unauthorized = false;
notice_refresh = false;
} }
GUI_RPC_CONN::~GUI_RPC_CONN() { GUI_RPC_CONN::~GUI_RPC_CONN() {

View File

@ -55,6 +55,9 @@ public:
GET_PROJECT_CONFIG_OP get_project_config_op; GET_PROJECT_CONFIG_OP get_project_config_op;
LOOKUP_ACCOUNT_OP lookup_account_op; LOOKUP_ACCOUNT_OP lookup_account_op;
CREATE_ACCOUNT_OP create_account_op; CREATE_ACCOUNT_OP create_account_op;
bool notice_refresh;
// next time we get a get_notices RPC,
// send a -1 seqno, then the whole list
GUI_RPC_CONN(int); GUI_RPC_CONN(int);
~GUI_RPC_CONN(); ~GUI_RPC_CONN();
@ -96,4 +99,9 @@ public:
void send_quits(); void send_quits();
bool quits_sent(); bool quits_sent();
bool poll(); bool poll();
void set_notice_refresh() {
for (unsigned int i=0; i<gui_rpcs.size(); i++) {
gui_rpcs[i]->notice_refresh = true;
}
}
}; };

View File

@ -1055,16 +1055,16 @@ static void handle_set_cc_config(char* buf, MIOFILE& fout) {
); );
} }
static void handle_get_notices(char* buf, MIOFILE& fout) { static void handle_get_notices(char* buf, MIOFILE& fout, bool notice_refresh) {
int seqno = 0; int seqno = 0;
parse_int(buf, "<seqno>", seqno); parse_int(buf, "<seqno>", seqno);
notices.write(seqno, fout, false); notices.write(seqno, fout, false, notice_refresh);
} }
static void handle_get_notices_public(char* buf, MIOFILE& fout) { static void handle_get_notices_public(char* buf, MIOFILE& fout, bool notice_refresh) {
int seqno = 0; int seqno = 0;
parse_int(buf, "<seqno>", seqno); parse_int(buf, "<seqno>", seqno);
notices.write(seqno, fout, true); notices.write(seqno, fout, true, notice_refresh);
} }
// Some of the RPCs have empty-element request messages. // Some of the RPCs have empty-element request messages.
@ -1166,7 +1166,8 @@ int GUI_RPC_CONN::handle_rpc() {
} else if (match_req(request_msg, "get_all_projects_list")) { } else if (match_req(request_msg, "get_all_projects_list")) {
read_all_projects_list_file(mf); read_all_projects_list_file(mf);
} else if (match_req(request_msg, "get_notices_public")) { } else if (match_req(request_msg, "get_notices_public")) {
handle_get_notices_public(request_msg, mf); handle_get_notices_public(request_msg, mf, notice_refresh);
notice_refresh = false;
// Operations that require authentication start here // Operations that require authentication start here
@ -1247,7 +1248,8 @@ int GUI_RPC_CONN::handle_rpc() {
} else if (match_req(request_msg, "set_debts")) { } else if (match_req(request_msg, "set_debts")) {
handle_set_debts(request_msg, mf); handle_set_debts(request_msg, mf);
} else if (match_req(request_msg, "get_notices")) { } else if (match_req(request_msg, "get_notices")) {
handle_get_notices(request_msg, mf); handle_get_notices(request_msg, mf, notice_refresh);
notice_refresh = false;
} else { } else {
// RPCs after this point require authentication, // RPCs after this point require authentication,

View File

@ -16,7 +16,11 @@
// along with BOINC. If not, see <http://www.gnu.org/licenses/>. // along with BOINC. If not, see <http://www.gnu.org/licenses/>.
// Example multi-thread BOINC application. // Example multi-thread BOINC application.
// It does 64 "units" of computation, where each units is about 1 GFLOP. // This app defines its own classes (THREAD, THREAD_SET) for managing threads.
// You can also use libraries such as OpenMP.
// Just make sure you call boinc_init_parallel().
//
// This app does 64 "units" of computation, where each units is about 1 GFLOP.
// It divides this among N "worker" threads. // It divides this among N "worker" threads.
// N is passed in the command line, and defaults to 1. // N is passed in the command line, and defaults to 1.
// //