Changeset - 5bee5e566377
[Not reviewed]
default
0 2 0
Nathan Brink (binki) - 16 years ago 2009-09-13 14:45:41
ohnobinki@ohnopublishing.net
removed remove_job, use distrenjob_remove
2 files changed with 12 insertions and 39 deletions:
0 comments (0 inline, 0 general)
src/server/distrend.c
Show inline comments
 
@@ -27,97 +27,96 @@
 
#include "slavefuncs.h"
 

	
 
#include <confuse.h>
 
#include <stdio.h>
 
#include <stdlib.h>
 
#include <malloc.h>
 
#include <unistd.h> /* getopt */
 
#include <time.h>
 
#include <sys/stat.h>
 

	
 
/* ******************* Structs ************************ */
 

	
 
// Gets config info from confs
 
struct distrend_config
 
{
 
  cfg_t *mycfg;
 
  struct options_common *options;
 
  struct distrend_listen **listens; /*< Null terminated array of structs */
 
  char *datadir;
 
};
 

	
 

	
 

	
 
/*
 
 frame[frame] Status Assignments:
 
  "NULL" - don't render me
 
  "0" - canceled
 
  "1" - unassigned
 
  "2" - assigned to slave
 
  "3" - completed by slave and uploaded
 
*/
 

	
 
struct general_info {
 
  short int jobs_in_queue; //
 
  unsigned short int free_clients;
 
  unsigned short int rendering_clients;//
 
  unsigned short int total_finished_jobs; //
 
  unsigned int total_frames_rendered; //
 
  unsigned int highest_jobnum;
 
} general_info;
 

	
 

	
 

	
 
/*
 
  internally defined funcs's prototypes
 
*/
 
void status_report_generator(struct distrenjob **distrenjobs_head);
 
void distrenjob_remove(struct distrenjob **head, struct distrenjob *bj);
 
struct distrenjob *remove_job(int jobnum_t);
 

	
 
struct distrenjob *distrenjob_get(struct distrenjob *head, jobnum_t jobnum);
 
struct distrenjob *head; /*@TODO:declare struct with no starting data */
 

	
 
/* Global Vars, try to cut down on these */
 
jobnum_t jobnum = 0; // The next job number to create in the queue
 
int hcfjob; // Highest consecutively finished job
 
int highest_jobnum; // The job number of the most recently created job, this is used when creating new jobs
 

	
 

	
 
/* ********************** Functions ************************* */
 

	
 
/** Dumps all data in RAM to an xml file (such as current jobs, etc) which is parsed by start_data. Remember to invoke this before shutting down! */
 
int xml_dump()
 
{
 
  return 0;
 
}
 
/**
 
   Performs command stored in a client's request.
 
*/
 
int distrend_do()
 
{
 
  return 0;
 
}
 
/**
 
   Accepts a client's connection
 
 */
 
void distrend_accept()
 
{
 

	
 
}
 
/**
 
   Frees the action
 
*/
 
void distrend_action_free()
 
{
 

	
 
}
 
/**
 
   Start listening
 
*/
 
void distrend_listen()
 
{
 

	
 
}
 
/**
 
   Stop listening
 
*/
 
