Changeset - e696db7b7db2
[Not reviewed]
default
0 2 0
Nathan Brink (binki) - 16 years ago 2010-01-24 18:31:04
ohnobinki@ohnopublishing.net
fix job_list.xml, store jobnum in distrenjob.xml
2 files changed with 34 insertions and 10 deletions:
0 comments (0 inline, 0 general)
src/server/distrend.c
Show inline comments
 
@@ -669,474 +669,487 @@ int distrend_do_config(int argc, char *a
 
      CFG_END()
 
    };
 
  cfg_opt_t myopts[] =
 
    {
 
      CFG_SEC("listen",  /* this must be imported into struct listens (which must still be declared) */
 
          myopts_listen,
 
          CFGF_MULTI),
 
      CFG_SIMPLE_STR("datadir", NULL),
 
      CFG_STR_LIST("render_types", NULL, CFGF_NONE),
 
      CFG_END()
 
    };
 

	
 
  cfg_t *cfg_listen;
 

	
 
  fprintf(stderr, "%s:%d: running config\n", __FILE__, __LINE__);
 
  *config = malloc(sizeof(struct distrend_config));
 
  myopts[1].simple_value = &(*config)->datadir;
 

	
 
  if(options_init(argc, argv, &(*config)->mycfg, myopts, "daemon", &(*config)->options))
 
    return 1;
 

	
 
  /**
 
     grab listen blocks:
 
   */
 
  (*config)->listens = malloc(sizeof(struct distrend_listen) * (cfg_size((*config)->mycfg, "listen") + 1));
 
  for(counter = 0; counter < cfg_size((*config)->mycfg, "listen"); counter ++)
 
    {
 
      cfg_listen = cfg_getnsec((*config)->mycfg, "listen", counter);
 
      (*config)->listens[counter].port = cfg_getint(cfg_listen, "port");
 
      (*config)->listens[counter].sock = -1;
 
    }
 
  memset(&(*config)->listens[counter], '\0', sizeof(struct distrend_listen));
 

	
 
  fprintf(stderr, "using %s as datadir\n", (*config)->datadir);
 

	
 
  return 0;
 
}
 
int distrend_config_free(struct distrend_config *config)
 
{
 
  options_free(config->options);
 
  free(config);
 

	
 
  return 0;
 
}
 
/* ************************** 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 update_general_info(struct general_info *geninfo)
 
{
 
  xmlTextWriterPtr writer;
 
  char *tmp;
 

	
 
  writer = xmlNewTextWriterFilename(geninfo->files.geninfo, 0);
 
  xmlTextWriterStartDocument(writer, NULL, "utf-8", NULL);
 

	
 
  xmlTextWriterStartElement(writer, (xmlChar*)"general_info");
 

	
 
  _distren_asprintf(&tmp, "%d", geninfo->jobs_in_queue);
 
  xmlTextWriterWriteElement(writer, (xmlChar*)"jobs_in_queue", (xmlChar*)tmp);
 
  free(tmp);
 

	
 
  _distren_asprintf(&tmp, "%d", geninfo->total_finished_jobs);
 
  xmlTextWriterWriteElement(writer, (xmlChar*)"total_finished_jobs", (xmlChar*)tmp);
 
  free(tmp);
 

	
 
  _distren_asprintf(&tmp, "%d", geninfo->total_frames_rendered);
 
  xmlTextWriterWriteElement(writer, (xmlChar*)"total_frames_rendered", (xmlChar*)tmp);
 
  free(tmp);
 

	
 
  _distren_asprintf(&tmp, "%d", geninfo->highest_jobnum);
 
  xmlTextWriterWriteElement(writer, (xmlChar*)"highest_jobnum", (xmlChar*)tmp);
 
  free(tmp);
 

	
 
  xmlTextWriterEndDocument(writer);
 
  xmlFreeTextWriter(writer);
 
}
 

	
 
/**
 
   Reads general state information from general_info.xml
 
   into the general_info structure.
 
*/
 
int import_general_info(struct general_info *general_info)
 
