Files @ ec90f545efc5
Branch filter:

Location: DistRen/src/server/distrenjob.c - annotation

binki
Fix random warnings.
45bf3be8fb93
abcf8952747b
25ea5b51c17a
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
d6d0d0d26d0b
92659c5651ef
92659c5651ef
12f4253fa8db
45bf3be8fb93
45bf3be8fb93
c3b079b8a2dd
c3b079b8a2dd
d6d0d0d26d0b
45bf3be8fb93
5b7ab20c5306
92659c5651ef
45bf3be8fb93
12f4253fa8db
45bf3be8fb93
12f4253fa8db
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
5bee5e566377
5bee5e566377
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
12f4253fa8db
45bf3be8fb93
12f4253fa8db
45bf3be8fb93
12f4253fa8db
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
6e74651480a0
6e74651480a0
45bf3be8fb93
45bf3be8fb93
6e74651480a0
86c54813cdc2
734207e4d1f8
734207e4d1f8
6e74651480a0
6e74651480a0
45bf3be8fb93
45bf3be8fb93
6e74651480a0
6e74651480a0
6e74651480a0
25ea5b51c17a
1aeb6d2aebd0
e469bd961670
6e74651480a0
45bf3be8fb93
25ea5b51c17a
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
64aa85927a9d
64aa85927a9d
64aa85927a9d
64aa85927a9d
64aa85927a9d
64aa85927a9d
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
45bf3be8fb93
5b7ab20c5306
45bf3be8fb93
12f4253fa8db
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
25ea5b51c17a
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
25ea5b51c17a
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
25ea5b51c17a
45bf3be8fb93
f1fb3f3ed558
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
25ea5b51c17a
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
25ea5b51c17a
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
f1fb3f3ed558
f1fb3f3ed558
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
45bf3be8fb93
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
e696db7b7db2
e696db7b7db2
e696db7b7db2
e696db7b7db2
e696db7b7db2
e696db7b7db2
e696db7b7db2
e696db7b7db2
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
45bf3be8fb93
e696db7b7db2
45bf3be8fb93
45bf3be8fb93
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
ec90f545efc5
ec90f545efc5
ec90f545efc5
ec90f545efc5
ec90f545efc5
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
45bf3be8fb93
45bf3be8fb93
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
f1fb3f3ed558
86c54813cdc2
86c54813cdc2
86c54813cdc2
1e4bbbad6d0b
1e4bbbad6d0b
1e4bbbad6d0b
1e4bbbad6d0b
1e4bbbad6d0b
e696db7b7db2
1e4bbbad6d0b
1e4bbbad6d0b
1e4bbbad6d0b
1e4bbbad6d0b
1e4bbbad6d0b
1e4bbbad6d0b
f1fb3f3ed558
1e4bbbad6d0b
1e4bbbad6d0b
1e4bbbad6d0b
1e4bbbad6d0b
1e4bbbad6d0b
64aa85927a9d
f1fb3f3ed558
45bf3be8fb93
45bf3be8fb93
45bf3be8fb93
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
e696db7b7db2
e696db7b7db2
e696db7b7db2
6e74651480a0
6e74651480a0
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
86c54813cdc2
86c54813cdc2
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
86c54813cdc2
86c54813cdc2
5b7ab20c5306
86c54813cdc2
5b7ab20c5306
5b7ab20c5306
86c54813cdc2
86c54813cdc2
86c54813cdc2
86c54813cdc2
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
5b7ab20c5306
/*
  Copyright 2010 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 "common/config.h"

#include "distrenjob.h"
#include "slavefuncs.h"

#include "common/asprintf.h"

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlwriter.h>
#include <time.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);

  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 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)
    {
      /*
       * even though GCC says this is implicitly declared, POSIX
       * requires that time.h declare this function. Thus, we don't
       * have to worry about the warning.
       */
      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 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;
}