@@ -245,173 +244,152 @@ void status_report_generator(struct dist
 
	{
 
	  unsigned int framecounter;  /*< to scan through frames */
 
	  unsigned long finished_frames; /*< variable that counts the completed frames */
 
	  unsigned int pending_frames; /*< variable that counts the assigned frames */
 
	  float percent_frames_finished;  /*< variable that stores the percent done of the distrenjob */
 
	  unsigned int total_time;  /*< total time taken to render all the completed frames for a job */
 

	
 
	  framecounter = 0;
 
	  finished_frames = 0;
 
	  pending_frames = 0;
 
	  percent_frames_finished = 0;
 
	  total_time = 0;
 

	
 
	  while(framecounter < distrenjob_ptr->total_frames)
 
	    /* scans through frames, based on their status it runs a statement(s) */
 
	    {
 
	      if(distrenjob_ptr->frameset[framecounter].status == 2)
 
		/* If the frame is done */
 
		{
 
		  finished_frames ++;
 
		  total_time += distrenjob_ptr->frameset[framecounter].time_to_render;
 
		}
 

	
 
	      if(distrenjob_ptr->frameset[framecounter].status == 1)
 
		/* If the frame is assigned */
 
		{
 
		  pending_frames ++;
 
		  workers_working ++;
 
		}
 

	
 
	      framecounter ++;
 
	    } /* while(framecounter < distrenjob_ptr->total_frames) */
 

	
 
	  // find the percent of completed frames
 
	  percent_frames_finished = (finished_frames / distrenjob_ptr->total_frames) * 100; /*< @LordofWar: extraneous parentheses! */
 

	
 
	  /* updates values in the distrenjob struct */
 
	  distrenjob_ptr->completed_frames = finished_frames;
 
	  distrenjob_ptr->assigned_frames = pending_frames;
 
	  distrenjob_ptr->percent_done = percent_frames_finished;
 
	  distrenjob_ptr->avg_render_time = (total_time / finished_frames); /*< extraneous parentheses! */
 
	  distrenjob_ptr->time_remaining = (distrenjob_ptr->avg_render_time * (distrenjob_ptr->total_frames - finished_frames)); /*< extraneous parentheses! */
 

	
 
	  if(finished_frames == distrenjob_ptr->total_frames)
 
	    /* If all frames are complete */
 
	    {
 
	      distrenjob_ptr->priority = 0; /*< set priority to zero to indicate job is complete */
 
	      distrenjob_remove(distrenjobs_head, distrenjob_ptr); /*< remove this job from the linkedlist */
 
	      distrenjob_free(distrenjob_ptr);
 
	      general_info.total_finished_jobs++; /*< add one to the total finished jobs */
 

	
 
	    }
 
	  else if (finished_frames > distrenjob_ptr->total_frames)
 
	    /* just in case ;-) */
 
	    {
 
	      fprintf(stderr, "%s:%d: finished_frames (%lu) > distrenjob_ptr->total_frames (%d)",
 
		      __FILE__, __LINE__,
 
		      finished_frames,
 
		      distrenjob_ptr->total_frames);
 
	      abort();
 
	    }
 
	}
 

	
 
      general_info.rendering_clients = workers_working; /*< should this be a +=? */
 

	
 
      distrenjob_ptr = distrenjob_ptr->next; /*< This is the essence of linked lists and iterating through them */
 
      numjobs ++;
 
    } /* while(distrenjob_ptr) */
 

	
 
  general_info.jobs_in_queue = (highest_jobnum - general_info.total_finished_jobs); /*< extraneous parentheses! */
 
}
 

	
 

	
 
/** Structure Builder: This function creates frame array based on the total number of frames to be rendered, which will then be parsed by function frame_farmer. */
 
/**
 
   Structure Builder: This function creates frame array based on the total number of frames to be rendered, which will then be parsed by function frame_farmer. 
 
*/
 
void add_job_to_queue(struct distrenjob *job) {
 
  struct distrenjob *prev_job = head; // create pointer to previous job
 
  struct distrenjob *current_job;     // create pointer to current_job (which job is being compared to)
 

	
 
  // iterate through linked list of jobs
 
  for(current_job = head; current_job != NULL; current_job = current_job->next){
 
    if(current_job == NULL){ // if it has reached the end of the list, add job there
 
      current_job = job;
 
      break;
 
    }
 
    else if(job->priority < current_job->priority){ // if job's priority is less than current_job's priority, insert job
 
      prev_job->next = job;                        // keep in mind 1 is the lowest priority
 
      job->next = current_job;
 
      break;
 
    }
 

	
 
    prev_job = current_job;
 
  } // end of for statement
 
}
 

	
 
void change_job_priority(int jobnum, int new_priority){
 
  struct distrenjob *job;
 
  job = remove_job(jobnum);
 
  job->priority = new_priority;
 
  add_job_to_queue(job);
 
  } /* for(current_job) */
 
}
 

	
 
/**
 
   Removes job from queue without freeing/deleting it. Meant to be temporary.
 
   @arg head I may end up changing the head if job == head
 
 */
 
struct distrenjob *remove_job(int jobnum_t)
 
{
 
  struct distrenjob *job;
 
  struct distrenjob *prev_job = head;
 

	
 
