4 require_once 'plc_login.php';
6 // Get session and API handles
7 require_once 'plc_session.php';
8 global $plc, $api, $adm;
11 require_once 'plc_functions.php';
12 require_once 'plc_sorts.php';
15 $_person= $plc->person;
16 $_roles= $_person['role_ids'];
18 //require 'sirius_func.php';
21 require_once 'plc_drupal.php';
22 drupal_set_title('Sirius');
23 include 'plc_header.php';
27 <h2>Sirius Calendar Service</h2>
29 You can choose to run your experiment at the earliest available
30 time or give a specific time. The number of repetitions has
31 the following meaning: if you want your job re-inserted on the
32 schedule list (in the earliest slot available) directly after it
33 gets a priority increase, you can do so (up to 4 times). Currently,
34 our admission control policy is that we
35 allow only one slice per time slot. <p>
38 time slots are only allocated on the granularity
40 only CPU is increased.
50 define("TOO_MANY_UNITS", 2);
51 define("NO_UNITS_LEFT", 3);
52 define("TIME_ALREADY_OCCURRED", 4);
53 define("NO_SUCH_SLICE", 5);
54 define("NOT_SLICE_OWNER", 6);
55 define("TOO_CLOSE_TO_DEADLINE", 7);
57 define("DELETE_THRESHOLD", 600);
58 define("MAX_JOBS", 1);
60 function authorizeSlice($sn) {
62 $_api = new xmlrpc_client('/PLCAPI/', 'planet-lab.org', 443);
64 $username = $_SESSION['username'];
65 $password = $_SESSION['password'];
69 $_api_auth = new xmlrpcval(array(
70 "AuthMethod" => new xmlrpcval("password"),
71 "Username" => new xmlrpcval($username),
72 "AuthString" => new xmlrpcval($password),
73 "Role" => new xmlrpcval("user")), "struct");
75 $func = new xmlrpcmsg("SliceInfo");
76 $func->addParam($_api_auth);
78 $result = $_api->send($func, 15, 'https');
81 // printf("problem: %s\n", $_api->errstring);
84 else if($result->faultCode() != 0) {
85 // printf("server problem: %s\n", $result->errstr);
89 $result_value = $result->value();
91 if( !$result_value ) {
92 // printf( "didn't get value back from api\n" );
96 $arr = xmlrpc_decode($result_value);
97 // printf( "return value success, value %s\n", $val);
99 $numElements = count($arr);
101 while ($i < $numElements) {
102 if ($sn == $arr[$i][name])
113 $slice_list= array();
114 $result= $api->GetSlices( $slice_list, array( "name" ) );
116 foreach ( $result AS $slice )
118 if ( $slice["name"] == $sn )
127 //can a request be satisfied? Currently, answer is yes unless
128 //either this time is taken or you asked for more than one unit
129 //probably will need to change this.
130 function validateRequest ($units, $timesOccupied, $requestedTime, $currentTime) {
132 return TOO_MANY_UNITS;
134 // buffer so we aren't too close to deadline, if your request is late
135 // OR if it's within 1 minute of deadline, it's too late
136 if ($requestedTime - 60 <= $currentTime)
137 return TIME_ALREADY_OCCURRED;
139 if (array_key_exists($requestedTime, $timesOccupied)) {
140 if ($timesOccupied[$requestedTime] == MAX_JOBS)
146 //can a request be satisfied? Currently, answer is yes unless
147 //either this time is taken or you asked for more than one unit
148 //probably will need to change this.
149 function validateAndMarkRequest ($units, &$timesOccupied, $requestedTime, $currentTime, $sn, $jobArray) {
150 // buffer so we aren't too close to deadline, if your request is late
151 // OR if it's within 1 minute of deadline, it's too late
152 if ($requestedTime - 60 <= $currentTime)
153 return TIME_ALREADY_OCCURRED;
155 if (array_key_exists($requestedTime, $timesOccupied)) {
156 if ($timesOccupied[$requestedTime] == MAX_JOBS)
159 $timesOccupied[$requestedTime]++;
162 $timesOccupied[$requestedTime] = 1;
163 if (array_key_exists($sn, $jobArray)) {
164 $ts = $jobArray[$sn]["timestamp"];
165 $timesOccupied[$ts]--;
170 return TOO_MANY_UNITS;
175 function findNextFreeSlot($units, $timesOccupied) {
176 $currYear = gmdate("y");
177 $currMonth = gmdate("m");
178 $currDate = gmdate("d");
179 $currHour = gmdate("H") + 1;
180 $currentTime = gmmktime();
181 $reqTime = gmmktime($currHour, 0, 0, $currMonth, $currDate, $currYear);
183 while ($retVal != SUCCESS) {
184 $retVal = validateRequest($units, $timesOccupied, $reqTime, $currentTime);
185 if ($retVal == NO_ROOM || $retVal == TIME_ALREADY_OCCURRED) { // advance timestamp one hour (3600 seconds)
186 $reqTime = $reqTime + 3600;
192 function dumpToFile($fileName, $buffer, $which, $timesOccupied) {
193 //open file, and dump newly list into it (buffer is the list)
194 //we're just currently overwriting (fopen with "w" truncates)
196 $fileHandle = fopen($fileName, "w");
197 //periodically, updateSliceUnits program will update the slices file
198 //this function is general, works for schedule or slices file
200 //lock in case of concurrent accesses
201 flock($fileHandle, LOCK_EX);
203 if ($which == "schedule") { // need to write timestamp in this case
205 fwrite($fileHandle, $s[sec]);
206 fwrite($fileHandle, "\n");
210 foreach ($buffer as $value) {
212 if ($which == "schedule") {
213 if (strcmp($value["timestamp"], mktime()) > 0) {
214 $numReps = $value["reps"];
215 $ts = $value["timestamp"];
216 $t = $value["sliceName"]." ".$value["id"]." ".$value["timestamp"]." ".$value["units"]." ".$value["reps"]." \n";
218 else { // job expired, does it need be run again?
219 if ($value["reps"] > 0) {
220 $ts = findNextFreeSlot($value["units"], $timesOccupied);
222 $numReps = $value["reps"] - 1;
225 $t = $value["sliceName"]." ".$value["id"]." ".$ts." ".$value["units"]." ".$numReps." \n";
227 else if ($which == "slices") {
228 $t = $value["sliceName"]." ".$value["units"]." \n";
232 fwrite($fileHandle, $t);
236 flock($fileHandle, LOCK_UN);
241 //update the slice file, takes a slice name (name) and number of units
242 function updateSliceFile($name, $units) {
243 $dummyArray = array();
245 $sliceFile = fopen("/var/www/html/planetlab/sirius/slices.txt", "rw");
247 echo "<p>Unable to open remote file.</p>";
251 flock($sliceFile, LOCK_EX);
253 //we'll construct a new list here, will be current slice file except
254 //the slice in question will have it's units decreased, if there are any...
255 while (!feof($sliceFile)) {
256 $num = fscanf($sliceFile, "%s %d\n", $sliceName, $unitsAvailable);
257 //for some reason feof seems to not quite work
258 //precisely, the last entry in the file is read twice (!?!), so hack here
262 $newArray["sliceName"] = $sliceName;
263 if ($name == $sliceName) {
264 $newUnits = $unitsAvailable - $units;
265 if ($newUnits < 0) // error, slice has no more units
268 $newArray["units"] = $newUnits;
271 $newArray["units"] = $unitsAvailable;
272 //append this tuple to the entire array
273 $sliceArray[] = $newArray;
275 flock($sliceFile, LOCK_UN);
277 //do the dump to new file
278 dumpToFile("/var/www/html/planetlab/sirius/slices.txt", $sliceArray, "slices", dummyArray);
283 //pretty obvious what this does; basically, does the slice exist in
284 //the slice file yet? (New user of calendar service user may not have
286 function isFirstSliceRequest($name) {
287 $sliceFile = fopen("/var/www/html/planetlab/sirius/slices.txt", "r");
289 echo "<p>Unable to open remote file.</p>";
293 flock($sliceFile, LOCK_EX);
295 while (!feof($sliceFile)) {
296 $num = fscanf($sliceFile, "%s %d\n", $sliceName, $unitsAvailable);
297 //for some reason feof seems to not quite work
298 //precisely, the last entry in the file is read twice (!?!), so hack here
302 if ($name == $sliceName) {
303 flock($sliceFile, LOCK_UN);
309 flock($sliceFile, LOCK_UN);
315 function cmp ($a, $b) {
316 if ($a["timestamp"] == $b["timestamp"])
319 return ($a["timestamp"] < $b["timestamp"]) ? -1 : 1;
322 function checkForErrors($requestStatus) {
323 if ($requestStatus == NO_ROOM) {
324 printf("<b> Error: Cannot add your request; that time slot is currently full. </b> <p>");
326 else if ($requestStatus == TOO_MANY_UNITS) {
327 printf("<b> Error: Cannot add your request; only 1 extra unit is allowed.</b> <p>");
329 else if ($requestStatus == NO_UNITS_LEFT) {
330 printf("<b> Error: Cannot add your request; no more units remaining.</b> <p>");
332 else if ($requestStatus == TIME_ALREADY_OCCURRED) {
333 printf("<b> Error: Cannot add your request; that time has already occurred, or is too close to the current time.</b> <p>");
335 else if ($requestStatus == NO_SUCH_SLICE) {
336 printf("<b> Error: Cannot delete nonexistent slice.</b> <p>");
338 else if ($requestStatus == NOT_SLICE_OWNER) {
339 printf("<b> Error: Only authorized user can manipulate slice.</b> <p>");
341 else if ($requestStatus == TOO_CLOSE_TO_DEADLINE) {
342 printf("<b> Error: Cannot delete your request; it is too close to
343 the time that your slice will receive its priority increase.</b> <p>");
347 function getCurrentSchedule (&$jobArray, &$timesOccupied, &$maxId) {
349 $schedFile = fopen("/var/www/html/planetlab/sirius/schedule.txt", "r");
351 echo "<p>Unable to open remote file.</p>";
355 flock($schedFile, LOCK_EX);
357 //first line is timestamp, throw it away.
358 fscanf($schedFile, "%s\n", $str);
360 //read in current file into array
363 $timesOccupied = array();
365 while (!feof($schedFile)) {
366 $num = fscanf($schedFile, "%s %d %s %d %d\n", $sliceName, $id, $timestamp, $units, $reps);
371 //for some reason feof seems to not quite work
372 //precisely, the last entry in the file is read twice (!?!), so hack here
375 $newArray["sliceName"] = $sliceName;
376 $newArray["id"] = $id;
377 $newArray["units"] = $units;
378 $newArray["timestamp"] = $timestamp;
379 $newArray["reps"] = $reps;
380 $jobArray[$sliceName] = $newArray;
382 if (array_key_exists($timestamp, $timesOccupied)) {
383 $timesOccupied[$timestamp]++;
386 $timesOccupied[$timestamp] = 1;
391 flock($schedFile, LOCK_UN);
396 // Reid: after below function call, you have the current schedule.
397 // It is stored in $jobArray, which is an array of arrays.
398 // Layout: each element of $jobArray is an array with
399 // the following fields.
400 // "sliceName": the name of the slice that occupies the slot
401 // "id": the id of the slice, currently not used; do not display
402 // "units": another field that will be used eventually...but not yet
403 // "reps": indicates how many repetitions slice has specified; for
404 // each repetition, the slice is automatically rescheduled
405 // after running for the earliest available slot
406 // I don't know if you want to pring the schedule out as part of the
407 // queue here, or wait to see if there was a submitted job.
408 // See my comments below for more details.
410 getCurrentSchedule ($jobArray, $timesOccupied, $maxId);
414 // Reid: here, we see if a new request is submitted (which would
415 // be done now as: did the user click into the queue and
416 // select a slice to get the next slot. I think you can just
417 // skip to the end of this if statement (see comment below)
419 // Reid: The problem here is, this is based on the current submission
420 // procedure, which is: click the submit button (or the delete
421 // button). I'm not sure how to change or modularize this
422 // function because I don't know how the queue would precisely
423 // be implemented. I've commented the code below to try to help.
425 //if form was submitted with new job, process it
426 if (isset($_POST['action']) && $_POST['action'] == 'submitted') {
427 $sname = $_POST['sliceName'];
429 if (!authorizeSlice($sname)) {
430 $requestStatus = NOT_SLICE_OWNER;
432 else if ($_POST['add_delete'] == "delete") {
433 // delete request. Make sure it exists and is early enough to delete,
435 if (array_key_exists($sname, $jobArray)) {
437 $ts = $jobArray[$sname]["timestamp"];
438 if ($ts - mktime() < DELETE_THRESHOLD)
439 $requestStatus = TOO_CLOSE_TO_DEADLINE;
441 $timesOccupied[$ts]--;
442 unset($jobArray[$sname]);
446 $requestStatus = NO_SUCH_SLICE;
450 // it's an add request
451 // grab all the data from the user.
453 // $minute = $_POST['minute'];
454 $reps = $_POST['reps'];
455 // $u = $_POST['units'];
458 $currentTime = mktime();
460 if ($_POST['whenToRun'] == "asap") {
461 $requestedTime = findNextFreeSlot($u, $timesOccupied);
464 // $requestedTime = gmmktime($hour, $minute, 0, $month, $date, $year);
465 if (!isset( $_POST['queue_time'] )) {
466 $year = $_POST['year'];
467 $month = $_POST['month'];
468 $date = $_POST['date'];
469 $hour = $_POST['hour'];
470 $requestedTime = gmmktime($hour, 0, 0, $month, $date, $year);
473 $currYear = gmdate("y");
474 $currMonth = gmdate("m");
475 $currDate = gmdate("d");
476 $currHour = gmdate("H");
477 $hour = $_POST['queue_time'];
478 if ($hour < $currHour) {
479 $requestedTime = gmmktime($hour, 0, 0, $currMonth, $currDate+1, $currYear);
482 $requestedTime = gmmktime($hour, 0, 0, $currMonth, $currDate, $currYear);
488 $requestStatus = validateAndMarkRequest($u, $timesOccupied, $requestedTime, $currentTime, $sname, $jobArray);
489 if ($requestStatus == SUCCESS) {
490 // ignore below, it is for future work anyways.
491 if (isFirstSliceRequest($sname)) {
492 $sliceFile = fopen("/var/www/html/planetlab/sirius/slices.txt", "a");
493 if ($sliceFile == 0) {
494 echo "<p>Unable to open file.</p>";
497 flock($sliceFile, LOCK_EX);
499 // should be max number of units, not 5
501 fwrite($sliceFile, $sname." "."6");
502 flock($sliceFile, LOCK_UN);
505 // if (updateSliceFile($sname, 1) < 0)
506 // temporarily not looking at units...
508 $requestStatus = NO_UNITS_LEFT;
510 // here, pretty simple, just stick all data into
511 // array element, then stick array into $jobArray.
512 $newArray["sliceName"] = $sname;
513 $newArray["id"] = $id;
514 $newArray["timestamp"] = $requestedTime;
515 $newArray["units"] = $u;
516 $newArray["reps"] = $reps;
517 $jobArray[$sname] = $newArray;
521 // header("Location: planetcal.php");
524 //sort job array by earliest time first ("cmp" function does this)
525 usort($jobArray, "cmp");
527 // Reid: after this above line, $jobArray holds a sorted list that
528 // you can output as the queue.
530 // Reid: below is the current printing of the schedule, which would
531 // certainly be deleted when you have the better representation
532 // of the schedule (the visual queue). It starts here and ends
533 // where I've marked below.
535 //print current job list as table on screen
536 printf("<table cellspacing=0 cellpadding=2>");
537 if (count($jobArray) > 0) {
539 printf("<th style='border: 1px black solid'> Slice name </th> <th style='border: 1px black solid'> Repetitions </th><th style='border: 1px black solid'> Time of priority </th>");
544 printf("<td>No jobs currently on queue </td><td></td><td></td>");
548 $deletedExpiredJob = 0;
552 foreach ($jobArray as $value) {
553 if (strcmp($value["timestamp"], mktime()) > 0) {
555 printf("<td> %s </td><td align=center> %d </td><td> %s </td>\n", $value["sliceName"], $value["reps"], gmdate("r", $value["timestamp"]));
556 $arr[$n]= $value["sliceName"];
561 $deletedExpiredJob = 1;
564 printf("</table>\n");
566 // Reid: end of current printing of the schedule.
568 // Reid: here is where we put the data back to the schedule file.
569 // It's already a function,
571 function findNextQueue($units, $timesOccupied, $arr) {
573 $currYear = gmdate("y");
574 $currMonth = gmdate("m");
575 $currDate = gmdate("d");
576 $currHour = gmdate("H") + 1;
577 $currentTime = gmmktime();
578 $reqTime = gmmktime($currHour, 0, 0, $currMonth, $currDate, $currYear);
584 // outputting table to display the queue
585 // green background will mean slot is open, and red will mean the slot is used
587 echo "<table cellspacing=\"2\" cellpadding=\"1\" border=\"0\" width=550>\n";
588 echo "<tr><td colspan=\"3\"><strong>24 hour Queue:</strong> Choose the GMT time slot you desire (<font color=\"#339933\">green</font> slots are open, <font color=\"#CC3333\">red</font> are taken) <p></td></tr>\n";
589 echo "<tr><td width=\"47%\" align=\"right\"><table cellspacing=1 cellpadding=1 border=0 width=130>\n";
591 // here's what this does below: it goes through each hour, and sees if the slot is occupied
592 // if so, it outputs in red, w/ slice name ($arr[$x], where $x is the number request, i.e.
593 // earlier when we dump out the list of slices on the schedule, we do $arr[$x++] = $slicename
595 // while ($reqTime < ( $reqTime + ( 24 * 3600 ) ) ) {
597 $retVal = validateRequest($units, $timesOccupied, $reqTime, $currentTime);
598 if ($retVal == SUCCESS) { // advance timestamp one hour (3600 seconds)
600 echo "<tr bgcolor=\"#339933\"><td><input type=\"radio\" name=\"queue_time\" value=\"" . gmdate("H:i:s", $reqTime) . "\"> " . gmdate("H:i:s", $reqTime) . " </td></tr>\n";
603 echo"<tr bgcolor=\"#CC3333\"><td align=center> " . $arr[$x] . " </td></tr>\n";
607 $reqTime = $reqTime + 3600;
610 echo "</table></td><td width=\"6%\"> </td><td><table cellspacing=1 cellpadding=1 border=0 width=130>\n";
612 while ($i < 24 && $i > 11) {
613 $retVal = validateRequest($units, $timesOccupied, $reqTime, $currentTime);
614 if ($retVal == SUCCESS) { // advance timestamp one hour (3600 seconds)
616 echo "<tr bgcolor=\"#339933\"><td><input type=\"radio\" name=\"queue_time\" value=\"" . gmdate("H:i:s", $reqTime) . "\"> " . gmdate("H:i:s", $reqTime) . " </td></tr>\n"; }
618 echo"<tr bgcolor=\"#CC3333\"><td align=center> " . $arr[$x] . " </td></tr>\n";
622 $reqTime = $reqTime + 3600;
625 echo "</table></td></tr>\n";
631 function sliceDropDown() {
633 $_api = new xmlrpc_client('/PLCAPI/', 'planet-lab.org', 443);
635 $username = $_SESSION['username'];
636 $password = $_SESSION['password'];
640 $_api_auth = new xmlrpcval(array(
641 "AuthMethod" => new xmlrpcval("password"),
642 "Username" => new xmlrpcval($username),
643 "AuthString" => new xmlrpcval($password),
644 "Role" => new xmlrpcval("user")), "struct");
646 $func = new xmlrpcmsg("SliceInfo");
647 $func->addParam($_api_auth);
649 $result = $_api->send($func, 15, 'https');
652 // printf("problem: %s\n", $_api->errstring);
655 else if($result->faultCode() != 0) {
656 // printf("server problem: %s\n", $result->errstr);
660 $result_value = $result->value();
662 if( !$result_value ) {
663 // printf( "didn't get value back from api\n" );
667 $arr = xmlrpc_decode($result_value);
668 // printf( "return value success, value %s\n", $val);
670 $numElements = count($arr);
672 while ($i < $numElements) {
673 echo "<option value='" . $arr[$i][name] . "'>" . $arr[$i][name] . "</option>\n";
683 $slice_list= array();
684 $result= $api->GetSlices( Null, array( "name" ) );
685 sort_slices( $result );
686 foreach ( $result AS $slice )
688 echo "<option value='" . $slice["name"] . "'>" . $slice["name"] . "\n";
693 //reopen schedule file, and dump newly sorted job list into it
694 //note that current timestamp is put in at beginning
695 //note also: only do this dump if a change has been made
697 if ($deletedExpiredJob || ($changeMade && $requestStatus == SUCCESS)) {
698 dumpToFile("/var/www/html/planetlab/sirius/schedule.txt", $jobArray, "schedule", $timesOccupied);
700 // hack here...the problem is that the file might not be sorted
701 // when it should, because of the stupid way it was designed. this
702 // happens when reps is not 0, and the next entry should go after
703 // another entry. what does happen is that it goes before, which is
704 // fine for displaying, but the sirius service code expects it to
705 // always be sorted, "it" being the schedule file
707 $hackArray = array();
708 getCurrentSchedule ($hackArray, $timesOccupied, $maxId);
709 usort($hackArray, "cmp");
710 dumpToFile("/var/www/html/planetlab/sirius/schedule.txt", $hackArray, "schedule", $timesOccupied);
713 checkForErrors($requestStatus);
720 <form action="/db/sirius/index.php" method="post">
721 <p>Choose your slice name:
722 <select name="sliceName">
723 <?php sliceDropDown(); ?>
727 Either Add a new time slot or remove a previously taken slot:
729 <b>Add</b> <input type=radio name="add_delete" value="add" checked/>
730 <b>Delete</b> <input type=radio name="add_delete" value="delete" />
732 ASAP will just select the next availible time, choose specific time if you want to specify a slot in the queue:
734 <b>ASAP</b> <input type=radio name="whenToRun" value="asap" checked/>
735 <b>Specific Time</b> <input type=radio name="whenToRun" value="specific" />
737 Choose a number of times you need CPU priority:
739 <b>Number of Repetitions</b>:
740 0 <input type=radio name="reps" value="0" checked/>
741 1 <input type=radio name="reps" value="1"/>
742 2 <input type=radio name="reps" value="2"/>
743 3 <input type=radio name="reps" value="3"/>
744 4 <input type=radio name="reps" value="4"/>
748 <?php findNextQueue( 1, $timesOccupied, $arr ); ?>
751 Only enter a time/date here if your request is for a time more than 24 hours from now.<br>
752 Year (two digits) <input type=text maxlength=2 size=2 name="year"/>
753 Month (1-12) <input type=text maxlength=2 size=2 name="month"/>
754 Date (1-31) <input type=text maxlength=2 size=2 name="date"/>
755 Hour (0-23) <input type=text maxlength=2 size=2 name="hour"/>
757 <!--Units <input type=text maxlength=2 size=2 name="units"/>-->
759 <input type="hidden" name="action" value="submitted" />
760 <input type="submit" name="submit" value="Submit" />
761 <input type="reset" name="reset" value="Reset" />