// The contents of this file are subject to the BOINC Public License // Version 1.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://boinc.berkeley.edu/license_1.0.txt // // Software distributed under the License is distributed on an "AS IS" // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the // License for the specific language governing rights and limitations // under the License. // // The Original Code is the Berkeley Open Infrastructure for Network Computing. // // The Initial Developer of the Original Code is the SETI@home project. // Portions created by the SETI@home project are Copyright (C) 2002 // University of California at Berkeley. All Rights Reserved. // // Contributor(s): // #include #include #include #include #include #include "util.h" #include "boinc_db.h" DB_CONN boinc_db; static struct random_init { random_init() { srand48(getpid() + time(0)); } } random_init; #define ESCAPE(x) escape_string(x, sizeof(x)) #define UNESCAPE(x) unescape_string(x, sizeof(x)) void PLATFORM::clear() {memset(this, 0, sizeof(*this));} void CORE_VERSION::clear() {memset(this, 0, sizeof(*this));} void APP::clear() {memset(this, 0, sizeof(*this));} void APP_VERSION::clear() {memset(this, 0, sizeof(*this));} void USER::clear() {memset(this, 0, sizeof(*this));} void TEAM::clear() {memset(this, 0, sizeof(*this));} void HOST::clear() {memset(this, 0, sizeof(*this));} void RESULT::clear() {memset(this, 0, sizeof(*this));} void WORKUNIT::clear() {memset(this, 0, sizeof(*this));} void MSG_FROM_HOST::clear() {memset(this, 0, sizeof(*this));} void MSG_TO_HOST::clear() {memset(this, 0, sizeof(*this));} DB_PLATFORM::DB_PLATFORM() : DB_BASE(boinc_db, "platform"){} DB_CORE_VERSION::DB_CORE_VERSION() : DB_BASE(boinc_db, "core_version"){} DB_APP::DB_APP() : DB_BASE(boinc_db, "app"){} DB_APP_VERSION::DB_APP_VERSION() : DB_BASE(boinc_db, "app_version"){} DB_USER::DB_USER() : DB_BASE(boinc_db, "user"){} DB_TEAM::DB_TEAM() : DB_BASE(boinc_db, "team"){} 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_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;} int DB_APP::get_id() {return id;} int DB_APP_VERSION::get_id() {return id;} int DB_USER::get_id() {return id;} int DB_TEAM::get_id() {return id;} int DB_HOST::get_id() {return id;} int DB_WORKUNIT::get_id() {return id;} int DB_RESULT::get_id() {return id;} int DB_MSG_FROM_HOST::get_id() {return id;} int DB_MSG_TO_HOST::get_id() {return id;} void DB_PLATFORM::db_print(char* buf){ sprintf(buf, "create_time=%d, name='%s', user_friendly_name='%s', " "deprecated=%d", create_time, name, user_friendly_name, deprecated ); } void DB_PLATFORM::db_parse(MYSQL_ROW &r) { int i=0; clear(); id=atol(r[i++]); create_time=atol(r[i++]); strcpy2(name, r[i++]); strcpy2(user_friendly_name, r[i++]); deprecated=atol(r[i++]); } void DB_CORE_VERSION::db_print(char* buf) { sprintf(buf, "create_time=%d, version_num=%d, platformid=%d, " "xml_doc='%s', message='%s', deprecated=%d", create_time, version_num, platformid, xml_doc, message, deprecated?1:0 ); } void DB_CORE_VERSION::db_parse(MYSQL_ROW &r) { int i=0; clear(); id=atol(r[i++]); create_time = atoi(r[i++]); version_num = atoi(r[i++]); platformid = atoi(r[i++]); strcpy2(xml_doc, r[i++]); strcpy2(message, r[i++]); deprecated = atoi(r[i++]); } void DB_APP::db_print(char* buf){ sprintf(buf, "create_time=%d, name='%s', min_version=%d, " "deprecated=%d, user_friendly_name='%s'", create_time, name, min_version, deprecated, user_friendly_name ); } void DB_APP::db_parse(MYSQL_ROW &r) { int i=0; clear(); id=atol(r[i++]); create_time = atoi(r[i++]); strcpy2(name, r[i++]); min_version = atoi(r[i++]); deprecated = atoi(r[i++]); strcpy2(user_friendly_name, r[i++]); } void DB_APP_VERSION::db_print(char* buf){ sprintf(buf, "create_time=%d, appid=%d, version_num=%d, platformid=%d, " "xml_doc='%s', " "min_core_version=%d, max_core_version=%d, deprecated=%d", create_time, appid, version_num, platformid, xml_doc, min_core_version, max_core_version, deprecated ); } void DB_APP_VERSION::db_parse(MYSQL_ROW &r) { int i=0; clear(); id=atol(r[i++]); create_time = atoi(r[i++]); appid = atoi(r[i++]); version_num = atoi(r[i++]); platformid = atoi(r[i++]); strcpy2(xml_doc, r[i++]); min_core_version = atoi(r[i++]); max_core_version = atoi(r[i++]); deprecated = atoi(r[i++]); } void DB_USER::db_print(char* buf){ ESCAPE(email_addr); ESCAPE(name); ESCAPE(country); ESCAPE(postal_code); ESCAPE(global_prefs); ESCAPE(project_prefs); ESCAPE(url); ESCAPE(signature); sprintf(buf, "create_time=%d, email_addr='%s', name='%s', " "authenticator='%s', " "country='%s', postal_code='%s', " "total_credit=%.15e, expavg_credit=%.15e, expavg_time=%.15e, " "global_prefs='%s', project_prefs='%s', " "teamid=%d, venue='%s', url='%s', send_email=%d, show_hosts=%d, " "posts=%d, " "seti_id=%d, seti_nresults=%d, seti_last_result_time=%d, " "seti_total_cpu=%.15e, signature='%s', has_profile=%d, " "cross_project_id='%s'", create_time, email_addr, name, authenticator, country, postal_code, total_credit, expavg_credit, expavg_time, global_prefs, project_prefs, teamid, venue, url, send_email, show_hosts, posts, seti_id, seti_nresults, seti_last_result_time, seti_total_cpu, signature, has_profile, cross_project_id ); UNESCAPE(email_addr); UNESCAPE(name); UNESCAPE(country); UNESCAPE(postal_code); UNESCAPE(global_prefs); UNESCAPE(project_prefs); UNESCAPE(url); UNESCAPE(signature); } void DB_USER::db_parse(MYSQL_ROW &r) { int i=0; clear(); id = atoi(r[i++]); create_time = atoi(r[i++]); strcpy2(email_addr, r[i++]); strcpy2(name, r[i++]); strcpy2(authenticator, r[i++]); strcpy2(country, r[i++]); strcpy2(postal_code, r[i++]); total_credit = atof(r[i++]); expavg_credit = atof(r[i++]); expavg_time = atof(r[i++]); strcpy2(global_prefs, r[i++]); strcpy2(project_prefs, r[i++]); teamid = atoi(r[i++]); strcpy2(venue, r[i++]); strcpy2(url, r[i++]); send_email = atoi(r[i++]); show_hosts = atoi(r[i++]); posts = safe_atoi(r[i++]); seti_id = safe_atoi(r[i++]); seti_nresults = safe_atoi(r[i++]); seti_last_result_time = safe_atoi(r[i++]); seti_total_cpu = safe_atof(r[i++]); strcpy2(signature, r[i++]); has_profile = atoi(r[i++]); strcpy2(cross_project_id, r[i++]); } void DB_TEAM::db_print(char* buf){ ESCAPE(name); ESCAPE(name_lc); ESCAPE(url); ESCAPE(name_html); ESCAPE(description); sprintf(buf, "create_time=%d, userid=%d, name='%s', " "name_lc='%s', url='%s', " "type=%d, name_html='%s', description='%s', nusers=%d, " "country='%s', " "total_credit=%.15e, expavg_credit=%.15e, expavg_time=%.15e, " "seti_id=%d", create_time, userid, name, name_lc, url, type, name_html, description, nusers, country, total_credit, expavg_credit, expavg_time, seti_id ); UNESCAPE(name); UNESCAPE(name_lc); UNESCAPE(url); UNESCAPE(name_html); UNESCAPE(description); } void DB_TEAM::db_parse(MYSQL_ROW &r) { int i=0; clear(); id = atoi(r[i++]); create_time = atoi(r[i++]); userid = atoi(r[i++]); strcpy2(name, r[i++]); strcpy2(name_lc, r[i++]); strcpy2(url, r[i++]); type = atoi(r[i++]); strcpy2(name_html, r[i++]); strcpy2(description, r[i++]); nusers = atoi(r[i++]); strcpy2(country, r[i++]); total_credit = atof(r[i++]); expavg_credit = atof(r[i++]); expavg_time = atof(r[i++]); seti_id = safe_atoi(r[i++]); } // set NaNs to a reasonable value void HOST::fix_nans() { if (isnan(p_fpops)) p_fpops = 0; if (isnan(p_iops)) p_iops = 0; if (isnan(p_membw)) p_membw = 0; if (isnan(m_nbytes)) m_nbytes = 0; if (isnan(m_cache)) m_cache = 0; if (isnan(m_swap)) m_swap = 0; if (isnan(d_total)) d_total = 0; if (isnan(d_free)) d_free = 0; if (isnan(d_boinc_used_total)) d_boinc_used_total = 0; if (isnan(d_boinc_used_project)) d_boinc_used_project = 0; if (isnan(d_boinc_max)) d_boinc_max = 0; if (isnan(n_bwup)) n_bwup = 0; if (isnan(n_bwdown)) n_bwdown = 0; } void DB_HOST::db_print(char* buf){ ESCAPE(domain_name); ESCAPE(serialnum); ESCAPE(last_ip_addr); ESCAPE(p_vendor); ESCAPE(p_model); ESCAPE(os_name); ESCAPE(os_version); sprintf(buf, "create_time=%d, userid=%d, " "rpc_seqno=%d, rpc_time=%d, " "total_credit=%.12e, expavg_credit=%.12e, expavg_time=%.15e, " "timezone=%d, domain_name='%s', serialnum='%s', " "last_ip_addr='%s', nsame_ip_addr=%d, " "on_frac=%.15e, connected_frac=%.15e, active_frac=%.15e, " "p_ncpus=%d, p_vendor='%s', p_model='%s', " "p_fpops=%.15e, p_iops=%.15e, p_membw=%.15e, " "os_name='%s', os_version='%s', " "m_nbytes=%.15e, m_cache=%.15e, m_swap=%.15e, " "d_total=%.15e, d_free=%.15e, " "d_boinc_used_total=%.15e, d_boinc_used_project=%.15e, d_boinc_max=%.15e, " "n_bwup=%.15e, n_bwdown=%.15e, " "credit_per_cpu_sec=%.15e, " "venue='%s', projects='%s', nresults_today=%d", create_time, userid, rpc_seqno, rpc_time, total_credit, expavg_credit, expavg_time, timezone, domain_name, serialnum, last_ip_addr, nsame_ip_addr, on_frac, connected_frac, active_frac, p_ncpus, p_vendor, p_model, p_fpops, p_iops, p_membw, os_name, os_version, m_nbytes, m_cache, m_swap, d_total, d_free, d_boinc_used_total, d_boinc_used_project, d_boinc_max, n_bwup, n_bwdown, credit_per_cpu_sec, venue, projects, nresults_today ); UNESCAPE(domain_name); UNESCAPE(serialnum); UNESCAPE(last_ip_addr); UNESCAPE(p_vendor); UNESCAPE(p_model); UNESCAPE(os_name); UNESCAPE(os_version); } void DB_HOST::db_parse(MYSQL_ROW &r) { int i=0; clear(); id=atol(r[i++]); create_time = atoi(r[i++]); userid = atoi(r[i++]); rpc_seqno = atoi(r[i++]); rpc_time = atoi(r[i++]); total_credit = atof(r[i++]); expavg_credit = atof(r[i++]); expavg_time = atof(r[i++]); timezone = atoi(r[i++]); strcpy2(domain_name, r[i++]); strcpy2(serialnum, r[i++]); strcpy2(last_ip_addr, r[i++]); nsame_ip_addr = atoi(r[i++]); on_frac = atof(r[i++]); connected_frac = atof(r[i++]); active_frac = atof(r[i++]); p_ncpus = atoi(r[i++]); strcpy2(p_vendor, r[i++]); strcpy2(p_model, r[i++]); p_fpops = atof(r[i++]); p_iops = atof(r[i++]); p_membw = atof(r[i++]); strcpy2(os_name, r[i++]); strcpy2(os_version, r[i++]); m_nbytes = atof(r[i++]); m_cache = atof(r[i++]); m_swap = atof(r[i++]); d_total = atof(r[i++]); d_free = atof(r[i++]); d_boinc_used_total = atof(r[i++]); d_boinc_used_project = atof(r[i++]); d_boinc_max = atof(r[i++]); n_bwup = atof(r[i++]); n_bwdown = atof(r[i++]); credit_per_cpu_sec = atof(r[i++]); strcpy2(venue, r[i++]); strcpy2(projects, r[i++]); nresults_today = atoi(r[i++]); } void DB_WORKUNIT::db_print(char* buf){ sprintf(buf, "create_time=%d, appid=%d, " "name='%s', xml_doc='%s', batch=%d, " "rsc_fpops_est=%.15e, rsc_fpops_bound=%.15e, " "rsc_memory_bound=%.15e, rsc_disk_bound=%.15e, " "need_validate=%d, " "canonical_resultid=%d, canonical_credit=%.15e, " "transition_time=%d, delay_bound=%d, " "error_mask=%d, file_delete_state=%d, assimilate_state=%d, " "workseq_next=%d, opaque=%f, " "min_quorum=%d, target_nresults=%d, max_error_results=%d, " "max_total_results=%d, max_success_results=%d, " "result_template='%s'", create_time, appid, name, xml_doc, batch, rsc_fpops_est, rsc_fpops_bound, rsc_memory_bound, rsc_disk_bound, need_validate, canonical_resultid, canonical_credit, transition_time, delay_bound, error_mask, file_delete_state, assimilate_state, workseq_next, opaque, min_quorum, target_nresults, max_error_results, max_total_results, max_success_results, result_template ); } void DB_WORKUNIT::db_parse(MYSQL_ROW &r) { int i=0; clear(); id=atol(r[i++]); create_time = atoi(r[i++]); appid = atoi(r[i++]); strcpy2(name, r[i++]); strcpy2(xml_doc, r[i++]); batch = atoi(r[i++]); rsc_fpops_est = atof(r[i++]); rsc_fpops_bound = atof(r[i++]); rsc_memory_bound = atof(r[i++]); rsc_disk_bound = atof(r[i++]); need_validate = atoi(r[i++]); canonical_resultid = atoi(r[i++]); canonical_credit = atof(r[i++]); transition_time = atoi(r[i++]); delay_bound = atoi(r[i++]); error_mask = atoi(r[i++]); file_delete_state = atoi(r[i++]); assimilate_state = atoi(r[i++]); workseq_next = atoi(r[i++]); opaque = atof(r[i++]); min_quorum = atoi(r[i++]); target_nresults = atoi(r[i++]); max_error_results = atoi(r[i++]); max_total_results = atoi(r[i++]); max_success_results = atoi(r[i++]); strcpy2(result_template, r[i++]); } void DB_RESULT::db_print(char* buf){ ESCAPE(xml_doc_out); ESCAPE(stderr_out); sprintf( buf, "create_time=%d, workunitid=%d, " "server_state=%d, outcome=%d, client_state=%d, " "hostid=%d, userid=%d, " "report_deadline=%d, sent_time=%d, received_time=%d, " "name='%s', cpu_time=%.15e, " "xml_doc_in='%s', xml_doc_out='%s', stderr_out='%s', " "batch=%d, file_delete_state=%d, validate_state=%d, " "claimed_credit=%.15e, granted_credit=%.15e, opaque=%f, random=%d, " "app_version_num=%d, appid=%d, exit_status=%d, teamid=%d", create_time, workunitid, server_state, outcome, client_state, hostid, userid, report_deadline, sent_time, received_time, name, cpu_time, xml_doc_in, xml_doc_out, stderr_out, batch, file_delete_state, validate_state, claimed_credit, granted_credit, opaque, random, app_version_num, appid, exit_status, teamid ); UNESCAPE(xml_doc_out); UNESCAPE(stderr_out); } void DB_RESULT::db_parse(MYSQL_ROW &r) { int i=0; clear(); id=atol(r[i++]); create_time = atoi(r[i++]); workunitid = atoi(r[i++]); server_state = atoi(r[i++]); outcome = atoi(r[i++]); client_state = atoi(r[i++]); hostid = atoi(r[i++]); userid = atoi(r[i++]); report_deadline = atoi(r[i++]); sent_time = atoi(r[i++]); received_time = atoi(r[i++]); strcpy2(name, r[i++]); cpu_time = atof(r[i++]); strcpy2(xml_doc_in, r[i++]); strcpy2(xml_doc_out, r[i++]); strcpy2(stderr_out, r[i++]); batch = atoi(r[i++]); file_delete_state = atoi(r[i++]); validate_state = atoi(r[i++]); claimed_credit = atof(r[i++]); granted_credit = atof(r[i++]); opaque = atof(r[i++]); random = atoi(r[i++]); app_version_num = atoi(r[i++]); appid = atoi(r[i++]); exit_status = atoi(r[i++]); teamid = atoi(r[i++]); } int DB_RESULT::insert() { random = lrand48(); return DB_BASE::insert(); } void DB_MSG_FROM_HOST::db_print(char* buf) { ESCAPE(xml); sprintf(buf, "create_time=%d, send_time=%d, " "hostid=%d, variety=%d, " "handled=%d, xml='%s'", create_time, send_time, hostid, variety, handled, xml ); UNESCAPE(xml); } void DB_MSG_FROM_HOST::db_parse(MYSQL_ROW& r) { int i=0; clear(); id = atol(r[i++]); create_time = atol(r[i++]); send_time = atol(r[i++]); hostid = atol(r[i++]); variety = atol(r[i++]); handled = atoi(r[i++]); strcpy2(xml, r[i++]); } void DB_MSG_TO_HOST::db_print(char* buf) { ESCAPE(xml); sprintf(buf, "create_time=%d, " "hostid=%d, variety=%d, " "handled=%d, xml='%s'", create_time, hostid, variety, handled, xml ); UNESCAPE(xml); } void DB_MSG_TO_HOST::db_parse(MYSQL_ROW& r) { int i=0; clear(); id = atol(r[i++]); create_time = atol(r[i++]); hostid = atol(r[i++]); variety = atol(r[i++]); 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; }