diff options
author | H. Peter Anvin <hpa@zytor.com> | 2001-10-20 02:12:22 +0000 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2001-10-20 02:12:22 +0000 |
commit | 50cedb0ff19233273ef33cb5b5e8725025a35024 (patch) | |
tree | 25b21afff2ef45d706df0b05f18473516b8911f5 /arena.c | |
parent | f3d637296f1f839d4a95a849a7dbfbb600f563f1 (diff) | |
download | lpsm-50cedb0ff19233273ef33cb5b5e8725025a35024.tar.gz lpsm-50cedb0ff19233273ef33cb5b5e8725025a35024.tar.xz lpsm-50cedb0ff19233273ef33cb5b5e8725025a35024.zip |
Split apart into modules. Create lpsm_zalloc()/lpsm_calloc().
Diffstat (limited to 'arena.c')
-rw-r--r-- | arena.c | 242 |
1 files changed, 114 insertions, 128 deletions
@@ -40,18 +40,12 @@ #include "lpsm.h" #include "internals.h" -/* This might end up being a bitmask eventually */ -enum page_status { - page_clean = 0, - page_dirty = 1, -}; - /* - * This is the data structure for the object store. Note that only - * one active object store is supported, due to the need to trap - * SIGSEGV. + * This is the data structure for the persistent memory arena. Note + * that only one arena is supported, due to the need to trap SIGSEGV + * and address space allocation issues. */ -struct ObjStore *lpsm_os_struct; +struct lpsm_arena *lpsm_memory_info = NULL; /* Wrappers for read() and write() which retries if incomplete */ static ssize_t lpsm_read(int fd, void *buf, size_t count) @@ -107,7 +101,6 @@ static ssize_t lpsm_write(int fd, void *buf, size_t count) */ static void lpsm_sigsegv(int signal, siginfo_t *siginfo, void *ptr) { - struct ObjStore *os = lpsm_os_struct; void *page; uintptr_t npage, offset; char *pageinfo; @@ -131,13 +124,13 @@ static void lpsm_sigsegv(int signal, siginfo_t *siginfo, void *ptr) # endif /* __i386__ */ #endif /* __linux__ */ - page = (void *)((uintptr_t)siginfo->si_addr & ~(os->pagesize-1)); - offset = (uintptr_t)page - (uintptr_t)os->arena; - npage = (offset >> os->pageshift); - pageinfo = os->pageinfo + npage; + page = (void *)((uintptr_t)siginfo->si_addr & ~(PM->pagesize-1)); + offset = (uintptr_t)page - (uintptr_t)PM->arena; + npage = (offset >> PM->pageshift); + pageinfo = PM->pageinfo + npage; if ( signal != SIGSEGV || siginfo->si_code != SEGV_ACCERR || - offset >= os->arena_len ) { + offset >= PM->arena_len ) { struct sigaction dfl; dfl.sa_handler = SIG_DFL; @@ -157,12 +150,12 @@ static void lpsm_sigsegv(int signal, siginfo_t *siginfo, void *ptr) return; /* Re-take fault */ } - mprotect(page, os->pagesize, PROT_READ|PROT_WRITE); + mprotect(page, PM->pagesize, PROT_READ|PROT_WRITE); switch ( (enum page_status) *pageinfo ) { case page_clean: *pageinfo = page_dirty; /* Page now dirty */ - os->dirty_count++; /* For accounting purposes */ + PM->dirty_count++; /* For accounting purposes */ /* Leave page r/w */ break; @@ -180,15 +173,14 @@ static void lpsm_sigsegv(int signal, siginfo_t *siginfo, void *ptr) */ static int lpsm_log_writeback(void) { - struct ObjStore *os = lpsm_os_struct; - struct ObjStore_LogRecord record; + struct lpsm_logrecord record; off_t position, last_commit; struct flock lockmain; last_commit = 0; /* Last COMMIT record found */ - position = lseek(os->log_fd, 0, SEEK_SET); + position = lseek(PM->log_fd, 0, SEEK_SET); - while ( lpsm_read(os->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 ) { @@ -198,7 +190,7 @@ static int lpsm_log_writeback(void) last_commit = position; /* Found a commit record */ } else if ( record.record_type == osrec_page ) { /* Advance past current page cluster */ - position = lseek(os->log_fd, record.size, SEEK_CUR); + position = lseek(PM->log_fd, record.size, SEEK_CUR); } else { return -1; /* Unknown record - unsafe to process */ } @@ -207,9 +199,9 @@ 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(os->log_fd, 0, SEEK_SET); + position = lseek(PM->log_fd, 0, SEEK_SET); - while ( lpsm_read(os->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 */ @@ -226,18 +218,18 @@ static int lpsm_log_writeback(void) lockmain.l_whence = SEEK_SET; lockmain.l_start = record.offset; lockmain.l_len = record.size; - while ( fcntl(os->main_fd, F_SETLKW, &lockmain) == -1 && errno == EINTR ); + while ( fcntl(PM->main_fd, F_SETLKW, &lockmain) == -1 && errno == EINTR ); data = mmap(NULL, record.size, PROT_WRITE, MAP_SHARED, - os->main_fd, record.offset); + PM->main_fd, record.offset); if ( data == MAP_FAILED ) return -1; - if ( lpsm_read(os->log_fd, data, record.size) != record.size ) + 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(os->main_fd, F_SETLKW, &lockmain) == -1 && errno == EINTR ); + while ( fcntl(PM->main_fd, F_SETLKW, &lockmain) == -1 && errno == EINTR ); position += record.size; } else { return -1; /* Unknown record - unsafe to process */ @@ -245,17 +237,17 @@ static int lpsm_log_writeback(void) } /* Log successfully recovered. Truncate. */ - fsync(os->main_fd); - ftruncate(os->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 = os->fork_seq; + record.size = PM->fork_seq; record.offset = 0x54494d43; /* For debugging */ - if ( lpsm_write(os->log_fd, &record, sizeof(record)) < sizeof(record) ) + if ( lpsm_write(PM->log_fd, &record, sizeof(record)) < sizeof(record) ) return -1; - fsync(os->log_fd); /* Indicate log recovery complete */ + fsync(PM->log_fd); /* Indicate log recovery complete */ return 0; } @@ -265,7 +257,6 @@ static int lpsm_log_writeback(void) */ static int lpsm_recover_log(void) { - struct ObjStore *os = lpsm_os_struct; struct flock lock; int rv = 0; @@ -274,17 +265,17 @@ static int lpsm_recover_log(void) lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; - while ( fcntl(os->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(); /* Increase the sequence number, since we just wrote a commit. */ - os->fork_seq++; + PM->fork_seq++; /* Unlock file and run. */ lock.l_type = F_UNLCK; - while ( fcntl(os->log_fd, F_SETLKW, &lock) == -1 && errno == EINTR ); + while ( fcntl(PM->log_fd, F_SETLKW, &lock) == -1 && errno == EINTR ); return rv; } @@ -296,7 +287,6 @@ static int lpsm_recover_log(void) */ void *lpsm_arena_init(const char *main_file, const char *log_file, size_t *arena_len) { - struct ObjStore *os; void *arena_ptr; struct sigaction sigact; struct flock lock; @@ -305,30 +295,30 @@ void *lpsm_arena_init(const char *main_file, const char *log_file, size_t *arena arena_ptr = ARENA_ADDRESS; - lpsm_os_struct = os = malloc(sizeof(struct ObjStore)); - if ( !os ) + PM = malloc(sizeof(struct lpsm_arena)); + if ( !PM ) goto errx0; - os->fork_seq = 0; /* Initialize sequence counter */ + PM->fork_seq = 0; /* Initialize sequence counter */ - os->main_fd = open(main_file, O_RDWR|O_CREAT, 0666); - if ( os->main_fd < 0 ) + PM->main_fd = open(main_file, O_RDWR|O_CREAT, 0666); + if ( PM->main_fd < 0 ) goto errx1; - os->pagesize = getpagesize(); - if ( os->pagesize & (os->pagesize - 1) ) + PM->pagesize = getpagesize(); + if ( PM->pagesize & (PM->pagesize - 1) ) goto errx2; /* WTF -- pagesize not a power of 2? */ - /* Compute log2(os->pagesize) */ - os->pageshift = 0; - while ( (1 << os->pageshift) < os->pagesize ) - os->pageshift++; + /* Compute log2(PM->pagesize) */ + PM->pageshift = 0; + while ( (1 << PM->pageshift) < PM->pagesize ) + PM->pageshift++; /* * Open log file */ - os->log_fd = open(log_file, O_RDWR|O_APPEND|O_CREAT, 0666); - if ( os->log_fd < 0 ) + 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 */ @@ -340,55 +330,55 @@ void *lpsm_arena_init(const char *main_file, const char *log_file, size_t *arena lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; - while ( fcntl(os->main_fd, F_SETLKW, &lock) == -1 && errno == EINTR ); - file_len = lseek(os->main_fd, 0, SEEK_END); + while ( fcntl(PM->main_fd, F_SETLKW, &lock) == -1 && errno == EINTR ); + file_len = lseek(PM->main_fd, 0, SEEK_END); if ( len < file_len ) { len = file_len; } - len = (len + os->pagesize - 1) & ~(os->pagesize - 1); + len = (len + PM->pagesize - 1) & ~(PM->pagesize - 1); if ( len > file_len ) { - ftruncate(os->main_fd, len); /* Extend file */ + ftruncate(PM->main_fd, len); /* Extend file */ } lock.l_type = F_UNLCK; - while ( fcntl(os->main_fd, F_SETLKW, &lock) == -1 && errno == EINTR ); + while ( fcntl(PM->main_fd, F_SETLKW, &lock) == -1 && errno == EINTR ); - os->arena = mmap(arena_ptr, len, PROT_READ, MAP_PRIVATE|MAP_FIXED, os->main_fd, 0); - if ( os->arena == MAP_FAILED ) + PM->arena = mmap(arena_ptr, len, PROT_READ, MAP_PRIVATE|MAP_FIXED, PM->main_fd, 0); + if ( PM->arena == MAP_FAILED ) goto errx3; - os->arena_len = len; + PM->arena_len = len; if ( *arena_len ) *arena_len = len; - os->pageinfo = malloc(len >> os->pageshift); - if ( !os->pageinfo ) + PM->pageinfo = malloc(len >> PM->pageshift); + if ( !PM->pageinfo ) goto errx4; - file_len = (file_len + os->pagesize - 1) & ~(os->pagesize-1); - file_pages = file_len >> os->pageshift; - len_pages = len >> os->pageshift; + file_len = (file_len + PM->pagesize - 1) & ~(PM->pagesize-1); + file_pages = file_len >> PM->pageshift; + len_pages = len >> PM->pageshift; /* All pages clean at this time */ - memset(os->pageinfo, page_clean, len_pages); + memset(PM->pageinfo, page_clean, len_pages); sigact.sa_sigaction = lpsm_sigsegv; sigemptyset(&sigact.sa_mask); sigact.sa_flags = SA_RESTART|SA_SIGINFO; - if ( sigaction(SIGSEGV, &sigact, &os->oldact) ) + if ( sigaction(SIGSEGV, &sigact, &PM->oldact) ) goto errx5; - return os->arena; + return PM->arena; errx5: - munmap(os->pageinfo, len >> os->pageshift); + munmap(PM->pageinfo, len >> PM->pageshift); errx4: munmap(arena_ptr, len); errx3: - if ( os->log_fd >= 0 ) close(os->log_fd); + if ( PM->log_fd >= 0 ) close(PM->log_fd); errx2: - close(os->main_fd); + close(PM->main_fd); errx1: - free(os); + free(PM); errx0: return NULL; @@ -416,13 +406,12 @@ void *lpsm_arena_init(const char *main_file, const char *log_file, size_t *arena pid_t lpsm_checkpoint(double gc_factor, enum psmsync wait) { static pid_t last_sync = 0; - struct ObjStore *os = lpsm_os_struct; pid_t f, w; char *pi, *epi; void *page; - pi = os->pageinfo; - epi = os->pageinfo + (os->arena_len >> os->pageshift); + pi = PM->pageinfo; + epi = PM->pageinfo + (PM->arena_len >> PM->pageshift); if ( last_sync ) { int status; @@ -461,11 +450,11 @@ pid_t lpsm_checkpoint(double gc_factor, enum psmsync wait) /* FIX: We probably want to do something more clever than memset() here, and perhaps keep around the old dirty array for a while. */ - mprotect(os->arena, os->arena_len, PROT_READ); - memset(os->pageinfo, page_clean, os->arena_len >> os->pageshift); + mprotect(PM->arena, PM->arena_len, PROT_READ); + memset(PM->pageinfo, page_clean, PM->arena_len >> PM->pageshift); - os->dirty_count = 0; /* No pages dirty */ - os->fork_seq++; /* Increase next sequence number */ + PM->dirty_count = 0; /* No pages dirty */ + PM->fork_seq++; /* Increase next sequence number */ if ( wait == PSMSYNC_SYNC ) { int status; @@ -482,7 +471,7 @@ pid_t lpsm_checkpoint(double gc_factor, enum psmsync wait) } else { /* Child process -- do the actual work of writing back dirty pages */ - struct ObjStore_LogRecord record, last_rec; + struct lpsm_logrecord record, last_rec; struct flock lock; off_t logsize; @@ -495,43 +484,43 @@ pid_t lpsm_checkpoint(double gc_factor, enum psmsync wait) for (;;) { /* First, lock the entire log file */ lock.l_type = F_WRLCK; - while ( fcntl(os->log_fd, F_SETLKW, &lock) == -1 && errno == EINTR ); + while ( fcntl(PM->log_fd, F_SETLKW, &lock) == -1 && errno == EINTR ); /* Make sure we were indeed next in turn */ - lseek(os->log_fd, -(off_t)sizeof(last_rec), SEEK_END); - if ( lpsm_read(os->log_fd, &last_rec, sizeof(last_rec)) < sizeof(last_rec) || + lseek(PM->log_fd, -(off_t)sizeof(last_rec), SEEK_END); + if ( lpsm_read(PM->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); } - if ( last_rec.size+1 == os->fork_seq ) + if ( last_rec.size+1 == PM->fork_seq ) break; /* It's for us... */ /* Someone else is ahead of us in line. Yield to them. */ lock.l_type = F_UNLCK; - while ( fcntl(os->log_fd, F_SETLKW, &lock) == -1 && errno == EINTR ); + while ( fcntl(PM->log_fd, F_SETLKW, &lock) == -1 && errno == EINTR ); sched_yield(); /* Snore... */ } /* Write dirty pages to log file */ - for ( pi = os->pageinfo ; pi < epi ; pi++ ) { + for ( pi = PM->pageinfo ; pi < epi ; pi++ ) { if ( *pi == page_dirty ) { - page = (char *)os->arena + - ((uintptr_t)(pi - os->pageinfo) << os->pageshift); - record.offset = (char *)page - (char *)os->arena; + page = (char *)PM->arena + + ((uintptr_t)(pi - PM->pageinfo) << PM->pageshift); + record.offset = (char *)page - (char *)PM->arena; /* Aggregate contiguous pages into a single record */ - record.size = os->pagesize; + record.size = PM->pagesize; while ( pi+1 < epi && pi[1] == page_dirty ) { pi++; - record.size += os->pagesize; + record.size += PM->pagesize; } - if ( lpsm_write(os->log_fd, &record, sizeof(record)) + if ( lpsm_write(PM->log_fd, &record, sizeof(record)) < sizeof(record) || - lpsm_write(os->log_fd, page, record.size) < record.size ) { + lpsm_write(PM->log_fd, page, record.size) < record.size ) { kill(getppid(), SIGABRT); /* Kill main process */ _exit(99); } @@ -539,21 +528,21 @@ pid_t lpsm_checkpoint(double gc_factor, enum psmsync wait) } /* This might be more efficiently done with fdatasync() */ - fsync(os->log_fd); /* Make sure we have written everything */ + fsync(PM->log_fd); /* Make sure we have written everything */ /* Write commit record */ record.record_type = osrec_commit; - record.size = os->fork_seq; + record.size = PM->fork_seq; record.offset = (off_t)0x54494d43; - if ( lpsm_write(os->log_fd, &record, sizeof(record)) < sizeof(record) ) { + if ( lpsm_write(PM->log_fd, &record, sizeof(record)) < sizeof(record) ) { kill(getppid(), SIGABRT); _exit(99); } - fsync(os->log_fd); + fsync(PM->log_fd); /* Check to see if it's time for garbage collect */ - logsize = lseek(os->log_fd, 0, SEEK_END); - if ( gc_factor < HUGE_VAL && (double)logsize >= gc_factor*os->arena_len ) { + logsize = lseek(PM->log_fd, 0, SEEK_END); + if ( gc_factor < HUGE_VAL && (double)logsize >= gc_factor*PM->arena_len ) { /* Replaying the log isn't the most efficient way to do this. We could also keep a status bit per page around, and flush them out of the shadow array. The biggest problem with that @@ -567,7 +556,7 @@ pid_t lpsm_checkpoint(double gc_factor, enum psmsync wait) /* Drop lock on log file */ lock.l_type = F_UNLCK; - while ( fcntl(os->log_fd, F_SETLKW, &lock) == -1 && errno == EINTR ); + while ( fcntl(PM->log_fd, F_SETLKW, &lock) == -1 && errno == EINTR ); _exit(0); /* Done! */ } @@ -582,7 +571,6 @@ pid_t lpsm_checkpoint(double gc_factor, enum psmsync wait) */ int lpsm_extend(size_t new_size) { - struct ObjStore *os = lpsm_os_struct; struct flock lock; void *newp, *infop; off_t file_size; @@ -591,12 +579,12 @@ int lpsm_extend(size_t new_size) size_t add_pages, old_pages, new_pages, file_pages; struct rlimit fsizelimit; - old_size = os->arena_len; + old_size = PM->arena_len; if ( new_size <= old_size ) return 0; /* No action */ - new_size = (new_size + os->pagesize - 1) & ~(os->pagesize - 1); + 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. */ @@ -609,50 +597,50 @@ int lpsm_extend(size_t new_size) lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; - while ( fcntl(os->main_fd, F_SETLKW, &lock) == -1 && errno == EINTR ); + while ( fcntl(PM->main_fd, F_SETLKW, &lock) == -1 && errno == EINTR ); lock.l_type = F_UNLCK; - file_size = lseek(os->main_fd, 0, SEEK_END); + file_size = lseek(PM->main_fd, 0, SEEK_END); if ( file_size < new_size ) - ft = ftruncate(os->main_fd, new_size); + ft = ftruncate(PM->main_fd, new_size); else ft = 0; if ( ft ) goto reset_size; /* Failure */ - newp = mmap((char*)os->arena + old_size, + newp = mmap((char*)PM->arena + old_size, add_size, PROT_READ, - MAP_PRIVATE|MAP_FIXED, os->main_fd, old_size); + MAP_PRIVATE|MAP_FIXED, PM->main_fd, old_size); if ( newp == MAP_FAILED ) goto reset_size; /* Failure */ /* Since we specified MAP_FIXED, this should be guaranteed */ - assert( newp == (char*)os->arena + old_size ); + assert( newp == (char*)PM->arena + old_size ); /* Convert sizes to pages */ - file_size = (file_size + os->pagesize - 1) & ~(os->pagesize-1); - new_pages = new_size >> os->pageshift; - old_pages = old_size >> os->pageshift; - file_pages = file_size >> os->pageshift; + file_size = (file_size + PM->pagesize - 1) & ~(PM->pagesize-1); + new_pages = new_size >> PM->pageshift; + old_pages = old_size >> PM->pageshift; + file_pages = file_size >> PM->pageshift; add_pages = new_pages - old_pages; - infop = realloc(os->pageinfo, new_pages); + infop = realloc(PM->pageinfo, new_pages); if ( !infop ) { munmap(newp, add_size); goto reset_size; } - os->arena_len = new_size; - os->pageinfo = infop; + PM->arena_len = new_size; + PM->pageinfo = infop; /* No more failure bailouts, unlock */ - while ( fcntl(os->main_fd, F_SETLKW, &lock) == -1 && errno == EINTR ); + while ( fcntl(PM->main_fd, F_SETLKW, &lock) == -1 && errno == EINTR ); /* Mark new pages clean */ assert(new_pages >= file_pages); - memset(os->pageinfo + file_pages, page_clean, new_pages-file_pages); + memset(PM->pageinfo + file_pages, page_clean, new_pages-file_pages); return 0; @@ -660,9 +648,9 @@ int lpsm_extend(size_t new_size) due to address space limitations. */ reset_size: /* Restore the original file size */ - ftruncate(os->main_fd, file_size); + ftruncate(PM->main_fd, file_size); /* Drop lock */ - while ( fcntl(os->main_fd, F_SETLKW, &lock) == -1 && errno == EINTR ); + while ( fcntl(PM->main_fd, F_SETLKW, &lock) == -1 && errno == EINTR ); return -1; } @@ -675,12 +663,10 @@ int lpsm_extend(size_t new_size) */ void lpsm_shutdown(void) { - struct ObjStore *os = lpsm_os_struct; - - munmap(os->arena, os->arena_len); - free(os->pageinfo); - sigaction(SIGSEGV, &os->oldact, NULL); - close(os->log_fd); - close(os->main_fd); - free(os); + munmap(PM->arena, PM->arena_len); + free(PM->pageinfo); + sigaction(SIGSEGV, &PM->oldact, NULL); + close(PM->log_fd); + close(PM->main_fd); + free(PM); } |