From d609e2bc482753e6ef7fadab270758e8445f4083 Mon Sep 17 00:00:00 2001 From: Rom Walton Date: Thu, 1 Jul 2004 18:43:36 +0000 Subject: [PATCH] Client spamming server hotfix svn path=/trunk/boinc/; revision=3734 --- checkin_notes | 9 +++ client/win/boinc_gui.rc | 11 +-- client/win/boinc_ss.rc | 4 +- db/boinc_db.C | 162 ++++++++++++++++++++++++++++++++++++---- db/boinc_db.h | 41 ++++++++++ db/db_base.C | 61 +++++++++++++++ db/db_base.h | 48 +++++++++--- 7 files changed, 305 insertions(+), 31 deletions(-) diff --git a/checkin_notes b/checkin_notes index fc2b74ca1e..5bbefbe2a7 100755 --- a/checkin_notes +++ b/checkin_notes @@ -14411,3 +14411,12 @@ Brian 1 July 2004 client/ gui_rpc_client.h + +Rom 1 July 2004 + - Introduce skeleton of new transitioner queue class that uses a specialized + query for its job. NOTE: I don't know if it will even compile, but need another + set of eyes looking over it as well. + + db/ + db_base.C, .h + boinc_db.C, .h diff --git a/client/win/boinc_gui.rc b/client/win/boinc_gui.rc index d0f15d1b10..398480aa87 100644 --- a/client/win/boinc_gui.rc +++ b/client/win/boinc_gui.rc @@ -8,6 +8,7 @@ // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h" +#include "win_config.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS @@ -30,12 +31,12 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 1 TEXTINCLUDE BEGIN "boinc_gui.h\0" - "win_config.h\0" END 2 TEXTINCLUDE BEGIN "#include ""afxres.h""\r\n" + "#include ""win_config.h""\r\n" "\0" END @@ -298,8 +299,8 @@ IDI_ICONWARNING ICON "res\\iconwarning.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,19,0,0 - PRODUCTVERSION 3,19,0,0 + FILEVERSION MAJOR_VERSION,MINOR_VERSION,0,0 + PRODUCTVERSION MAJOR_VERSION,MINOR_VERSION,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -316,12 +317,12 @@ BEGIN BEGIN VALUE "CompanyName", "Space Sciences Laboratory" VALUE "FileDescription", "boinc_gui" - VALUE "FileVersion", "3.19" + VALUE "FileVersion", VERSION "\0" VALUE "InternalName", "boinc_gui" VALUE "LegalCopyright", "Copyright © 2004 University of California" VALUE "OriginalFilename", "boinc_gui.exe" VALUE "ProductName", "BOINC Core Client" - VALUE "ProductVersion", "3.19" + VALUE "ProductVersion", PACKAGE_VERSION "\0" END END BLOCK "VarFileInfo" diff --git a/client/win/boinc_ss.rc b/client/win/boinc_ss.rc index acafe618d0..d6ab1da309 100755 --- a/client/win/boinc_ss.rc +++ b/client/win/boinc_ss.rc @@ -1,7 +1,6 @@ // Microsoft Visual C++ generated resource script. // #include "boinc_ss.h" -#include "win_config.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// @@ -9,6 +8,7 @@ // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h" +#include "win_config.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS @@ -31,12 +31,12 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 1 TEXTINCLUDE BEGIN "boinc_ss.h\0" - "win_config.h\0" END 2 TEXTINCLUDE BEGIN "#include ""afxres.h""\r\n" + "#include ""win_config.h""\r\n" "\0" END diff --git a/db/boinc_db.C b/db/boinc_db.C index d56f258877..44c8a8d245 100644 --- a/db/boinc_db.C +++ b/db/boinc_db.C @@ -34,19 +34,6 @@ static struct random_init { } } random_init; -// if SQL columns are not 'not null', you must use these safe_atoi, safe_atof -// instead of atoi, atof, since the strings returned by MySQL may be NULL. -// -inline int safe_atoi(const char* s) { - if (!s) return 0; - return atoi(s); -} - -inline float safe_atof(const char* s) { - if (!s) return 0; - return atof(s); -} - #define ESCAPE(x) escape_string(x, sizeof(x)) #define UNESCAPE(x) unescape_string(x, sizeof(x)) @@ -72,7 +59,7 @@ DB_HOST::DB_HOST() : DB_BASE(boinc_db, "host"){} DB_WORKUNIT::DB_WORKUNIT() : DB_BASE(boinc_db, "workunit"){} DB_RESULT::DB_RESULT() : DB_BASE(boinc_db, "result"){} DB_MSG_FROM_HOST::DB_MSG_FROM_HOST() : DB_BASE(boinc_db, "msg_from_host"){} -DB_MSG_TO_HOST::DB_MSG_TO_HOST() : DB_BASE(boinc_db, "msg_to_host"){} +DB_TRANSITIONER_QUEUE::DB_TRANSITIONER_QUEUE() : DB_BASE(boinc_db), current_entry_start_position(0), current_entry_workunit_id(0){} int DB_PLATFORM::get_id() {return id;} int DB_CORE_VERSION::get_id() {return id;} @@ -583,3 +570,150 @@ void DB_MSG_TO_HOST::db_parse(MYSQL_ROW& r) { handled = atol(r[i++]); strcpy2(xml, r[i++]); } + +int DB_TRANSITIONER_QUEUE::enumerate_queue_entries(int transition_time, int ntotal_transitioners, int ntransitioner, int nresult_limit) { + int x; + char query[MAX_QUERY_LEN]; + char priority[16]; + char mod[64]; + MYSQL_ROW row; + int temp_workunit_id; + MYSQL_ROW_OFFSET temp_entry_position; + + if (!cursor.active) { + cursor.active = true; + + memset(priority, '\0', sizeof(priority)); + if (db->mysql) { strcpy(priority, "HIGH_PRIORITY"); } + + memset(mod, '\0', sizeof(mod)); + if (0 < ntotal_transitioners) { sprintf(mod, "MOD(wu.id, %d) = %d", ntotal_transitioners, ntransitioner); } + + sprintf(query, + "SELECT %s " + " wu.id, " + " wu.name, " + " wu.appid, " + " wu.min_quorum, " + " wu.need_validate, " + " wu.canonical_resultid, " + " wu.transition_time, " + " wu.delay_bound, " + " wu.error_mask, " + " wu.max_error_results, " + " wu.max_total_results, " + " wu.file_delete_state, " + " wu.assimilate_state, " + " wu.target_nresults, " + " wu.result_template, " + " res.id AS res_id, " + " res.report_deadline AS res_report_deadline, " + " res.server_state AS res_server_state, " + " res.outcome AS res_outcome, " + " res.validate_state AS res_validate_state, " + " res.file_delete_state AS res_file_delete_state, " + " res.sent_time AS res_sent_time " + "FROM " + " workunit AS wu " + " LEFT JOIN result AS res ON wu.id = res.workunitid " + "WHERE " + " wu.transition_time < %d AND " + " %s " + "LIMIT " + " %d ", + priority, transition_time, mod, nresult_limit); + + x = db->do_query(query); + if (x) return mysql_errno(db->mysql); + cursor.rp = mysql_store_result(db->mysql); + if (!cursor.rp) return mysql_errno(db->mysql); + + current_entry_start_position = mysql_row_tell(cursor.rp); + } + + mysql_row_seek(current_entry_start_position); + + do + { + temp_entry_position = mysql_row_tell(cursor.rp); + row = mysql_fetch_row(cursor.rp); + if (!row) { + mysql_free_result(cursor.rp); + cursor.active = false; + return -1; + } else { + fetch_field_value(cursor.rp, row, "id", temp_workunit_id); + } + } + while ( row && ( temp_workunit_id == current_entry_workunit_id )); + + // New Workunit Detected + current_entry_workunit_id = temp_workunit_id; + current_entry_start_position = temp_entry_position; + + parse_entry(cursor.rp, row); + + return 0; +} + +void DB_TRANSITIONER_QUEUE::parse_entry(MYSQL_RES *result, MYSQL_ROW& row) { + int temp_need_validate = 0; + fetch_field_value(result, row, "id", id); + fetch_field_value(result, row, "name", name, sizeof(name)); + fetch_field_value(result, row, "appid", appid); + fetch_field_value(result, row, "min_quorum", min_quorum); + fetch_field_value(result, row, "need_validate", temp_need_validate); + if (temp_need_validate) { need_validate = true; } else { need_validate = false; } + fetch_field_value(result, row, "canonical_resultid", canonical_resultid); + fetch_field_value(result, row, "transition_time", transition_time); + fetch_field_value(result, row, "delay_bound", delay_bound); + fetch_field_value(result, row, "error_mask", error_mask); + fetch_field_value(result, row, "max_error_results", max_error_results); + fetch_field_value(result, row, "max_total_results", max_total_results); + fetch_field_value(result, row, "file_delete_state", file_delete_state); + fetch_field_value(result, row, "assimilate_state", assimilate_state); + fetch_field_value(result, row, "target_nresults", target_nresults); + parse_result(result, row); +} + +void DB_TRANSITIONER_QUEUE::parse_result(MYSQL_RES *result, MYSQL_ROW& row) { + fetch_field_value(result, row, "res_id", res_id); + fetch_field_value(result, row, "res_report_deadline", res_report_deadline); + fetch_field_value(result, row, "res_server_state", res_server_state); + fetch_field_value(result, row, "res_outcome", res_outcome); + fetch_field_value(result, row, "res_validate_state", res_validate_state); + fetch_field_value(result, row, "res_file_delete_state", res_file_delete_state); + fetch_field_value(result, row, "res_sent_time", res_sent_time); +} + +int DB_TRANSITIONER_QUEUE::seek_first_result() { + int retval; + MYSQL_ROW row; + + mysql_row_seek(current_entry_start_position); + row = mysql_fetch_row(cursor.rp); + if (!row) { + retval = -1; + } else { + parse_result(cursor.rp, row); + retval = 0; + } + + return retval; +} + +int DB_TRANSITIONER_QUEUE::seek_next_result() { + int retval; + MYSQL_ROW row; + + row = mysql_fetch_row(cursor.rp); + if (!row) { + retval = seek_first_result(); + } else { + parse_result(cursor.rp, row); + retval = 0; + } + + return retval; +} + diff --git a/db/boinc_db.h b/db/boinc_db.h index c8cb76eaf2..0de77f77a4 100755 --- a/db/boinc_db.h +++ b/db/boinc_db.h @@ -427,6 +427,31 @@ struct MSG_TO_HOST { void clear(); }; +struct TRANSITIONER_QUEUE { + int id; + char name[256]; + int appid; + int min_quorum; + bool need_validate; + int canonical_resultid; + int transition_time; + int delay_bound; + int error_mask; + int max_error_results; + int max_total_results; + int file_delete_state; + int assimilate_state; + int target_nresults; + int res_id; + int res_report_deadline; + int res_server_state; + int res_outcome; + int res_validate_state; + int res_file_delete_state; + int res_sent_time; + void clear(); +}; + #if 0 #define WORKSEQ_STATE_UNASSIGNED 0 #define WORKSEQ_STATE_ASSIGNED 1 @@ -537,6 +562,22 @@ public: void db_parse(MYSQL_ROW &row); }; +class DB_TRANSITIONER_QUEUE : public DB_BASE, public TRANSITIONER_QUEUE { +public: + DB_TRANSITIONER_QUEUE(); + + MYSQL_ROW_OFFSET current_entry_start_position; + int current_entry_workunit_id; + + int enumerate_entries(int transition_time, int ntotal_transitioners, int ntransitioner, int nresult_limit); + void parse_entry(MYSQL_RES *result, MYSQL_ROW& row); + void parse_result(MYSQL_RES *result, MYSQL_ROW& row); + + int seek_first_result(); + int seek_next_result(); + +}; + #if 0 class DB_WORKSEQ : public DB_BASE, public WORKSEQ { public: diff --git a/db/db_base.C b/db/db_base.C index 2e59c65c91..2efd5e4796 100644 --- a/db/db_base.C +++ b/db/db_base.C @@ -253,6 +253,67 @@ int DB_BASE::sum(double& x, char* field, char* clause) { return get_double(query, x); } + +DB_BASE_PERF::DB_BASE_PERF(DB_CONN& p) : db(&p) { + cursor.active = false; +} + +int DB_BASE_PERF::fetch_field_value(MYSQL_RES *result, MYSQL_ROW& row, const char* field_name, int& field_value) +{ + unsigned int num_fields; + unsigned int i; + MYSQL_FIELD* fields; + + num_fields = mysql_num_fields(result); + fields = mysql_fetch_fields(result); + for(i = 0; i < num_fields; i++) + { + if (0 == strncmp(field_name, fields[i].name, strlen(field_name))) { + field_value = safe_atoi(row[i]); + } + } + + return 0; +} + +int DB_BASE_PERF::fetch_field_value(MYSQL_RES *result, MYSQL_ROW& row, const char* field_name, float& field_value) +{ + unsigned int num_fields; + unsigned int i; + MYSQL_FIELD* fields; + + num_fields = mysql_num_fields(result); + fields = mysql_fetch_fields(result); + for(i = 0; i < num_fields; i++) + { + if (0 == strncmp(field_name, fields[i].name, strlen(field_name))) { + field_value = safe_atof(row[i]); + } + } + + return 0; +} + +int DB_BASE_PERF::fetch_field_value(MYSQL_RES *result, MYSQL_ROW& row, const char* field_name, char* field_value, int field_size) +{ + unsigned int num_fields; + unsigned int i; + MYSQL_FIELD* fields; + + num_fields = mysql_num_fields(result); + fields = mysql_fetch_fields(result); + for(i = 0; i < num_fields; i++) + { + if (0 == strncmp(field_name, fields[i].name, strlen(field_name))) { + memset(field_value, '\0', field_size); + strlcpy(field_value, row[i], field_size); + } + } + + return 0; +} + + // convert a string into a form that allows it to be used // in SQL queries delimited by single quotes: // replace ' with \', \ with \\ diff --git a/db/db_base.h b/db/db_base.h index 45faf113a4..716f08c7b9 100644 --- a/db/db_base.h +++ b/db/db_base.h @@ -22,6 +22,29 @@ #include "mysql.h" +// if SQL columns are not 'not null', you must use these safe_atoi, safe_atof +// instead of atoi, atof, since the strings returned by MySQL may be NULL. +// +inline int safe_atoi(const char* s) { + if (!s) return 0; + return atoi(s); +} + +inline float safe_atof(const char* s) { + if (!s) return 0; + return atof(s); +} + +#define strcpy2(x, y) \ + { \ + char* z = y; \ + if (!z) { \ + x[0]=0; \ + } else { \ + strlcpy(x, z, sizeof(x)); \ + } \ + } + struct CURSOR { bool active; MYSQL_RES *rp; @@ -38,7 +61,6 @@ public: int insert_id(); void print_error(char*); const char* error_string(); - bool is_high_priority; MYSQL* mysql; }; @@ -70,15 +92,21 @@ public: virtual void db_parse(MYSQL_ROW&); }; -#define strcpy2(x, y) \ - { \ - char* z = y; \ - if (!z) { \ - x[0]=0; \ - } else { \ - strlcpy(x, z, sizeof(x)); \ - } \ - } +// Base for derived classes that can access the DB +// Defines various generic operations on DB tables +// for specially designed queries +// +class DB_BASE_PERF { +public: + DB_BASE_PERF(DB_CONN&); + + int fetch_field_value(MYSQL_RES* result, MYSQL_ROW& row, const char* field_name, int& field_value); + int fetch_field_value(MYSQL_RES* result, MYSQL_ROW& row, const char* field_name, float& field_value); + int fetch_field_value(MYSQL_RES* result, MYSQL_ROW& row, const char* field_name, char* field_value, int field_size); + + DB_CONN* db; + CURSOR cursor; +}; void escape_string(char* field, int len); void unescape_string(char* p, int len);