  for(job = head; job != NULL; job = job->next){
 
    if(job == NULL){
 
      return NULL;
 
void change_job_priority(struct distrenjob **head, struct distrenjob *job, int new_priority){
 
  distrenjob_remove(head, job);
 
  job->priority = new_priority;
 
  add_job_to_queue(job);
 
    }
 
    if(job->jobnum = jobnum_t){
 
      prev_job = job->next;
 
      return job;
 
    }
 

	
 
    prev_job = job;
 
  }
 

	
 
  // job was not found if this point is reached
 
  return NULL;
 
}
 

	
 

	
 

	
 
/**
 
  Frame Finder: matches your computer up with a lovely frame to render
 
  TODO: Major issue here, the client needs to know the frame number, AND the job number!
 
  Notice that this function starts by looking at the oldest job first
 

	
 
	TODO: Link this up with the main() function to check if there are frames available or not and provide jobnum/framenum to the client
 

	
 
  @return 0 success, other: error
 
*/
 
int frame_finder(struct distrenjob *head, struct distrenjob **job, struct frameset **frame)
 
{
 
  int your_frame;  // your_frame is an integer value that will be given to the client as the frame number to render
 
  int your_job;	   // @TODO: Fixme: do we need this var? you_job is an integer value that must ALSO be given to the client
 

	
 
  unsigned short int found;
 
  unsigned short int priority;
 

	
 
  struct distrenjob *distrenjob_ptr;
 

	
 
  found = 0;
 
  while(!found)
 
    {
 
      /* enumerate through priority levels */
 
      for(priority = 10;
 
        priority > 0
 
            && !found;
 
           priority --)
 
	/* Find the job with the highest priority */
 
        for(distrenjob_ptr = head;
 
            distrenjob_ptr != NULL
 
            && !found;
 
            distrenjob_ptr = distrenjob_ptr->next)
 
          if(distrenjob_ptr->priority == priority)
 
	    found = 1;
 

	
 
      if(!found)
 
        {
 
          fprintf(stderr, "No more jobs to render\n");
 
          return 1;
 
        }
 

	
 
      found = 0;
 
      for(your_frame = 0;
 
        your_frame < distrenjob_ptr->total_frames;
 
        your_frame ++)
 
        if(distrenjob_ptr->frameset[your_frame].status == 0)
 
          found = 1;
 
@@ -468,102 +446,96 @@ void blend_frame_watchdog(struct distren
 
}
 

	
 
/**
 
   Finds a distrenjob struct based on the jobnum
 
   @arg jobnum job number to search for
 
   @return NULL on job doesn't exist
 
 */
 
struct distrenjob *distrenjob_get(struct distrenjob *head, jobnum_t jobnum)
 
{
 
  struct distrenjob *distrenjob_ptr;
 

	
 
  /*
 
    The conditions of the for loop will leave distrenjob_ptr at NULL if the end of the list is reached. It will leave it pointing to the correct job if it is found.
 
   */
 
  for(distrenjob_ptr = head;
 
      distrenjob_ptr
 
        && distrenjob_ptr->jobnum != jobnum;
 
      distrenjob_ptr = distrenjob_ptr->next);
 

	
 
  return distrenjob_ptr;
 
}
 

	
 

	
 
/**
 
   Removes a distrenjob from the distrenjob linked list.
 

	
 
   @arg head a double pointer. the head pointer will have to be changed if distrenjob == *head. Thus, make sure that the pointer points to the pointer to the head that all functions use. (I'm going to come back to this and misunderstand myself ;-))
 
 */
 
void distrenjob_remove(struct distrenjob **head, struct distrenjob *bj)
 
{
 
  struct distrenjob *previous_distrenjob;
 

	
 
  if(bj == *head)
 
    *head = bj->next;
 
  else
 
    {
 

	
 
      for(previous_distrenjob = *head;
 
        previous_distrenjob
 
          && previous_distrenjob->next != bj; /*< stop on the distrenjob that comes before bj */
 
          previous_distrenjob = previous_distrenjob->next)
 
	/* all of the action is in the definition of the for loop itself */;
 

	
 
      /*
 
	This removes references to bj from the linked list. I.E., we now skip bj when iterating through the list
 
       */
 
      previous_distrenjob->next = bj->next;
 
    }
 

	
 
  /*
 
     @lordofwar: the magic deallocation of memory ;-)
 
   */
 
  free(bj->frameset);
 
  free(bj);
 
}
 

	
 

	
 
/* Grabs config info from confs */
 
int distrend_do_config(int argc, char *argv[], struct distrend_config **config)
 
{
 
  cfg_opt_t myopts_listen[] =
 
    {
 
      CFG_SIMPLE_STR("type", NULL),
 
      CFG_SIMPLE_STR("path", NULL),
 
      CFG_SIMPLE_INT("port", NULL),
 
      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_END()
 
    };
 

	
 
  struct distrenjob *distrenjob;
 

	
 
  int tmp;
 

	
 
  xmlinit();
 
  /*
 
   * test xml2distrenjob()
 
   */
 
  tmp = xml2distrenjob(&distrenjob, "distrenjob.xml.example");
 
  if(tmp)
 
    fprintf(stderr, "xml2distrenjob() returned %d. Try to cd to distren/doc if you want to test out the xml2distrenjob() function. (This will only fix this error if the error is due to an inability of the xml library to access distrenjob.xml.example)\n", tmp);
 
  else
 
    fprintf(stderr, "using email ``%s'' for user ``%s'' -- reading in XML files and pulling data from them using libxml2+XPath works!!!\n", distrenjob->email, distrenjob->submitter);
 

	
 
  fprintf(stderr, "%s:%d running config\n", __FILE__, __LINE__);
 

	
 
  *config = malloc(sizeof(struct distrend_config));
 
  myopts[1].simple_value = &(*config)->datadir;
 

	
 
  options_init(argc, argv, &(*config)->mycfg, myopts, "server", &(*config)->options);
 

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

	
 
  xmlcleanup();
 
  return 0;
 
}
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->percent_done = 0;
 
  dj->completed_frames = 0;
 
  dj->assigned_frames = 0;
 
  dj->avg_render_time = 0;
 
  dj->time_remaining = (unsigned int)-1;
 
  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;
0 comments (0 inline, 0 general)