{
 
  xmlDocPtr doc;
 
  xmlNodePtr cur;
 

	
 
  doc = xmlParseFile(general_info->files.geninfo);
 
  cur = xmlDocGetRootElement(doc);
 
  if (xmlStrcmp(cur->name, (xmlChar*)"general_info"))
 
    {
 
      fprintf(stderr, "xml document is wrong type");
 
      xmlFreeDoc(doc);
 
      return 1;
 
    }
 

	
 
  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;
 
  general_info->timestamp = 0;
 
  general_info->total_render_power = 0;
 
  general_info->total_priority_pieces = 0;
 

	
 
  xmlFreeDoc(doc);
 

	
 
  return 0;
 
}
 

	
 
/**
 
   determines path to the distenjob XML file and
 
   calls distrenjob_unserialize()
 
 */
 
int restore_distrenjob(struct general_info *geninfo, struct distrenjob **distrenjob, jobnum_t jobnum)
 
{
 
  int tmp;
 
  char *file_name;
 

	
 
  tmp = job_getserialfilename(&file_name, geninfo, jobnum, 0);
 
  if(tmp)
 
    return tmp;
 

	
 
  tmp = distrenjob_unserialize(distrenjob, file_name);
 
  if(tmp)
 
    fprintf(stderr, "failed to load job %d from ``%s''\n",
 
	    jobnum, file_name);
 
  
 
  free(file_name);
 
  return tmp;
 
}
 

	
 
int updateJobStatsXML(struct distrenjob *job)
 
{
 
	  xmlTextWriterPtr writer;
 
	  char *tmp;
 

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

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

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

	
 
	  _distren_asprintf(&tmp, "%d", job->completed_frames);
 
	  xmlTextWriterWriteAttribute(writer, (xmlChar*)"completed_frames", (xmlChar*)tmp);
 
	  free(tmp);
 

	
 
	  _distren_asprintf(&tmp, "%d", job->total_render_time);
 
	  xmlTextWriterWriteAttribute(writer, (xmlChar*)"total_render_time", (xmlChar*)tmp);
 
	  free(tmp);
 

	
 
	  /**
 
	     end document
 
	  */
 
	  xmlTextWriterEndDocument(writer);
 
	  /**
 
	     free writer and save xml file to disk
 
	     @TODO confirma that calling xmlFreeTextWriter calls
 
	           write() and close(), respectively.
 
		   (close() causes asynchronous writes to be
 
		   completed).
 
	  */
 
	  xmlFreeTextWriter(writer);
 

	
 
	  return 1;
 
}
 

	
 

	
 
/**
 
   updates job_list.xml which lists all the jobs in the queue
 
   @return 0 means success
 
*/
 
int update_xml_joblist(struct general_info *geninfo)
 
