diff --git a/checkin_notes b/checkin_notes index 7aa7e5bacb..c05f7ebda2 100644 --- a/checkin_notes +++ b/checkin_notes @@ -4376,3 +4376,25 @@ David 26 July 2011 forum_thread.php submit_example.php submit.php + +David 26 July 2011 + - web: remote job submission: + - add fields to batch table, extend APIs accordingly + - require that example web interface run on BOINC server + (this makes many things easier; + an actual remote interface would require a bit more work) + + db/ + boinc_db.h + schema.sql + html/ + ops/ + db_update.php + inc/ + submit_db.inc + submit.inc + util.inc + result.inc + user/ + submit_example.php + submit.php diff --git a/db/boinc_db.h b/db/boinc_db.h index d82c559243..f37f549788 100644 --- a/db/boinc_db.h +++ b/db/boinc_db.h @@ -563,6 +563,48 @@ struct RESULT { void clear(); }; +struct BATCH { + int id; + int user_id; + // submitter + int create_time; + double logical_start_time; + double logical_end_time; + double est_completion_time; + // current estimate of completion time + int njobs; + // # of workunits + double fraction_done; + // based on workunits completed + int nerror_jobs; + // # of workunits with error + int state; + // see below + double completion_time; + // when state became >= COMPLETE + double credit_estimate; + // initial estimate of required credit, counting replicas + double credit_canonical; + // the sum of credits of canonical results + double credit_total; + // the sum of credits of all results + char name[256]; + // user-assigned name; need not be unique + int app_id; +} + +// values of batch.state +// +#define BATCH_STATE_INIT 0 +#define BATCH_STATE_IN_PROGRESS 1 +#define BATCH_STATE_COMPLETE 2 + // "complete" means all workunits have either + // a canonical result or an error +#define BATCH_STATE_ABORTED 3 +#define BATCH_STATE_CLEANED_UP 4 + // input/output files can be deleted, + // result and workunit records can be purged. + struct MSG_FROM_HOST { int id; int create_time; diff --git a/db/schema.sql b/db/schema.sql index c3cf0ef20f..0600a2de2d 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -282,6 +282,42 @@ create table result ( primary key (id) ) engine=InnoDB; +-- see boinc_db.h for doc +create table batch ( + id serial primary key, + user_id integer not null, + create_time integer not null, + logical_start_time double not null, + logical_end_time double not null, + est_completion_time double not null, + njobs integer not null, + fraction_done double not null, + nerror_jobs integer not null, + state integer not null, + completion_time double not null, + credit_estimate double not null, + credit_canonical double not null, + credit_total double not null, + name varchar(255) not null, + app_id integer not null +) engine = InnoDB; + +-- permissions for job submission +-- +create table user_submit ( + user_id integer not null, + quota double not null, + logical_start_time double not null, + all_apps tinyint not null +) engine = InnoDB; + +-- (user, app) submit permissions +-- +create table user_submit_app ( + user_id integer not null, + app_id integer not null +) engine = InnoDB; + -- the following are used to implement trickle messages create table msg_from_host ( @@ -638,29 +674,3 @@ create table notify ( opaque integer not null -- some other ID, e.g. that of the thread, user or PM record ); - -create table batch ( - id serial primary key, - user_id integer not null, - create_time integer not null, - logical_start_time double not null, - logical_end_time double not null, - est_completion_time double not null, - njobs integer not null -) engine = InnoDB; - --- permissions for job submission --- -create table user_submit ( - user_id integer not null, - quota double not null, - logical_start_time double not null, - all_apps tinyint not null -) engine = InnoDB; - --- (user, app) submit permissions --- -create table user_submit_app ( - user_id integer not null, - app_id integer not null -) engine = InnoDB; diff --git a/html/inc/result.inc b/html/inc/result.inc index fbf033865f..b7d0d80aff 100644 --- a/html/inc/result.inc +++ b/html/inc/result.inc @@ -567,7 +567,7 @@ function get_outfile_paths($result) { function abort_workunit($wu) { BoincResult::update_aux( - "server_state=5, outcome=5 where server_state=2 and workunit=$wu->id" + "server_state=5, outcome=5 where server_state=2 and workunitid=$wu->id" ); $wu->update("error_mask=error_mask|16"); } diff --git a/html/inc/submit.inc b/html/inc/submit.inc index c3cba8bb3a..5d076b08a5 100644 --- a/html/inc/submit.inc +++ b/html/inc/submit.inc @@ -25,6 +25,7 @@ function req_to_xml($req, $op) { $req->authenticator $req->app_name + $req->batch_name "; foreach ($req->jobs as $job) { $x .= " @@ -107,6 +108,24 @@ function boinc_submit_batch($req) { } } +function batch_xml_to_object($batch) { + $b = null; + $b->id = (int)($batch->id); + $b->create_time = (double)($batch->create_time); + $b->est_completion_time = (double)($batch->est_completion_time); + $b->njobs = (int)($batch->njobs); + $b->fraction_done = (double) $batch->fraction_done; + $b->nerror_jobs = (int)($batch->nerror_jobs); + $b->state = (int)($batch->state); + $b->completion_time = (double)($batch->completion_time); + $b->credit_estimate = (double)($batch->credit_estimate); + $b->credit_canonical = (double)($batch->credit_canonical); + $b->credit_total = (double)($batch->credit_total); + $b->name = (string)($batch->name); + $b->app_name = (string)($batch->app_name); + return $b; +} + function boinc_query_batches($req) { $req_xml = " $req->authenticator @@ -116,14 +135,7 @@ function boinc_query_batches($req) { if ($errmsg) return array(null, $errmsg); $batches = array(); foreach ($reply->batch as $batch) { - $b = null; - $b->id = (int)($batch->id); - $b->completed = (int)($batch->completed); - $b->njobs = (int)($batch->njobs); - $b->create_time = (double)($batch->create_time); - if (!$b->completed) { - $b->fraction_done = (double) $batch->fraction_done; - } + $b = batch_xml_to_object($batch); $batches[] = $b; } return array($batches, null); @@ -144,11 +156,7 @@ function boinc_query_batch($req) { $j->canonical_instance_id = (int)($job->canonical_instance_id); $jobs[] = $j; } - $r = null; - $r->fraction_done = (double)($reply->fraction_done); - $r->completed = (int)($reply->completed); - $r->create_time = (double)($reply->create_time); - $r->est_completion_time = (double)($reply->est_completion_time); + $r = batch_xml_to_object($reply); $r->jobs = $jobs; return array($r, null); } @@ -208,11 +216,11 @@ function boinc_get_output_files($req) { return $req->project."/get_output.php?batch_id=$batch_id&auth_str=$auth_str"; } -function boinc_cleanup_batch($req) { - $req_xml = " +function boinc_retire_batch($req) { + $req_xml = " $req->authenticator $req->batch_id - + "; list($reply, $errmsg) = do_http_op($req->project, $req_xml); if ($errmsg) return $errmsg; @@ -223,6 +231,17 @@ function boinc_cleanup_batch($req) { return null; } +function batch_state_string($state) { + switch ($state) { + case BATCH_STATE_INIT: return "New"; + case BATCH_STATE_IN_PROGRESS: return "In progress"; + case BATCH_STATE_COMPLETE: return "Completed"; + case BATCH_STATE_ABORTED: return "Aborted"; + case BATCH_STATE_RETIRED: return "Retired"; + } + return "Unknown state $state"; +} + //// example usage follows $req->project = "http://isaac.ssl.berkeley.edu/test/"; diff --git a/html/inc/submit_db.inc b/html/inc/submit_db.inc index 0c32649b7e..27ce1aed20 100644 --- a/html/inc/submit_db.inc +++ b/html/inc/submit_db.inc @@ -33,8 +33,20 @@ class BoincBatch { if (!$ret) return $ret; return $db->insert_id(); } + function update($clause) { + $db = BoincDb::get(); + return $db->update($this, 'batch', $clause); + } } +// see db/boinc_db.h +// +define('BATCH_STATE_INIT', 0); +define('BATCH_STATE_IN_PROGRESS', 1); +define('BATCH_STATE_COMPLETE', 2); +define('BATCH_STATE_ABORTED', 3); +define('BATCH_STATE_RETIRED', 4); + class BoincUserSubmit { static function enum($clause) { $db = BoincDb::get(); diff --git a/html/inc/util.inc b/html/inc/util.inc index 1a0a8a810f..4f480f950b 100644 --- a/html/inc/util.inc +++ b/html/inc/util.inc @@ -32,8 +32,6 @@ if (array_key_exists("PATH_INFO", $_SERVER)) { ini_set("memory_limit", "64M"); -date_default_timezone_set("UTC"); - if (!defined('SECURE_URL_BASE')) { define('SECURE_URL_BASE', URL_BASE); } @@ -261,6 +259,11 @@ function time_str($x) { return gmdate('j M Y | G:i:s', $x) . " UTC"; } +function local_time_str($x) { + if ($x == 0) return "---"; + return date('j M Y | H:i:s', $x); +} + function pretty_time_str($x) { return time_str($x); } diff --git a/html/ops/db_update.php b/html/ops/db_update.php index 8a2ead545e..5ef035cc85 100755 --- a/html/ops/db_update.php +++ b/html/ops/db_update.php @@ -751,6 +751,21 @@ create table user_submit_app ( ) engine = InnoDB"); } +function update_7_26_2011() { + do_query(" + alter table batch + add fraction_done double not null, + add nerror_jobs integer not null, + add state integer not null, + add completion_time double not null, + add credit_estimate double not null, + add credit_canonical double not null, + add credit_total double not null, + add name varchar(255) not null, + add app_id integer not null + "); +} + // Updates are done automatically if you use "upgrade". // // If you need to do updates manually, @@ -770,6 +785,7 @@ $db_updates = array ( array(21728, "update_6_10_2010"), array(23635, "update_6_3_2011"), array(23762, "update_6_20_2011"), + array(23881, "update_7_26_2011"), ); ?> diff --git a/html/user/submit.php b/html/user/submit.php index 0da83873fc..cb1b3a1f2c 100644 --- a/html/user/submit.php +++ b/html/user/submit.php @@ -73,13 +73,17 @@ function project_flops() { return $y; } +function est_elapsed_time($r) { + // crude estimate: batch FLOPs / project FLOPS + // + return batch_flop_count($r) / project_flops(); +} + function estimate_batch($r) { $app = get_app($r); list($user, $user_submit) = authenticate_user($r, $app); - // crude estimate: batch FLOPs / project FLOPS - // - $e = batch_flop_count($r) / project_flops(); + $e = est_elapsed_time($r); echo "\n$e\n\n"; } @@ -142,49 +146,84 @@ function submit_batch($r) { stage_files($r, $template); $njobs = count($r->batch->job); $now = time(); + $batch_name = (string)($r->batch->batch_name); $batch_id = BoincBatch::insert( - "(user_id, create_time, njobs) values ($user->id, $now, $njobs)" + "(user_id, create_time, njobs, name, app_id) values ($user->id, $now, $njobs, '$batch_name', $app->id)" ); $i = 0; foreach($r->batch->job as $job) { submit_job($job, $template, $app, $batch_id, $i++); } + $batch = BoincBatch::lookup_id($batch_id); + $batch->update("state=".BATCH_STATE_IN_PROGRESS); echo "$batch_id\n"; } -function fraction_done($batch) { - $wus = BoincWorkunit::enum("batch = $batch->id"); +// compute and update params of a batch +// NOTE: eventually this should be done by server components +// (transitioner, validator etc.) as jobs complete or time out +// +// TODO: update est_completion_time +// +function get_batch_params($batch, $wus) { + if ($batch->state > BATCH_STATE_IN_PROGRESS) return $batch; $fp_total = 0; $fp_done = 0; - $completed = 1; + $completed = true; + $nerror_jobs = 0; + $credit_canonical = 0; foreach ($wus as $wu) { $fp_total += $wu->rsc_fpops_est; if ($wu->canonical_resultid) { $fp_done += $wu->rsc_fpops_est; + $credit_canonical += $wu->canonical_credit; + } else if ($wu->error_mask) { + $nerror_jobs++; } else { - $completed = 0; + $completed = false; } } - if (!$fp_total) return array(1, true);; - $fd= $fp_done / $fp_total; - return array($fd, $completed); + if ($fp_total) { + $batch->fraction_done = $fp_done / $fp_total; + } + if ($completed && $batch->state < BATCH_STATE_COMPLETE) { + $batch->state = BATCH_STATE_COMPLETE; + $batch->completion_time = time(); + } + $batch->nerror_jobs = $nerror_jobs; + $batch->update("fraction_done = $batch->fraction_done, nerror_jobs = $batch->nerror_jobs, state=$batch->state, completion_time = $batch->completion_time, credit_canonical = $batch->credit_canonical"); + return $batch; +} + +function print_batch_params($batch) { + $app = BoincApp::lookup_id($batch->app_id); + echo " + $batch->id + $batch->create_time + $batch->est_completion_time + $batch->njobs + $batch->fraction_done + $batch->nerror_jobs + $batch->state + $batch->completion_time + $batch->credit_estimate + $batch->credit_canonical + $batch->credit_total + $batch->name + $app->name +"; } function query_batches($r) { list($user, $user_submit) = authenticate_user($r, null); $batches = BoincBatch::enum("user_id = $user->id"); echo "\n"; - foreach ($batches as $b) { - list($fd, $completed) = fraction_done($b); - echo " - $b->id - $fd - $completed - $b->create_time - $b->est_completion_time - $b->njobs - -"; + foreach ($batches as $batch) { + $wus = BoincWorkunit::enum("batch = $batch->id"); + $batch = get_batch_params($batch, $wus); + echo " \n"; + print_batch_params($batch); + echo " \n"; } echo "\n"; } @@ -199,23 +238,23 @@ function query_batch($r) { list($user, $user_submit) = authenticate_user($r, null); $batch_id = (int)($r->batch_id); $batch = BoincBatch::lookup_id($batch_id); + if (!$batch) { + error("no such batch"); + } if ($batch->user_id != $user->id) { error("not owner"); } - echo "\n"; - list($fd, $completed) = fraction_done($batch); - echo " - $fd - $completed - $b->create_time - $b->est_completion_time - "; + $wus = BoincWorkunit::enum("batch = $batch_id"); + $batch = get_batch_params($batch, $wus); + echo "\n"; + print_batch_params($batch); + $n_outfiles = n_outfiles($wus[0]); foreach ($wus as $wu) { echo " $wu->id $wu->canonical_resultid - ".n_outfiles($wu)." + $n_outfiles "; } @@ -267,10 +306,11 @@ function abort_batch($r) { foreach ($wus as $wu) { abort_workunit($wu); } + $batch->update("state=".BATCH_STATE_ABORTED); echo "1"; } -function cleanup_batch($r) { +function retire_batch($r) { list($user, $user_submit) = authenticate_user($r, null); $batch_id = (int)($r->batch_id); $batch = BoincBatch::lookup_id($batch_id); @@ -282,6 +322,7 @@ function cleanup_batch($r) { foreach ($wus as $wu) { $wu->update("assimilate_state=2, transition_time=$now"); } + $batch->update("state=".BATCH_STATE_RETIRED); echo "1"; } @@ -309,7 +350,7 @@ switch ($r->getName()) { case 'query_batch': query_batch($r); break; case 'query_job': query_job($r); break; case 'abort_batch': abort_batch($r); break; - case 'cleanup_batch': cleanup_batch($r); break; + case 'retire_batch': retire_batch($r); break; default: error("bad command"); } diff --git a/html/user/submit_example.php b/html/user/submit_example.php index e27aa677a6..aa7f7212c2 100644 --- a/html/user/submit_example.php +++ b/html/user/submit_example.php @@ -20,28 +20,30 @@ // example of a web interface to remote job submission // // Notes: -// - You'll need to adapt/extend this considerably; -// e.g. the project URL, app name and user authenticator are hardwired here. -// - This can run on any host, not just the project server -// (that's the "remote" part). +// - You'll need to adapt/extend this considerably, +// especially if you want to run this +// on a server other than the BOINC project serve. // - For convenience, this uses some functions from BOINC // (page_head() etc.). // When you adapt this to your own purposes, // you can strip out this stuff if the web site doesn't use BOINC require_once("../inc/submit.inc"); +require_once("../inc/submit_db.inc"); require_once("../inc/util.inc"); +require_once("../project/project.inc"); error_reporting(E_ALL); ini_set('display_errors', true); ini_set('display_startup_errors', true); -$project = "http://isaac.ssl.berkeley.edu/test/"; -$auth = "157f96a018b0b2f2b466e2ce3c7f54db"; -$app_name = "uppercase"; + +$project = $master_url; // from project.inc +$user = get_logged_in_user(); +$auth = $user->authenticator; function handle_main() { - global $project, $auth, $app_name; + global $project, $auth; $req->project = $project; $req->authenticator = $auth; list($batches, $errmsg) = boinc_query_batches($req); @@ -49,52 +51,119 @@ function handle_main() { page_head("Job submission and control"); + echo date("F j, Y, g:i a"); show_button("submit_example.php?action=create_form", "Create new batch"); - echo "Batches in progress\n"; - start_table(); - table_header("ID", "# jobs", "progress", "submitted"); + $first = true; foreach ($batches as $batch) { - if ($batch->completed) continue; + if ($batch->state != BATCH_STATE_IN_PROGRESS) continue; + if ($first) { + $first = false; + echo "In progress\n"; + start_table(); + table_header("name", "ID", "app", "# jobs", "progress", "submitted"); + } $pct_done = (int)($batch->fraction_done*100); table_row( + "id>$batch->name", "id>$batch->id", + $batch->app_name, $batch->njobs, "$pct_done%", - time_str($batch->create_time) + local_time_str($batch->create_time) ); } - end_table(); + if (!$first) { + end_table(); + } - echo "Batches completed\n"; - start_table(); - table_header("ID", "# jobs", "submitted"); + $first = true; foreach ($batches as $batch) { - if (!$batch->completed) continue; + if ($batch->state != BATCH_STATE_COMPLETE) continue; + if ($first) { + $first = false; + echo "Completed\n"; + start_table(); + table_header("name", "ID", "# jobs", "submitted"); + } table_row( + "id>$batch->name", "id>$batch->id", $batch->njobs, - time_str($batch->create_time) + local_time_str($batch->create_time) ); } - end_table(); + if (!$first) { + end_table(); + } + + $first = true; + foreach ($batches as $batch) { + if ($batch->state != BATCH_STATE_ABORTED) continue; + if ($first) { + $first = false; + echo "Aborted\n"; + start_table(); + table_header("name", "ID", "# jobs", "submitted"); + } + table_row( + "id>$batch->name", + "id>$batch->id", + $batch->njobs, + local_time_str($batch->create_time) + ); + } + if (!$first) { + end_table(); + } page_tail(); } -function handle_create_form() { - global $project, $auth, $app_name; +function eligible_apps() { + global $user; + $apps = BoincApp::enum("deprecated = 0"); + $user_submit = BoincUserSubmit::lookup_userid($user->id); + if (!$user_submit) return null; + $a = array(); + foreach($apps as $app) { + if ($user_submit->all_apps) { + $a[] = $app; + } else { + if (BoincUserSubmitApp::lookup("user_id=$user->id and app_id=$app->id")) { + $a[] = $app; + } + } + } + return $a; +} +function app_select($apps) { + $x = "\n"; + foreach ($apps as $app) { + $x .= "name>$app->user_friendly_name\n"; + } + $x .= "\n"; + return $x; +} + +function handle_create_form() { + global $project, $auth; + + $apps = eligible_apps(); + if (!$apps) error_page("You are not allowed to submit jobs"); page_head("Create batch"); echo " "; start_table(); - row2("Input file URL", ""); - row2("Parameter low value", ""); - row2("Parameter high value", ""); - row2("Parameter increment", ""); + row2("Name", ""); + row2("Application", app_select($apps)); + row2("Input file URL", ""); + row2("Parameter low value", ""); + row2("Parameter high value", ""); + row2("Parameter increment", ""); row2("", "" ); @@ -109,27 +178,30 @@ function handle_create_form() { // build a request object for boinc_*_batch() from form variables // function form_to_request() { - global $project, $auth, $app_name; + global $project, $auth; $input_url = get_str('input_url'); if (!$input_url) error_page("missing input URL"); - $param_lo = get_str('param_lo'); - if (!$param_lo) error_page("missing param lo"); - $param_hi = get_str('param_hi'); - if (!$param_hi) error_page("missing param hi"); - $param_inc = get_str('param_inc'); - if (!$param_inc) error_page("missing param inc"); + $param_lo = (double)get_str('param_lo'); + if ($param_lo<0 || $param_lo>60) error_page("param lo must be in 0..60"); + $param_hi = (double)get_str('param_hi'); + if ($param_hi<0 || $param_hi>60 || $param_hi <= $param_lo) { + error_page("param hi must be in 0..60 and > param lo"); + } + $param_inc = (double)get_str('param_inc'); + if ($param_inc < 1) error_page("param inc must be >= 1"); $req->project = $project; $req->authenticator = $auth; - $req->app_name = $app_name; + $req->app_name = get_str('app_name'); + $req->batch_name = get_str('batch_name'); $req->jobs = Array(); $f->source = $input_url; $f->name = "in"; $job->input_files = Array($f); - for ($x=(double)$param_lo; $x<(double)$param_hi; $x += (double)$param_inc) { + for ($x=$param_lo; $x<$param_hi; $x += $param_inc) { $job->rsc_fpops_est = $x*1e9; $job->command_line = "--t $x"; $req->jobs[] = $job; @@ -139,7 +211,7 @@ function form_to_request() { } function handle_create_action() { - global $project, $auth, $app_name; + global $project, $auth; $get_estimate = get_str('get_estimate', true); if ($get_estimate) { @@ -147,47 +219,68 @@ function handle_create_action() { list($e, $errmsg) = boinc_estimate_batch($req); if ($errmsg) error_page($errmsg); page_head("Batch estimate"); - echo "Estimate: $e seconds"; + echo sprintf("Estimate: %.0f seconds", $e); page_tail(); } else { $req = form_to_request($project, $auth); list($id, $errmsg) = boinc_submit_batch($req); if ($errmsg) error_page($errmsg); page_head("Batch submitted"); - echo "Batch ID: $id"; + echo "Batch created, ID: $id + + Return to job control page + "; page_tail(); } } function handle_query_batch() { - global $project, $auth, $app_name; + global $project, $auth; $req->project = $project; $req->authenticator = $auth; $req->batch_id = get_int('batch_id'); - list($reply, $errmsg) = boinc_query_batch($req); + list($batch, $errmsg) = boinc_query_batch($req); if ($errmsg) error_page($errmsg); page_head("Batch $req->batch_id"); $url = boinc_get_output_files($req); show_button($url, "Get zipped output files"); - if ($reply->completed) { - echo ""; - show_button( - "submit_example.php?action=cleanup_batch_confirm&batch_id=$req->batch_id", - "Delete batch" - ); - } else { + start_table(); + row2("name", $batch->name); + row2("application", $batch->app_name); + row2("state", batch_state_string($batch->state)); + row2("# jobs", $batch->njobs); + row2("# error jobs", $batch->nerror_jobs); + row2("progress", sprintf("%.0f%%", $batch->fraction_done*100)); + if ($batch->completion_time) { + row2("completed", local_time_str($batch->completion_time)); + } + row2("Credit, estimated", $batch->credit_estimate); + row2("Credit, canonical instances", $batch->credit_canonical); + row2("Credit, total", $batch->credit_total); + end_table(); + switch ($batch->state) { + case BATCH_STATE_IN_PROGRESS: echo ""; show_button( "submit_example.php?action=abort_batch_confirm&batch_id=$req->batch_id", "Abort batch" ); + break; + case BATCH_STATE_COMPLETE: + case BATCH_STATE_ABORTED: + echo ""; + show_button( + "submit_example.php?action=retire_batch_confirm&batch_id=$req->batch_id", + "Retire batch" + ); + break; } echo "Jobs\n"; start_table(); table_header("Job ID", "Canonical instance"); - foreach($reply->jobs as $job) { + foreach($batch->jobs as $job) { $id = (int)$job->id; $resultid = (int)$job->canonical_instance_id; if ($resultid) { @@ -206,7 +299,7 @@ function handle_query_batch() { } function handle_query_job() { - global $project, $auth, $app_name; + global $project, $auth; $req->project = $project; $req->authenticator = $auth; $req->job_id = get_int('job_id'); @@ -252,7 +345,7 @@ function handle_abort_batch_confirm() { } function handle_abort_batch() { - global $project, $auth, $app_name; + global $project, $auth; $req->project = $project; $req->authenticator = $auth; $req->batch_id = get_int('batch_id'); @@ -265,29 +358,29 @@ function handle_abort_batch() { page_tail(); } -function handle_cleanup_batch_confirm() { +function handle_retire_batch_confirm() { $batch_id = get_int('batch_id'); - page_head("Confirm delete batch"); + page_head("Confirm retire batch"); echo " - Deleting a batch will remove all of its output files. + Retiring a batch will remove all of its output files. Are you sure you want to do this? "; show_button( - "submit_example.php?action=cleanup_batch&batch_id=$batch_id", - "Yes - delete batch" + "submit_example.php?action=retire_batch&batch_id=$batch_id", + "Yes - retire batch" ); page_tail(); } -function handle_cleanup_batch() { - global $project, $auth, $app_name; +function handle_retire_batch() { + global $project, $auth; $req->project = $project; $req->authenticator = $auth; $req->batch_id = get_int('batch_id'); - $errmsg = boinc_cleanup_batch($req); + $errmsg = boinc_retire_batch($req); if ($errmsg) error_page($errmsg); - page_head("Batch deleted"); + page_head("Batch retired"); echo " Return to job control page. "; @@ -318,11 +411,11 @@ case 'abort_batch_confirm': case 'abort_batch': handle_abort_batch(); break; -case 'cleanup_batch_confirm': - handle_cleanup_batch_confirm(); +case 'retire_batch_confirm': + handle_retire_batch_confirm(); break; -case 'cleanup_batch': - handle_cleanup_batch(); +case 'retire_batch': + handle_retire_batch(); break; default: error_page('no such action');
+ Return to job control page + "; page_tail(); } } function handle_query_batch() { - global $project, $auth, $app_name; + global $project, $auth; $req->project = $project; $req->authenticator = $auth; $req->batch_id = get_int('batch_id'); - list($reply, $errmsg) = boinc_query_batch($req); + list($batch, $errmsg) = boinc_query_batch($req); if ($errmsg) error_page($errmsg); page_head("Batch $req->batch_id"); $url = boinc_get_output_files($req); show_button($url, "Get zipped output files"); - if ($reply->completed) { - echo ""; - show_button( - "submit_example.php?action=cleanup_batch_confirm&batch_id=$req->batch_id", - "Delete batch" - ); - } else { + start_table(); + row2("name", $batch->name); + row2("application", $batch->app_name); + row2("state", batch_state_string($batch->state)); + row2("# jobs", $batch->njobs); + row2("# error jobs", $batch->nerror_jobs); + row2("progress", sprintf("%.0f%%", $batch->fraction_done*100)); + if ($batch->completion_time) { + row2("completed", local_time_str($batch->completion_time)); + } + row2("Credit, estimated", $batch->credit_estimate); + row2("Credit, canonical instances", $batch->credit_canonical); + row2("Credit, total", $batch->credit_total); + end_table(); + switch ($batch->state) { + case BATCH_STATE_IN_PROGRESS: echo ""; show_button( "submit_example.php?action=abort_batch_confirm&batch_id=$req->batch_id", "Abort batch" ); + break; + case BATCH_STATE_COMPLETE: + case BATCH_STATE_ABORTED: + echo ""; + show_button( + "submit_example.php?action=retire_batch_confirm&batch_id=$req->batch_id", + "Retire batch" + ); + break; } echo "
"; show_button( - "submit_example.php?action=cleanup_batch&batch_id=$batch_id", - "Yes - delete batch" + "submit_example.php?action=retire_batch&batch_id=$batch_id", + "Yes - retire batch" ); page_tail(); } -function handle_cleanup_batch() { - global $project, $auth, $app_name; +function handle_retire_batch() { + global $project, $auth; $req->project = $project; $req->authenticator = $auth; $req->batch_id = get_int('batch_id'); - $errmsg = boinc_cleanup_batch($req); + $errmsg = boinc_retire_batch($req); if ($errmsg) error_page($errmsg); - page_head("Batch deleted"); + page_head("Batch retired"); echo " Return to job control page. "; @@ -318,11 +411,11 @@ case 'abort_batch_confirm': case 'abort_batch': handle_abort_batch(); break; -case 'cleanup_batch_confirm': - handle_cleanup_batch_confirm(); +case 'retire_batch_confirm': + handle_retire_batch_confirm(); break; -case 'cleanup_batch': - handle_cleanup_batch(); +case 'retire_batch': + handle_retire_batch(); break; default: error_page('no such action');