Changeset - e469bd961670
[Not reviewed]
default
0 2 0
LordOfWar - 16 years ago 2009-10-14 00:45:34

auto-initialized watchdog forgiveness, cleaned up for loop
2 files changed with 2 insertions and 1 deletions:
0 comments (0 inline, 0 general)
src/server/distrend.c
Show inline comments
 
@@ -543,385 +543,385 @@ void updateGeneralInfo()
 
}
 

	
 
// 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
 
// 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
 

	
 
  _distren_asprintf(&tmp, "stor/job%d/job_info.xml", job->jobnum);
 

	
 
  // create xml document at the location tmp with no compression
 
  writer = xmlNewTextWriterFilename(tmp, 0);
 
  xmlTextWriterStartDocument(writer, NULL, "utf-8", NULL);
 

	
 
  // 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);
 
  xmlTextWriterWriteAttribute(writer, (xmlChar*)"priority", (xmlChar*)tmp);
 

	
 
  // write resolution element and add its attributes
 
  xmlTextWriterStartElement(writer, (xmlChar*)"resolution");
 
  _distren_asprintf(&tmp, "%d", job->width);
 
  xmlTextWriterWriteAttribute(writer, (xmlChar*)"width", (xmlChar*)tmp);
 
  _distren_asprintf(&tmp, "%d", job->height);
 
  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);
 

	
 
  // end document
 
  xmlTextWriterEndDocument(writer);
 

	
 
  // free writer and save xml file to disk
 
  xmlFreeTextWriter(writer);
 

	
 
  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");
 

	
 
  cur = cur->next;
 
  distrenjob->watchdog_forgiveness = atoi((char*)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1));
 

	
 
  xmlFreeDoc(doc);
 

	
 
  // load up stats.xml file to retrieve data
 
  _distren_asprintf(&file_name, "stor/job%d/stats.xml", job_number);
 

	
 
  doc = xmlParseFile(file_name);
 
  cur = xmlDocGetRootElement(doc);
 

	
 
  distrenjob->total_render_time = (time_t)atol((char*)xmlGetProp(cur, (xmlChar*)"total_render_time"));
 

	
 
  xmlFreeDoc(doc);
 

	
 
  distrenjob->frameset = malloc(sizeof(struct frameset) * distrenjob->total_frames);
 

	
 
  // change the status of all frames to "unassigned"
 
  counter2 = start_frame;
 
  for(counter = 0; counter <= distrenjob->total_frames; counter++){
 
    distrenjob->frameset[counter].num = counter2;
 
    distrenjob->frameset[counter].status = FRAMESETSTATUS_UNASSIGNED;
 

	
 
    counter2++;
 
  }
 

	
 
  restoreJobState(distrenjob);
 
  return distrenjob;
 
}
 

	
 
int updateJobStatsXML(struct distrenjob *job)
 
{
 
	  xmlTextWriterPtr writer;
 
	  char *tmp; // temporarily holds strings to be given to the xml writer
 

	
 
	  _distren_asprintf(&tmp, "stor/job%d/stats.xml", job->jobnum);
 

	
 
	  // create xml document at the location tmp with no compression
 
	  writer = xmlNewTextWriterFilename(tmp, 0);
 
	  xmlTextWriterStartDocument(writer, NULL, "utf-8", NULL);
 

	
 
	  xmlTextWriterStartElement(writer, (xmlChar*)"stats");
 
	  _distren_asprintf(&tmp, "%d", job->assigned_frames);
 
	  xmlTextWriterWriteAttribute(writer, (xmlChar*)"assigned_frames", (xmlChar*)tmp);
 
	  _distren_asprintf(&tmp, "%d", job->completed_frames);
 
	  xmlTextWriterWriteAttribute(writer, (xmlChar*)"completed_frames", (xmlChar*)tmp);
 
	  _distren_asprintf(&tmp, "%d", job->total_render_time);
 
	  xmlTextWriterWriteAttribute(writer, (xmlChar*)"total_render_time", (xmlChar*)tmp);
 

	
 
	  // end document
 
	  xmlTextWriterEndDocument(writer);
 
	  // free writer and save xml file to disk
 
	  xmlFreeTextWriter(writer);
 

	
 
	  return 1;
 
}
 

	
 
