// this host is declared dead; deal with the loss of data // int handle_host(DB_HOST& h) { DB_VDA_CHUNK_HOST ch; char buf[256]; int retval; log_messages.printf(MSG_NORMAL, "processing dead host %d\n", h.id); sprintf(buf, "where host_id=%d", h.id); while (1) { retval = ch.enumerate(buf); if (retval == ERR_DB_NOT_FOUND) break; if (retval) return retval; log_messages.printf(MSG_NORMAL, " updating file%d\n", ch.vda_file_id); DB_VDA_FILE vf; retval = vf.lookup_id(ch.vda_file_id); if (retval) { log_messages.printf(MSG_CRITICAL, " file lookup failed%d\n", ch.vda_file_id ); return retval; } retval = vf.update_field("need_update=1"); if (retval) { log_messages.printf(MSG_CRITICAL, " file update failed%d\n", ch.vda_file_id ); return retval; } } return 0; }
int CHUNK::start_upload() { // if no upload of this chunk is in progress, start one. // NOTE: all instances are inherently present_on_host, // since this is only called if chunk is not present on server // VDA_CHUNK_HOST* chp; set<VDA_CHUNK_HOST*>::iterator i; for (i=hosts.begin(); i!=hosts.end(); i++) { chp = *i; if (chp->transfer_in_progress) return 0; } chp = *(hosts.begin()); DB_VDA_CHUNK_HOST dch; char set_clause[256], where_clause[256]; sprintf(set_clause, "transfer_in_progress=1, transfer_wait=1, transfer_request_time=%f", dtime() ); sprintf(where_clause, "where vda_file_id=%d and host_id=%d and name='%s'", chp->vda_file_id, chp->host_id, name ); int retval = dch.update_fields_noid(set_clause, where_clause); return retval; }
int handle_remove(const char* name) { DB_VDA_FILE vf; char buf[1024]; sprintf(buf, "where file_name='%s'", name); int retval = vf.lookup(buf); if (retval) return retval; // delete DB records // DB_VDA_CHUNK_HOST ch; sprintf(buf, "vda_file_id=%d", vf.id); ch.delete_from_db_multi(buf); vf.delete_from_db(); // remove symlink from download hier // dir_hier_path(name, config.download_dir, config.uldl_dir_fanout, buf); unlink(buf); // remove encoded data and directories // retval = chdir(vf.dir); if (retval) perror("chdir"); retval = system("/bin/rm -r [0-9]* Coding data.vda"); if (retval) perror("system"); return 0; }
// Process a present file; possibilities: // - a download finished // - this host hasn't communicated in a while, and we deleted the // VDA_CHUNK_HOST record // So: // - create a vda_chunk_host record if needed // - set present_on_host flag in vda_chunk_host // - mark our in-memory vda_chunk_host record as "found" // - mark vda_file for update // static void process_present_file(FILE_INFO& fi, CHUNK_LIST& chunks) { char fname[256], chunk_name[256], buf[256]; int hostid, retval; retval = parse_physical_filename(fi.name, hostid, chunk_name, fname); if (retval) { log_messages.printf(MSG_CRITICAL, "Can't parse VDA filename %s\n", fi.name ); return; } DB_VDA_FILE vf; sprintf(buf, "where file_name='%s'", fname); retval = vf.lookup(buf); if (retval) { log_messages.printf(MSG_CRITICAL, "No VDA file %s\n", fname); return; } if (fi.nbytes != vf.chunk_size) { log_messages.printf(MSG_CRITICAL, "wrong chunk size: %.0f != %.0f\n", fi.nbytes, vf.chunk_size ); return; } CHUNK_LIST::iterator cli = chunks.find(string(fi.name)); if (cli == chunks.end()) { // don't have a record of this chunk on this host; make one // DB_VDA_CHUNK_HOST ch; ch.create_time = dtime(); ch.vda_file_id = vf.id; ch.host_id = g_reply->host.id; strcpy(ch.physical_file_name, fi.name); ch.present_on_host = true; ch.transfer_in_progress = false; ch.transfer_wait = false; ch.transfer_request_time = 0; ch.transfer_send_time = 0; retval = ch.insert(); if (retval) { log_messages.printf(MSG_CRITICAL, "ch.insert() failed\n"); return; } } else { // update the existing record // DB_VDA_CHUNK_HOST* chp = &(cli->second); chp->transfer_in_progress = false; chp->transfer_wait = false; chp->present_on_host = true; chp->update(); } mark_for_update(vf.id); }
// 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; i<policy.coding_levels; i++) { int n = fscanf(f, "%lf\n", &(policy.chunk_sizes[i])); if (n != 1) { fclose(f); return -1; } } fclose(f); meta_chunk = new META_CHUNK(this, NULL, 0); int retval = meta_chunk->get_state(dir, 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<int> chunk_numbers; retval = get_chunk_numbers(vch, chunk_numbers); if (retval) { log_messages.printf(MSG_CRITICAL, "get_chunk_numbers(): %d\n", retval ); return retval; } if ((int)(chunk_numbers.size()) != policy.coding_levels) { log_messages.printf(MSG_CRITICAL, "wrong get_chunk_numbers: got %d, expected %d\n", (int)(chunk_numbers.size()), policy.coding_levels ); return -1; } META_CHUNK* mc = meta_chunk; for (int i=0; i<policy.coding_levels; i++) { if (i == policy.coding_levels-1) { CHUNK* c = (CHUNK*)(mc->children[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; }
// assign this chunk to a host // int CHUNK::assign() { int host_id = parent->dfile->choose_host(); if (!host_id) { return ERR_NOT_FOUND; } DB_VDA_CHUNK_HOST ch; ch.create_time = dtime(); ch.vda_file_id = parent->dfile->id; ch.host_id = host_id; strcpy(ch.name, name); ch.size = parent->dfile->policy.chunk_size(); ch.present_on_host = 0; ch.transfer_in_progress = true; ch.transfer_wait = true; ch.transfer_request_time = ch.create_time; ch.transfer_send_time = 0; int retval = ch.insert(); if (retval) { log_messages.printf(MSG_CRITICAL, "ch.insert() failed\n"); return retval; } return 0; }
// handle a scheduler request: // // - handle completed uploads // - handle set of files present on client // (update or create VDA_CHUNK_HOST record) // - handle files expected but not present // - issue delete commands if needed to enforce share // - issue upload or download commands to client // // relevant fields of SCHEDULER_REQUEST // file_infos: list of sticky files // file_xfer_results: list of completed file xfers // void handle_vda() { int retval; unsigned int i; CHUNK_LIST chunks; // chunks that are supposed to be on this host // if client is outdated, mark as dead // if (outdated_client(g_reply->host)) { g_reply->host.cpu_efficiency = 1; return; } // otherwise mark it as alive // g_reply->host.cpu_efficiency = 0; // enumerate the vda_chunk_host records for this host from DB // DB_VDA_CHUNK_HOST ch; char buf[256]; sprintf(buf, "where host_id=%d", g_reply->host.id); while (1) { retval = ch.enumerate(buf); if (retval == ERR_DB_NOT_FOUND) break; if (retval) { // if we didn't get a complete enumeration, // give up rather than continuing with partial info // log_messages.printf(MSG_NORMAL, "[vda]: ch.enumerate() failed %d\n", retval ); return; } if (config.debug_vda) { log_messages.printf(MSG_NORMAL, "[vda] DB: has chunk %s, file %d\n", ch.physical_file_name, ch.vda_file_id ); } chunks.insert( pair<string, DB_VDA_CHUNK_HOST>(string(ch.physical_file_name), ch) ); } // process completed uploads // (completed downloads are handled below) // for (i=0; i<g_request->file_xfer_results.size(); i++) { RESULT& r = g_request->file_xfer_results[i]; if (strstr(r.name, "upload_vda_")) { char* phys_file_name = r.name + strlen("upload_"); if (config.debug_vda) { log_messages.printf(MSG_NORMAL, "[vda] completed upload of %s\n", phys_file_name ); } retval = process_completed_upload(phys_file_name, chunks); if (retval) { log_messages.printf(MSG_CRITICAL, "[vda] process_completed_upload(): %d\n", retval ); return; } } } // process files present on client // for (i=0; i<g_request->file_infos.size(); i++) { FILE_INFO& fi = g_request->file_infos[i]; if (!starts_with(fi.name, "vda_")) { continue; } if (config.debug_vda) { log_messages.printf(MSG_NORMAL, "[vda] request: client has file %s, status %d\n", fi.name, fi.status ); } if (fi.status != FILE_PRESENT) { continue; } process_chunk_present_on_client(fi, chunks); } process_chunks_missing_on_client(chunks); enforce_quota(chunks); issue_transfer_commands(chunks); }
// Process a file that's present on client. // A VDA_CHUNK_HOST record may not be in the DB, // e.g. because this host hasn't communicated in a while // and we deleted the VDA_CHUNK_HOST record // So: // - create a vda_chunk_host record if needed // - set present_on_host flag in vda_chunk_host // - mark our in-memory vda_chunk_host record as "found" // - mark vda_file for update // static void process_chunk_present_on_client(FILE_INFO& fi, CHUNK_LIST& chunks) { char fname[256], chunk_name[256], buf[1024]; int hostid, retval; retval = parse_physical_filename(fi.name, hostid, chunk_name, fname); if (retval) { log_messages.printf(MSG_CRITICAL, "Can't parse VDA filename %s\n", fi.name ); return; } DB_VDA_FILE vf; sprintf(buf, "where file_name='%s'", fname); retval = vf.lookup(buf); if (retval) { log_messages.printf(MSG_CRITICAL, "No VDA file for %s, deleting\n", fi.name ); delete_file_xml(fi.name, buf); g_reply->file_transfer_requests.push_back(string(buf)); return; } if (fi.nbytes != vf.chunk_size) { log_messages.printf(MSG_CRITICAL, "wrong chunk size for %s: %.0f != %.0f, deleting\n", fi.name, fi.nbytes, vf.chunk_size ); delete_file_xml(fi.name, buf); g_reply->file_transfer_requests.push_back(string(buf)); return; } CHUNK_LIST::iterator cli = chunks.find(string(fi.name)); if (cli == chunks.end()) { // we don't have a record of this chunk on this host; make one // DB_VDA_CHUNK_HOST ch; ch.create_time = dtime(); ch.vda_file_id = vf.id; ch.host_id = g_reply->host.id; strcpy(ch.physical_file_name, fi.name); ch.present_on_host = true; ch.transfer_in_progress = false; ch.transfer_wait = false; ch.transfer_request_time = 0; ch.transfer_send_time = 0; retval = ch.insert(); if (retval) { log_messages.printf(MSG_CRITICAL, "ch.insert() failed\n"); return; } mark_for_update(vf.id); } else { // we already have a DB record. // If needed, update it and mark file for update // DB_VDA_CHUNK_HOST* chp = &(cli->second); chp->found = true; // if file wasn't previously on host, update the main file // if (!chp->present_on_host) { mark_for_update(vf.id); chp->transfer_in_progress = false; chp->transfer_wait = false; chp->present_on_host = true; sprintf(buf, "host_id=%d and physical_file_name='%s'", chp->host_id, chp->physical_file_name ); chp->update_fields_noid( "transfer_in_progress=0, transfer_wait=0, present_on_host=1", buf ); } } }
// Pick a host to send a chunk of this file to. // The host must: // 1) be alive (recent RPC time) // 2) not have any chunks of this file // // We maintain a cache of such hosts // The policy is: // // - scan the cache, removing hosts that are no longer alive; // return if find a live host // - pick a random starting point in host ID space, // and enumerate 100 live hosts; wrap around if needed. // Return one and put the rest in cache // int VDA_FILE_AUX::choose_host() { int retval; DB_HOST host; return 467; // replenish cache if needed // if (!available_hosts.size()) { int nhosts_scanned = 0; int rand_id; for (int i=0; i<2; i++) { char buf[256]; if (i == 0) { retval = host.max_id(rand_id, ""); if (retval) { log_messages.printf(MSG_CRITICAL, "host.max_id() failed\n"); return 0; } rand_id = (int)(((double)id)*drand()); sprintf(buf, "where %s and id>=%d order by id limit 100", host_alive_clause(), rand_id ); } else { sprintf(buf, "where %s and id<%d order by id limit %d", host_alive_clause(), rand_id, 100-nhosts_scanned ); } while (1) { retval = host.enumerate(buf); if (retval == ERR_DB_NOT_FOUND) break; if (retval) { log_messages.printf(MSG_CRITICAL, "host enum failed\n"); return 0; } nhosts_scanned++; DB_VDA_CHUNK_HOST ch; char buf2[256]; int count; sprintf(buf2, "where vda_file_id=%d and host_id=%d", id, host.id); #if 0 retval = ch.count(count, buf2); if (retval) { log_messages.printf(MSG_CRITICAL, "ch.count failed\n"); return 0; } #else count = 0; #endif if (count == 0) { available_hosts.push_back(host.id); } if (nhosts_scanned == 100) break; } if (nhosts_scanned == 100) break; } } while (available_hosts.size()) { int hostid = available_hosts.back(); available_hosts.pop_back(); retval = host.lookup_id(hostid); if (retval || !alive(host)) { continue; } return hostid; } log_messages.printf(MSG_CRITICAL, "No hosts available\n"); return 0; }
// handle a scheduler request: // // - handle completed uploads // - handle set of files present on client // (update or create VDA_CHUNK_HOST record) // - handle files expected but not present // - issue delete commands if needed to enforce share // - issue upload or download commands to client // // relevant fields of SCHEDULER_REQUEST // file_infos: list of sticky files // file_xfer_results: list of completed file xfers // void handle_vda() { int retval; unsigned int i; CHUNK_LIST chunks; // chunks that are supposed to be on this host // enumerate the vda_chunk_host records for this host from DB // DB_VDA_CHUNK_HOST ch; char buf[256]; sprintf(buf, "where host_id=%d", g_reply->host.id); while (1) { retval = ch.enumerate(buf); if (retval == ERR_DB_NOT_FOUND) break; if (retval) { // if we didn't get a complete enumeration, // give up rather than continuing with partial info // log_messages.printf(MSG_NORMAL, "[vda]: ch.enumerate() failed %d\n", retval ); return; } if (config.debug_vda) { log_messages.printf(MSG_NORMAL, "[vda] DB: has chunk %s\n", ch.name ); } chunks.insert(pair<string, DB_VDA_CHUNK_HOST>(string(ch.name), ch)); } // process completed uploads // for (i=0; i<g_request->file_xfer_results.size(); i++) { RESULT& r = g_request->file_xfer_results[i]; if (!starts_with(r.name, "vda_upload_")) continue; char* chunk_name = r.name + strlen("vda_upload_"); if (config.debug_vda) { log_messages.printf(MSG_NORMAL, "[vda] DB: completed upload %s\n", chunk_name ); } retval = process_completed_upload(chunk_name, chunks); if (retval) { log_messages.printf(MSG_CRITICAL, "[vda] process_completed_upload(): %d\n", retval ); return; } } // process files present on host // for (i=0; i<g_request->file_infos.size(); i++) { FILE_INFO& fi = g_request->file_infos[i]; if (!starts_with(fi.name, "vda_")) { continue; } if (config.debug_vda) { log_messages.printf(MSG_NORMAL, "[vda] request: client has file %s\n", fi.name ); } process_present_file(fi, chunks); } process_missing_chunks(chunks); enforce_quota(chunks); issue_transfer_commands(chunks); }