// 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: [-d n] db_dump -dump_spec file // -d debug level (1,2,3) // // dump_spec file: // // x // x // // user
// x // x x = id, total_credit, expavg_credit // // [n] // [] // [x ] x = zip or gzip // // ... //
// ... //
#include #include #include #include #include #include #include #include #include "boinc_db.h" #include "util.h" #include "error_numbers.h" #include "md5_file.h" #include "parse.h" #include "sched_config.h" #include "sched_util.h" #include "sched_msgs.h" using std::string; using std::vector; #define LOCKFILE "db_dump.out" #define COMPRESSION_NONE 0 #define COMPRESSION_GZIP 1 #define COMPRESSION_ZIP 2 #define SORT_ID 0 #define SORT_TOTAL_CREDIT 1 #define SORT_EXPAVG_CREDIT 2 #define TABLE_USER 0 #define TABLE_TEAM 1 #define TABLE_HOST 2 // must match the above char* table_name[3] = {"user", "team", "host"}; char* tag_name[3] = {"users", "teams", "hosts"}; struct OUTPUT { int recs_per_file; bool detail; int compression; class ZFILE* zfile; class NUMBERED_ZFILE* nzfile; int parse(FILE*); }; struct ENUMERATION { int table; int sort; char filename[256]; vector outputs; int parse(FILE*); int make_it_happen(char*); }; struct DUMP_SPEC { char output_dir[256]; char final_output_dir[256]; vector enumerations; int parse(FILE*); }; int OUTPUT::parse(FILE* in) { char buf[256], buf2[256]; recs_per_file = 0; detail = false; compression = COMPRESSION_NONE; zfile = 0; nzfile = 0; while (fgets(buf, 256, in)) { if (match_tag(buf, "")) return 0; if (parse_int(buf, "", recs_per_file)) continue; if (match_tag(buf, "")) { detail = true; continue; } if (parse_str(buf, "", buf2, sizeof(buf2))) { if (!strcmp(buf2, "gzip")) { compression = COMPRESSION_GZIP; } else if (!strcmp(buf2, "zip")) { compression = COMPRESSION_ZIP; } else { printf("unrecognized: %s", buf); } continue; } printf("unrecognized: %s", buf); } return ERR_XML_PARSE; } int ENUMERATION::parse(FILE* in) { char buf[256], buf2[256]; int retval, i; table = -1; sort = SORT_ID; strcpy(filename, ""); while (fgets(buf, 256, in)) { if (match_tag(buf, "")) { if (table == -1) return ERR_XML_PARSE; if (sort == -1) return ERR_XML_PARSE; if (!strlen(filename)) return ERR_XML_PARSE; return 0; } if (match_tag(buf, "")) { OUTPUT output; retval = output.parse(in); if (!retval) outputs.push_back(output); } if (parse_str(buf, "", filename, sizeof(filename))) { continue; } if (parse_str(buf, "", buf2, sizeof(buf2))) { for (i=0; i<3; i++) { if (!strcmp(buf2, table_name[i])) { table = i; break; } } } if (parse_str(buf, "", buf2, sizeof(buf2))) { if (!strcmp(buf2, "id")) sort = SORT_ID; if (!strcmp(buf2, "total_credit")) sort = SORT_TOTAL_CREDIT; if (!strcmp(buf2, "expavg_credit")) sort = SORT_EXPAVG_CREDIT; } } return ERR_XML_PARSE; } int DUMP_SPEC::parse(FILE* in) { char buf[256]; int retval; while (fgets(buf, 256, in)) { if (match_tag(buf, "")) return 0; if (match_tag(buf, "")) { ENUMERATION e; retval = e.parse(in); if (!retval) enumerations.push_back(e); } if (parse_str(buf, "\n<%s>\n", tag.c_str() ); strcpy(current_path, filename); } void open_num(const char* filename, int filenum) { char buf[256]; sprintf(buf, "%s_%d", filename, filenum); open(buf); } void close() { char buf[256]; if (f) { fprintf(f, "\n", tag.c_str()); fclose(f); printf("close compression: %d\n", compression); switch(compression) { case COMPRESSION_ZIP: sprintf(buf, "zip -q %s", current_path); printf("system: %s\n", buf); system(buf); break; case COMPRESSION_GZIP: sprintf(buf, "gzip -fq %s", current_path); printf("system: %s\n", buf); system(buf); break; } f = 0; } } }; // class that automatically opens a new file every N IDs // class NUMBERED_ZFILE : public ZFILE { const char* filename_base; int nids_per_file; int last_filenum; public: NUMBERED_ZFILE(string tag_, int comp, const char* fb, int nids_per_file_) : ZFILE(tag_, comp), filename_base(fb), nids_per_file(nids_per_file_), last_filenum(-1) {} void set_id(int); }; void NUMBERED_ZFILE::set_id(int id) { int filenum = id/nids_per_file; if (!f || (filenum != last_filenum)) { open_num(filename_base, filenum); last_filenum = filenum; } } 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) { fprintf(f, "\n" " %d\n", host.id ); if (detail) { DB_USER user; user.lookup_id(host.userid); if (user.show_hosts) { fprintf(f, " %d\n", host.userid ); } } fprintf(f, " %f\n" " %f\n" " %f\n" " %s\n" " %s\n" " %s\n" " %s\n", host.total_credit, host.expavg_credit, host.expavg_time, 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) { DB_HOST host; char buf[1024]; char cpid[MD5_LEN]; string name, url; xml_escape(user.name, name); xml_escape(user.url, url); strcpy(buf, user.cross_project_id); strcat(buf, user.email_addr); md5_block((unsigned char*)buf, strlen(buf), cpid); fprintf(f, "\n" " %d\n" " %s\n" " %s\n" " %d\n" " %f\n" " %f\n" " %f\n" " %s\n", user.id, name.c_str(), user.country, user.create_time, user.total_credit, user.expavg_credit, user.expavg_time, cpid ); if (strlen(user.url)) { fprintf(f, " %s\n", url.c_str() ); } if (user.teamid) { fprintf(f, " %d\n", user.teamid ); } if (user.has_profile) { fprintf(f, " \n" ); } if (detail && user.show_hosts) { sprintf(buf, "where userid=%d", user.id); while (!host.enumerate(buf)) { if (host.total_credit > 0) { write_host(host, f, false); } } } fprintf(f, "\n" ); } void write_team(TEAM& team, FILE* f, bool detail) { DB_USER user; char buf[256]; string name; xml_escape(team.name, name); fprintf(f, "\n" " %d\n" " %s\n" " %f\n" " %f\n" " %f\n" " %d\n", team.id, name.c_str(), team.total_credit, team.expavg_credit, team.expavg_time, 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); } } fprintf(f, "\n" ); } void core_versions(char* dir) { char buf[256]; sprintf(buf, "%s/core_versions.xml", dir); ZFILE f("core_versions", false); f.open(buf); 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.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 ); } } f.close(); } int print_app(FILE* f, APP& app) { DB_RESULT result; char buf[256]; int n, retval; fprintf(f, " \n"); fprintf(f, " %s\n", app.user_friendly_name); #if 0 // can't do this stuff because MySQL/InnoDB can't do counts efficiently // sprintf(buf, "where appid=%d and server_state=%d", app.id, RESULT_SERVER_STATE_UNSENT); retval = result.count(n, buf); if (!retval) { fprintf(f, " %d\n", n); } sprintf(buf, "where appid=%d and server_state=%d", app.id, RESULT_SERVER_STATE_IN_PROGRESS); retval = result.count(n, buf); if (!retval) { fprintf(f, " %d\n", n); } sprintf(buf, "where appid=%d and server_state=%d", app.id, RESULT_SERVER_STATE_OVER); retval = result.count(n, buf); if (!retval) { fprintf(f, " %d\n", n); } #endif fprintf(f, " \n"); return 0; } int print_apps(FILE* f) { DB_APP app; fprintf(f, " \n"); while (!app.enumerate()) { print_app(f, app); } fprintf(f, " \n"); return 0; } int tables_file(char* dir) { int nusers, nteams, nhosts; int retval; char buf[256]; DB_USER user; DB_TEAM team; DB_HOST host; ZFILE f("tables", false); sprintf(buf, "%s/tables.xml", dir); f.open(buf); fprintf(f.f, " %d\n", (int)time(0) ); #if 0 // can't do counts in MySQL/InnoDB 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.f, " %d\n" " %d\n" " %d\n", nusers, nteams, nhosts ); #endif print_apps(f.f); f.close(); return 0; } int ENUMERATION::make_it_happen(char* output_dir) { unsigned int i; int n; DB_USER user; DB_TEAM team; DB_HOST host; char clause[256]; char path[256]; sprintf(path, "%s/%s", output_dir, filename); for (i=0; iopen(path); } } switch(sort) { case SORT_ID: strcpy(clause, "order by id"); break; case SORT_TOTAL_CREDIT: strcpy(clause, "order by total_credit desc"); break; case SORT_EXPAVG_CREDIT: strcpy(clause, "order by expavg_credit desc"); break; } switch(table) { case TABLE_USER: n = 0; while(!user.enumerate(clause)) { for (i=0; iset_id(n++); } if (out.zfile) { write_user(user, out.zfile->f, out.detail); } else { write_user(user, out.nzfile->f, out.detail); } } } break; case TABLE_HOST: n = 0; while(!host.enumerate(clause)) { for (i=0; iset_id(n++); } if (out.zfile) { write_host(host, out.zfile->f, out.detail); } else { write_host(host, out.nzfile->f, out.detail); } } } break; case TABLE_TEAM: n = 0; while(!team.enumerate(clause)) { for (i=0; iset_id(n++); } if (out.zfile) { write_team(team, out.zfile->f, out.detail); } else { write_team(team, out.nzfile->f, out.detail); } } } break; } for (i=0; iclose(); if (out.nzfile) out.nzfile->close(); } return 0; } int main(int argc, char** argv) { SCHED_CONFIG config; int retval, i; DUMP_SPEC spec; char spec_filename[256], buf[256]; check_stop_daemons(); setbuf(stderr, 0); strcpy(spec_filename, ""); for (i=1; i