diff --git a/checkin_notes b/checkin_notes
index 87c51309a9..5a24183157 100644
--- a/checkin_notes
+++ b/checkin_notes
@@ -3332,3 +3332,11 @@ David 17 Apr 2012
client/
client_types.h
gui_rpc_server_ops.cpp
+
+David 17 Apr 2012
+ - scheduler: add a program that targets remaining jobs in a batch
+ to a particular user (e.g. for cloud execution).
+ From Derrick Kondo.
+
+ sched/
+ target_batch.cpp
diff --git a/sched/target_batch.cpp b/sched/target_batch.cpp
new file mode 100644
index 0000000000..059bc3e7f6
--- /dev/null
+++ b/sched/target_batch.cpp
@@ -0,0 +1,214 @@
+// NOTE: this is from Derrick Kondo (INRIA). Needs to be cleaned up a bit.
+
+/* Assigns uncompleted (and unassigned) workunits of a batch to hosts
+ registered under a DEDICATED_USER_ID. The constant DEDICATED_USER_ID
+ should be defined accordingly below.
+
+ The constant MAX_TO_ASSIGN should be defined according to the size of
+ the feeder's shmem array.
+
+ The project dir must be defined in the projects config.xml file.
+
+ Input parameter of the form 'batch=[id]' can be passed via url or commmand line.
+
+ Example usage from command line:
+ ./target_batch batch=1
+
+ Example usage from URL:
+ http://abenaki.imag.fr/clouds_ops/target_batch?batch=1
+
+ ----------------
+
+ To enable targeted jobs in general in BOINC, add
+ 1
+ to the config.xml file.
+
+*/
+
+/* TESTS
+
+PLAIN OLD SCHEDULING OF A BATCH
+
+Works as long as boinc client is up-to-date.
+
+-----------------------
+
+SCHEDULING OF BATCH TARGETTED TO DEDICATED HOST
+
+Create a batch of low-priority tasks:
+./create_test_work.pl -appname example_app -numwu 10 -batch 0 -label "lowpri" -db clouds -password "" -wu "templates/example_app_in.xml" -result "templates/example_app_out.xml"
+
+
+Target batch to dedicated workers:
+/bin/target_batch batch=0
+
+Start dedicated work with USER_ID corresonding to DEDICATED_USER_ID.
+
+Check that these tasks are only assigned to dedicated workers.
+
+* Assignment table appears correct
+* Cloud worker downloads and processes targetted results. Results in ops
+* php page have status "Didn't need"
+* Non-cloud workers do not download targetted results
+
+-----------------------
+
+OOO What cleans up the assignment table?
+
+*/
+
+
+#include "config.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using std::vector;
+using std::string;
+
+#include "boinc_db.h"
+#include "crypt.h"
+#include "util.h"
+#include "backend_lib.h"
+#include "sched_config.h"
+#include "parse.h"
+#include "sched_util.h"
+#include "sched_msgs.h"
+#include "str_util.h"
+#include "svn_version.h"
+
+
+
+
+#define DEDICATED_USER_ID 1
+#define MAX_TO_ASSIGN 100
+
+int main(int argc, char *argv[])
+{
+ //must have two lines after content header. Else you will get "Internal
+ //Server Error" when executing script
+ printf ("Content-type: text/plain\n\n");
+ printf ("Targeting batch\n\n");
+
+ int retval = config.parse_file();
+ if (retval) {
+ log_messages.printf(MSG_CRITICAL,
+ "Can't parse config.xml: %s\n", boincerror(retval)
+ );
+ exit(1);
+ }
+
+
+
+ retval = boinc_db.open(config.db_name, config.db_host, config.db_user, config.db_passwd);
+ if (retval) {
+ log_messages.printf(MSG_CRITICAL, "can't open DB\n");
+ exit(1);
+ }
+
+
+ char buf[256];
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Get targetted batch id
+ char * query_str = getenv("QUERY_STRING");
+ if (query_str == NULL){
+ printf ("Batch id not provided in url. Checking for command line argument...\n");
+
+ if (argc==2 && argv[1] != NULL){
+ printf ("\tUsing batch id from command line\n\n");
+ query_str = argv[1];
+ } else {
+ printf ("Error: batch id not provided, argc: %d\n", argc);
+ exit(1);
+ }
+ }
+
+ char batch_str[256];
+ int batch;
+ if (sscanf(query_str, "batch=%256s", &batch_str) == 1){
+ batch = atoi(batch_str);
+ printf ("Targetting batch id: %d\n\n", batch);
+ } else {
+ printf ("Bad argument format. Should be \"batch=[id]\"\n");
+ exit(1);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Left join to get workunits not already in the
+ // assignment table
+
+ // TESTED: DOESN'T RESELECT ASSIGNED WUS
+ sprintf(buf,
+"SELECT workunit.* \
+FROM workunit \
+LEFT JOIN assignment \
+ON workunit.id = assignment.workunitid \
+WHERE assignment.workunitid IS NULL \
+AND canonical_resultid = 0 AND batch = %d \
+LIMIT %d",
+ batch, MAX_TO_ASSIGN);
+ // Tried moving "AND canonical_resultid = 0 AND batch = %d \" in line
+ // where join appears, but the results of the query were wrong
+
+
+ retval = boinc_db.do_query(buf);
+ if (retval) {
+ printf ("Problem with db\n");
+ boinc_db.close();
+ exit(1);
+ }
+
+ MYSQL_RES* rp;
+
+ rp = mysql_store_result(boinc_db.mysql);
+ if (!rp) {
+ printf ("Problem with db\n");
+ boinc_db.close();
+ exit(1);
+
+ }
+
+ MYSQL_ROW row;
+ DB_WORKUNIT workunit;
+
+ int num_assigned=0;
+ while ((row = mysql_fetch_row(rp))){
+ workunit.db_parse(row);
+ printf ("Assigning WU %d to user \n", workunit.id, DEDICATED_USER_ID);
+
+ restrict_wu_to_user (workunit, DEDICATED_USER_ID);
+
+ num_assigned++;
+ printf ("End of this WU assignment\n\n");
+
+ }
+
+ mysql_free_result(rp);
+
+ ///////////////////////////////////////////////////////////////////////////
+ // reset the feeder
+
+ char cmd_buf[256];
+
+ if (num_assigned>0){
+ sprintf (cmd_buf, "touch %s/reread_db", config.project_dir);
+
+ printf ("Running cmd: %s", cmd_buf);
+
+ int ret_val = system (cmd_buf);
+ if (ret_val > 0){
+ printf ("Houston: we have a reread_db problem\n");
+ }
+ }
+
+ printf ("\nDONE.\n");
+}
+
+