aboutsummaryrefslogtreecommitdiffstats
path: root/arena.c
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2001-10-25 18:34:11 +0000
committerH. Peter Anvin <hpa@zytor.com>2001-10-25 18:34:11 +0000
commit9f4b121beb7c16b26f25a694ceba998d3d1a23c8 (patch)
tree1bdec3198144dc7dd2c846ba84ca27edab4bde64 /arena.c
parent731beed733a3fa023eeeb63477cfbc80e0edc43a (diff)
downloadlpsm-9f4b121beb7c16b26f25a694ceba998d3d1a23c8.tar.gz
lpsm-9f4b121beb7c16b26f25a694ceba998d3d1a23c8.tar.xz
lpsm-9f4b121beb7c16b26f25a694ceba998d3d1a23c8.zip
- Clean up documentation.lpsm-0.1.8
- Add lpsm_recover(). - Add zalloc test. - Be better about returning useful error information in errno.
Diffstat (limited to 'arena.c')
-rw-r--r--arena.c226
1 files changed, 147 insertions, 79 deletions
diff --git a/arena.c b/arena.c
index ff8d2bf..6c5a1b0 100644
--- a/arena.c
+++ b/arena.c
@@ -174,27 +174,34 @@ static void lpsm_sigsegv(int signal, siginfo_t *siginfo, void *ptr)
* as well as during-execution garbage collect.
* THIS ROUTINE SHOULD BE INVOKED WITH LOCK HELD ON THE LOG FILE.
*/
-static int lpsm_log_writeback(void)
+static int lpsm_log_writeback(struct lpsm_arena *pm)
{
struct lpsm_logrecord record;
off_t position, last_commit;
struct flock lockmain;
last_commit = 0; /* Last COMMIT record found */
- position = lseek(PM->log_fd, 0, SEEK_SET);
+ position = lseek(pm->log_fd, 0, SEEK_SET);
- while ( lpsm_read(PM->log_fd, &record, sizeof(record)) == sizeof(record) ) {
+ while ( lpsm_read(pm->log_fd, &record, sizeof(record)) == sizeof(record) ) {
if ( record.magic != LOGRECORD_MAGIC )
break; /* Bad magic, assume rest of log corrupt */
- if ( record.record_type == osrec_commit ) {
+
+ switch ( record.record_type ) {
+ case osrec_commit:
/* NOTE: last_commit points to the final byte to examine, thus
at the *end* of the final commit record. */
position += sizeof(record);
last_commit = position; /* Found a commit record */
- } else if ( record.record_type == osrec_page ) {
+ break;
+
+ case osrec_page:
/* Advance past current page cluster */
- position = lseek(PM->log_fd, record.size, SEEK_CUR);
- } else {
+ position = lseek(pm->log_fd, record.size, SEEK_CUR);
+ break;
+
+ default:
+ errno = EINVAL;
return -1; /* Unknown record - unsafe to process */
}
}
@@ -202,55 +209,64 @@ static int lpsm_log_writeback(void)
/* Now we know where the last commit was. Now we can process
everything up to that point. */
- position = lseek(PM->log_fd, 0, SEEK_SET);
+ position = lseek(pm->log_fd, 0, SEEK_SET);
- while ( lpsm_read(PM->log_fd, &record, sizeof(record))
+ while ( lpsm_read(pm->log_fd, &record, sizeof(record))
== sizeof(record) && position < last_commit ) {
if ( record.magic != LOGRECORD_MAGIC )
break; /* Bad magic, assume rest of log corrupt */
- if ( record.record_type == osrec_commit ) {
+
+ switch ( record.record_type ) {
+ case osrec_commit:
/* Found a commit record, do nothing */
position += sizeof(record);
- } else if ( record.record_type == osrec_page ) {
- /* Write back data to file */
- char *data;
-
- position += sizeof(record);
-
- lockmain.l_type = F_WRLCK;
- lockmain.l_whence = SEEK_SET;
- lockmain.l_start = record.offset;
- lockmain.l_len = record.size;
- while ( fcntl(PM->main_fd, F_SETLKW, &lockmain) == -1 && errno == EINTR );
- data = mmap(NULL, record.size, PROT_WRITE, MAP_SHARED,
- PM->main_fd, record.offset);
- if ( data == MAP_FAILED )
- return -1;
- if ( lpsm_read(PM->log_fd, data, record.size) != record.size )
- return -1; /* Badness */
- if ( munmap(data, record.size) )
- return -1;
-
- lockmain.l_type = F_UNLCK;
- while ( fcntl(PM->main_fd, F_SETLKW, &lockmain) == -1 && errno == EINTR );
- position += record.size;
- } else {
+ break;
+
+ case osrec_page:
+ {
+ /* Write back data to file */
+ char *data;
+
+ position += sizeof(record);
+
+ lockmain.l_type = F_WRLCK;
+ lockmain.l_whence = SEEK_SET;
+ lockmain.l_start = record.offset;
+ lockmain.l_len = record.size;
+ while ( fcntl(pm->main_fd, F_SETLKW, &lockmain) == -1 && errno == EINTR );
+ data = mmap(NULL, record.size, PROT_WRITE, MAP_SHARED,
+ pm->main_fd, record.offset);
+ if ( data == MAP_FAILED )
+ return -1;
+ if ( lpsm_read(pm->log_fd, data, record.size) != record.size )
+ return -1; /* Badness */
+ if ( munmap(data, record.size) )
+ return -1;
+
+ lockmain.l_type = F_UNLCK;
+ while ( fcntl(pm->main_fd, F_SETLKW, &lockmain) == -1 && errno == EINTR );
+ position += record.size;
+ }
+ break;
+
+ default:
+ errno = EINVAL;
return -1; /* Unknown record - unsafe to process */
}
}
/* Log successfully recovered. Truncate. */
- fsync(PM->main_fd);
- ftruncate(PM->log_fd, 0);
+ fsync(pm->main_fd);
+ ftruncate(pm->log_fd, 0);
/* Write initial commit record, for sequence number recovery */
record.magic = LOGRECORD_MAGIC;
record.record_type = osrec_commit;
- record.size = PM->fork_seq;
+ record.size = pm->fork_seq;
record.offset = 0x54494d43; /* For debugging */
- if ( lpsm_write(PM->log_fd, &record, sizeof(record)) < sizeof(record) )
+ if ( lpsm_write(pm->log_fd, &record, sizeof(record)) < sizeof(record) )
return -1;
- fsync(PM->log_fd); /* Indicate log recovery complete */
+ fsync(pm->log_fd); /* Indicate log recovery complete */
return 0;
}
@@ -258,31 +274,81 @@ static int lpsm_log_writeback(void)
/*
* Routine to do log recovery
*/
-static int lpsm_recover_log(void)
+static int lpsm_recover_log(struct lpsm_arena *pm)
{
struct flock lock;
int rv = 0;
+ int rerrno;
/* First, lock the log file */
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
- while ( fcntl(PM->log_fd, F_SETLKW, &lock) == -1 && errno == EINTR );
+ while ( fcntl(pm->log_fd, F_SETLKW, &lock) == -1 && errno == EINTR );
/* Do log recovery, and write initial commit record. */
- rv = lpsm_log_writeback();
+ rv = lpsm_log_writeback(pm);
+ rerrno = errno;
/* Increase the sequence number, since we just wrote a commit. */
- PM->fork_seq++;
+ pm->fork_seq++;
/* Unlock file and run. */
lock.l_type = F_UNLCK;
- while ( fcntl(PM->log_fd, F_SETLKW, &lock) == -1 && errno == EINTR );
+ while ( fcntl(pm->log_fd, F_SETLKW, &lock) == -1 && errno == EINTR );
+ errno = rerrno;
return rv;
}
+static int
+lpsm_open_and_recover(struct lpsm_arena *pm, const char *main_file,
+ const char *log_file)
+{
+ int myerrno;
+
+ pm->fork_seq = 0; /* Initialize sequence counter */
+ pm->main_fd = pm->log_fd = 0;
+
+ pm->main_fd = open(main_file, O_RDWR|O_CREAT, 0666);
+ if ( pm->main_fd < 0 )
+ goto errx1;
+
+ pm->pagesize = getpagesize();
+ if ( pm->pagesize & (pm->pagesize - 1) )
+ goto errx2; /* WTF -- pagesize not a power of 2? */
+
+ /* Compute log2(pm->pagesize) */
+ pm->pageshift = 0;
+ while ( (1 << pm->pageshift) < pm->pagesize )
+ pm->pageshift++;
+
+ /*
+ * Open log file
+ */
+ pm->log_fd = open(log_file, O_RDWR|O_APPEND|O_CREAT, 0666);
+ if ( pm->log_fd < 0 )
+ goto errx2;
+
+ /* Now, do log recovery if needed */
+ if ( lpsm_recover_log(pm) )
+ goto errx3;
+
+ return 0;
+
+ errx3:
+ myerrno = errno;
+ close(pm->log_fd);
+ errno = myerrno;
+ errx2:
+ myerrno = errno;
+ close(pm->main_fd);
+ errno = myerrno;
+ errx1:
+ return -1;
+}
+
/*
* Opens the object store. This includes log
* playback (crash recovery) if the log file exists
@@ -291,6 +357,7 @@ static int lpsm_recover_log(void)
void *lpsm_arena_init(const char *main_file, const char *log_file,
size_t *arena_len, void *arena_ptr)
{
+ int myerrno;
struct sigaction sigact;
struct flock lock;
off_t file_len, len = arena_len ? *arena_len : 0;
@@ -302,32 +369,9 @@ void *lpsm_arena_init(const char *main_file, const char *log_file,
if ( !PM )
goto errx0;
- PM->fork_seq = 0; /* Initialize sequence counter */
-
- PM->main_fd = open(main_file, O_RDWR|O_CREAT, 0666);
- if ( PM->main_fd < 0 )
+ if ( lpsm_open_and_recover(PM, main_file, log_file) )
goto errx1;
- PM->pagesize = getpagesize();
- if ( PM->pagesize & (PM->pagesize - 1) )
- goto errx2; /* WTF -- pagesize not a power of 2? */
-
- /* Compute log2(PM->pagesize) */
- PM->pageshift = 0;
- while ( (1 << PM->pageshift) < PM->pagesize )
- PM->pageshift++;
-
- /*
- * Open log file
- */
- PM->log_fd = open(log_file, O_RDWR|O_APPEND|O_CREAT, 0666);
- if ( PM->log_fd < 0 )
- goto errx3;
-
- /* Now, do log recovery if needed */
- if ( lpsm_recover_log() )
- goto errx3;
-
/* Allocate arena memory space */
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
@@ -373,21 +417,44 @@ void *lpsm_arena_init(const char *main_file, const char *log_file,
return PM->arena;
errx5:
+ myerrno = errno;
munmap(PM->pageinfo, len >> PM->pageshift);
+ errno = myerrno;
errx4:
+ myerrno = errno;
munmap(arena_ptr, len);
+ errno = myerrno;
errx3:
+ myerrno = errno;
if ( PM->log_fd >= 0 ) close(PM->log_fd);
- errx2:
close(PM->main_fd);
+ errno = myerrno;
errx1:
+ myerrno = errno;
free(PM);
+ errno = myerrno;
errx0:
return NULL;
}
/*
+ * Do an offline log recovery (exported function.)
+ */
+int lpsm_recover(const char *mainfile, const char *logfile)
+{
+ struct lpsm_arena pm;
+ int rv;
+
+ rv = lpsm_open_and_recover(&pm, mainfile, logfile);
+ if ( !rv ) {
+ close(pm.log_fd);
+ close(pm.main_fd);
+ }
+ return rv;
+}
+
+/*
* Object store checkpoint. Writes entries to the log file.
* The "gc_factor" is the factor of maximum log size file relative
* to the arena size. For example, if gc_factor == 0.5 then if the
@@ -551,7 +618,7 @@ pid_t lpsm_checkpoint(double gc_factor, enum psmsync wait)
them out of the shadow array. The biggest problem with that
is that it probably can't be done in the background, unlike
this method. Leave this as-is for now. */
- if ( lpsm_log_writeback() ) {
+ if ( lpsm_log_writeback(PM) ) {
kill(getppid(), SIGABRT);
_exit(99);
}
@@ -580,7 +647,7 @@ int lpsm_extend(size_t new_size)
int ft;
size_t add_size, old_size;
size_t add_pages, old_pages, new_pages, file_pages;
- struct rlimit fsizelimit;
+ int realerrno;
old_size = PM->arena_len;
@@ -590,12 +657,6 @@ int lpsm_extend(size_t new_size)
new_size = (new_size + PM->pagesize - 1) & ~(PM->pagesize - 1);
add_size = new_size - old_size;
- /* Make sure we won't run afoul of a set resource limit. */
- if ( getrlimit(RLIMIT_FSIZE, &fsizelimit) == 0 &&
- fsizelimit.rlim_cur != RLIM_INFINITY &&
- fsizelimit.rlim_cur < new_size )
- return -1; /* Would exceed the file limit. */
-
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
@@ -609,15 +670,19 @@ int lpsm_extend(size_t new_size)
else
ft = 0;
- if ( ft )
+ if ( ft ) {
+ realerrno = errno;
goto reset_size; /* Failure */
+ }
newp = mmap((char*)PM->arena + old_size,
add_size, PROT_READ,
MAP_PRIVATE|MAP_FIXED, PM->main_fd, old_size);
- if ( newp == MAP_FAILED )
+ if ( newp == MAP_FAILED ) {
+ realerrno = errno;
goto reset_size; /* Failure */
+ }
/* Since we specified MAP_FIXED, this should be guaranteed */
assert( newp == (char*)PM->arena + old_size );
@@ -631,6 +696,7 @@ int lpsm_extend(size_t new_size)
infop = realloc(PM->pageinfo, new_pages);
if ( !infop ) {
+ realerrno = errno;
munmap(newp, add_size);
goto reset_size;
}
@@ -654,6 +720,8 @@ int lpsm_extend(size_t new_size)
ftruncate(PM->main_fd, file_size);
/* Drop lock */
while ( fcntl(PM->main_fd, F_SETLKW, &lock) == -1 && errno == EINTR );
+ /* Set errno to the real error */
+ errno = realerrno;
return -1;
}