// returns 1 if successful
 
// updates job_list.xml which lists all the jobs in the queue
 
int updateJobListXML(struct distrenjob *head)
 
{
 
  struct distrenjob *job;
 
  xmlTextWriterPtr writer;
 
  char *tmp;
 
  char *tmp2;
 
  int counter;
 

	
 
  writer = xmlNewTextWriterFilename("job_list.xml", 0);
 
  xmlTextWriterStartDocument(writer, NULL, "utf-8", NULL);
 

	
 
  // create root element job_list
 
  xmlTextWriterStartElement(writer, (xmlChar*)"job_list");
 

	
 
  _distren_asprintf(&tmp, "%d", general_info.jobs_in_queue);
 
  xmlTextWriterWriteAttribute(writer, (xmlChar*)"amount", (xmlChar*)tmp);
 

	
 
  counter = 0;
 
  for(job = head->next; !job; job = job->next)
 
  for(job = head->next; job; job = job->next)
 
    {
 
      _distren_asprintf(&tmp, "jobnum%d", counter);
 
      _distren_asprintf(&tmp2, "%d", job->jobnum);
 
      xmlTextWriterWriteElement(writer, (xmlChar*)tmp, (xmlChar*)tmp2);
 
      counter++;
 
    }
 

	
 
  // close elements and end document
 
  xmlTextWriterEndDocument(writer);
 

	
 
  // free writer and save xml file to disk
 
  xmlFreeTextWriter(writer);
 
  return 1;
 
}
 

	
 
// returns 1 if completed successfully, 0 if not
 
// this reads a list of jobs in the queue before DistRen was shut down
 
// and then adds the jobs to the queue, as if it were never shut down
 
int createQueueFromXML(struct distrenjob *head)
 
