mirror of https://github.com/BOINC/boinc.git
svn path=/trunk/boinc/; revision=20269
This commit is contained in:
parent
904137dfd6
commit
42683a8a31
|
@ -667,3 +667,27 @@ David 25 Jan 2010
|
|||
|
||||
client/
|
||||
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
|
||||
|
|
|
@ -88,7 +88,7 @@ void MESSAGE_DESCS::insert(PROJECT* p, int priority, int now, char* message) {
|
|||
}
|
||||
n.create_time = n.arrival_time = gstate.now;
|
||||
strcpy(n.category, "client");
|
||||
notices.append(n);
|
||||
notices.append(n, false, false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
using std::vector;
|
||||
using std::string;
|
||||
using std::set;
|
||||
using std::deque;
|
||||
|
||||
NOTICES notices;
|
||||
RSS_FEEDS rss_feeds;
|
||||
|
@ -230,6 +231,7 @@ void NOTICES::init() {
|
|||
if (log_flags.notice_debug) {
|
||||
msg_printf(0, MSG_INFO, "read %d BOINC notices", (int)notices.size());
|
||||
}
|
||||
write_archive(NULL);
|
||||
}
|
||||
|
||||
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()) {
|
||||
n.seqno = 1;
|
||||
} else {
|
||||
if (!remove_dups(n, keep_old)) {
|
||||
return false;
|
||||
}
|
||||
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) {
|
||||
msg_printf(0, MSG_INFO,
|
||||
"[notice_debug] appending notice: %s",
|
||||
n.title
|
||||
);
|
||||
}
|
||||
append(n);
|
||||
notices.push_front(n);
|
||||
if (archive && !strlen(n.feed_url)) {
|
||||
write_archive(NULL);
|
||||
}
|
||||
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
|
||||
//
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
// 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
|
||||
// (or, if NULL, non-RSS notices)
|
||||
//
|
||||
|
@ -368,13 +387,20 @@ void NOTICES::write_archive(RSS_FEED* rfp) {
|
|||
// write notices newer than seqno as XML (for GUI RPC).
|
||||
// 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;
|
||||
fout.printf("<notices>\n");
|
||||
if (notice_refresh) {
|
||||
NOTICE n;
|
||||
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--) {
|
||||
NOTICE& n = notices[i-1];
|
||||
if (public_only && n.is_private) continue;
|
||||
|
@ -485,7 +511,7 @@ int RSS_FEED::parse_items(XML_PARSER& xp, int& nitems) {
|
|||
} else {
|
||||
n.arrival_time = gstate.now;
|
||||
strcpy(n.feed_url, url);
|
||||
if (notices.append_unique(n)) {
|
||||
if (notices.append(n, true, false)) {
|
||||
nitems++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,14 +67,13 @@
|
|||
|
||||
struct NOTICES {
|
||||
std::deque<NOTICE> notices;
|
||||
void write(int seqno, MIOFILE&, bool public_only);
|
||||
void append(NOTICE&);
|
||||
bool append_unique(NOTICE&);
|
||||
void write(int seqno, MIOFILE&, bool public_only, bool notice_refresh);
|
||||
bool append(NOTICE&, bool keep_old, bool archive);
|
||||
void init();
|
||||
void init_rss();
|
||||
int read_archive_file(char* file, char* feed_url);
|
||||
void write_archive(struct RSS_FEED*);
|
||||
void prune();
|
||||
bool remove_dups(NOTICE&, bool keep_old);
|
||||
};
|
||||
|
||||
extern NOTICES notices;
|
||||
|
|
|
@ -79,6 +79,7 @@ GUI_RPC_CONN::GUI_RPC_CONN(int s):
|
|||
got_auth1 = false;
|
||||
got_auth2 = false;
|
||||
sent_unauthorized = false;
|
||||
notice_refresh = false;
|
||||
}
|
||||
|
||||
GUI_RPC_CONN::~GUI_RPC_CONN() {
|
||||
|
|
|
@ -55,6 +55,9 @@ public:
|
|||
GET_PROJECT_CONFIG_OP get_project_config_op;
|
||||
LOOKUP_ACCOUNT_OP lookup_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();
|
||||
|
@ -96,4 +99,9 @@ public:
|
|||
void send_quits();
|
||||
bool quits_sent();
|
||||
bool poll();
|
||||
void set_notice_refresh() {
|
||||
for (unsigned int i=0; i<gui_rpcs.size(); i++) {
|
||||
gui_rpcs[i]->notice_refresh = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
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;
|
||||
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.
|
||||
|
@ -1166,7 +1166,8 @@ int GUI_RPC_CONN::handle_rpc() {
|
|||
} else if (match_req(request_msg, "get_all_projects_list")) {
|
||||
read_all_projects_list_file(mf);
|
||||
} 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
|
||||
|
||||
|
@ -1247,7 +1248,8 @@ int GUI_RPC_CONN::handle_rpc() {
|
|||
} else if (match_req(request_msg, "set_debts")) {
|
||||
handle_set_debts(request_msg, mf);
|
||||
} 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 {
|
||||
|
||||
// RPCs after this point require authentication,
|
||||
|
|
|
@ -16,7 +16,11 @@
|
|||
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// 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.
|
||||
// N is passed in the command line, and defaults to 1.
|
||||
//
|
||||
|
|
Loading…
Reference in New Issue