{
 
  struct distrenjob *job;
 
  xmlTextWriterPtr writer;
 
  char *tmp;
 
  char *tmp2;
 
  int counter;
 

	
 
  /**
 
     update timestamp
 
  */
 
  geninfo->timestamp ++;
 
  if(geninfo->timestamp > 65530)
 
    geninfo->timestamp = 0;
 

	
 
  writer = xmlNewTextWriterFilename("job_list.xml", 0);
 
  _distren_asprintf(&tmp, "%s/job_list.xml",
 
		    geninfo->config->datadir);
 
  writer = xmlNewTextWriterFilename(tmp, 0);
 
  free(tmp);
 

	
 
  xmlTextWriterStartDocument(writer, NULL, "utf-8", NULL);
 

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

	
 
  _distren_asprintf(&tmp, "%d", geninfo->timestamp);
 
  xmlTextWriterWriteAttribute(writer, (xmlChar*)"timestamp", (xmlChar*)tmp);
 
  free(tmp);
 

	
 
  geninfo->total_priority_pieces = 0;
 
  counter = 0;
 
  for(job = geninfo->head.next; job; job = job->next)
 
    {
 
      _distren_asprintf(&tmp, "jobnum%d", counter);
 
      _distren_asprintf(&tmp2, "%d", job->jobnum);
 
      xmlTextWriterWriteElement(writer, (xmlChar*)tmp, (xmlChar*)tmp2);
 
      free(tmp2);
 
      _distren_asprintf(&tmp, "%d", job->jobnum);
 
      xmlTextWriterWriteElement(writer, (xmlChar*)"jobnum", (xmlChar*)tmp);
 
      free(tmp);
 

	
 
      /**
 
	this is needed for the new frame finder to work 
 
      
 
	Why the random constant numeral 11? --ohnobinki
 
      */
 
      geninfo->total_priority_pieces = geninfo->total_priority_pieces + (NUMBER_ELEVEN - job->priority);
 

	
 
      counter++;
 
    }
 

	
 
  xmlTextWriterEndElement(writer);
 

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

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

	
 
/**
 
 returns 0 if completed successfully
 
 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 general_info *geninfo)
 
{
 
  int tmp;
 

	
 
  xmlDocPtr doc;
 
  xmlNodePtr cur;
 

	
 
  char *xmllist_path;
 

	
 
  /**
 
     load xml document
 
  */
 
  doc = xmlParseFile("job_list.xml");
 

	
 
  _distren_asprintf(&xmllist_path, "%s/job_list.xml", geninfo->config->datadir);
 
  doc = xmlParseFile(xmllist_path);
 
  if(doc == NULL)
 
    {
 
      fprintf(stderr, "createQueueFromXML: document not found\n");
 
      fprintf(stderr, "createQueueFromXML: ``%s'' could not be not loaded\n",
 
	      xmllist_path);
 

	
 
      free(xmllist_path);
 
      return 1;
 
    }
 
  free(xmllist_path);
 

	
 
  /**
 
     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 1;
 
    }
 

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

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

	
 
  tmp = reCreateQueueFromXML(geninfo, doc, cur);
 

	
 
  xmlFreeDoc(doc);
 

	
 
  return tmp;
 
}
 

	
 
/**
 
   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 general_info *geninfo, 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;
 
  jobnum_t 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
 
  */
 
  if(reCreateQueueFromXML(geninfo, doc, current->next))
 
    /**
 
       bail if failure recursevely
 
        ^-- is this the best thing to do in this case?
 
	@TODO bail-out cleanup
 
     */
 
    return 1;
 

	
 
  /** actual work is done now: add the job to the front of the queue */
 
  holder = geninfo->head.next;
 

	
 
  tmp = xmlNodeListGetString(doc, current->xmlChildrenNode, 1); // get job number
 
  job_num = atoi((char*)tmp);
 
  xmlFree(tmp);
 

	
 
  if(restore_distrenjob(geninfo, &job, job_num))
 
    return 1;
 

	
 
  /**
 
     insert job at front of the queue
 
  */
 
  geninfo->head.next = job;
 
  job->next = holder;
 

	
 
  return 0;
 
}
 

	
 
/* ************************** Test Functions ************************* */
 
int 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\n", frame->num, status);
 
  free(status);
 

	
 
  return 0;
 
}
 

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

	
 
  return 1;
 
}
 

	
 
int printJobInfo(struct distrenjob *job)
 
{
 
  fprintf(stderr, "type: %d\n", job->type);
 
  fprintf(stderr, "name: %s\n", job->name);
 
  fprintf(stderr, "submitter: %s\n", job->submitter);
 
  fprintf(stderr, "priority: %d\n", job->priority);
 
  fprintf(stderr, "completed: %d\n", job->completed_frames);
 
  fprintf(stderr, "assigned: %d\n", job->assigned_frames);
 
  fprintf(stderr, "total: %d\n", job->total_frames);
 
  fprintf(stderr, "watchdog: %d\n", job->watchdog_forgiveness);
 
  fprintf(stderr, "hibernate: %d\n", job->hibernate);
 
  fprintf(stderr, "prev_frame: %d\n", job->prev_frame_index);
 
  fprintf(stderr, "render power: %ld\n", job->assigned_render_power);
 

	
 
  return 1;
 
}
 

	
 
