2006-06-12 21:50:21 +00:00
|
|
|
#include <limits.h>
|
2007-06-11 21:36:57 +00:00
|
|
|
#include <stasis/truncation.h>
|
2006-05-19 20:17:44 +00:00
|
|
|
#include <pbl/pbl.h>
|
2007-06-11 21:36:57 +00:00
|
|
|
#include <stasis/logger/logger2.h>
|
2008-04-13 04:02:57 +00:00
|
|
|
#include <stasis/page.h>
|
2006-05-19 20:17:44 +00:00
|
|
|
#include <assert.h>
|
|
|
|
|
2007-03-04 02:44:19 +00:00
|
|
|
static int initialized = 0;
|
2006-05-19 20:17:44 +00:00
|
|
|
static int automaticallyTuncating = 0;
|
|
|
|
static pthread_t truncationThread;
|
|
|
|
|
2006-05-30 22:59:22 +00:00
|
|
|
static pthread_mutex_t shutdown_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
static pthread_cond_t shutdown_cond = PTHREAD_COND_INITIALIZER;
|
|
|
|
|
2006-05-19 20:17:44 +00:00
|
|
|
static pblHashTable_t * dirtyPages = 0;
|
|
|
|
static pthread_mutex_t dirtyPages_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
|
2006-06-12 22:45:41 +00:00
|
|
|
#ifdef LONG_TEST
|
|
|
|
#define TARGET_LOG_SIZE (1024 * 1024 * 5)
|
|
|
|
#define TRUNCATE_INTERVAL 1
|
|
|
|
#define MIN_INCREMENTAL_TRUNCATION (1024 * 1024 * 1)
|
|
|
|
#else
|
2006-05-19 20:17:44 +00:00
|
|
|
#define TARGET_LOG_SIZE (1024 * 1024 * 50)
|
|
|
|
#define TRUNCATE_INTERVAL 1
|
2006-06-12 22:45:41 +00:00
|
|
|
#define MIN_INCREMENTAL_TRUNCATION (1024 * 1024 * 25)
|
|
|
|
#endif
|
2006-05-19 20:17:44 +00:00
|
|
|
void dirtyPages_add(Page * p) {
|
|
|
|
pthread_mutex_lock(&dirtyPages_mutex);
|
|
|
|
if(!p->dirty) {
|
|
|
|
p->dirty = 1;
|
2006-05-24 02:19:04 +00:00
|
|
|
//assert(p->LSN);
|
2008-10-03 02:42:25 +00:00
|
|
|
void* ret = pblHtLookup(dirtyPages, &(p->id), sizeof(p->id));
|
2006-05-24 02:19:04 +00:00
|
|
|
assert(!ret);
|
2006-11-07 22:37:05 +00:00
|
|
|
lsn_t * insert = malloc(sizeof(lsn_t));
|
|
|
|
*insert = p->LSN;
|
2008-10-03 02:42:25 +00:00
|
|
|
pblHtInsert(dirtyPages, &(p->id), sizeof(p->id), insert); //(void*)p->LSN);
|
2006-05-19 20:17:44 +00:00
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&dirtyPages_mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
void dirtyPages_remove(Page * p) {
|
|
|
|
pthread_mutex_lock(&dirtyPages_mutex);
|
|
|
|
// printf("Removing page %d\n", p->id);
|
|
|
|
//assert(pblHtLookup(dirtyPages, &(p->id), sizeof(int)));
|
|
|
|
// printf("With lsn = %d\n", (lsn_t)pblHtCurrent(dirtyPages));
|
2006-06-12 20:05:28 +00:00
|
|
|
p->dirty = 0;
|
2008-10-03 02:42:25 +00:00
|
|
|
lsn_t * old = pblHtLookup(dirtyPages, &(p->id),sizeof(p->id));
|
|
|
|
pblHtRemove(dirtyPages, &(p->id), sizeof(p->id));
|
2007-11-04 01:51:37 +00:00
|
|
|
if(old) {
|
|
|
|
free(old);
|
|
|
|
}
|
2006-05-24 02:19:04 +00:00
|
|
|
//assert(!ret); <--- Due to a bug in the PBL compatibility mode,
|
|
|
|
//there is no way to tell whether the value didn't exist, or if it
|
|
|
|
//was null.
|
2006-05-19 20:17:44 +00:00
|
|
|
pthread_mutex_unlock(&dirtyPages_mutex);
|
|
|
|
}
|
|
|
|
|
2006-06-12 20:05:28 +00:00
|
|
|
int dirtyPages_isDirty(Page * p) {
|
|
|
|
int ret;
|
|
|
|
pthread_mutex_lock(&dirtyPages_mutex);
|
|
|
|
ret = p->dirty;
|
|
|
|
pthread_mutex_unlock(&dirtyPages_mutex);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-05-19 20:17:44 +00:00
|
|
|
static lsn_t dirtyPages_minRecLSN() {
|
2006-06-12 21:50:21 +00:00
|
|
|
lsn_t lsn = LSN_T_MAX; // LogFlushedLSN ();
|
2008-10-03 02:42:25 +00:00
|
|
|
pageid_t* pageid;
|
2006-05-19 20:17:44 +00:00
|
|
|
pthread_mutex_lock(&dirtyPages_mutex);
|
|
|
|
|
2008-10-03 02:42:25 +00:00
|
|
|
for( pageid = (pageid_t*)pblHtFirst (dirtyPages); pageid; pageid = (pageid_t*)pblHtNext(dirtyPages)) {
|
2006-11-07 22:37:05 +00:00
|
|
|
lsn_t * thisLSN = (lsn_t*) pblHtCurrent(dirtyPages);
|
2006-05-19 20:17:44 +00:00
|
|
|
// printf("lsn = %d\n", thisLSN);
|
2006-11-07 22:37:05 +00:00
|
|
|
if(*thisLSN < lsn) {
|
|
|
|
lsn = *thisLSN;
|
2006-05-19 20:17:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&dirtyPages_mutex);
|
|
|
|
|
|
|
|
return lsn;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dirtyPages_flush() {
|
2008-10-03 02:42:25 +00:00
|
|
|
pageid_t * staleDirtyPages = malloc(sizeof(pageid_t) * (MAX_BUFFER_SIZE));
|
2006-05-19 20:17:44 +00:00
|
|
|
int i;
|
2006-05-22 23:59:02 +00:00
|
|
|
for(i = 0; i < MAX_BUFFER_SIZE; i++) {
|
2006-05-19 20:17:44 +00:00
|
|
|
staleDirtyPages[i] = -1;
|
|
|
|
}
|
|
|
|
Page* p = 0;
|
|
|
|
pthread_mutex_lock(&dirtyPages_mutex);
|
|
|
|
void* tmp;
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
for(tmp = pblHtFirst(dirtyPages); tmp; tmp = pblHtNext(dirtyPages)) {
|
2008-10-03 02:42:25 +00:00
|
|
|
staleDirtyPages[i] = *((pageid_t*) pblHtCurrentKey(dirtyPages));
|
2006-05-19 20:17:44 +00:00
|
|
|
i++;
|
|
|
|
}
|
2006-05-22 23:59:02 +00:00
|
|
|
assert(i < MAX_BUFFER_SIZE);
|
2006-05-19 20:17:44 +00:00
|
|
|
pthread_mutex_unlock(&dirtyPages_mutex);
|
|
|
|
|
|
|
|
for(i = 0; i < MAX_BUFFER_SIZE && staleDirtyPages[i] != -1; i++) {
|
|
|
|
p = loadPage(-1, staleDirtyPages[i]);
|
2007-03-04 00:36:45 +00:00
|
|
|
writeBackPage(p);
|
2006-05-19 20:17:44 +00:00
|
|
|
releasePage(p);
|
|
|
|
}
|
2006-05-22 23:59:02 +00:00
|
|
|
free(staleDirtyPages);
|
2006-05-19 20:17:44 +00:00
|
|
|
}
|
2007-11-11 23:22:21 +00:00
|
|
|
void dirtyPages_flushRange(pageid_t start, pageid_t stop) {
|
2008-10-03 02:42:25 +00:00
|
|
|
pageid_t * staleDirtyPages = malloc(sizeof(pageid_t) * (MAX_BUFFER_SIZE));
|
2007-11-11 23:22:21 +00:00
|
|
|
int i;
|
|
|
|
Page * p = 0;
|
2007-11-15 01:33:39 +00:00
|
|
|
|
2007-11-11 23:22:21 +00:00
|
|
|
pthread_mutex_lock(&dirtyPages_mutex);
|
2007-11-15 01:33:39 +00:00
|
|
|
|
2007-11-11 23:22:21 +00:00
|
|
|
void *tmp;
|
|
|
|
i = 0;
|
|
|
|
for(tmp = pblHtFirst(dirtyPages); tmp; tmp = pblHtNext(dirtyPages)) {
|
2008-10-03 02:42:25 +00:00
|
|
|
pageid_t num = *((pageid_t*) pblHtCurrentKey(dirtyPages));
|
2007-11-11 23:22:21 +00:00
|
|
|
if(num <= start && num < stop) {
|
|
|
|
staleDirtyPages[i] = num;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
staleDirtyPages[i] = -1;
|
|
|
|
pthread_mutex_unlock(&dirtyPages_mutex);
|
2006-05-19 20:17:44 +00:00
|
|
|
|
2007-11-11 23:22:21 +00:00
|
|
|
for(i = 0; i < MAX_BUFFER_SIZE && staleDirtyPages[i] != -1; i++) {
|
|
|
|
p = loadPage(-1, staleDirtyPages[i]);
|
|
|
|
writeBackPage(p);
|
|
|
|
releasePage(p);
|
|
|
|
}
|
|
|
|
free(staleDirtyPages);
|
2007-11-12 00:49:00 +00:00
|
|
|
forcePageRange(start*PAGE_SIZE,stop*PAGE_SIZE);
|
2007-11-15 01:33:39 +00:00
|
|
|
|
2007-11-11 23:22:21 +00:00
|
|
|
}
|
2006-05-19 20:17:44 +00:00
|
|
|
void dirtyPagesInit() {
|
|
|
|
dirtyPages = pblHtCreate();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void dirtyPagesDeinit() {
|
2006-11-07 22:37:05 +00:00
|
|
|
void * tmp;
|
2007-03-04 02:44:19 +00:00
|
|
|
int areDirty = 0;
|
2006-11-07 22:37:05 +00:00
|
|
|
for(tmp = pblHtFirst(dirtyPages); tmp; tmp = pblHtNext(dirtyPages)) {
|
2007-03-04 02:44:19 +00:00
|
|
|
free(pblHtCurrent(dirtyPages));
|
2007-10-23 23:16:58 +00:00
|
|
|
if((!areDirty) &&
|
|
|
|
(!stasis_suppress_unclean_shutdown_warnings)) {
|
|
|
|
printf("Warning: dirtyPagesDeinit detected dirty, unwritten pages. "
|
|
|
|
"Updates lost?\n");
|
2007-03-04 02:44:19 +00:00
|
|
|
areDirty = 1;
|
|
|
|
}
|
2006-11-07 22:37:05 +00:00
|
|
|
}
|
2006-05-19 20:17:44 +00:00
|
|
|
pblHtDelete(dirtyPages);
|
|
|
|
dirtyPages = 0;
|
|
|
|
}
|
|
|
|
void truncationInit() {
|
|
|
|
initialized = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void truncationDeinit() {
|
2007-03-04 02:44:19 +00:00
|
|
|
pthread_mutex_lock(&shutdown_mutex);
|
2006-05-19 20:17:44 +00:00
|
|
|
initialized = 0;
|
|
|
|
if(automaticallyTuncating) {
|
|
|
|
void * ret = 0;
|
2007-03-04 02:44:19 +00:00
|
|
|
pthread_mutex_unlock(&shutdown_mutex);
|
2006-05-30 22:59:22 +00:00
|
|
|
pthread_cond_broadcast(&shutdown_cond);
|
2006-05-19 20:17:44 +00:00
|
|
|
pthread_join(truncationThread, &ret);
|
2007-03-04 02:44:19 +00:00
|
|
|
} else {
|
|
|
|
pthread_mutex_unlock(&shutdown_mutex);
|
2006-05-19 20:17:44 +00:00
|
|
|
}
|
|
|
|
automaticallyTuncating = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void* periodicTruncation(void * ignored) {
|
2006-05-30 22:59:22 +00:00
|
|
|
pthread_mutex_lock(&shutdown_mutex);
|
2006-05-19 20:17:44 +00:00
|
|
|
while(initialized) {
|
|
|
|
if(LogFlushedLSN() - LogTruncationPoint() > TARGET_LOG_SIZE) {
|
|
|
|
truncateNow();
|
|
|
|
}
|
2006-05-30 22:59:22 +00:00
|
|
|
struct timeval now;
|
|
|
|
struct timespec timeout;
|
|
|
|
int timeret = gettimeofday(&now, 0);
|
|
|
|
assert(0 == timeret);
|
|
|
|
|
|
|
|
timeout.tv_sec = now.tv_sec;
|
|
|
|
timeout.tv_nsec = now.tv_usec;
|
|
|
|
timeout.tv_sec += TRUNCATE_INTERVAL;
|
|
|
|
|
|
|
|
pthread_cond_timedwait(&shutdown_cond, &shutdown_mutex, &timeout);
|
2006-05-19 20:17:44 +00:00
|
|
|
}
|
2006-05-30 22:59:22 +00:00
|
|
|
pthread_mutex_unlock(&shutdown_mutex);
|
2006-05-19 20:17:44 +00:00
|
|
|
return (void*)0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void autoTruncate() {
|
|
|
|
assert(!automaticallyTuncating);
|
|
|
|
automaticallyTuncating = 1;
|
|
|
|
pthread_create(&truncationThread, 0, &periodicTruncation, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int truncateNow() {
|
2006-06-12 21:50:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
// *_minRecLSN() used to return the same value as flushed if
|
|
|
|
//there were no outstanding transactions, but flushed might
|
|
|
|
//not point to the front of a log entry... now, both return
|
|
|
|
//LSN_T_MAX if there are no outstanding transactions / no
|
|
|
|
//dirty pages.
|
|
|
|
|
2006-05-19 20:17:44 +00:00
|
|
|
lsn_t page_rec_lsn = dirtyPages_minRecLSN();
|
|
|
|
lsn_t xact_rec_lsn = transactions_minRecLSN();
|
2006-06-12 21:50:21 +00:00
|
|
|
lsn_t flushed_lsn = LogFlushedLSN();
|
|
|
|
|
2006-05-19 20:17:44 +00:00
|
|
|
lsn_t rec_lsn = page_rec_lsn < xact_rec_lsn ? page_rec_lsn : xact_rec_lsn;
|
2006-06-12 21:50:21 +00:00
|
|
|
rec_lsn = (rec_lsn < flushed_lsn) ? rec_lsn : flushed_lsn;
|
|
|
|
|
2006-05-19 20:17:44 +00:00
|
|
|
lsn_t log_trunc = LogTruncationPoint();
|
2006-05-24 23:21:33 +00:00
|
|
|
if((xact_rec_lsn - log_trunc) > MIN_INCREMENTAL_TRUNCATION) {
|
2006-09-25 22:27:13 +00:00
|
|
|
//fprintf(stderr, "xact = %ld \t log = %ld\n", xact_rec_lsn, log_trunc);
|
2006-05-24 23:21:33 +00:00
|
|
|
if((rec_lsn - log_trunc) > MIN_INCREMENTAL_TRUNCATION) {
|
2006-09-25 22:27:13 +00:00
|
|
|
// fprintf(stderr, "Truncating now. rec_lsn = %ld, log_trunc = %ld\n", rec_lsn, log_trunc);
|
2006-10-04 04:41:53 +00:00
|
|
|
// fprintf(stderr, "Truncating to rec_lsn = %ld\n", rec_lsn);
|
2007-03-04 00:36:45 +00:00
|
|
|
forcePages();
|
2006-05-24 23:21:33 +00:00
|
|
|
LogTruncate(rec_lsn);
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
lsn_t flushed = LogFlushedLSN();
|
|
|
|
if(flushed - log_trunc > 2 * TARGET_LOG_SIZE) {
|
2006-09-25 22:27:13 +00:00
|
|
|
//fprintf(stderr, "Flushing dirty buffers: rec_lsn = %ld log_trunc = %ld flushed = %ld\n", rec_lsn, log_trunc, flushed);
|
2006-05-24 23:21:33 +00:00
|
|
|
dirtyPages_flush();
|
|
|
|
|
|
|
|
page_rec_lsn = dirtyPages_minRecLSN();
|
|
|
|
rec_lsn = page_rec_lsn < xact_rec_lsn ? page_rec_lsn : xact_rec_lsn;
|
2006-06-12 21:50:21 +00:00
|
|
|
rec_lsn = (rec_lsn < flushed_lsn) ? rec_lsn : flushed_lsn;
|
2006-05-24 23:21:33 +00:00
|
|
|
|
2006-10-04 04:41:53 +00:00
|
|
|
//fprintf(stderr, "Flushed Dirty Buffers. Truncating to rec_lsn = %ld\n", rec_lsn);
|
2006-06-12 21:50:21 +00:00
|
|
|
|
2007-03-04 00:36:45 +00:00
|
|
|
forcePages();
|
2006-06-12 20:55:49 +00:00
|
|
|
LogTruncate(rec_lsn);
|
|
|
|
return 1;
|
2006-06-12 21:50:21 +00:00
|
|
|
|
2006-05-24 23:21:33 +00:00
|
|
|
} else {
|
2006-05-19 20:17:44 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2006-05-24 23:21:33 +00:00
|
|
|
} else {
|
|
|
|
return 0;
|
2006-05-19 20:17:44 +00:00
|
|
|
}
|
|
|
|
}
|