// 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): // // db_dump: dump database views in XML format // // usage: db_dump [-dir path] [-summary_recs num_recs_per_file] // [-detail_recs num_recs_per_file] [-gzip] [-zip] // files: // NOTE: the goal is to make the full DB available (view *_id files) // to those who want it, // while allowing those who want to see only a particular row, // or the highest-ranked rows, to get this info with a small download // // // tables.xml // for each table (team, user, host): // total number of records // number of records per file for summary files // number of records per file for detailed files // team_total_credit_N.xml // list of teams by decreasing total credit (summary) // team_expavg_credit_N.xml // team_id_N.xml // teams by ID (detailed, including list of user summaries) // user_total_credit_N.xml // list of users by total credit (summary) // user_expavg_credit_N.xml // user_id_N.xml // users by ID (detailed, including list of host summaries) // host_total_credit_N.xml // hosts by decreasing total credit (summary) // host_expavg_credit_N.xml // host_id_N.xml // hosts by ID (detailed) // NOTE: for now we're using verbose XML tag names. // We may change to short tag names to save bandwidth. #include #include #include #include #include #include "boinc_db.h" #include "util.h" #include "sched_config.h" #include "sched_util.h" #include "parse.h" #define LOCKFILE "db_dump.out" #define DEFAULT_NRECS_PER_FILE_SUMMARY 1000 #define DEFAULT_NRECS_PER_FILE_DETAIL 100 int nrecs_per_file_summary; int nrecs_per_file_detail; bool zip_files = false; string zip_cmd; // class that automatically compresses on close class ZFILE { protected: string tag; FILE* f; string filename; bool zip_file; public: ZFILE(string tag_, bool zip_file_ = zip_files) : tag(tag_), f(0), zip_file(zip_file_) {} ~ZFILE() { close(); } operator FILE* () { return f; } bool operator ! () { return !f; } void open(const char* filename_format, ...) { close(); va_list ap; char filename_buf[256]; va_start(ap, filename_format); vsprintf(filename_buf, filename_format, ap); va_end(ap); filename = filename_buf; f = fopen(filename.c_str(), "w"); if (!f) { fprintf(stderr, "db_dump: Couldn't open %s for output\n", filename.c_str()); } fprintf(f, "\n<%s>\n", tag.c_str() ); } void close() { if (f) { fprintf(f, "\n", tag.c_str()); fclose(f); if (zip_file) { string cmd = zip_cmd + ' ' + filename; system(cmd.c_str()); } f = 0; } } }; // class that automatically opens a new file every N records class NUMBERED_ZFILE : public ZFILE { const char* filename_format; int nrec_max; int nfile, nrec; public: NUMBERED_ZFILE(string tag_, const char* filename_format_, int nrec_max_) : ZFILE(tag_), filename_format(filename_format_), nrec_max(nrec_max_), nfile(0), nrec(0) { } NUMBERED_ZFILE& operator ++() { if (!f || nrec >= nrec_max) { open(filename_format, nfile); ++nfile; nrec = 0; } ++nrec; return *this; } }; void string_replace(string& str, string& old, string& newstr) { string::size_type oldlen = old.size(); string::size_type newlen = newstr.size(); string::size_type start = 0; while (1) { string::size_type pos = str.find(old, start); if (pos == string::npos) break; str.replace(pos, oldlen, newstr); start = pos+newlen; } } string x1("&"); string z1("&"); string x2("\""); string y2("""); string x3("'"); string y3("'"); string x4("<"); string y4("<"); string x5(">"); string y5(">"); void xml_escape(char* in, string& out) { out = in; string_replace(out, x1, z1); string_replace(out, x2, y2); string_replace(out, x3, y3); string_replace(out, x4, y4); string_replace(out, x5, y5); } void write_host(HOST& host, FILE* f, bool detail, bool show_user) { fprintf(f, "\n" " %d\n", host.id ); if (show_user) { DB_USER user; user.lookup_id(host.userid); if (user.show_hosts) { fprintf(f, " %d\n", host.userid ); } } fprintf(f, " %f\n" " %f\n" " %s\n" " %s\n" " %s\n" " %s\n", host.total_credit, host.expavg_credit, host.p_vendor, host.p_model, host.os_name, host.os_version ); if (detail) { fprintf(f, " %d\n" " %d\n" " %d\n" " %d\n" " %f\n" " %f\n" " %f\n" " %f\n" " %f\n" " %f\n" " %f\n" " %f\n" " %f\n" " %f\n", host.create_time, host.rpc_time, host.timezone, host.p_ncpus, host.p_fpops, host.p_iops, host.p_membw, host.m_nbytes, host.m_cache, host.m_swap, host.d_total, host.d_free, host.n_bwup, host.n_bwdown ); } fprintf(f, "\n" ); } void write_user(USER& user, FILE* f, bool detail, bool show_team) { DB_HOST host; char buf[256]; string name, url; xml_escape(user.name, name); xml_escape(user.url, url); fprintf(f, "\n" " %d\n" " %s\n" " %s\n" " %s\n" " %d\n" " %f\n" " %f\n", user.id, name.c_str(), url.c_str(), user.country, user.create_time, user.total_credit, user.expavg_credit ); if (show_team) { fprintf(f, " %d\n", user.teamid ); } if (detail && user.show_hosts) { sprintf(buf, "where userid=%d", user.id); while (!host.enumerate(buf)) { write_host(host, f, false, false); } } fprintf(f, "\n" ); } void write_team(TEAM& team, FILE* f, bool detail) { DB_USER user; char buf[MAX_BLOB_SIZE*2]; string name; xml_escape(team.name, name); fprintf(f, "\n" " %d\n" " %s\n" " %f\n" " %f\n" " %d\n", team.id, name.c_str(), team.total_credit, team.expavg_credit, team.nusers ); if (detail) { string url, name_html, description; fprintf(f, " %d\n", team.create_time ); if (strlen(team.url)) { xml_escape(team.url, url); fprintf(f, " %s\n", url.c_str() ); } if (strlen(team.name_html)) { xml_escape(team.name_html, name_html); fprintf(f, "%s\n", name_html.c_str() ); } if (strlen(team.description)) { xml_escape(team.description, description); fprintf(f, "%s\n", description.c_str() ); } fprintf(f, " %s\n", team.country ); sprintf(buf, "where teamid=%d", team.id); while (!user.enumerate(buf)) { write_user(user, f, false, false); } } fprintf(f, "\n" ); } void team_total_credit() { DB_TEAM team; NUMBERED_ZFILE f("teams", "team_total_credit_%d", nrecs_per_file_summary); while (!team.enumerate("order by total_credit desc")) { write_team(team, ++f, false); } } void team_expavg_credit() { DB_TEAM team; NUMBERED_ZFILE f("teams", "team_expavg_credit_%d", nrecs_per_file_summary); while (!team.enumerate("order by expavg_credit desc")) { write_team(team, ++f, false); } } void team_id() { DB_TEAM team; NUMBERED_ZFILE f("teams", "team_id_%d", nrecs_per_file_detail); while (!team.enumerate("order by id")) { write_team(team, ++f, true); } } void user_total_credit() { DB_USER user; NUMBERED_ZFILE f("users", "user_total_credit_%d", nrecs_per_file_summary); while (!user.enumerate("order by total_credit desc")) { write_user(user, ++f, false, true); } } void user_expavg_credit() { DB_USER user; NUMBERED_ZFILE f("users", "user_expavg_credit_%d", nrecs_per_file_summary); while (!user.enumerate("order by expavg_credit desc")) { write_user(user, ++f, false, true); } } void user_id() { DB_USER user; NUMBERED_ZFILE f("users", "user_id_%d", nrecs_per_file_detail); while (!user.enumerate("order by id")) { write_user(user, ++f, true, true); } } void host_total_credit() { DB_HOST host; NUMBERED_ZFILE f("hosts", "host_total_credit_%d", nrecs_per_file_summary); while (!host.enumerate("order by total_credit desc")) { write_host(host, ++f, false, true); } } void host_expavg_credit() { DB_HOST host; NUMBERED_ZFILE f("hosts", "host_expavg_credit_%d", nrecs_per_file_summary); while (!host.enumerate("order by expavg_credit desc")) { write_host(host, ++f, false, true); } } void host_id() { DB_HOST host; NUMBERED_ZFILE f("hosts", "host_id_%d", nrecs_per_file_detail); while (!host.enumerate("order by id")) { write_host(host, ++f, true, true); } } void core_versions() { ZFILE f("core_versions", false); f.open("core_versions.xml"); if (!f) return; fprintf(f, "\n"); DB_PLATFORM platform; while (!platform.enumerate("order by name")) { DB_CORE_VERSION core_version; char query_buf[256]; sprintf(query_buf, "where platformid=%d order by version_num desc", platform.id); if (!core_version.enumerate(query_buf)) { char url[256] = ""; parse_str(core_version.xml_doc, "", url, sizeof(url)); fprintf(f, " \n" " %d\n" " %s\n" " %d\n" " %d\n" " %s\n" " \n", core_version.id, platform.id, platform.name, platform.user_friendly_name, core_version.version_num, core_version.create_time, url ); } } fprintf(f, "\n"); f.close(); } int tables_file() { int nusers, nteams, nhosts; int retval; DB_USER user; DB_TEAM team; DB_HOST host; ZFILE f("tables", false); f.open("tables.xml"); if (!f) return -1; retval = user.count(nusers); if (retval) return retval; retval = team.count(nteams); if (retval) return retval; retval = host.count(nhosts); if (retval) return retval; fprintf(f, " %d\n" " %d\n" " %d\n" " %d\n" " %d\n" " %d\n" " %d\n" " %d\n" " %d\n" " %d\n", (int)time(0), nusers, nrecs_per_file_summary, nrecs_per_file_detail, nteams, nrecs_per_file_summary, nrecs_per_file_detail, nhosts, nrecs_per_file_summary, nrecs_per_file_detail ); f.close(); return 0; } int main(int argc, char** argv) { SCHED_CONFIG config; int retval, i; char dir[256]; check_stop_trigger(); nrecs_per_file_summary = DEFAULT_NRECS_PER_FILE_SUMMARY; nrecs_per_file_detail = DEFAULT_NRECS_PER_FILE_DETAIL; strcpy(dir, ""); for (i=1; i