int printAllJobnums(struct distrenjob *head)
 
{
 
  struct distrenjob *current_job;
 
  int total_jobs;
 
  fprintf(stderr, "job numbers in the order they will be processed:\n");
 

	
 
  total_jobs = 0;
 
  for(current_job = head->next; current_job; current_job = current_job->next)
 
    {
 
      fprintf(stderr, "%d: %s\n", current_job->jobnum, current_job->name);
 
      total_jobs++;
 
    }
 

	
 
  fprintf(stderr, "\n%d jobs in queue\n\n", total_jobs);
 

	
 
  return 1;
 
}
 

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

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

	
 
  /* Argument-parser */
 
  int counter;
 
  int test; /*< Interactive mode if 1 */
 

	
 
  struct general_info general_info;
 

	
 
  int cont;
 
  struct distrend_clientset *clients;
 

	
 
  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;
 
  int priority;
 
  int width;
 
  int height;
 
  int start_frame;
 
  int end_frame;
 
  size_t read_buf;
 

	
 
  xmlinit();
 

	
 
  test = 0;
 
  for(counter = 0; counter < argc; counter ++)
 
    {
 
      if(strcmp(argv[counter], "-h") == 0)
 
      {
 
    	  fprintf(stderr, "Usage: distrend [option] \nStarts the distrend server\n\t-h\tshow this help\n\t-t\tlaunches queue testing interface \n");
 
		  return 2;
 
      }
 

	
 
      else if(strcmp(argv[counter], "-t") == 0)
 
      {
 
    	  fprintf(stderr, "Entering into test mode...\n\n");
 
		  test=1;
 
      }
 
    }
 
  cont = 1;
 

	
 
  if(distrend_do_config(argc, argv, &general_info.config))
 
    return 1;
 

	
 
  /** preset paths */
src/server/distrenjob.c
Show inline comments
 
@@ -3,353 +3,364 @@
 

	
 
  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 "asprintf.h"
 
#include "distrenjob.h"
 
#include "slavefuncs.h"
 

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

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

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

	
 
  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->jobnum = 0; /*< @todo there should be a central jobnum allocator and a way to save the maximum jobnumber allocated */
 
  dj->type = 1;
 
  dj->name = (char *)NULL;
 
  dj->submitter = (char *)NULL;
 

	
 
  dj->output_format = (char *)NULL;
 
  dj->width = 0;
 
  dj->height = 0;
 

	
 
  dj->priority = 0;
 
  dj->completed_frames = 0;
 
  dj->assigned_frames = 0;
 
  dj->total_frames = 0;
 
  dj->prev_frame_index = -1;
 

	
 
  dj->total_render_time = 0;
 
  dj->assigned_render_power = 0;
 
  dj->watchdog_forgiveness = 3600; // initialize watchdog forgiveness at 1 hour
 
  dj->hibernate = 0;
 
  dj->frameset = (struct frameset *)NULL; /*< @todo does frameset need to be initialized here? */
 

	
 
  return 0;
 
}
 

	
 
/**
 
   read an unsigned integer property from an xmlNode
 

	
 
   convenience function for distrenjob_unserialize()
 
   @param xmlnode may be NULL for convenience
 
   @return 0 on success, other on error
 
 */
 
int _distrenjob_xml_readuint(xmlNodePtr xmlnode, xmlChar *propname, unsigned int *num)
 
{
 
  xmlChar *string;
 

	
 
  if(!xmlnode)
 
    return 1;
 

	
 
  string = xmlGetProp(xmlnode, propname);
 
  if(!string)
 
    {
 
      fprintf(stderr, "_distrenjob_xml_readuint(): warning: unable to get property ``%s''\n",
 
	      propname);
 
      return 1;
 
    }
 
  
 
  *num = (unsigned int)strtoul((char *)string, (char **)NULL, 10);
 
#ifndef NDEBUG
 
  fprintf(stderr, "_distrenjob_xml_readuint(%zx, \"%s\", *(%zx)=%u): read %s=\"%d\"\n",
 
	  (size_t)xmlnode, propname, (size_t)num, *num, propname, *num);
 
#endif
 

	
 
  xmlFree(string);
 
  return 0;
 
}
 

	
 
