aboutsummaryrefslogtreecommitdiffstats
path: root/arena.c
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2001-10-16 03:38:27 +0000
committerH. Peter Anvin <hpa@zytor.com>2001-10-16 03:38:27 +0000
commit9466634b21f2e936b4d6f5ddca0df095e33add89 (patch)
tree9fffceece60d95dca1c9c833d480ea5a172ef4cc /arena.c
parentbafa642948c55d4848fe1c66206eec267ec8119f (diff)
downloadlpsm-9466634b21f2e936b4d6f5ddca0df095e33add89.tar.gz
lpsm-9466634b21f2e936b4d6f5ddca0df095e33add89.tar.xz
lpsm-9466634b21f2e936b4d6f5ddca0df095e33add89.zip
Beginnings of a synchronicity model...to-tytso-20011015c
Diffstat (limited to 'arena.c')
-rw-r--r--arena.c66
1 files changed, 60 insertions, 6 deletions
diff --git a/arena.c b/arena.c
index c8f0fa5..c95c1ce 100644
--- a/arena.c
+++ b/arena.c
@@ -34,6 +34,7 @@
#include <sched.h>
#include <sys/time.h>
#include <sys/resource.h>
+#include <sys/wait.h>
#include "objstore.h"
#include "internals.h"
@@ -419,20 +420,59 @@ void *objstore_init(const char *main_file, const char *log_file, size_t *arena_l
* checkpoints will have to wait!
*
* Set gc_factor to 0.0 to force a gc, and to HUGE_VAL to inhibit gc.
+ *
+ * The "wait" argument determines the level of synchronicity required.
+ *
+ * Returns 0 on synchronous completion, 1 if the checkpoint was skipped,
+ * (pid_t)-1 on error, or the pid_t of the asynchronous process. Note:
+ * if an asynchronous process is launched, and the next call uses
+ * OBJSYNC_NONE, then it is up to the parent process to wait for the
+ * launched processes; this process only remembers the last process launched.
+ * FIXME: perhaps we should double-fork these processes?
*/
-int objstore_checkpoint(double gc_factor)
+pid_t objstore_checkpoint(double gc_factor, enum objsync_enum wait)
{
+ static pid_t last_sync = 0;
struct ObjStore *os = objstore_os_struct;
- int f;
+ pid_t f, w;
char *pi, *epi;
void *page;
pi = os->pageinfo;
epi = os->pageinfo + (os->arena_len >> os->pageshift);
+ if ( last_sync ) {
+ int status;
+ switch (wait) {
+ case OBJSYNC_NONE:
+ break;
+ case OBJSYNC_SKIP:
+ w = waitpid(last_sync, &status, WNOHANG);
+ if ( w == 0 )
+ return 1; /* Skip */
+ if ( w == (pid_t)-1 ) {
+ /* Note: under strace, waitpid() will return -1 instead of 0 */
+ return (pid_t)-1;
+ } else if ( WIFSIGNALED(status) || (WIFEXITED(status) && WEXITSTATUS(status)) ) {
+ return (pid_t)-1; /* Badness */
+ }
+ break;
+ case OBJSYNC_WAIT:
+ case OBJSYNC_SYNC:
+ w = waitpid(last_sync, &status, 0);
+ if ( w == (pid_t)-1 ) {
+ if ( errno != ECHILD )
+ return (pid_t)-1; /* Badness */
+ } else if ( WIFSIGNALED(status) || (WIFEXITED(status) && WEXITSTATUS(status)) ) {
+ return (pid_t)-1; /* Badness */
+ }
+ break;
+ }
+ }
+
f = fork();
- if ( f < 0 )
- return 1; /* Checkpoint failed! */
+ if ( f == (pid_t)-1 )
+ return (pid_t)-1; /* Checkpoint failed! */
else if ( f > 0 ) {
/* Parent process -- just mark all dirty pages clean */
@@ -466,7 +506,19 @@ int objstore_checkpoint(double gc_factor)
}
os->dirty_count = 0; /* No pages dirty */
os->fork_seq++; /* Increase next sequence number */
- return 0;
+
+ if ( wait == OBJSYNC_SYNC ) {
+ int status;
+ waitpid(f, &status, 0);
+ last_sync = 0;
+ if ( WIFSIGNALED(status) || (WIFEXITED(status) && WEXITSTATUS(status)) )
+ return (pid_t)-1; /* Something very bad happened... */
+ else
+ return 0;
+ } else {
+ last_sync = f;
+ return f;
+ }
} else {
/* Child process -- do the actual work of writing back dirty pages */
@@ -487,7 +539,9 @@ int objstore_checkpoint(double gc_factor)
/* Make sure we were indeed next in turn */
lseek(os->log_fd, -(off_t)sizeof(last_rec), SEEK_END);
- if ( objstore_read(os->log_fd, &last_rec, sizeof(last_rec)) < sizeof(last_rec)) {
+ if ( objstore_read(os->log_fd, &last_rec, sizeof(last_rec)) < sizeof(last_rec) ||
+ last_rec.magic != LOGRECORD_MAGIC ) {
+ /* Something bad happened... */
kill(getppid(), SIGABRT); /* Kill main process */
_exit(99);
}