// This file is part of BOINC. // http://boinc.berkeley.edu // Copyright (C) 2012 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License // as published by the Free Software Foundation, // either version 3 of the License, or (at your option) any later version. // // BOINC is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with BOINC. If not, see . // vdad - volunteer data archival daemon // // Enumerates files needing updating from the DB. // Creates the corresponding tree of META_CHUNKs, CHUNKs, // and VDA_CHUNK_HOSTs. // Calls the recovery routines to initiate transfers, // update the DB, etc. #include #include #include using std::vector; #include "boinc_db.h" #include "error_numbers.h" #include "util.h" #include "filesys.h" #include "vda_lib.h" // return the name of a file created by Jerasure's encoder // // encoder creates files with names of the form // Coding/fname_k01.ext // Coding/fname_m01.ext // void encoder_filename( const char* base, const char* ext, CODING& c, int i, char* buf ) { int ndigits = 1; if (c.m > 9) ndigits = 2; else if (c.m > 99) ndigits = 3; else if (c.m > 999) ndigits = 4; int j; char ch; if (i >= c.n) { j = i-c.n + 1; ch = 'm'; } else { j = i+1; ch = 'k'; } sprintf(buf, "%s_%c%0*d%s", base, ch, ndigits, j, ext); } // encode a meta-chunk. // precondition: "dir" contains a file "fname". // postcondition: dir contains // a subdir Coding with encoded chunks // subdirs fname_0 ... fname_m, // each containing a same-named symbolic link to the corresponding chunk // // The size of these chunks is returned in "size" // int encode(const char* dir, const char* fname, CODING& c, double& size) { char cmd[1024]; sprintf(cmd, "cd %s; /mydisks/b/users/boincadm/vda_test/encoder %s %d %d cauchy_good 32 1024 500000", dir, fname, c.n, c.k ); printf("%s\n", cmd); int s = system(cmd); if (WIFEXITED(s)) { int status = WEXITSTATUS(s); if (status != 32) return -1; // encoder returns 32 for some reason } char base[256], ext[256]; strcpy(base, fname); char* p = strchr(base, '.'); if (p) { strcpy(ext, p); *p = 0; } else { strcpy(ext, ""); } for (int i=0; iinit(child_dir, child_fname, p, level+1); if (retval) return retval; children.push_back(mc); } } else { for (int i=0; iinit(dir, name, policy, 0); if (retval) return retval; sprintf(buf, "%s/chunk_sizes.txt", dir); FILE* f = fopen(buf, "w"); for (int i=0; iget_state(child_dir, child_fname, p, level+1); if (retval) return retval; children.push_back(mc); } } else { for (int i=0; i& chunk_numbers) { char* p, *q; p = vch.name; // find the last __ in filename // while (1) { q = strstr(p, "__"); if (!q) { if (p == vch.name) return ERR_NOT_FOUND; } else { break; } p = q; } p += 2; while (p) { int i = atoi(p); chunk_numbers.push_back(i); p = strchr(p, '_'); } return 0; } // get the state of an already-initialized file: // expand the encoding tree, // enumerate the VDA_HOST_CHUNKs from the DB // and put them in the appropriate lists // int VDA_FILE_AUX::get_state() { char buf[256]; sprintf(buf, "%s/chunk_sizes.txt", dir); FILE* f = fopen(buf, "r"); if (!f) return -1; for (int i=0; iget_state(dir, name, policy, 0); if (retval) return retval; DB_VDA_CHUNK_HOST vch; sprintf(buf, "where vda_file_id=%d", id); while (1) { retval = vch.enumerate(buf); if (retval == ERR_DB_NOT_FOUND) break; if (retval) return retval; vector chunk_numbers; retval = get_chunk_numbers(vch, chunk_numbers); if (retval) return retval; if ((int)(chunk_numbers.size()) != policy.coding_levels) { return -1; } META_CHUNK* mc = meta_chunk; for (int i=0; ichildren[chunk_numbers[i]]); VDA_CHUNK_HOST* vchp = new VDA_CHUNK_HOST(); *vchp = vch; c->hosts.insert(vchp); } else { mc = (META_CHUNK*)(mc->children[chunk_numbers[i]]); } } } return 0; } int handle_file(VDA_FILE_AUX& vf) { int retval; char buf[1024]; // read the policy file // sprintf(buf, "%s/boinc_meta.txt", vf.dir); retval = vf.policy.parse(buf); if (retval) { fprintf(stderr, "Can't parse policy file %s\n", buf); return retval; } if (vf.inited) { retval = vf.get_state(); if (retval) return retval; } else { retval = vf.init(); if (retval) return retval; } vf.meta_chunk->recovery_plan(); vf.meta_chunk->recovery_action(dtime()); return 0; } // handle files // bool scan_files() { DB_VDA_FILE vf; bool found = false; int retval; while (vf.enumerate("need_update<>0")) { VDA_FILE_AUX vfa(vf); found = true; retval = handle_file(vfa); if (retval) { fprintf(stderr, "handle_file() failed: %d\n", retval); } else { vf.need_update = 0; vf.update(); } } return found; } void handle_chunk(VDA_CHUNK_HOST& ch) { } // handle timed-out transfers // bool scan_chunks() { DB_VDA_CHUNK_HOST ch; char buf[256]; bool found = false; sprintf(buf, "transition_time < %f", dtime()); while (ch.enumerate(buf)) { found = true; handle_chunk(ch); } return found; } int main(int argc, char** argv) { #if 0 VDA_FILE vf; strcpy(vf.dir, "/mydisks/b/users/boincadm/vda_test"); strcpy(vf.name, "file.ext"); handle_file(vf); exit(0); #endif while(1) { bool action = scan_files(); action |= scan_chunks(); if (!action) boinc_sleep(5.); } }