{
 
  xmlDocPtr doc;  // holds xml document in memory
 
  xmlNodePtr cur; // points to the current xml element node
 

	
 
  // load xml document
 
  doc = xmlParseFile("job_list.xml");
 
  if(doc == NULL)
 
    {
 
      fprintf(stderr, "createQueueFromXML: document not found\n");
 
      return 0;
 
    }
 

	
 
  // have cur point to the root element of the xml document pointed to by doc
 
  cur = xmlDocGetRootElement(doc);
 
  if(cur == NULL)
 
    {
 
      fprintf(stderr, "createQueueFromXML: document empty\n");
 
      return 0;
 
    }
 

	
 
  if(xmlStrcmp(cur->name, (const xmlChar*)"job_list"))
 
    {
 
      fprintf(stderr, "createQueueFromXML: incorrect root element (%s)", (char*)cur->name);
 
    }
 

	
 
  // moves into the children elements of job_list
 
  cur = cur->xmlChildrenNode;
 

	
 
  reCreateQueueFromXML(head, doc, cur);
 
  /* scans the list of all jobs that were in queue before DistRen shutdown
 
  while(cur != NULL)
 
    {
 
      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;
 
}
 

	
 
/* ************************** Test Functions ************************* */
 
void printFrameInfo(struct frameset *frame)
 
{
 
  char *status;
 

	
 
  status = NULL;
 

	
 
  switch(frame->status)
 
  {
 
    case FRAMESETSTATUS_UNASSIGNED:
 
      _distren_asprintf(&status, "%s", "unassigned");
 
      break;
 
    case FRAMESETSTATUS_ASSIGNED:
 
      _distren_asprintf(&status, "%s", "assigned");
 
      break;
 
    case FRAMESETSTATUS_DONE:
 
      _distren_asprintf(&status, "%s", "completed");
 
      break;
 
    case FRAMESETSTATUS_CANCELED:
 
      _distren_asprintf(&status, "%s", "canceled");
 
  }
 

	
 
  printf("frame #: %d --> %s", frame->num, status);
 
}
 

	
 
void printJob(struct distrenjob *job)
 
{
 
  int counter;
 
  printf("frame_num: status");
 
  for(counter = 0; counter < job->total_frames; counter++)
 
    {
 
      printFrameInfo(&job->frameset[counter]);
 
    }
 
}
 

	
 
void printJobInfo(struct distrenjob *job)
 
{
 
  printf("type: %d", job->type);
 
  printf("name: %s", job->email);
 
  printf("submitter: %s", job->submitter);
 
  printf("e-mail: %s", job->email);
 
  printf("priority, %d", job->priority);
 
  printf("completed: %d", job->completed_frames);
 
  printf("assigned: %d", job->assigned_frames);
 
  printf("total: %d", job->total_frames);
 
  printf("watchdog: %d", job->watchdog_forgiveness);
 
  printf("hibernate: %d", job->hibernate);
 
  printf("prev_frame: %d", job->prev_frame_index);
 
}
 

	
 
void printAllJobnums(struct distrenjob *head)
 
{
 
  struct distrenjob *current_job;
 
  int total_jobs;
 
  printf("job numbers in the order they will be processed:");
 

	
 
  total_jobs = 0;
 
  for(current_job = head; !current_job; current_job = current_job->next)
 
    {
 
      printf("%d", current_job->jobnum);
 
      total_jobs++;
 
    }
 

	
 
  printf("%d jobs in queue", total_jobs);
 
}
 

	
 
/* ************************** Main ************************* */
 

	
 
int main(int argc, char *argv[])
 
{
 

	
 
  /* Argument-parser */
 
  int counter;
 
  int test; // Have some fun if-ness that does fun stuff when this is 1
 

	
 

	
 
  struct distrenjob head;
 

	
 
  int cont;
 
  struct distrend_listenset *listenset;
 
  struct distrend_config *config;
 

	
 
  enum clientstatus
 
  {
 
    CLIENTSTATUS_UNINITIALIZED = 0,
 
    CLIENTSTATUS_BUSY = 1,
 
    CLIENTSTATUS_IDLE = 2
 
  } clientstatus;
 

	
 

	
 
  int command;
 
  jobnum_t jobnum;
 
  struct distrenjob *tmp_job;
 
  struct frameset *tmp_frame;
 
  int type;
 
  char *name;
 
  char *submitter;
 
  char *email;
src/server/distrenjob.c
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink <ohnobinki@ohnopublishing.net>
 

	
 
  This file is a part of DistRen.
 

	
 
  DistRen is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU Affero General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  DistRen 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 Affero General Public License for more details.
 

	
 
  You should have received a copy of the GNU Affero General Public License
 
  along with DistRen.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 
#include "distrenjob.h"
 
#include "slavefuncs.h"
 
#include "asprintf.h"
 

	
 
#include <libxml/tree.h>
 
#include <libxml/parser.h>
 

	
 
void distrenjob_free(struct distrenjob **distrenjob)
 
{
 
  struct distrenjob *dj;
 

	
 
  dj = *distrenjob;
 
  xmlFree(dj->name);
 
  xmlFree(dj->submitter);
 
  xmlFree(dj->email);
 

	
 
  free(dj->frameset);
 

	
 
  free(dj);
 
  *distrenjob = NULL;
 
}
 

	
 
int distrenjob_new(struct distrenjob **distrenjob)
 
{
 
  struct distrenjob *dj;
 

	
 
  dj = malloc(sizeof(struct distrenjob));
 
  if(!dj)
 
    {
 
      /* try to catch code that doesn't respect return values
 
       faster: */
 
      *distrenjob = NULL;
 
      return 1;
 
    }
 
  *distrenjob = dj;
 

	
 
  dj->next = NULL;
 
  dj->name = (char *)NULL;
 
  dj->submitter = (char *)NULL;
 
  dj->email = (char *)NULL;
 
  dj->jobnum = 0; /*< @todo there should be a central jobnum allocator and a way to save the maximum jobnumber allocated */
 
  dj->priority = 0;
 
  dj->width = 0;
 
  dj->height = 0;
 
  dj->completed_frames = 0;
 
  dj->assigned_frames = 0;
 
  dj->total_render_time = 0;
 
  dj->hibernate = 0;
 
  dj->watchdog_forgiveness = 3600; // initialize watchdog forgiveness at 1 hour
 
  dj->frameset = (struct frameset *)NULL; /*< @todo does frameset need to be initialized here? */
 

	
 
  return 0;
 
}
 

	
 
/**
 
   writes struct from xml
 
*/
 
int xml2distrenjob(struct distrenjob **distrenjob, char *pathtoxml)
 
{
 
  struct distrenjob *dj;
 

	
 
  xmlDocPtr xmldoc;
 
  xmlNodePtr xmlnode;
 
  xmlChar *xmlchar;
 

	
 
  xmlXPathContextPtr xmlxpathcontext;
 

	
 
  int tmp;
 

	
 
  if(distrenjob_new(distrenjob))
 
    return 1;
 
  dj = *distrenjob;
 

	
 
  xmldoc = xmlReadFile(pathtoxml, NULL, XML_PARSE_PEDANTIC);
 
  if(!xmldoc)
 
    {
 
      /**
 
	 @todo are we able to depend on libxml2's printed errors or
 
	 channel them into syslog output (eventually)? Currently,
 
	 this error is repetitious of a libxml2 error printed on stderr
 
	 for us.
 
       */
 
      fprintf(stderr, "error reading XML file ``%s''\n", pathtoxml);
 

	
 
      distrenjob_free(distrenjob);
 
      return 2;
 
    }
 

	
 
  xmlxpathcontext = xmlXPathNewContext(xmldoc);
 
  xmlnode = xml_quickxpath(xmlxpathcontext, (xmlChar *)"/distren/job");
 
  if(!xmlnode)
 
    {
 
      distrenjob_free(distrenjob);
 
      return 3;
 
    }
 

	
 
  /*< @todo should we use xmlChar everywhere too? */
 
  dj->name = (char *)xmlGetProp(xmlnode, (xmlChar *)"name");
 
  if(!dj->name)
 
    {
 
      distrenjob_free(distrenjob);
 
      return 4;
 
    }
 

	
 
  /*< @todo validation needs to be done on usernames. e.g., currently, they shouldn't contain the '"' char  */
 
  dj->submitter = (char *)xmlGetProp(xmlnode, (xmlChar *)"submitter");
 
  if(!dj->submitter)
 
    {
 
      distrenjob_free(distrenjob);
 
      return 5;
 
    }
 

	
 
  tmp = _distren_asprintf((char **)&xmlchar, "/distren/submitters/submitter[attribute::name=\"%s\"]", dj->submitter);
 
  if(tmp <= 0
 
     || !xmlchar)
 
    {
 
      fprintf(stderr, "error using _distren_asprintf\n");
 
      distrenjob_free(distrenjob);
 
      return 6;
 
    }
 
  xmlnode = xml_quickxpath(xmlxpathcontext, xmlchar);
 
  free(xmlchar);
 
  dj->email = (char *)xmlGetProp(xmlnode, (xmlChar *)"email");
 
  if(!dj->email)
 
    {
 
      fprintf(stderr, "error getting email for user ``%s'' from ``%s''\n",
 
	      dj->submitter, pathtoxml);
 
      distrenjob_free(distrenjob);
 
      return 7;
 
    }
 

	
 
  xmlXPathFreeContext(xmlxpathcontext);
 
  xmlFreeDoc(xmldoc);
 
  return 0;
 
}
 

	
0 comments (0 inline, 0 general)