Changeset - bd3a8baa47b6
[Not reviewed]
default
0 1 0
Nathan Brink (binki) - 16 years ago 2009-07-28 23:33:51
ohnobinki@ohnopublishing.net
compromisingly eliminate compile errors
1 file changed with 3 insertions and 0 deletions:
0 comments (0 inline, 0 general)
src/server/distrend.c
Show inline comments
 
/*
 
  Copyright 2009 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando
 

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

	
 
*/
 

	
 
/* This file contains the code which both processes (renders) jobs as a slave, and the code which distributes frames to slaves after receiving them from the client portion of the codebase. */
 

	
 
 /* Just some notes -- Ethan Zonca
 
 * ++ Make data availible for other apps to parse
 
 * Server<==>Client Communication
 
 * Upload while rendering
 
 */
 

	
 

	
 
/* XML notes --
 
 *
 
 * First off, is XML in our build environment?
 
 * Next, what files are we going to have?:
 
 *  - XML file sent with (.blend/.pov/.lux(xml)/whatever) by distren telling the server what to do
 
 *  	+ Includes submitter name, filename, emailaddress, etc
 
 *  - XML file on server storing info on current and finished jobs
 
 *  - XML file sent by distren when submitting a render to the server
 

	
 
 *
 
 *  Overall, we could use XML to make our client/server communication load
 
 *  a lot lighter, especially if clients are sent customized xml files telling
 
 *  them what frame(s) to render... although that would be inefficient if rendering
 
 *  single frames. Maybe not tell it what frames to render in the xml file, the server
 
 *  can spit out that info.
 
 *
 
 *  Please edit my ramblings if you please,
 
 *  --ethanzonca
 
 *
 
 */
 

	
 

	
 

	
 
#include "execio.h"
 
#include "options.h"
 
#include "blendjob.h"
 
#include "protocol.h"
 

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

	
 

	
 

	
 

	
 

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

	
 
// Stores config info? editmycomment
 
struct distrend_config
 
{
 
  cfg_t *mycfg;
 
  struct options_common *options;
 
  struct distrend_listen **listens; /*< Null terminated array of structs */
 
};
 

	
 

	
 

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

	
 
 Have a script crawl through each job in the arrays, priority-biased, and assign a frame to each slave.
 
 Then we will need some sort of watchdog to monitor slaves on the main server to check for stales. Maybe not worry about this for now.
 
*/
 

	
 
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; //
 
} general_info;
 

	
 

	
 

	
 
/*
 
  internally defined funcs's prototypes
 
*/
 
void status_report_generator(struct blendjob **blendjobs_head);
 
void blendjob_remove(struct blendjob **head, struct blendjob *bj);
 

	
 
struct blendjob *blendjob_get(struct blendjob *head, jobnum_t jobnum);
 

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

	
 
void start_data(){
 

	
 
	if(1 == 0){
 
		// retrieve total_finished_jobs and total_finished_frames from xml file
 
	}
 
	else{
 
		general_info.total_finished_jobs = 0;
 
		general_info.total_frames_rendered = 0;
 
	}
 
}
 

	
 
// **** Finish-Setter: Sets a frame to the "completed" status.
 
void finish_frame(struct blendjob *blendjob, int frame){
 
  blendjob->frameset[frame].status = 2;
 
  blendjob->frameset[frame].time_to_render = (clock() - blendjob[jobnum].frameset[frame].start_time); // Consider changing time-to-render to time-for-frame or something?
 

	
 
  general_info.total_frames_rendered++; // Increase total frames var for stats
 
}
 

	
 

	
 
// **** Queuer: Adds files to the queue
 
void queue(struct blendjob *blendjob, int type, char *name, char *submitter, char *email, int priority, int mode, int spp, struct frameset *frameset) {
 
	// Type: 1 = blender, add more types later
 
	// jobnum is the next available job number
 
	if(type == 1){
 
    blendjob->name = name;
 
    blendjob->submitter = submitter;
 
    blendjob->email = email;
 
    blendjob->priority = priority;
 
    blendjob->frameset = frameset;
 
  }
 
  else{
 
    // Throw error.
 
  }
 
@@ -390,145 +391,147 @@ struct blendjob *blendjob_get(struct ble
 
   Removes a blendjob from the blendjob linkelist.
 

	
 
   @arg head a double pointer. the head pointer will have to be changed if blendjob == *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 blendjob_remove(struct blendjob **head, struct blendjob *bj)
 
{
 
  struct blendjob *previous_blendjob;
 

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

	
 
      for(previous_blendjob = *head;
 
	  previous_blendjob
 
	    && previous_blendjob->next != bj; /*< stop on the blendjob that comes before bj */
 
	  previous_blendjob = previous_blendjob->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_blendjob->next = bj->next;
 
    }
 

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

	
 

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

	
 

	
 
// Begin non-working framework?
 
	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_END()
 
	    };
 

	
 
	  config = malloc(sizeof(struct distrend_config));
 
	  options_init(argc, argv, &config->mycfg, myopts, "server", &config->options);
 

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

	
 
	  return 0;
 
	}
 
// End non-working framework?
 

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

	
 
  /* TODO: Put some arg-grabbing code here */
 

	
 
  struct blendjob *head;
 

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

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

	
 
  head = NULL;
 
  cont = 1;
 

	
 
  distrend_do_config(argc, argv, config);
 

	
 
  distrend_listen(&listenset, config);
 
  /* This is called the ``main loop'' */
 
  while(cont)
 
    {
 
      struct distren_action *action;
 
      int clientsays; /*< temporary example variable, will be replaced when we can handle messages */
 
      int framenumprevious; /*< @TODO why is this variable used?  */
 

	
 
      distrend_accept(&action);
 
      cont = distrend_do(action);
 

	
 

	
 
      /* Somewhat Pseudo-code for basic server operation, should be more event-driven */
 

	
 
      start_data();
 
      status_report_generator(&head);
 
      blend_frame_watchdog(head);
 

	
 

	
 
      struct frameset *frame;
 
      struct blendjob *job;
 

	
 
      /* If the client is idle (meaning a client without the "busy" status connected via ssh), all clients should be idle by default. */
 
      if(clientstatus == CLIENTSTATUS_IDLE)
 
	{
 
	  /**
 
	      normaldotcom: learn about ``return by pointer''
 
	  */
 
	  int returnnum = frame_finder(head, &job, &frame); // give framefinder args, framefinder should return job number and frame number somehow
 
	  if(returnnum)
 
	    {
 
	      fprinf(stderr,"No frames are available to render at this time");
 
	      sleep(10);
 
	    }
 
	  else
 
	    /* returnnum == 0 */
 
	    remotio_send_to_client(frame->num, job->jobnum); // Did you actually make this function, ohnobinki? --normaldotcom
 
	}
 

	
 
      /* If the client states that they finished the frame */
 
      	if(clientsays == DISTREN_REQUEST_DONEFRAME){
 
      		clientstatus = CLIENTSTATUS_IDLE; // Sets the client back to idle
 
      		finish_frame(jobnum, framenumprevious); // make it finish the previous frame or something, why framenumprevios? Is that the whole linked list thing coming in?
 
      	}
 

	
 
      /* End Somewhat Pseudo-code */
 

	
 

	
 
      distrend_action_free(action);
 
    }
 

	
 
  distrend_unlisten(listenset);
 
  distrend_config_free(config);
 

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