/**
 
   Loads a distrenjob that was serialized with distrenjob_serialize()
 

	
 
   @see distrenjob_serialize()
 
   @param pathtoxml path to XML file
 
   @param distrenjob will be set to a pointer
 
*/
 
int distrenjob_unserialize(struct distrenjob **distrenjob, char *pathtoxml)
 
{
 
  struct distrenjob *dj;
 
  struct frameset *fs;
 
  unsigned int start_frame;
 
  unsigned int end_frame;
 
  unsigned int counter;
 

	
 
  struct tm tm;
 

	
 
  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 *)"/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 = _distrenjob_xml_readuint(xmlnode, (xmlChar *)"priority", &dj->priority);
 
  if(tmp)
 
    {
 
      distrenjob_free(distrenjob);
 
      return 6;
 
    }
 
  
 
  dj->output_format = (char *)xmlGetProp(xmlnode, (xmlChar *)"output_format");
 
  if(!dj->output_format)
 
    {
 
      distrenjob_free(distrenjob);
 

	
 
      return 6;
 
    }
 

	
 
  tmp = _distrenjob_xml_readuint(xmlnode, (xmlChar *)"jobnum", &dj->jobnum);
 
  if(tmp)
 
    {
 
      distrenjob_free(distrenjob);
 
      
 
      return 7;
 
    }
 

	
 
  xmlnode = xml_quickxpath(xmlxpathcontext, (xmlChar *)"/job/resolution");
 
  tmp = _distrenjob_xml_readuint(xmlnode, (xmlChar *)"width"   , &dj->width   );
 
  tmp += _distrenjob_xml_readuint(xmlnode, (xmlChar *)"height"  , &dj->height  );
 

	
 
  xmlnode = xml_quickxpath(xmlxpathcontext, (xmlChar *)"/job/video");
 
  tmp += _distrenjob_xml_readuint(xmlnode, (xmlChar *)"start_frame", &start_frame);
 
  tmp += _distrenjob_xml_readuint(xmlnode, (xmlChar *)"end_frame", &end_frame);
 

	
 
  if(tmp)
 
    {
 
      fprintf(stderr, "distrenjob_unserialize(): error reading integer values from ``%s''\n",
 
	      pathtoxml);
 
      distrenjob_free(distrenjob);
 
      return 7;
 
      return 8;
 
    }
 

	
 
  /**
 
     total_render_time and watchdog stuff doesn't need error
 
     checking, just good defaults
 
  */
 
  xmlnode = xml_quickxpath(xmlxpathcontext, (xmlChar *)"/job/stats");
 
  dj->total_render_time = 0;
 
  xmlchar = xmlGetProp(xmlnode, (xmlChar *)"total_render_time");
 
  if(xmlchar)
 
    {
 
      if(strptime((char *)xmlchar, "%D %T", &tm))
 
	dj->total_render_time = mktime(&tm);
 
      xmlFree(xmlchar);
 
    }
 

	
 
  xmlnode = xml_quickxpath(xmlxpathcontext, (xmlChar *)"/job/watchdog");
 
  dj->watchdog_forgiveness = 3600;
 
  tmp =_distrenjob_xml_readuint(xmlnode, (xmlChar *)"forgiveness", &dj->watchdog_forgiveness);
 
  if(tmp)
 
    fprintf(stderr, "distrenjob_unserialize(): warning: watchdog forgiveness is unspecified in ``%s'', defaulting to 3600\n", pathtoxml);
 

	
 
  xmlXPathFreeContext(xmlxpathcontext);
 
  xmlFreeDoc(xmldoc);
 

	
 
  /**
 
     reconstruct the frameset
 
  */
 
  dj->total_frames = end_frame - start_frame + 1;
 
#ifndef NDEBUG
 
  fprintf(stderr, "distrenjob_unserialize(): restoring %d frames\n", dj->total_frames);
 
