- web: fix bugs that cause backslashes to be introduced

in global prefs update via account manager RPC

svn path=/trunk/boinc/; revision=15602
This commit is contained in:
David Anderson 2008-07-14 19:13:19 +00:00
parent 679229b859
commit 1147e60b1a
12 changed files with 281 additions and 293 deletions

View File

@ -5716,3 +5716,14 @@ Rytis 13 July 2008
profile_menu.php
languages/translations/
en.po
David 14 July 2008
- web: fix bugs that cause backslashes to be introduced
in global prefs update via account manager RPC
html/user/
am_set_info.php
account_finish_action.php
account_finish.php
sched/
sched_send.C

View File

@ -14,7 +14,7 @@ create table bossa_app (
info text,
-- app-specific info, JSON
primary key(id)
);
) engine = InnoDB;
create table bossa_job (
id integer not null auto_increment,
@ -22,7 +22,6 @@ create table bossa_job (
app_id integer not null,
batch_id integer not null,
state integer not null,
transition_time integer not null,
info text,
is_calibration tinyint not null,
priority_0 float not null,
@ -37,6 +36,7 @@ create table bossa_job_inst (
job_id integer not null,
user_id integer not null,
finish_time integer not null,
transition_time integer not null,
info text,
primary key(id)
) engine=InnoDB;
@ -48,7 +48,7 @@ create table bossa_user (
-- debug, show_all
info text
-- Project-dependent info about users ability and performance.
);
) engine = InnoDB;
create table bossa_batch (
id integer not null auto_increment,
@ -56,4 +56,4 @@ create table bossa_batch (
name varchar(255) not null,
app_id integer not null,
primary key(id)
);
) engine = InnoDB;

View File

@ -3,14 +3,16 @@
require_once("../inc/util.inc");
require_once("../inc/bossa_db.inc");
function bossa_job_create($app_id, $batch_id, $info, $is_calibration, $priority) {
function bossa_job_create(
$app_id, $batch_id, $info, $is_calibration, $priority
) {
$job = new BossaJob;
$info = serialize($info);
$is_calibration = $is_calibration?1:0;
$now = time();
$int_max = 2147483647;
$clause = "(create_time, app_id, batch_id, state, transition_time, info, is_calibration, priority_0) values ($now, $app_id, $batch_id, 0, $int_max, '$info', $is_calibration, $priority)";
$clause = "(create_time, app_id, batch_id, state, info, is_calibration, priority_0) values ($now, $app_id, $batch_id, 0, '$info', $is_calibration, $priority)";
return $job->insert($clause);
}
@ -24,13 +26,4 @@ function bossa_app_lookup($name) {
return $app->id;
}
function bossa_update_job_info($inst, $info) {
$info = serialize($info);
$inst->update("info='$info'");
}
function bossa_job_get_info($job) {
return deserialize($job->info);
}
?>

View File

@ -37,6 +37,14 @@ class BossaDb extends DbConn {
$db = self::get();
return $db->base_escape_string($string);
}
static function start_transaction() {
$db = BossaDb::get();
$db->do_query("start transaction");
}
static function commit() {
$db = BossaDb::get();
$db->do_query("commit");
}
}
class BossaUser {
@ -116,6 +124,15 @@ class BossaJob {
$db = BossaDb::get();
return $db->enum('bossa_job', 'BossaJob', $clause);
}
// app-callable:
//
function get_info() {
return unserialize($this->info);
}
function set_priority($x) {
return $this->update("priority_0=$x");
}
}
class BossaJobInst {
@ -158,7 +175,11 @@ class BossaJobInst {
// this query skips jobs for which this user
// has already been assigned an instance
//
$prio = "priority_".$user->bossa->category;
if (isset($user->bossa->category)) {
$prio = "priority_".$user->bossa->category;
} else {
$prio = "priority_0";
}
$query = "select * from DBNAME.bossa_job where app_id=$app->id and (select count(*) from DBNAME.bossa_job_inst where job_id=bossa_job.id and user_id=$user->id) = 0 and state=1 and is_calibration=0 order by $prio desc limit 1";
$result = $db->do_query($query);
if (!$result) return null;
@ -171,6 +192,13 @@ class BossaJobInst {
$id = BossaJobInst::insert($clause);
return BossaJobInst::lookup_id($id);
}
// app-callable functions
//
function update_info($info) {
$info = serialize($info);
return $this->update("info='$info'");
}
}
class BossaBatch {

View File

@ -37,4 +37,172 @@ function bossa_example_handle($bj, $c) {
$bj->update("info='$i'");
}
// return the total confidence of the instances that agree with the given one
//
function agree_conf($app, $instances, $inst) {
$sum = $inst->confidence;
foreach ($instances as $i) {
if (!$i->finish_time) continue;
if ($i->id == $inst->id) continue;
$c = $app->compare;
if ($c($i, $inst)) {
$sum += $i->confidence;
}
}
return $sum;
}
// return the total confidence of the finished instances
//
function finished_confidence($instances) {
$sum = 0;
foreach ($instances as $i) {
if (!$i->finish_time) continue;
$sum += $i->confidence;
}
return $sum;
}
// return the total confidence of the viable instances
//
function viable_confidence($instances, $job) {
$sum = 0;
foreach ($instances as $i) {
if (!$i->finish_time) continue;
if (timed_out($i, $job)) continue;
$sum += $i->confidence;
}
return $sum;
}
// See if there's a canonical instance.
// If there's not, return the confidence of the largest compatible set
//
function find_canonical($app, $instances, $finished_conf, &$max_conf) {
$best = null;
$best_conf = 0;
foreach ($instances as $inst) {
if (!$inst->finish_time) continue;
$ac = agree_conf($app, $instances, $inst);
debug(" agree conf for $inst->id: $ac");
if ($ac > $best_conf) {
$best_conf = $ac;
$best = $inst;
}
}
if (!$best) return;
$max_conf = $best_conf;
if ($best_conf < $app->min_conf_sum) return;
if ($best_conf/$finished_conf < $app->min_conf_frac) return;
return $best;
}
// A canonical instance has just been identified
// Mark instances as valid/invalid, and call the app's handler function
//
function handle_canonical($app, $job, $cinst, $instances) {
$valid_instances = array();
$c = $app->compare;
foreach ($instances as $inst) {
if (!$inst->finish_time) continue;
if ($inst->id == $cinst->id) {
$inst->validate_state = VALIDATE_STATE_VALID;
$valid_instances[] = $inst;
} else if ($c($inst, $cinst)) {
$inst->validate_state = VALIDATE_STATE_VALID;
$valid_instances[] = $inst;
} else {
$inst->validate_state = VALIDATE_STATE_INVALID;
}
$inst->update("validate_state=$inst->validate_state");
}
$h = $app->handle;
$h($job, $valid_instances);
$job->update("canonical_inst_id=$cinst->id");
}
function lookup_canonical($instances, $id) {
foreach ($instances as $i) {
if ($i->id == $id) return $i;
}
return null;
}
// this gets invoked when
// 1) an instance has been completed
// 2) an instance has timed out
//
function handle_job($job) {
global $int_max;
global $now;
$next_transition = $int_max;
debug("processing job $job->id ($job->name)");
$app = lookup_bapp($job->app_id);
if (!$app) {
echo "ERROR: missing app: $job->app_id\n";
$job->update("transition_time=$int_max");
return;
}
$instances = BossaJobInst::enum("job_id=$job->id");
if ($job->canonical_inst_id) {
// Already have a canonical instance.
// Are there new instances to validate?
//
debug(" Already have CI $job->canonical_inst_id");
$canonical_inst = lookup_canonical($instances, $job->canonical_inst_id);
if (!$canonical_inst) {
echo "ERROR: can't find canonical instance for job $job->id\n";
return;
}
foreach ($instances as $inst) {
switch ($inst->validate_state) {
case VALIDATE_STATE_INIT:
if (compatible($inst, $canonical_inst)) {
$inst->validate_state = VALIDATE_STATE_VALID;
} else {
$inst->validate_state = VALIDATE_STATE_INVALID;
}
debug(" Instance $inst->id: valid=$inst->validate_state");
$inst->update("validate_state=$inst->validate_state");
}
}
$conf_needed = 0;
} else {
// No canonical instance yet.
// If we have enough total confidence, check for consensus
//
$finished_conf = finished_confidence($instances);
$vc = viable_confidence($instances, $job);
debug(" Don't have CI yet; finished confidence is $finished_conf");
if ($finished_conf >= $app->min_conf_sum) {
$inst = find_canonical($app, $instances, $finished_conf, $max_conf);
if ($inst) {
debug(" Found CI ($inst->id); max conf $max_conf finished conf $finished_conf");
handle_canonical($app, $job, $inst, $instances);
$conf_needed = 0;
} else {
debug(" No CI found; max conf $max_conf finished conf $finished_conf");
$f = $app->min_conf_frac;
$conf_needed = ($f*$vc - $max_conf)/(1-$f);
debug(" f $f vc $vc max_conf $max_conf -> conf_needed $conf_needed");
}
} else {
$conf_needed = $app->min_conf_sum - $vc;
}
foreach ($instances as $inst) {
if (!$inst->finish_time) {
$deadline = $inst->create_time + $job->time_limit;
if ($deadline > $now) {
if ($deadline < $next_transition) $next_transition = $deadline;
}
}
}
}
// set job's new transition time and conf_needed
//
debug(" New transition time $next_transition, conf_needed $conf_needed");
$job->update("transition_time=$next_transition, conf_needed=$conf_needed");
}
?>

View File

@ -1,16 +1,19 @@
<?php
function show_next_job($app, $user) {
BossaDb::start_transaction();
$inst = BossaJobInst::assign($app, $user);
if ($inst) {
$job = BossaJob::lookup_id($inst->job_id);
$file = "../inc/$app->short_name.inc";
echo "file: $file";
require_once($file);
job_issued($job, $inst, $user);
BossaDb::commit();
page_head("Bossa job");
job_show($job, $inst, $user);
page_tail();
} else {
BossaDb::commit();
page_head("No jobs available");
echo "
Sorry, no jobs are available right now.

View File

@ -3,223 +3,51 @@
require_once("../inc/bossa_db.inc");
$int_max = 2147483647;
$now = 0;
function debug($x) {
//return;
echo "$x\n";
}
function lookup_bapp($id) {
global $apps;
foreach ($apps as $app) {
if ($app->id == $id) return $app;
}
return null;
}
// is the job instance timed out?
//
function timed_out($ji, $job) {
$deadline = $ji->create_time + $job->time_limit;
}
// return the total confidence of the instances that agree with the given one
//
function agree_conf($app, $instances, $inst) {
$sum = $inst->confidence;
foreach ($instances as $i) {
if (!$i->finish_time) continue;
if ($i->id == $inst->id) continue;
$c = $app->compare;
if ($c($i, $inst)) {
$sum += $i->confidence;
}
}
return $sum;
}
// return the total confidence of the finished instances
//
function finished_confidence($instances) {
$sum = 0;
foreach ($instances as $i) {
if (!$i->finish_time) continue;
$sum += $i->confidence;
}
return $sum;
}
// return the total confidence of the viable instances
//
function viable_confidence($instances, $job) {
$sum = 0;
foreach ($instances as $i) {
if (!$i->finish_time) continue;
if (timed_out($i, $job)) continue;
$sum += $i->confidence;
}
return $sum;
}
// See if there's a canonical instance.
// If there's not, return the confidence of the largest compatible set
//
function find_canonical($app, $instances, $finished_conf, &$max_conf) {
$best = null;
$best_conf = 0;
foreach ($instances as $inst) {
if (!$inst->finish_time) continue;
$ac = agree_conf($app, $instances, $inst);
debug(" agree conf for $inst->id: $ac");
if ($ac > $best_conf) {
$best_conf = $ac;
$best = $inst;
}
}
if (!$best) return;
$max_conf = $best_conf;
if ($best_conf < $app->min_conf_sum) return;
if ($best_conf/$finished_conf < $app->min_conf_frac) return;
return $best;
}
// A canonical instance has just been identified
// Mark instances as valid/invalid, and call the app's handler function
//
function handle_canonical($app, $job, $cinst, $instances) {
$valid_instances = array();
$c = $app->compare;
foreach ($instances as $inst) {
if (!$inst->finish_time) continue;
if ($inst->id == $cinst->id) {
$inst->validate_state = VALIDATE_STATE_VALID;
$valid_instances[] = $inst;
} else if ($c($inst, $cinst)) {
$inst->validate_state = VALIDATE_STATE_VALID;
$valid_instances[] = $inst;
} else {
$inst->validate_state = VALIDATE_STATE_INVALID;
}
$inst->update("validate_state=$inst->validate_state");
}
$h = $app->handle;
$h($job, $valid_instances);
$job->update("canonical_inst_id=$cinst->id");
}
function lookup_canonical($instances, $id) {
foreach ($instances as $i) {
if ($i->id == $id) return $i;
}
return null;
}
// this gets invoked when
// 1) an instance has been completed
// 2) an instance has timed out
//
function handle_job($job) {
global $int_max;
global $now;
$next_transition = $int_max;
debug("processing job $job->id ($job->name)");
$app = lookup_bapp($job->app_id);
if (!$app) {
echo "ERROR: missing app: $job->app_id\n";
$job->update("transition_time=$int_max");
return;
}
$instances = BossaJobInst::enum("job_id=$job->id");
if ($job->canonical_inst_id) {
// Already have a canonical instance.
// Are there new instances to validate?
//
debug(" Already have CI $job->canonical_inst_id");
$canonical_inst = lookup_canonical($instances, $job->canonical_inst_id);
if (!$canonical_inst) {
echo "ERROR: can't find canonical instance for job $job->id\n";
return;
}
foreach ($instances as $inst) {
switch ($inst->validate_state) {
case VALIDATE_STATE_INIT:
if (compatible($inst, $canonical_inst)) {
$inst->validate_state = VALIDATE_STATE_VALID;
} else {
$inst->validate_state = VALIDATE_STATE_INVALID;
}
debug(" Instance $inst->id: valid=$inst->validate_state");
$inst->update("validate_state=$inst->validate_state");
}
}
$conf_needed = 0;
} else {
// No canonical instance yet.
// If we have enough total confidence, check for consensus
//
$finished_conf = finished_confidence($instances);
$vc = viable_confidence($instances, $job);
debug(" Don't have CI yet; finished confidence is $finished_conf");
if ($finished_conf >= $app->min_conf_sum) {
$inst = find_canonical($app, $instances, $finished_conf, $max_conf);
if ($inst) {
debug(" Found CI ($inst->id); max conf $max_conf finished conf $finished_conf");
handle_canonical($app, $job, $inst, $instances);
$conf_needed = 0;
} else {
debug(" No CI found; max conf $max_conf finished conf $finished_conf");
$f = $app->min_conf_frac;
$conf_needed = ($f*$vc - $max_conf)/(1-$f);
debug(" f $f vc $vc max_conf $max_conf -> conf_needed $conf_needed");
}
} else {
$conf_needed = $app->min_conf_sum - $vc;
}
foreach ($instances as $inst) {
if (!$inst->finish_time) {
$deadline = $inst->create_time + $job->time_limit;
if ($deadline > $now) {
if ($deadline < $next_transition) $next_transition = $deadline;
}
}
}
}
// set job's new transition time and conf_needed
//
debug(" New transition time $next_transition, conf_needed $conf_needed");
$job->update("transition_time=$next_transition, conf_needed=$conf_needed");
}
function do_pass() {
global $now;
global $int_max;
$now = time();
$jobs = BossaJob::enum("transition_time < $now");
if (!count($jobs)) return false;
foreach ($jobs as $job) {
handle_job($job);
$insts = BossaJobInst::enum("transition_time < $now");
if (!count($insts)) return false;
foreach ($insts as $inst) {
BossaDb::start_transaction();
$inst = BossaJobInst::lookup_id($inst->id);
// reread instance within transation
if ($inst->transition_time < $now) {
$job = BossaJob::lookup_id($inst->job_id);
$user = BoincUser::lookup_id($inst->user_id);
BossaUser::lookup($user);
if ($inst->finished_time) {
job_finished($job, $inst, $user);
} else {
job_timed_out($job, $inst, $user);
}
}
$inst->update("transition_time=$int_max");
BossaDb::commit();
}
return true;
}
function main() {
global $apps;
$apps = BossaApp::enum();
foreach ($apps as $app) {
$bs = "../inc/".$app->short_name.".inc";
require_once($bs);
$app->compare = $app->short_name."_compare";
$app->handle = $app->short_name."_handle";
}
while (1) {
if (!do_pass()) {
debug("Sleeping");
sleep(10);
}
$name = $argv[1];
$app = BossaApp::lookup("short_name='$name'");
if (!$app) {
echo "No app named $name\n";
exit;
}
$bs = "../inc/".$name.".inc";
require_once($bs);
while (1) {
if (!do_pass()) {
debug("Sleeping");
sleep(10);
}
}
main();
?>

View File

@ -9,7 +9,7 @@ require_once('../inc/util.inc');
require_once('../inc/countries.inc');
require_once('../inc/translation.inc');
$auth = process_user_text(get_str("auth"));
$auth = get_str("auth");
$user = lookup_user_auth($auth);
if (!$user) {
error_page("no such account");

View File

@ -21,7 +21,6 @@ if (!is_valid_country($country)) {
$postal_code = strip_tags(post_str("postal_code", true));
$auth = process_user_text($auth);
$name = process_user_text($name);
$postal_code = process_user_text($postal_code);

View File

@ -43,14 +43,14 @@ if (!$user) {
xml_error(-136);
}
$name = process_user_text($_GET["name"]);
$country = $_GET["country"];
$name = process_user_text(get_str("name"));
$country = get_str("country");
if ($country && !is_valid_country($country)) {
xml_error(-1, "invalid country");
}
$postal_code = process_user_text($_GET["postal_code"]);
$global_prefs = process_user_text($_GET["global_prefs"]);
$project_prefs = process_user_text($_GET["project_prefs"]);
$postal_code = process_user_text(get_str("postal_code"));
$global_prefs = process_user_text(get_str("global_prefs"));
$project_prefs = process_user_text(get_str("project_prefs"));
// Do processing on project prefs so that we don't overwrite project-specific
// settings if AMS has no idea about them
@ -62,13 +62,13 @@ if (stripos($project_prefs, "<project_specific>") === false) {
$project_prefs = str_ireplace("<project_preferences>", "<project_preferences>\n".$orig_project_specific, $project_prefs);
}
$url = process_user_text($_GET["url"]);
$send_email = process_user_text($_GET["send_email"]);
$show_hosts = process_user_text($_GET["show_hosts"]);
$url = process_user_text(get_str("url"));
$send_email = process_user_text(get_str("send_email"));
$show_hosts = process_user_text(get_str("show_hosts"));
$teamid = get_int("teamid", true);
$venue = process_user_text($_GET["venue"]);
$email_addr = strtolower(process_user_text($_GET["email_addr"]));
$password_hash = process_user_text($_GET["password_hash"]);
$venue = process_user_text(get_str("venue"));
$email_addr = strtolower(process_user_text(get_str("email_addr")));
$password_hash = process_user_text(get_str("password_hash"));
$query = "";
if ($name) {

View File

@ -1,44 +0,0 @@
<?php
require_once("../inc/bossa.inc");
// Bossa example.
// Show the user an image and ask them to click on the ellipse
function job_show($job, $inst, $user) {
$info = bossa_job_get_info($job);
$path = $info->path;
echo "
<h2>Find the Ellipse!</h2>
<form method=get action=bossa_job_finished.php>
Click on the center of the ellipse.
If you don't see one, click here:
<input type=submit name=submit value=None>
<br><br>
<input type=hidden name=bji value=$inst->id>
<input type=image name=pic src=$img_url>
</form>
";
}
function job_issued($job, $inst, $user) {
bossa_job_set_priority($job, 0);
}
function job_finished($job, $inst) {
$response = null;
if (get_str('submit', true)) {
$response->have_ellipse = 0;
} else {
$response->have_ellipse = 1;
$response->cx = get_int('pic_x');
$response->cy = get_int('pic_y');
}
bossa_update_job_info($inst, $response);
}
function job_timed_out($job, $inst, $user) {
bossa_job_set_priority($job, 1);
}
?>

View File

@ -541,25 +541,27 @@ static inline int check_bandwidth(
static inline int check_deadline(
WORKUNIT& wu, SCHEDULER_REQUEST& request, SCHEDULER_REPLY& reply
) {
if (config.ignore_delay_bound) return 0;
// skip delay check if host currently doesn't have any work
// (i.e. everyone gets one result, no matter how slow they are)
//
if (!config.ignore_delay_bound && request.estimated_delay>0) {
double ewd = estimate_wallclock_duration(wu, request, reply);
double est_completion_delay = request.estimated_delay + ewd;
double est_report_delay = max(est_completion_delay, request.global_prefs.work_buf_min());
double diff = est_report_delay - wu.delay_bound;
if (diff > 0) {
if (config.debug_send) {
log_messages.printf(MSG_DEBUG,
"[WU#%d %s] est report delay %d on [HOST#%d]; delay_bound is %d\n",
wu.id, wu.name, (int)est_report_delay,
reply.host.id, wu.delay_bound
);
}
reply.wreq.speed.set_insufficient(diff);
return INFEASIBLE_CPU;
if (request.estimated_delay == 0) return 0;
double ewd = estimate_wallclock_duration(wu, request, reply);
double est_completion_delay = request.estimated_delay + ewd;
double est_report_delay = max(est_completion_delay, request.global_prefs.work_buf_min());
double diff = est_report_delay - wu.delay_bound;
if (diff > 0) {
if (config.debug_send) {
log_messages.printf(MSG_DEBUG,
"[WU#%d %s] est report delay %d on [HOST#%d]; delay_bound is %d\n",
wu.id, wu.name, (int)est_report_delay,
reply.host.id, wu.delay_bound
);
}
reply.wreq.speed.set_insufficient(diff);
return INFEASIBLE_CPU;
}
return 0;
}