# HG changeset patch # User Binki # Date 2009-10-10 12:42:21 # Node ID dab7d18a7366f75990d0e76f8ea8972a7624ad74 # Parent 68948a4680f174c5f68df97e400a0cc38a2380e2 # Parent befcc7fbb76546d1a576090e4de362f75f5d2542 merge in lordofwar's changes diff --git a/src/server/distrend.c b/src/server/distrend.c --- a/src/server/distrend.c +++ b/src/server/distrend.c @@ -73,6 +73,12 @@ void distrenjob_remove(struct distrenjob struct distrenjob *distrenjob_get(struct distrenjob *head, jobnum_t jobnum); void distrenjob_enqueue(struct distrenjob *head, struct distrenjob *job); void mortition(struct distrenjob *head, struct distrenjob *job); +int makeJobDataXML(struct distrenjob *job); +int updateJobListXML(struct distrenjob *head); +int createQueueFromXML(struct distrenjob *head); +int reCreateQueueFromXML(struct distrenjob *head, xmlDocPtr doc, xmlNodePtr current); +void updateGeneralInfo(); +void importGeneralInfo(); /* Global Vars, eliminate these */ jobnum_t jobnum = 0; // The next job number to create in the queue @@ -131,20 +137,24 @@ void remotio_send_to_client() } /** Fill variables after crash / shutdown from XML dumps */ -int start_data() +int start_data(struct distrenjob *head) { - general_info.hibernate = 0; struct stat buffer; - if(stat(SYSCONFDIR "/data.xml", &buffer) == 0){ - - // @TODO: retrieve total_finished_jobs and total_finished_frames from xml file + if(stat("general_info.xml", &buffer) == 0){ + importGeneralInfo(); fprintf(stderr,"Parsing XML files and restoring previous state...\n"); + createQueueFromXML(head); return 1; } else{ general_info.total_finished_jobs = 0; general_info.total_frames_rendered = 0; + general_info.free_clients = 0; + general_info.highest_jobnum = 0; + general_info.jobs_in_queue = 0; + general_info.rendering_clients = 0; + general_info.hibernate = 0; fprintf(stderr,"Couldn't find XML dump, starting up fresh.\n"); return 2; } @@ -163,6 +173,8 @@ void finish_frame(struct distrenjob *hea { mortition(head, distrenjob); } + + updateGeneralInfo(); } /** "mortition" check to see if a job is actually done by scanning the folder of the job to make sure all frames are present*/ @@ -181,6 +193,7 @@ void mortition(struct distrenjob *head, { job->frameset[counter].status = FRAMESETSTATUS_UNASSIGNED; job->completed_frames--; + general_info.total_frames_rendered--; isJobDone = 0; // if a missing frame is found, set isJobDone to false } } @@ -190,10 +203,13 @@ void mortition(struct distrenjob *head, distrenjob_remove(head, job); distrenjob_free(&job); general_info.jobs_in_queue--; + updateJobListXML(head); } else{ job->prev_frame_index = 0; // if the job isn't done, have frame_finder() start from the first frame, allowing it to see the frames that are now unassigned } + + updateGeneralInfo(); } /** scans the frames of a job to initialize a job after server */ @@ -250,9 +266,12 @@ void prepare_distrenjob(struct distrenjo } /* add job to queue */ + makeJobDataXML(distrenjob); distrenjob_enqueue(head, distrenjob); general_info.jobs_in_queue++; + updateJobListXML(head); + updateGeneralInfo(); } @@ -303,6 +322,7 @@ void change_job_priority(struct distrenj prev_job = current_job; } } + updateJobListXML(head); } /** @@ -471,8 +491,65 @@ int distrend_config_free(struct distrend } /* ************************** XML Functions ************************* */ +// writes the general_info.xml file which is a copy of the general_info structure +// except that it doesn't hold free_clients and rendering_clients +void updateGeneralInfo() +{ + xmlTextWriterPtr writer; + char *tmp; + + writer = xmlNewTextWriterFilename("general_info.xml", 0); + xmlTextWriterStartDocument(writer, NULL, "utf-8", NULL); + + xmlTextWriterStartElement(writer, (xmlChar*)"general_info"); + + _distren_asprintf(&tmp, "%d", general_info.jobs_in_queue); + xmlTextWriterWriteElement(writer, (xmlChar*)"jobs_in_queue", (xmlChar*)tmp); + _distren_asprintf(&tmp, "%d", general_info.total_finished_jobs); + xmlTextWriterWriteElement(writer, (xmlChar*)"total_finished_jobs", (xmlChar*)tmp); + _distren_asprintf(&tmp, "%d", general_info.total_frames_rendered); + xmlTextWriterWriteElement(writer, (xmlChar*)"total_frames_rendered", (xmlChar*)tmp); + _distren_asprintf(&tmp, "%d", general_info.highest_jobnum); + xmlTextWriterWriteElement(writer, (xmlChar*)"highest_jobnum", (xmlChar*)tmp); + + xmlTextWriterEndDocument(writer); + xmlFreeTextWriter(writer); +} + +// this reads the information from general_info.xml to the general_info structure +void importGeneralInfo() +{ + xmlDocPtr doc; + xmlNodePtr cur; + + doc = xmlParseFile("general_info.xml"); + cur = xmlDocGetRootElement(doc); + if (xmlStrcmp(cur->name, (xmlChar*)"general_info")) + { + fprintf(stderr, "xml document is wrong type"); + xmlFreeDoc(doc); + return; + } + + cur = cur->xmlChildrenNode; + general_info.jobs_in_queue = atoi((char*)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1)); + cur = cur->next; + general_info.total_finished_jobs = atoi((char*)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1)); + cur = cur->next; + general_info.total_frames_rendered = atoi((char*)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1)); + cur = cur->next; + general_info.highest_jobnum = atoi((char*)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1)); + + general_info.hibernate = 0; + general_info.free_clients = 0; + general_info.rendering_clients = 0; + + xmlFreeDoc(doc); +} + // returns 1 on successful completion of xml file -int makeSlaveDataXML(struct distrenjob *job) +// creates the xml file that slaves read from, and is used to restart distren +int makeJobDataXML(struct distrenjob *job) { xmlTextWriterPtr writer; char *tmp; // temporarily holds strings to be given to the xml writer @@ -481,10 +558,10 @@ int makeSlaveDataXML(struct distrenjob * // create xml document at the location tmp with no compression writer = xmlNewTextWriterFilename(tmp, 0); - xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL); + xmlTextWriterStartDocument(writer, NULL, "utf-8", NULL); - // write resolution element and add its attributes - xmlTextWriterStartElement(writer, (xmlChar*)"distrenjob"); + // write distrenjob element and add its attributes + xmlTextWriterStartElement(writer, (xmlChar*)"job"); xmlTextWriterWriteAttribute(writer, (xmlChar*)"name", (xmlChar*)job->name); xmlTextWriterWriteAttribute(writer, (xmlChar*)"submitter", (xmlChar*)job->submitter); _distren_asprintf(&tmp, "%d", job->priority); @@ -498,6 +575,23 @@ int makeSlaveDataXML(struct distrenjob * xmlTextWriterWriteAttribute(writer, (xmlChar*)"height", (xmlChar*)tmp); xmlTextWriterEndElement(writer); + // write video element and its attributes + xmlTextWriterStartElement(writer, (xmlChar*)"video"); + _distren_asprintf(&tmp, "%d", job->frameset[0].num); + xmlTextWriterWriteAttribute(writer, (xmlChar*)"start_frame", (xmlChar*)tmp); + _distren_asprintf(&tmp, "%d", job->frameset[(job->total_frames - 1)].num); + xmlTextWriterWriteAttribute(writer, (xmlChar*)"end_fame", (xmlChar*)tmp); + xmlTextWriterWriteAttribute(writer, (xmlChar*)"output_format", (xmlChar*)job->output_format); + xmlTextWriterEndElement(writer); + + // write watchdog forgiveness element + _distren_asprintf(&tmp, "%d", job->watchdog_forgiveness); + xmlTextWriterWriteElement(writer, (xmlChar*)"wd_forgiveness", (xmlChar*)tmp); + + // write total_render_time element + _distren_asprintf(&tmp, "%d", job->total_render_time); + xmlTextWriterWriteElement(writer, (xmlChar*)"total_render_time", (xmlChar*)tmp); + // end document xmlTextWriterEndDocument(writer); @@ -507,6 +601,59 @@ int makeSlaveDataXML(struct distrenjob * return 1; } +// extracts data from the xml created by above function and creates a job from it +// it returns a pointer to the created job +struct distrenjob *createJobFromXML(int job_number) +{ + xmlDocPtr doc; + xmlNodePtr cur; + char *file_name; + struct distrenjob *distrenjob; + int start_frame; + int counter; + int counter2; + + distrenjob_new(&distrenjob); + + _distren_asprintf(&file_name, "stor/job%d/job_info.xml", job_number); + + doc = xmlParseFile(file_name); + cur = xmlDocGetRootElement(doc); + + distrenjob->name = (char*)xmlGetProp(cur, (xmlChar*)"name"); + distrenjob->submitter = (char*)xmlGetProp(cur, (xmlChar*)"submitter"); + distrenjob->priority = atoi((char*)xmlGetProp(cur, (xmlChar*)"priority")); + + cur = cur->xmlChildrenNode; + distrenjob->width = atoi((char*)xmlGetProp(cur, (xmlChar*)"width")); + distrenjob->height = atoi((char*)xmlGetProp(cur, (xmlChar*)"number")); + + cur = cur->next; + start_frame = atoi((char*)xmlGetProp(cur, (xmlChar*)"start_frame")); + distrenjob->total_frames = atoi((char*)xmlGetProp(cur, (xmlChar*)"end_frame")) - start_frame + 1; + distrenjob->output_format = (char*)xmlGetProp(cur, (xmlChar*)"output_format"); + + counter2 = start_frame; + for(counter = 0; counter <= distrenjob->total_frames; counter++) + { + distrenjob->frameset[counter].num = counter2; + distrenjob->frameset[counter].status = FRAMESETSTATUS_UNASSIGNED; + + counter2++; + } + + cur = cur->next; + distrenjob->watchdog_forgiveness = atoi((char*)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1)); + + cur = cur->next; + distrenjob->total_render_time = (time_t)atol((char*)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1)); + + xmlFreeDoc(doc); + + restoreJobState(distrenjob); + return distrenjob; +} + // returns 1 if successful // updates job_list.xml which lists all the jobs in the queue int updateJobListXML(struct distrenjob *head) @@ -519,7 +666,7 @@ int updateJobListXML(struct distrenjob * _distren_asprintf(&tmp, "job_list.xml"); writer = xmlNewTextWriterFilename(tmp, 0); - xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL); + xmlTextWriterStartDocument(writer, NULL, "utf-8", NULL); // create root element job_list xmlTextWriterStartElement(writer, (xmlChar*)"job_list"); @@ -549,7 +696,6 @@ int updateJobListXML(struct distrenjob * // and then adds the jobs to the queue, as if it were never shut down int createQueueFromXML(struct distrenjob *head) { - xmlChar *tmp2; xmlDocPtr doc; // holds xml document in memory xmlNodePtr cur; // points to the current xml element node @@ -577,16 +723,49 @@ int createQueueFromXML(struct distrenjob // moves into the children elements of job_list cur = cur->xmlChildrenNode; - // scans the list of all jobs that were in queue before DistRen shutdown + reCreateQueueFromXML(head, doc, cur); + /* scans the list of all jobs that were in queue before DistRen shutdown while(cur != NULL) { - tmp2 = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); - fprintf(stderr, "adding job: %s", tmp2); + tmp = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + fprintf(stderr, "adding job: %s", tmp); // add job from job number @TODO create function with parameters (struct distrenjob *head, int job_number) // LordOfWar calls dibs on above todo + + xmlFree(tmp); cur = cur->next; // go to next child element of job_list element - } + }*/ + + xmlFreeDoc(doc); + + return 1; +} + +// inserts jobs at front of queue, starting with the last job in the job_list xml file +// to preserve the order of the queue +int reCreateQueueFromXML(struct distrenjob *head, xmlDocPtr doc, xmlNodePtr current) +{ + struct distrenjob *holder; // holds the job that "was" after head, so that the new struct can be inserted after head + struct distrenjob *job; // job to be added + xmlChar *tmp; + int job_num; + if(current == NULL) // base case, if element doesn't exist then don't do anything + return 0; + + // recursively call itself so that the next job in the queue is added to the front before the current one + reCreateQueueFromXML(head, doc, current->next); + + // now actual work is done, adding the job to the front of the queue + holder = head->next; // initialize holder + tmp = xmlNodeListGetString(doc, current->xmlChildrenNode, 1); // get job number + job_num = atoi((char*)tmp); + job = createJobFromXML(job_num); + xmlFree(tmp); // free xml char (that holds the job number) + + // insert job at front of the queue + head->next = job; + job->next = holder; return 1; } @@ -696,7 +875,7 @@ int main(int argc, char *argv[]) cont = 1; memset(&head, '\0', sizeof(struct distrenjob)); - start_data(); // Starts fresh or loads data from xml dump. Should we grab the return? + start_data(&head); // Starts fresh or loads data from xml dump. Should we grab the return? distrend_do_config(argc, argv, &config);