diff --git a/checkin_notes b/checkin_notes index 3ed7e82e17..3c089e7177 100755 --- a/checkin_notes +++ b/checkin_notes @@ -220,3 +220,9 @@ David A. May 29, 2002 test_uc_slow.php tools/ add.C + +David A. May 29, 2002 + - forgot to add a couple of files + sched/ + feeder.C + sched_shmem.C,h diff --git a/sched/feeder.C b/sched/feeder.C new file mode 100644 index 0000000000..73bdf5641d --- /dev/null +++ b/sched/feeder.C @@ -0,0 +1,189 @@ +// The contents of this file are subject to the Mozilla Public License +// Version 1.0 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations +// under the License. +// +// The Original Code is the Berkeley Open Infrastructure for Network Computing. +// +// The Initial Developer of the Original Code is the SETI@home project. +// Portions created by the SETI@home project are Copyright (C) 2002 +// University of California at Berkeley. All Rights Reserved. +// +// Contributor(s): +// + +// feeder.C +// +// Creates a shared memory segment containing DB info, +// including results/workunits to send. +// This means that the scheduler CGI program doesn't have to +// access the DB to get this info. + +// TODO: +// - check for wu/results that don't get sent for a long time; +// generate a warning message +// - mechanism for rereading static tables (trigger file? signal?) + +// Trigger file mechanism: +// The feeder program periodically checks for a file "feeder_trigger". +// It this file exists it contains a command to the feeder: +// +// destroy shmem and exit +// reread DB contents into existing shmem +// +// The feeder deletes the trigger file to indicate that it +// has completed the request. + +#include + +#include "db.h" +#include "shmem.h" +#include "sched_shmem.h" + +#define RESULTS_PER_ENUM 100 +#define TRIGGER_FILENAME "feeder_trigger" + +int check_trigger(SCHED_SHMEM* ssp) { + FILE* f; + char buf[256]; + + f = fopen(TRIGGER_FILENAME, "r"); + if (!f) return 0; + fread(buf, 1, 256, f); + fclose(f); + if (!strcmp(buf, "")) { + destroy_shmem(BOINC_KEY); + exit(0); + } else if (!strcmp(buf, "")) { + ssp->init(); + ssp->scan_tables(); + } else { + fprintf(stderr, "feeder: unknown command in trigger file: %s\n", buf); + } + unlink(TRIGGER_FILENAME); + return 0; +} + +int main() { + SCHED_SHMEM* ssp; + void* p; + int i, j, nadditions, ncollisions, retval; + RESULT result; + WORKUNIT wu; + bool no_wus, collision, restarted_enum; + + retval = destroy_shmem(BOINC_KEY); + if (retval) { + fprintf(stderr, "feeder: can't destroy shmem\n"); + exit(1); + } + retval = create_shmem(BOINC_KEY, sizeof(SCHED_SHMEM), &p); + if (retval) { + fprintf(stderr, "feeder: can't create shmem\n"); + exit(1); + } + ssp = (SCHED_SHMEM*)p; + ssp->init(); + retval = db_open("boinc"); + if (retval) { + fprintf(stderr, "feeder: db_open: %d\n", retval); + exit(1); + } + ssp->scan_tables(); + + printf( + "feeder: read\n" + "%d platforms\n" + "%d apps\n" + "%d app_versions\n", + ssp->nplatforms, + ssp->napps, + ssp->napp_versions + ); + + // Try keep the wu_results array filled. + // This is actually a little tricky. + // We use an enumerator. + // The inner loop scans the wu_result table, + // looking for empty slots and trying to fill them in. + // When the enumerator reaches the end, it is restarted; + // hopefully there will be some new workunits. + // There are two complications: + // - An enumeration may return results already in the array. + // So, for each result, we scan the entire array to make sure + // it's not there already. Can this be streamlined? + // - We must avoid excessive re-enumeration, + // especially when the number of results is less than the array size. + // Crude approach: if a "collision" (as above) occurred on + // a pass through the array, wait a long time (60 sec) + // + while (1) { + nadditions = 0; + ncollisions = 0; + no_wus = false; + restarted_enum = false; + for (i=0; inwu_results; i++) { + if (!ssp->wu_results[i].present) { + retval = db_result_enum_to_send(result, RESULTS_PER_ENUM); + if (retval) { + + // if we already restarted the enum on this pass, + // there's no point in doing it again. + // + if (restarted_enum) { + printf("feeder: already restarted enum\n"); + break; + } + + // restart the enumeration + // + restarted_enum = true; + retval = db_result_enum_to_send(result, RESULTS_PER_ENUM); + printf("feeder: restarting enumeration: %d\n", retval); + if (retval) { + no_wus = true; + break; + } + } + collision = false; + for (j=0; jnwu_results; j++) { + if (ssp->wu_results[j].present + && ssp->wu_results[j].result.id == result.id + ) { + ncollisions++; + collision = true; + break; + } + } + if (!collision) { + printf("feeder: adding result %d\n", result.id); + retval = db_workunit(result.workunitid, wu); + if (retval) continue; + ssp->wu_results[i].result = result; + ssp->wu_results[i].workunit = wu; + ssp->wu_results[i].present = true; + nadditions++; + } + } + } + if (nadditions == 0) { + sleep(1); + } else { + printf("feeder: added %d results to array\n", nadditions); + } + if (no_wus) { + printf("feeder: no results available\n"); + sleep(10); + } + if (ncollisions) { + printf("feeder: some results already in array - sleeping\n"); + sleep(60); + } + check_trigger(ssp); + } +} diff --git a/sched/sched_shmem.C b/sched/sched_shmem.C new file mode 100644 index 0000000000..011cb14295 --- /dev/null +++ b/sched/sched_shmem.C @@ -0,0 +1,108 @@ +#include +#include + +#include "db.h" + +#include "sched_shmem.h" + +void SCHED_SHMEM::init() { + memset(this, 0, sizeof(SCHED_SHMEM)); + ss_size = sizeof(SCHED_SHMEM); + platform_size = sizeof(PLATFORM); + app_size = sizeof(APP); + app_version_size = sizeof(APP_VERSION); + wu_result_size = sizeof(WU_RESULT); + max_platforms = MAX_PLATFORMS; + max_apps = MAX_APPS; + max_app_versions = MAX_APP_VERSIONS; + max_wu_results = MAX_WU_RESULTS; + nwu_results = MAX_WU_RESULTS; +} + +int SCHED_SHMEM::verify() { + if (ss_size != sizeof(SCHED_SHMEM)) return -1; + if (platform_size != sizeof(PLATFORM)) return -1; + if (app_size != sizeof(APP)) return -1; + if (app_version_size != sizeof(APP_VERSION)) return -1; + if (wu_result_size != sizeof(WU_RESULT)) return -1; + if (max_platforms != MAX_PLATFORMS) return -1; + if (max_apps != MAX_APPS) return -1; + if (max_app_versions != MAX_APP_VERSIONS) return -1; + if (max_wu_results != MAX_WU_RESULTS) return -1; + return 0; +} + +static void overflow(char* table) { + fprintf(stderr, + "The SCHED_SHMEM structure is too small for table %s.\n" + "Increase the size and restart feeder and fcgi.\n", + table + ); +} + +int SCHED_SHMEM::scan_tables() { + PLATFORM platform; + APP app; + APP_VERSION app_version; + int n; + + n = 0; + while (!db_platform_enum(platform)) { + platforms[n++] = platform; + if (n == MAX_PLATFORMS) overflow("platforms"); + } + nplatforms = n; + + + n = 0; + while (!db_app_enum(app)) { + apps[n++] = app; + if (n == MAX_APPS) overflow("apps"); + } + napps = n; + + n = 0; + while (!db_app_version_enum(app_version)) { + app_versions[n++] = app_version; + if (n == MAX_APP_VERSIONS) overflow("app_versions"); + } + napp_versions = n; + return 0; +} + +PLATFORM* SCHED_SHMEM::lookup_platform(char* name) { + int i; + + for (i=0; iappid == appid && avp->platformid == platformid && avp->version_num == version) { + return avp; + } + } + return 0; +} diff --git a/sched/sched_shmem.h b/sched/sched_shmem.h new file mode 100644 index 0000000000..f2a17656c1 --- /dev/null +++ b/sched/sched_shmem.h @@ -0,0 +1,46 @@ +#include "db.h" + +#define BOINC_KEY 0xdadacafe + +#define MAX_PLATFORMS 50 +#define MAX_APPS 10 +#define MAX_APP_VERSIONS 100 +#define MAX_WU_RESULTS 1000 + +// a workunit/result pair +struct WU_RESULT { + bool present; + WORKUNIT workunit; + RESULT result; +}; + +struct SCHED_SHMEM { + // the following fields let the scheduler make sure + // that the shared mem has the right format + int ss_size; // sizeof(SCHED_SHMEM) + int platform_size; // sizeof(PLATFORM) + int app_size; // sizeof(APP) + int app_version_size; // sizeof(APP_VERSION) + int wu_result_size; // sizeof(WU_RESULT) + int nplatforms; + int napps; + int napp_versions; + int nwu_results; + int max_platforms; + int max_apps; + int max_app_versions; + int max_wu_results; + PLATFORM platforms[MAX_PLATFORMS]; + APP apps[MAX_APPS]; + APP_VERSION app_versions[MAX_APP_VERSIONS]; + WU_RESULT wu_results[MAX_WU_RESULTS]; + + void init(); + int verify(); + int scan_tables(); + + APP* lookup_app(int); + APP_VERSION* lookup_app_version(int appid, int platform, int version); + PLATFORM* lookup_platform(char*); +}; +