diff options
author | H. Peter Anvin <hpa@zytor.com> | 2001-10-18 06:15:32 +0000 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2001-10-18 06:15:32 +0000 |
commit | 3adff3ab0f554dc8d08c563f61b93e7c1ca80805 (patch) | |
tree | 6021f89e30cd33b74700615161e889135134133b /testrecovery.c | |
parent | 26f21f20a407f7982a9710e95bdc7496a2609edd (diff) | |
download | lpsm-3adff3ab0f554dc8d08c563f61b93e7c1ca80805.tar.gz lpsm-3adff3ab0f554dc8d08c563f61b93e7c1ca80805.tar.xz lpsm-3adff3ab0f554dc8d08c563f61b93e7c1ca80805.zip |
Change the object store to use a file-backed mmap by default.
*** THIS MIGHT HAVE TO BE BACKED OUT IF THE LINUX KERNEL IS TOO DUMB ***
Add recovery test.
Diffstat (limited to 'testrecovery.c')
-rw-r--r-- | testrecovery.c | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/testrecovery.c b/testrecovery.c new file mode 100644 index 0000000..4c14b01 --- /dev/null +++ b/testrecovery.c @@ -0,0 +1,214 @@ +#ident "$Id$" +/* ----------------------------------------------------------------------- * + * + * Copyright 2001 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * testrecovery.c + * + * This test verifies that we can indeed recover from a failure gracefully. + * It is basically the same as the allocation test, except it keeps data- + * structures in persistent memory and periodically kills off the processes. + */ + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <unistd.h> +#include <limits.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/wait.h> +#include "objstore.h" + +#define COUNT 32768 +#define SLOTS 1024 +#define MAXLOG 26 + +void **areas; +int *sizes; + +void verify_no_overlap(int slot) +{ + char *start = areas[slot]; + char *end = start+sizes[slot]; + char *xs, *xe; + int i; + + for ( i = 0 ; i < SLOTS ; i++ ) { + if ( i != slot && areas[i] ) { + xs = areas[i]; + xe = xs + sizes[i]; + + if ( xs < end && xe > start ) { + printf("OVERLAP ALERT: [%p,%p) -> [%p,%p)\n", + start, end, xs, xe); + abort(); + } + } + } +} + +struct misc_info { + unsigned long occupied; + int count; +}; + +int main(int argc, char *argv[]) +{ + int i, slot, newsize; + double rnd; + void **root_ptr; + struct misc_info *misc_ptr; + void *nptr; + pid_t pid; + pid_t master_pid = getpid(); + + /* Do initial setup */ + + setlinebuf(stdout); + setlinebuf(stderr); + + unlink("arena.dat"); + unlink("arena.log"); + + if ( !(root_ptr = objstore_arena_init("arena.dat", "arena.log")) ) { + fprintf(stderr, "%s: objstore_arena_init() failed\n", argv[0]); + return 1; + } + + printf("Arena: initialized, %d root pointers at %p\n", + ROOT_DATA_POINTERS, root_ptr); + + root_ptr[0] = misc_ptr = objstore_malloc(sizeof(struct misc_info)); + root_ptr[1] = areas = objstore_malloc(sizeof(void *) * SLOTS); + root_ptr[2] = sizes = objstore_malloc(sizeof(int) * SLOTS); + + misc_ptr->count = misc_ptr->occupied = 0; + + memset(areas, 0, sizeof(areas)); + memset(sizes, 0, sizeof(sizes)); + + objstore_checkpoint(0.0, OBJSYNC_SYNC); + objstore_shutdown(); + + /* Become our own process group and ignore SIGTERM to make it easier to + "kill everything". Become our own session to keep shell job control + from interfering with stop signals. */ + + setpgrp(); + + while ( 1 ) { + int master_waits = rand() & 1; + + pid = fork(); + if ( pid < 0 ) { + perror("fork"); + return 1; + } else if ( pid > 0 ) { + int status; + + /* Give the child process a reasonable chance to finish log replay, + otherwise we'll never get through the test. On the other hand, + we want to check for failures during log replay too! */ + if ( master_waits ) { + waitpid(pid, &status, WUNTRACED); + if ( !WIFSTOPPED(status) ) { + printf("*** CHILD ERROR, exit code = 0x%x\n", status); + exit(1); + } + kill(pid, SIGCONT); + } + sleep(rand() & 63); + signal(SIGTERM, SIG_IGN); + kill(-master_pid, SIGTERM); + signal(SIGTERM, SIG_DFL); + waitpid(pid, &status, 0); + + if ( WIFEXITED(status) ) + break; /* Child exited, not killed, consider us done */ + } else { + pid = getpid(); + + printf("*** Process starting: %d, master_waits = %d\n", + pid, master_waits); + + root_ptr = objstore_arena_init("arena.dat", "arena.log"); + + misc_ptr = root_ptr[0]; + areas = root_ptr[1]; + sizes = root_ptr[2]; + + printf("*** Recovering at count %d, occupied = %ld,\n" + "*** areas = %p, sizes = %p\n", + misc_ptr->count, misc_ptr->occupied, areas, sizes); + + /* In case the master process decided to be kind and wait for replay */ + if ( master_waits ) + kill(pid, SIGTSTP); /* The master will wait for this and SIGCONT */ + + for ( i = misc_ptr->count+1 ; i <= COUNT ; i++ ) { + misc_ptr->count = i; + slot = rand() % SLOTS; + + printf("Count: %d Slot: %d\n", i, slot); + + if ( areas[slot] ) { + if ( rand() % 1 ) { + objstore_free(areas[slot]); + printf("Free: %d (0x%08x) bytes at %p\n", + sizes[slot], sizes[slot], areas[slot]); + areas[slot] = NULL; + misc_ptr->occupied -= sizes[slot]; + } else { + rnd = (double)rand()/RAND_MAX; + newsize = (int)pow(2.0, MAXLOG*pow(rnd,3.0)); + nptr = objstore_realloc(areas[slot], newsize); + if ( nptr ) { + printf("Realloc: %d bytes at %p -> %d bytes at %p\n", + sizes[slot], areas[slot], newsize, nptr); + misc_ptr->occupied += newsize; + misc_ptr->occupied -= sizes[slot]; + sizes[slot] = newsize; + areas[slot] = nptr; + verify_no_overlap(slot); + } else { + printf("Realloc: %d bytes at %p -> %d bytes FAILED\n", + sizes[slot], areas[slot], newsize); + } + } + } else { + rnd = (double)rand()/RAND_MAX; + sizes[slot] = (int)pow(2.0, MAXLOG*pow(rnd,5.0)); + areas[slot] = objstore_malloc(sizes[slot]); + printf("Alloc: %d (0x%08x) bytes at %p\n", + sizes[slot], sizes[slot], areas[slot]); + misc_ptr->occupied += sizes[slot]; + verify_no_overlap(slot); + } + + if ( (i & 255) == 0 ) { + printf("Arena: checkpointing, count = %d\n", i); + objstore_checkpoint(0.1, OBJSYNC_SKIP); + } + printf("Arena: %ld bytes officially occupied\n", misc_ptr->occupied); + } + /* If the loop finishes, exit... */ + fprintf(stderr, "ready...\n"); + objstore_checkpoint(0.0, OBJSYNC_SYNC); /* Synchronous checkpoint */ + exit(0); + } + } + + return 0; +} |