#endif
 
  dj->frameset = malloc(sizeof(struct frameset) * dj->total_frames);
 
  if(!dj->frameset)
 
    {
 
      fprintf(stderr, "OOM!\n");
 
      distrenjob_free(distrenjob);
 
      return 8;
 
      return 9;
 
    }
 
  fs = dj->frameset;
 
  for(counter = start_frame; counter <= end_frame; counter ++)
 
    {
 
      fs->num = counter;
 
      fs->status = FRAMESETSTATUS_UNASSIGNED; /*< @todo job partial completion and resumption support */
 

	
 
      fs ++;
 
    }
 
 
 
#ifndef NDEBUG
 
  fprintf(stderr, "distrenjob_unserialize(): finished loading ``%s''\n", pathtoxml);
 
#endif
 

	
 
  return 0;
 
}
 

	
 
int distrenjob_serialize(struct distrenjob *job, char *outfile)
 
{
 
  xmlTextWriterPtr writer;
 
  char *tmp;
 
  char *tmpfile;
 
  int tmprtn;
 

	
 
  /**
 
     transactional FS access for POSIX systems...
 
     (probably not implemented correctly)
 
   */
 
  _distren_asprintf(&tmpfile, "%s_", outfile);
 

	
 
  /* create xml document at the location tmp with no compression */
 
  writer = xmlNewTextWriterFilename(tmpfile, 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);
 
  free(tmp);
 
  _distren_asprintf(&tmp, "%d", job->jobnum);
 
  xmlTextWriterWriteAttribute(writer, (xmlChar *)"jobnum", (xmlChar *)tmp);
 
  free(tmp);
 
  xmlTextWriterWriteAttribute(writer, (xmlChar *)"output_format", (xmlChar *)job->output_format);
 
  
 

	
 
  /**
 
     write resolution element and add its attributes */
 
  xmlTextWriterStartElement(writer, (xmlChar*)"resolution");
 
  _distren_asprintf(&tmp, "%d", job->width);
 
  xmlTextWriterWriteAttribute(writer, (xmlChar*)"width", (xmlChar*)tmp);
 
  free(tmp);
 

	
 
  _distren_asprintf(&tmp, "%d", job->height);
 
  xmlTextWriterWriteAttribute(writer, (xmlChar*)"height", (xmlChar*)tmp);
 
  free(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);
 
  free(tmp);
 

	
 
  _distren_asprintf(&tmp, "%d", job->frameset[ job->total_frames - 1 ].num);
 
  xmlTextWriterWriteAttribute(writer, (xmlChar*)"end_frame", (xmlChar*)tmp);
 
  free(tmp);
 

	
 
  xmlTextWriterWriteAttribute(writer, (xmlChar*)"output_format", (xmlChar*)job->output_format);
 
  xmlTextWriterEndElement(writer);
 

	
 
  /**
 
     write watchdog forgiveness element */
 
  xmlTextWriterStartElement(writer, (xmlChar*)"watchdog");
 

	
 
  _distren_asprintf(&tmp, "%d", job->watchdog_forgiveness);
 
  xmlTextWriterWriteAttribute(writer, (xmlChar *)"forgiveness", (xmlChar *)tmp);
 
  free(tmp);
 

	
 
  xmlTextWriterEndElement(writer); /* </watchdog> */
 

	
 
  xmlTextWriterEndElement(writer); /* </job> */
 

	
 
  /**
 
     end document */
 
  xmlTextWriterEndDocument(writer);
 

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

	
 
  /**
 
     This is the key to transactioanl POSIX
 
     FS programming.
 
   */
 
  tmprtn = rename(tmpfile, outfile);
 
  if(tmprtn == -1)
 
    {
 
      fprintf(stderr, "%s:%d: Error renaming ``%s'' to ``%s''\n",
 
	      __FILE__, __LINE__,
 
	      tmpfile, outfile);
 
      perror("rename");
 
      tmprtn = 1;
 
    }
 
  free(tmpfile);
 

	
 
  return tmprtn;
 
}
0 comments (0 inline, 0 general)