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*);
+};
+