diff --git a/src/server/slave.c b/src/server/slave.c --- a/src/server/slave.c +++ b/src/server/slave.c @@ -31,6 +31,8 @@ #include #include +#define DEBUG 0 + int main(int argc, char *argv[]) { @@ -38,9 +40,12 @@ int main(int argc, char *argv[]) char *datadir; char *server; char *username; + char *password; char *hostname; + cfg_opt_t myopts[] = { CFG_SIMPLE_STR("username", &username), + CFG_SIMPLE_STR("password", &password), CFG_SIMPLE_STR("datadir", &datadir), CFG_SIMPLE_STR("server", &server), CFG_SIMPLE_STR("hostname", &hostname), @@ -50,7 +55,7 @@ int main(int argc, char *argv[]) struct options_common *commonopts; - struct distrenjob *myjob; /* Structure to hold data gathered from the XML file */ + // struct distrenjob *myjob; /* Structure to hold data gathered from the XML file - not needed anymore? */ struct remoteio *comm_slave; @@ -60,10 +65,13 @@ int main(int argc, char *argv[]) datadir = NULL; server = NULL; username = NULL; + password = NULL; + hostname = NULL; char curopt; + int runBenchmark = 0; - while(((char)-1) != (curopt = getopt(argc, argv, "u:th"))) + while(((char)-1) != (curopt = getopt(argc, argv, "u:rh"))) { if(curopt == ':') { @@ -77,17 +85,19 @@ int main(int argc, char *argv[]) } else if(curopt == 'h') { - fprintf(stderr, "Usage: distrenslave [option] \nStarts a distren slave\n\t-u\tset username (run after fresh install)\n\t-t\tEnter test mode\n\t-h\tshow this help\n"); + fprintf(stderr, "Usage: distrenslave [option] \nStarts a distren slave\n\t-u\tset username (run after fresh install)\n\t-r\tRecalculate render power (benchmark)\n\t-h\tshow this help\n"); return 2; } - else if(curopt == 't') + else if(curopt == 'r') { - slaveTest(); - return 0; + runBenchmark = 1; + break; } else if(curopt == 'u') username = strdup(optarg); - fprintf(stderr, "Putting username \"%s\" in distrenslave.conf\n", username); + if(DEBUG) + fprintf(stderr, "Putting username \"%s\" in distrenslave.conf\n", username); + conf_replace("distrenslave.conf", "!username", username); fprintf(stderr, "Please invoke distrenslave with no arguments to run with the username you just set\n"); return 0; @@ -96,10 +106,40 @@ int main(int argc, char *argv[]) /* Get conf data */ options_init(argc, argv, &my_cfg, myopts, "slave", &commonopts); + if(!datadir) + { + fprintf(stderr, "datadir not set\n"); + return 1; + } + if(!server) + { + fprintf(stderr, "server not set\n"); + return 1; + } + if(!username) + { + fprintf(stderr, "username not set\n"); + return 1; + } + if(!password) + { + fprintf(stderr, "password not set\n"); + return 1; + } + if(!hostname) + { + fprintf(stderr, "hostname not set\n"); + return 1; + } /* Notifies the user if there no username in .conf */ if(checkUsername(username)) return 1; + if(!strncmp(password, "!password",10)) + { + fprintf(stderr, "You haven't specified a password. Please edit distrenslave.conf!\n"); + return 1; + } fprintf(stderr, "Connecting to server...\n"); if(remoteio_open(&comm_slave, commonopts->remoteio, server)) @@ -113,32 +153,59 @@ int main(int argc, char *argv[]) int jobnum = 0; int framenum = 0; int slavekey = atoi(username); // @TODO: Make this more friendly + char *urltoTar; /* Full URL to the server-side location of job#.tgz */ char *pathtoTar; /* Full path to the location of the job#.tgz */ char *pathtoTardir; - char *pathtoRenderOutput; char *urltoOutput; /* Full URL where output is posted */ char *pathtoOutput; /* Full path to the output (rendered) file */ char *pathtoOutdir; /* Full path to output directory */ + char *pathtoRenderOutput; /* Contains blender framenum placeholder */ - // Temporary for uncomressed testing + // Temporary for uncomressed testing @TODO: remove char *urltoJobfile; char *pathtoJob; /* Full path to job data folder */ char *pathtoJobfile; /* Full path to the job's main file */ - char *outputExt; /* Output Extension (e.g., JPG) */ + char *outputExt = "jpg"; /* Output Extension (e.g., JPG) */ int haveWork = 0; int quit = 0; + fprintf(stderr,"\nDistRen Slave Pre-Alpha %s\n- Experimental build: Use at your own risk!\n\n", PACKAGE_VERSION); + + int benchmarkTime = 0; + int renderPower = 0; + + // @TODO: add call to function to force recalc if $render_power == "" + if(runBenchmark) + { + if(slaveBenchmark(datadir, &benchmarkTime, &renderPower)) + { + fprintf(stderr,"Benchmark failed! Exiting.\n"); + return 1; + } + else + { + fprintf(stderr,"Benchmark successful, time taken was %d seconds, giving you a render power of %d.\n", + benchmarkTime, renderPower); + _web_setrenderpower(slavekey, password, renderPower); + return 0; + } + } + + if(!DEBUG) + fprintf(stderr, "Running.."); + + // Main loop while(!quit) { // request work fprintf(stderr,"Requesting work...\n"); - sendSignal(comm_slave, DISTREN_REQUEST_GETWORK); + haveWork = getwork(comm_slave, &jobnum, &framenum); /* If we got a frame */ if(haveWork) @@ -149,39 +216,94 @@ int main(int argc, char *argv[]) // framenum = remoteio_read(jobnum); /* Set framenum from remoteio */ // outputExt = remotio)read(outputExt); /* Set output extension from remotio */ - fprintf(stderr, "Preparing to render frame %d in job %d\n", framenum, jobnum); + if(DEBUG) + fprintf(stderr, "Preparing to render frame %d in job %d\n", framenum, jobnum); prepareJobPaths(jobnum, framenum, outputExt, datadir, &urltoTar, &pathtoTar,&pathtoTardir,&pathtoJob, &pathtoJobfile, &urltoJobfile, &urltoOutput, &pathtoOutput, &pathtoRenderOutput, &pathtoOutdir); free(outputExt); - if(downloadTar(urltoTar, pathtoTar)) - return 1; + int dlret = downloadTar(urltoTar, pathtoTar); + if(dlret == 0) + fprintf(stderr,"Data retrieved successfully!\n"); + else if(dlret == 3){ + resetframe(comm_slave, jobnum, framenum); // Unassign the frame on the server so other slaves can render it + return 0; // ouput dir doesn't exist + } + else + if(DEBUG) + fprintf(stderr,"Using existing tarball %s...\n", pathtoTar); + + // Decompress tarball + struct stat jbuffer; + int jstatus = stat(pathtoJobfile, &jbuffer); + if(jstatus == -1){ + if(DEBUG) + fprintf(stderr,"Main job file does not exist, extracting...\n"); - unpackJob(datadir, pathtoTar); + // If error unpacking tarball + if(unpackJob(pathtoJob, pathtoTar)){ + resetframe(comm_slave, jobnum, framenum); // Unassign the frame on the server so other slaves can render it + fprintf(stderr,"Error decompressing tarball! Exiting.\n"); + return 1; + } + } + + /* ignore return because directory may exist already */ + if(DEBUG) + fprintf(stderr,"Creating output directory %s\n", pathtoOutdir); + mkdir(pathtoOutdir, 0700); + + if(DEBUG) + fprintf(stderr,"Marking frame started on server... "); + _web_startframe(slavekey, password, jobnum, framenum); + + /* Execute blender */ + if(DEBUG){ + fprintf(stderr,"Executing blender on file %s\n", pathtoJobfile); + fprintf(stderr,"Directing output to file %s\n", pathtoOutput); + } /* Execute blender */ if(exec_blender(pathtoJobfile, pathtoOutput, framenum)) { fprintf(stderr,"Error running Blender. Check your installation and/or your PATH.\n"); + resetframe(comm_slave, jobnum, framenum); // Unassign the frame on the server so other slaves can render it return 1; } free(pathtoJobfile); + pathtoJobfile = NULL; - /* Post-execution */ - fprintf(stderr, "Finished frame %d in job %d, uploading...\n", framenum, jobnum); - uploadOutput(pathtoOutput, urltoOutput, jobnum, framenum, slavekey); // @TODO: Handle return value - - free(urltoOutput); - free(pathtoOutput); + struct stat buffer; + int fstatus = stat(pathtoOutput, &buffer); + if(fstatus == -1){ + fprintf(stderr,"*** %s doesn't exist! Scene may not have camera, or your blender installation is not working.\n", pathtoOutput); + resetframe(comm_slave, jobnum, framenum); // Unassign the frame on the server so other slaves can render it + return 1; + } + else{ + /* Post-execution */ + if(DEBUG) + fprintf(stderr, "Finished frame %d in job %d, uploading...\n", framenum, jobnum); + else + fprintf(stderr,"Finished frame.\n"); + uploadOutput(pathtoOutput, urltoOutput, jobnum, framenum, slavekey); // @TODO: Handle return value - // Tell the server that rendering and upload are complete of "jobjum.framenum" - char *jobFrame; - _distren_asprintf(&jobFrame, "%s.%s", jobnum, framenum); - sendExtSignal(comm_slave, DISTREN_REQUEST_DONEFRAME, jobFrame); - free(jobFrame); - } - else - fprintf(stderr,"Nothing to do. Idling...\n"); + free(urltoOutput); + free(pathtoOutput); + urltoOutput = NULL; + pathtoOutput = NULL; + + // Tell the server that rendering and upload are complete of "jobjum.framenum" + finishframe(comm_slave, jobnum, framenum); + } + } + else{ + if(DEBUG) + fprintf(stderr,"Nothing to do. Idling...\n"); + else + fprintf(stderr,"."); + sleep(300); // Poll every 300 seconds @TODO: remove polling + } // @TODO: If the server says that every frame for the last jobnum is finished, OR if the data is getting old if(1 == 0) @@ -196,6 +318,18 @@ int main(int argc, char *argv[]) fprintf(stderr,"Closing connection to server...\n"); remoteio_close(comm_slave); + free(my_cfg); + free(outputExt); + free(datadir); + free(urltoTar); + free(pathtoTar); + free(pathtoTardir); + free(pathtoJob); + free(pathtoJobfile); + free(urltoJobfile); + free(urltoOutput); + free(pathtoRenderOutput); + free(pathtoOutdir); fprintf(stderr,"Goodbye!\n"); return 0; }