stasis-aries-wal/src/lladd/pageCache.c

178 lines
3.7 KiB
C
Raw Normal View History

/**
@file
pageCache handles the replacement policy for buffer manager. This
allows bufferManager's implementation to focus on providing atomic
writes, and locking.
*/
#include <config.h>
#include <lladd/common.h>
#include "page.h"
#include <lladd/pageCache.h>
#include <lladd/bufferManager.h>
#include <assert.h>
#include <stdio.h>
/** @todo break dependency between pageCache and pageFile */
#include "pageFile.h"
static unsigned int bufferSize; /* < MAX_BUFFER_SIZE */
static Page *repHead, *repMiddle, *repTail; /* replacement policy */
2004-07-20 00:15:17 +00:00
int cache_state;
2004-07-20 00:15:17 +00:00
void pageCacheInit(Page * first) {
2004-07-20 00:15:17 +00:00
bufferSize = 1;
cache_state = INITIAL;
2004-07-20 00:15:17 +00:00
DEBUG("pageCacheInit()");
2004-07-20 00:15:17 +00:00
first->inCache = 1;
first->prev = first->next = NULL;
/* pageMap(first); */
pageRead(first);
repHead = repTail = first;
repMiddle = NULL;
2004-07-20 00:15:17 +00:00
}
void pageCacheDeinit() {
2004-07-20 00:15:17 +00:00
}
static void headInsert(Page *ret) {
assert(ret != repMiddle);
assert(ret != repTail);
assert(ret != repHead);
repHead->prev = ret;
ret->next = repHead;
ret->prev = NULL;
repHead = ret;
}
static void middleInsert(Page *ret) {
2004-07-20 00:15:17 +00:00
assert(cache_state == FULL);
2004-07-20 00:15:17 +00:00
/* assert( bufferSize == MAX_BUFFER_SIZE ); */
assert(ret != repMiddle);
assert(ret != repTail);
assert(ret != repHead);
ret->prev = repMiddle->prev;
ret->next = repMiddle;
repMiddle->prev = ret;
ret->prev->next = ret;
ret->queue = 2;
repMiddle = ret;
assert(ret->next != ret && ret->prev != ret);
}
2004-07-20 00:15:17 +00:00
/** @todo Under high contention, the buffer pool can empty. What should be done about this, other than making sure that # threads > buffer size? */
static void qRemove(Page *ret) {
assert(cache_state == FULL);
2004-07-20 00:15:17 +00:00
assert(ret->next != ret && ret->prev != ret);
if( ret->prev )
ret->prev->next = ret->next;
else /* is head */
repHead = ret->next; /* won't have head == tail because of test in loadPage */
if( ret->next ) {
ret->next->prev = ret->prev;
/* TODO: these if can be better organizeed for speed */
if( ret == repMiddle )
/* select new middle */
repMiddle = ret->next;
}
else /* is tail */
repTail = ret->prev;
assert(ret != repMiddle);
assert(ret != repTail);
assert(ret != repHead);
}
2004-07-20 00:15:17 +00:00
void cacheInsertPage (Page * ret) {
2004-07-20 00:15:17 +00:00
bufferSize++;
assert(!ret->inCache);
ret->inCache ++;
if(cache_state == FULL) {
2004-07-20 00:15:17 +00:00
middleInsert(ret);
} else {
if(bufferSize == MAX_BUFFER_SIZE/* - 1*/) { /* Set up page kick mechanism. */
int i;
Page *iter;
cache_state = FULL;
2004-07-20 00:15:17 +00:00
headInsert(ret);
assert(ret->next != ret && ret->prev != ret);
/* split up queue:
* "in all cases studied ... fixing the primary region to 30% ...
* resulted in the best performance"
*/
repMiddle = repHead;
for( i = 0; i < MAX_BUFFER_SIZE / 3; i++ ) {
repMiddle->queue = 1;
repMiddle = repMiddle->next;
}
for( iter = repMiddle; iter; iter = iter->next ) {
iter->queue = 2;
}
} else { /* Just insert it. */
headInsert(ret);
assert(ret->next != ret && ret->prev != ret);
assert(ret->next != ret && ret->prev != ret);
}
}
}
void cacheRemovePage(Page * ret) {
2004-07-20 00:15:17 +00:00
assert(ret->inCache);
qRemove(ret);
ret->inCache--;
bufferSize --;
}
void cacheHitOnPage(Page * ret) {
2004-07-20 00:15:17 +00:00
/* The page may not be in cache if it is about to be freed. */
if(ret->inCache && cache_state == FULL) { /* we need to worry about page sorting */
2004-07-20 00:15:17 +00:00
/* move to head */
if( ret != repHead ) {
qRemove(ret);
headInsert(ret);
assert(ret->next != ret && ret->prev != ret);
if( ret->queue == 2 ) {
/* keep first queue same size */
repMiddle = repMiddle->prev;
repMiddle->queue = 2;
ret->queue = 1;
}
}
}
}
Page * cacheStalePage() {
return repTail;
2004-07-20 00:15:17 +00:00
}