2006-06-22 19:10:02 +00:00
|
|
|
#include "../page.h"
|
|
|
|
#include <lladd/operations.h>
|
2006-07-18 23:59:00 +00:00
|
|
|
#include "../page/slotted.h"
|
|
|
|
#include <assert.h>
|
2006-06-22 19:10:02 +00:00
|
|
|
|
2006-07-25 00:56:50 +00:00
|
|
|
typedef struct regionAllocLogArg{
|
|
|
|
int startPage;
|
|
|
|
unsigned int pageCount;
|
|
|
|
int allocationManager;
|
|
|
|
} regionAllocArg;
|
|
|
|
|
2006-07-27 00:15:29 +00:00
|
|
|
static pthread_mutex_t region_mutex = PTHREAD_MUTEX_INITIALIZER;
|
2006-08-10 23:57:49 +00:00
|
|
|
pthread_t holding_mutex;
|
2006-07-25 00:56:50 +00:00
|
|
|
static void TregionAllocHelper(int xid, unsigned int pageid, unsigned int pageCount, int allocationManager);
|
2006-10-05 22:08:42 +00:00
|
|
|
static void TallocBoundaryTag(int xid, unsigned int page, boundary_tag* tag);
|
|
|
|
static void TreadBoundaryTag(int xid, unsigned int page, boundary_tag* tag);
|
|
|
|
static void TsetBoundaryTag(int xid, unsigned int page, boundary_tag* tag);
|
|
|
|
static void TdeallocBoundaryTag(int xid, unsigned int page);
|
2006-07-18 23:59:00 +00:00
|
|
|
|
2006-08-11 02:25:17 +00:00
|
|
|
/** This doesn't need a latch since it is only initiated within nested
|
|
|
|
top actions (and is local to this file. During abort(), the nested
|
|
|
|
top action's logical undo grabs the necessary latches.
|
|
|
|
|
|
|
|
@todo opearate_alloc_boundary_tag is executed without holding the
|
|
|
|
proper mutex during REDO. For now this doesn't matter, but it
|
|
|
|
could matter in the future.
|
|
|
|
*/
|
2006-07-18 23:59:00 +00:00
|
|
|
static int operate_alloc_boundary_tag(int xid, Page * p, lsn_t lsn, recordid rid, const void * dat) {
|
|
|
|
slottedPageInitialize(p);
|
|
|
|
*page_type_ptr(p) = BOUNDARY_TAG_PAGE;
|
|
|
|
slottedPostRalloc(xid, p, lsn, rid);
|
2007-01-22 20:55:25 +00:00
|
|
|
slottedWrite(p, rid, dat);
|
2006-07-18 23:59:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2006-06-22 19:10:02 +00:00
|
|
|
|
2006-07-25 00:56:50 +00:00
|
|
|
static int operate_alloc_region(int xid, Page * p, lsn_t lsn, recordid rid, const void * datP) {
|
|
|
|
pthread_mutex_lock(®ion_mutex);
|
2006-08-10 23:57:49 +00:00
|
|
|
assert(0 == holding_mutex);
|
|
|
|
holding_mutex = pthread_self();
|
2006-07-25 00:56:50 +00:00
|
|
|
regionAllocArg *dat = (regionAllocArg*)datP;
|
|
|
|
TregionAllocHelper(xid, dat->startPage, dat->pageCount, dat->allocationManager);
|
2006-08-10 23:57:49 +00:00
|
|
|
holding_mutex = 0;
|
2006-07-25 00:56:50 +00:00
|
|
|
pthread_mutex_unlock(®ion_mutex);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-10-05 22:08:42 +00:00
|
|
|
static int operate_dealloc_region_unlocked(int xid, Page * p, lsn_t lsn, recordid rid, const void * datP) {
|
2006-07-25 00:56:50 +00:00
|
|
|
regionAllocArg *dat = (regionAllocArg*)datP;
|
2006-10-05 22:08:42 +00:00
|
|
|
|
|
|
|
unsigned int firstPage = dat->startPage + 1;
|
|
|
|
|
|
|
|
boundary_tag t;
|
|
|
|
|
|
|
|
TreadBoundaryTag(xid, firstPage - 1, &t);
|
|
|
|
|
|
|
|
t.status = REGION_VACANT;
|
|
|
|
t.region_xid = xid;
|
|
|
|
|
|
|
|
TsetBoundaryTag(xid, firstPage -1, &t);
|
|
|
|
|
|
|
|
// TregionDealloc(xid, dat->startPage+1);
|
2006-07-25 00:56:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-10-05 22:08:42 +00:00
|
|
|
static int operate_dealloc_region(int xid, Page * p, lsn_t lsn, recordid rid, const void * datP) {
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
pthread_mutex_lock(®ion_mutex);
|
|
|
|
assert(0 == holding_mutex);
|
|
|
|
holding_mutex = pthread_self();
|
|
|
|
|
2006-10-07 20:05:54 +00:00
|
|
|
ret = operate_dealloc_region_unlocked(xid, p, lsn, rid, datP);
|
2006-10-05 22:08:42 +00:00
|
|
|
|
|
|
|
holding_mutex = 0;
|
|
|
|
pthread_mutex_unlock(®ion_mutex);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-07-20 01:29:39 +00:00
|
|
|
static void TallocBoundaryTag(int xid, unsigned int page, boundary_tag* tag) {
|
2006-07-27 00:15:29 +00:00
|
|
|
//printf("Alloc boundary tag at %d = { %d, %d, %d }\n", page, tag->size, tag->prev_size, tag->status);
|
2006-08-10 23:57:49 +00:00
|
|
|
assert(holding_mutex == pthread_self());
|
2006-07-18 23:59:00 +00:00
|
|
|
recordid rid = {page, 0, sizeof(boundary_tag)};
|
|
|
|
Tupdate(xid, rid, tag, OPERATION_ALLOC_BOUNDARY_TAG);
|
|
|
|
}
|
2006-07-25 22:23:15 +00:00
|
|
|
|
2006-07-20 01:29:39 +00:00
|
|
|
static void TreadBoundaryTag(int xid, unsigned int page, boundary_tag* tag) {
|
2006-08-10 23:57:49 +00:00
|
|
|
assert(holding_mutex == pthread_self());
|
2006-07-18 23:59:00 +00:00
|
|
|
recordid rid = { page, 0, sizeof(boundary_tag) };
|
2006-07-27 00:15:29 +00:00
|
|
|
assert(TpageGetType(xid, rid.page) == BOUNDARY_TAG_PAGE);
|
2006-07-18 23:59:00 +00:00
|
|
|
Tread(xid, rid, tag);
|
2006-07-27 00:15:29 +00:00
|
|
|
assert((page == 0 && tag->prev_size == UINT32_MAX) || (page != 0 && tag->prev_size != UINT32_MAX));
|
|
|
|
//printf("Read boundary tag at %d = { %d, %d, %d }\n", page, tag->size, tag->prev_size, tag->status);
|
2006-07-18 23:59:00 +00:00
|
|
|
}
|
2006-07-20 01:29:39 +00:00
|
|
|
static void TsetBoundaryTag(int xid, unsigned int page, boundary_tag* tag) {
|
2006-07-27 00:15:29 +00:00
|
|
|
//printf("Write boundary tag at %d = { %d, %d, %d }\n", page, tag->size, tag->prev_size, tag->status);
|
|
|
|
|
|
|
|
// Sanity checking:
|
|
|
|
assert((page == 0 && tag->prev_size == UINT32_MAX) || (page != 0 && tag->prev_size < UINT32_MAX/2));
|
2006-08-10 23:57:49 +00:00
|
|
|
assert(holding_mutex == pthread_self());
|
2006-07-27 00:15:29 +00:00
|
|
|
|
|
|
|
boundary_tag t2;
|
|
|
|
TreadBoundaryTag(xid, page, &t2);
|
|
|
|
//assert(tag->size != t2.size || tag->prev_size != t2.prev_size || tag->status != t2.status); <-- Useful for finding performance problems.
|
|
|
|
|
|
|
|
// Now, set the record:
|
2006-07-18 23:59:00 +00:00
|
|
|
recordid rid = { page, 0, sizeof(boundary_tag) };
|
|
|
|
Tset(xid, rid, tag);
|
2006-06-22 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
2006-07-25 22:23:15 +00:00
|
|
|
static void TdeallocBoundaryTag(int xid, unsigned int page) {
|
|
|
|
boundary_tag t;
|
2006-08-10 23:57:49 +00:00
|
|
|
assert(holding_mutex == pthread_self());
|
2006-07-27 00:15:29 +00:00
|
|
|
|
2006-07-25 22:23:15 +00:00
|
|
|
TreadBoundaryTag(xid, page, &t);
|
|
|
|
t.status = REGION_CONDEMNED;
|
2006-07-27 00:15:29 +00:00
|
|
|
t.region_xid = xid;
|
2006-07-25 22:23:15 +00:00
|
|
|
TsetBoundaryTag(xid, page, &t);
|
2006-07-27 00:15:29 +00:00
|
|
|
|
2006-07-25 22:23:15 +00:00
|
|
|
}
|
|
|
|
|
2006-07-18 23:59:00 +00:00
|
|
|
void regionsInit() {
|
|
|
|
Page * p = loadPage(-1, 0);
|
|
|
|
int pageType = *page_type_ptr(p);
|
2006-08-10 23:57:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
holding_mutex = pthread_self();
|
2006-07-18 23:59:00 +00:00
|
|
|
if(pageType != BOUNDARY_TAG_PAGE) {
|
|
|
|
boundary_tag t;
|
2006-07-20 01:29:39 +00:00
|
|
|
t.size = UINT32_MAX;
|
|
|
|
t.prev_size = UINT32_MAX;
|
2006-07-18 23:59:00 +00:00
|
|
|
t.status = REGION_VACANT;
|
|
|
|
t.region_xid = INVALID_XID;
|
|
|
|
t.allocation_manager = 0;
|
2006-07-20 01:29:39 +00:00
|
|
|
|
|
|
|
// This does what TallocBoundaryTag(-1, 0, &t); would do, but it
|
|
|
|
// doesn't produce a log entry. The log entry would be invalid
|
|
|
|
// since we haven't initialized everything yet. We don't need to
|
|
|
|
// flush the page, since this code is deterministic, and will be
|
|
|
|
// re-run before recovery if this update doesn't make it to disk
|
|
|
|
// after a crash.
|
|
|
|
recordid rid = {0,0,sizeof(boundary_tag)};
|
|
|
|
|
|
|
|
operate_alloc_boundary_tag(0,p,0,rid,&t);
|
2006-07-18 23:59:00 +00:00
|
|
|
}
|
2006-08-10 23:57:49 +00:00
|
|
|
holding_mutex = 0;
|
2006-07-21 01:07:09 +00:00
|
|
|
releasePage(p);
|
2006-06-22 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
2006-07-25 22:23:15 +00:00
|
|
|
void fsckRegions(int xid) {
|
|
|
|
|
|
|
|
// Ignore region_xid, allocation_manager for now.
|
2006-08-11 02:25:17 +00:00
|
|
|
pthread_mutex_lock(®ion_mutex);
|
|
|
|
holding_mutex = pthread_self();
|
2006-07-25 22:23:15 +00:00
|
|
|
int pageType;
|
|
|
|
boundary_tag tag;
|
|
|
|
boundary_tag prev_tag;
|
|
|
|
prev_tag.size = UINT32_MAX;
|
|
|
|
int tagPage = 0;
|
|
|
|
pageType = TpageGetType(xid, tagPage);
|
|
|
|
assert(pageType == BOUNDARY_TAG_PAGE);
|
2006-07-27 00:15:29 +00:00
|
|
|
|
2006-07-25 22:23:15 +00:00
|
|
|
TreadBoundaryTag(xid, tagPage, &tag);
|
|
|
|
|
|
|
|
assert(tag.prev_size == UINT32_MAX);
|
|
|
|
|
|
|
|
while(tag.size != UINT32_MAX) {
|
|
|
|
// Ignore region_xid, allocation_manager for now.
|
|
|
|
assert(tag.status == REGION_VACANT || tag.status == REGION_ZONED);
|
|
|
|
assert(prev_tag.size == tag.prev_size);
|
|
|
|
|
|
|
|
for(int i = 0; i < tag.size; i++) {
|
|
|
|
int thisPage = tagPage + 1 + i;
|
|
|
|
pageType = TpageGetType(xid, thisPage);
|
|
|
|
|
|
|
|
if(pageType == BOUNDARY_TAG_PAGE) {
|
|
|
|
boundary_tag orphan;
|
|
|
|
TreadBoundaryTag(xid, thisPage, &orphan);
|
|
|
|
assert(orphan.status == REGION_CONDEMNED);
|
|
|
|
Page * p = loadPage(xid, thisPage);
|
|
|
|
fsckSlottedPage(p);
|
|
|
|
releasePage(p);
|
|
|
|
} else if (pageType == SLOTTED_PAGE) {
|
|
|
|
Page * p = loadPage(xid, thisPage);
|
|
|
|
fsckSlottedPage(p);
|
|
|
|
releasePage(p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
prev_tag = tag;
|
|
|
|
tagPage = tagPage + 1 + prev_tag.size;
|
|
|
|
TreadBoundaryTag(xid, tagPage, &tag);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(tag.status == REGION_VACANT); // space at EOF better be vacant!
|
2006-08-11 02:25:17 +00:00
|
|
|
holding_mutex = 0;
|
|
|
|
pthread_mutex_unlock(®ion_mutex);
|
|
|
|
|
2006-07-25 22:23:15 +00:00
|
|
|
}
|
|
|
|
|
2006-07-25 00:56:50 +00:00
|
|
|
static void TregionAllocHelper(int xid, unsigned int pageid, unsigned int pageCount, int allocationManager) {
|
2006-07-27 00:15:29 +00:00
|
|
|
|
2006-07-18 23:59:00 +00:00
|
|
|
boundary_tag t;
|
2006-07-25 00:56:50 +00:00
|
|
|
TreadBoundaryTag(xid, pageid, &t);
|
2006-07-18 23:59:00 +00:00
|
|
|
|
2006-07-27 00:15:29 +00:00
|
|
|
|
2006-07-18 23:59:00 +00:00
|
|
|
if(t.size != pageCount) {
|
2006-06-22 19:10:02 +00:00
|
|
|
// need to split region
|
2006-07-18 23:59:00 +00:00
|
|
|
// allocate new boundary tag.
|
|
|
|
|
2006-07-27 00:15:29 +00:00
|
|
|
assert(t.size > pageCount);
|
|
|
|
|
2006-07-20 01:29:39 +00:00
|
|
|
unsigned int newPageid = pageid + pageCount + 1;
|
2006-07-18 23:59:00 +00:00
|
|
|
boundary_tag new_tag;
|
|
|
|
|
2006-07-20 01:29:39 +00:00
|
|
|
if(t.size != UINT32_MAX) {
|
2006-07-18 23:59:00 +00:00
|
|
|
|
|
|
|
new_tag.size = t.size - pageCount - 1; // pageCount must be strictly less than t->size, so this is non-negative.
|
|
|
|
|
|
|
|
boundary_tag succ_tag;
|
|
|
|
TreadBoundaryTag(xid, pageid + t.size + 1, &succ_tag);
|
2006-07-20 01:29:39 +00:00
|
|
|
succ_tag.prev_size = new_tag.size;
|
2006-07-18 23:59:00 +00:00
|
|
|
TsetBoundaryTag(xid, pageid + t.size + 1, &succ_tag);
|
|
|
|
|
2006-06-22 19:10:02 +00:00
|
|
|
} else {
|
2006-07-18 23:59:00 +00:00
|
|
|
|
2006-07-20 01:29:39 +00:00
|
|
|
new_tag.size = UINT32_MAX;
|
2006-07-18 23:59:00 +00:00
|
|
|
|
2006-06-22 19:10:02 +00:00
|
|
|
}
|
2006-07-18 23:59:00 +00:00
|
|
|
new_tag.prev_size = pageCount;
|
|
|
|
// Create the new region, and disassociate it from this transaction immediately.
|
|
|
|
// This has two implications:
|
|
|
|
// - It could cause some fragmentation if interleaved transactions are allocating, and some abort.
|
|
|
|
// - Multiple transactions can allocate space at the end of the page file without blocking each other.
|
|
|
|
new_tag.status = REGION_VACANT;
|
|
|
|
new_tag.region_xid = INVALID_XID;
|
|
|
|
new_tag.allocation_manager = 0;
|
|
|
|
|
|
|
|
TallocBoundaryTag(xid, newPageid, &new_tag);
|
2006-06-22 19:10:02 +00:00
|
|
|
|
|
|
|
}
|
2006-07-18 23:59:00 +00:00
|
|
|
|
2006-07-20 01:29:39 +00:00
|
|
|
t.status = REGION_ZONED;
|
|
|
|
t.region_xid = xid;
|
|
|
|
t.allocation_manager = allocationManager;
|
|
|
|
t.size = pageCount;
|
|
|
|
|
2006-07-18 23:59:00 +00:00
|
|
|
TsetBoundaryTag(xid, pageid, &t);
|
2006-06-22 19:10:02 +00:00
|
|
|
|
2006-07-25 00:56:50 +00:00
|
|
|
}
|
|
|
|
|
2006-07-27 00:15:29 +00:00
|
|
|
static void consolidateRegions(int xid, unsigned int * firstPage, boundary_tag *t) {
|
2006-06-22 19:10:02 +00:00
|
|
|
|
2006-07-27 00:15:29 +00:00
|
|
|
if(t->status != REGION_VACANT || TisActiveTransaction(t->region_xid)) { return; }
|
2006-07-18 23:59:00 +00:00
|
|
|
|
2006-07-27 00:15:29 +00:00
|
|
|
// (*firstPage)++;
|
2006-07-18 23:59:00 +00:00
|
|
|
|
2006-07-27 00:15:29 +00:00
|
|
|
int mustWriteOriginalTag = 0;
|
2006-07-20 01:29:39 +00:00
|
|
|
|
2006-07-18 23:59:00 +00:00
|
|
|
// If successor is vacant, merge.
|
2006-07-27 00:15:29 +00:00
|
|
|
if(t->size != UINT32_MAX) { // is there a successor?
|
|
|
|
unsigned int succ_page = (*firstPage) + 1 + t->size;
|
2006-07-18 23:59:00 +00:00
|
|
|
boundary_tag succ_tag;
|
|
|
|
TreadBoundaryTag(xid, succ_page, &succ_tag);
|
|
|
|
|
|
|
|
// TODO: Check page_type_ptr()...
|
2006-07-25 22:23:15 +00:00
|
|
|
|
2006-07-20 01:29:39 +00:00
|
|
|
if(succ_tag.size == UINT32_MAX) {
|
2006-07-27 00:15:29 +00:00
|
|
|
t->size = UINT32_MAX;
|
2006-07-25 22:23:15 +00:00
|
|
|
assert(succ_tag.status == REGION_VACANT);
|
2006-07-18 23:59:00 +00:00
|
|
|
// TODO: Truncate page file.
|
|
|
|
TdeallocBoundaryTag(xid, succ_page);
|
2006-07-27 00:15:29 +00:00
|
|
|
mustWriteOriginalTag = 1;
|
|
|
|
} else if(succ_tag.status == REGION_VACANT && (!TisActiveTransaction(succ_tag.region_xid))) {
|
2006-06-22 19:10:02 +00:00
|
|
|
|
2006-07-27 00:15:29 +00:00
|
|
|
t->size = t->size + succ_tag.size + 1;
|
2006-07-20 01:29:39 +00:00
|
|
|
unsigned int succ_succ_page = succ_page + succ_tag.size + 1;
|
2006-06-22 19:10:02 +00:00
|
|
|
|
2006-07-18 23:59:00 +00:00
|
|
|
boundary_tag succ_succ_tag;
|
|
|
|
|
|
|
|
TreadBoundaryTag(xid, succ_succ_page, &succ_succ_tag);
|
2006-07-27 00:15:29 +00:00
|
|
|
succ_succ_tag.prev_size = t->size;
|
2006-07-18 23:59:00 +00:00
|
|
|
TsetBoundaryTag(xid, succ_succ_page, &succ_succ_tag);
|
2006-07-25 22:23:15 +00:00
|
|
|
|
|
|
|
TdeallocBoundaryTag(xid, succ_page);
|
2006-07-27 00:15:29 +00:00
|
|
|
mustWriteOriginalTag = 1;
|
|
|
|
} else {
|
|
|
|
mustWriteOriginalTag = 0;
|
2006-07-18 23:59:00 +00:00
|
|
|
}
|
2006-07-27 00:15:29 +00:00
|
|
|
|
2006-07-18 23:59:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If predecessor is vacant, merge. (Doing this after the successor
|
|
|
|
// is merged makes life easier, since merging with the predecessor
|
|
|
|
// creates a situation where the current page is not a boundary
|
|
|
|
// tag...)
|
|
|
|
|
2006-07-27 00:15:29 +00:00
|
|
|
if(t->prev_size != UINT32_MAX) {
|
|
|
|
|
|
|
|
unsigned int pred_page = ((*firstPage) - 1) - t->prev_size; // If the predecessor is length zero, then it's boundary tag is two pages before this region's tag.
|
2006-07-18 23:59:00 +00:00
|
|
|
|
|
|
|
boundary_tag pred_tag;
|
|
|
|
TreadBoundaryTag(xid, pred_page, &pred_tag);
|
|
|
|
|
2006-07-27 00:15:29 +00:00
|
|
|
if(pred_tag.status == REGION_VACANT && (!TisActiveTransaction(pred_tag.region_xid))) {
|
|
|
|
|
|
|
|
TdeallocBoundaryTag(xid, *firstPage);
|
|
|
|
|
|
|
|
if(t->size == UINT32_MAX) {
|
2006-07-20 01:29:39 +00:00
|
|
|
pred_tag.size = UINT32_MAX;
|
2006-07-18 23:59:00 +00:00
|
|
|
|
|
|
|
// TODO: truncate region
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
2006-07-27 00:15:29 +00:00
|
|
|
pred_tag.size += (t->size + 1);
|
2006-07-18 23:59:00 +00:00
|
|
|
|
2006-07-27 00:15:29 +00:00
|
|
|
unsigned int succ_page = (*firstPage) + 1+ t->size;
|
2006-07-20 01:29:39 +00:00
|
|
|
assert(pred_page + pred_tag.size + 1 == succ_page);
|
2006-07-27 00:15:29 +00:00
|
|
|
|
2006-07-18 23:59:00 +00:00
|
|
|
boundary_tag succ_tag;
|
|
|
|
TreadBoundaryTag(xid, succ_page, &succ_tag);
|
|
|
|
succ_tag.prev_size = pred_tag.size;
|
|
|
|
TsetBoundaryTag(xid, succ_page, &succ_tag);
|
|
|
|
|
2006-07-27 00:15:29 +00:00
|
|
|
// assert(succ_tag.status != REGION_VACANT);
|
2006-07-20 01:29:39 +00:00
|
|
|
assert(succ_page - pred_page - 1 == pred_tag.size);
|
2006-07-18 23:59:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TsetBoundaryTag(xid, pred_page, &pred_tag);
|
|
|
|
|
2006-07-27 00:15:29 +00:00
|
|
|
assert(pred_page < *firstPage);
|
|
|
|
(*firstPage) = pred_page;
|
|
|
|
(*t) = pred_tag;
|
2006-07-18 23:59:00 +00:00
|
|
|
} else {
|
2006-07-27 00:15:29 +00:00
|
|
|
if(mustWriteOriginalTag) {
|
|
|
|
TsetBoundaryTag(xid, (*firstPage), t);
|
|
|
|
}
|
2006-07-18 23:59:00 +00:00
|
|
|
}
|
|
|
|
} else {
|
2006-07-27 00:15:29 +00:00
|
|
|
if(mustWriteOriginalTag) {
|
|
|
|
TsetBoundaryTag(xid, (*firstPage), t);
|
|
|
|
}
|
2006-07-18 23:59:00 +00:00
|
|
|
}
|
2006-07-27 00:15:29 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void TregionDealloc(int xid, unsigned int firstPage) {
|
|
|
|
|
|
|
|
// Note that firstPage is the first *caller visible* page in the
|
|
|
|
// region. The boundary tag is stored on firstPage - 1. Also, note
|
|
|
|
// that a region of size N takes up N+1 pages on disk.
|
|
|
|
|
|
|
|
// Deferred coalescing would probably make sense...
|
|
|
|
|
|
|
|
pthread_mutex_lock(®ion_mutex);
|
2006-08-10 23:57:49 +00:00
|
|
|
assert(0 == holding_mutex);
|
|
|
|
holding_mutex = pthread_self();
|
2006-07-27 00:15:29 +00:00
|
|
|
|
|
|
|
boundary_tag t;
|
|
|
|
TreadBoundaryTag(xid, firstPage-1, &t);
|
|
|
|
|
|
|
|
regionAllocArg arg = { firstPage-1, t.size, t.allocation_manager };
|
|
|
|
|
2006-10-05 22:08:42 +00:00
|
|
|
assert(t.status != REGION_VACANT);
|
2006-07-27 00:15:29 +00:00
|
|
|
|
2006-10-05 22:08:42 +00:00
|
|
|
void * handle = TbeginNestedTopAction(xid, OPERATION_DEALLOC_REGION, (const byte*)&arg, sizeof(regionAllocArg));
|
2006-07-27 00:15:29 +00:00
|
|
|
|
2006-10-05 22:08:42 +00:00
|
|
|
operate_dealloc_region_unlocked(xid, 0, 0, NULLRID, (const byte*)&arg);
|
2006-07-27 00:15:29 +00:00
|
|
|
|
2006-10-05 22:08:42 +00:00
|
|
|
/*t.status = REGION_VACANT;
|
2006-07-27 00:15:29 +00:00
|
|
|
t.region_xid = xid;
|
|
|
|
|
2006-10-05 22:08:42 +00:00
|
|
|
TsetBoundaryTag(xid, firstPage -1, &t); */
|
2006-07-27 00:15:29 +00:00
|
|
|
|
|
|
|
firstPage --;
|
|
|
|
|
|
|
|
TendNestedTopAction(xid, handle);
|
2006-10-05 22:08:42 +00:00
|
|
|
|
2006-08-10 23:57:49 +00:00
|
|
|
holding_mutex = 0;
|
2006-07-18 23:59:00 +00:00
|
|
|
pthread_mutex_unlock(®ion_mutex);
|
2006-06-22 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
2006-07-27 00:15:29 +00:00
|
|
|
unsigned int TregionAlloc(int xid, unsigned int pageCount, int allocationManager) {
|
|
|
|
// Initial implementation. Naive first fit.
|
2006-10-05 22:08:42 +00:00
|
|
|
|
2006-07-27 00:15:29 +00:00
|
|
|
pthread_mutex_lock(®ion_mutex);
|
2006-08-10 23:57:49 +00:00
|
|
|
assert(0 == holding_mutex);
|
|
|
|
holding_mutex = pthread_self();
|
2006-07-27 00:15:29 +00:00
|
|
|
|
|
|
|
void * ntaHandle = TbeginNestedTopAction(xid, OPERATION_NOOP, 0, 0);
|
|
|
|
|
|
|
|
unsigned int pageid = 0;
|
|
|
|
boundary_tag t;
|
|
|
|
|
|
|
|
TreadBoundaryTag(xid, pageid, &t); // XXX need to check if there is a boundary tag there or not!
|
|
|
|
|
|
|
|
// printf("consolidateRegions pageid, t: %d, {%d, %d, %d} -> ", pageid, t.size, t.prev_size, t.status);
|
|
|
|
|
|
|
|
consolidateRegions(xid, &pageid, &t);
|
|
|
|
|
|
|
|
// printf(" %d, {%d, %d, %d}\tpageCount=%d\n", pageid, t.size, t.prev_size, t.status, pageCount);
|
|
|
|
|
|
|
|
while(t.status != REGION_VACANT || t.size < pageCount || TisActiveTransaction(t.region_xid)) {
|
|
|
|
// TODO: This while loop and the boundary tag manipulation below should be factored into two submodules.
|
|
|
|
|
|
|
|
// printf("t.status = %d, REGION_VACANT = %d, t.size = %d, pageCount = %d\n", t.status, REGION_VACANT, t.size, pageCount);
|
|
|
|
pageid += ( t.size + 1 );
|
|
|
|
TreadBoundaryTag(xid, pageid, &t);
|
|
|
|
|
|
|
|
// printf("\tconsolidateRegions pageid, t: %d, {%d, %d, %d} -> ", pageid, t.size, t.prev_size, t.status);
|
|
|
|
|
|
|
|
consolidateRegions(xid, &pageid, &t);
|
|
|
|
|
|
|
|
// printf(" %d, {%d, %d, %d}\tpageCount=%d\n", pageid, t.size, t.prev_size, t.status, pageCount);
|
|
|
|
|
|
|
|
}
|
|
|
|
// printf("page = %d, t.status = %d, REGION_VACANT = %d, t.size = %d, pageCount = %d (alloced)\n", pageid, t.status, REGION_VACANT, t.size, pageCount);
|
|
|
|
|
|
|
|
TendNestedTopAction(xid, ntaHandle);
|
|
|
|
|
|
|
|
regionAllocArg arg = { pageid, pageCount, allocationManager };
|
|
|
|
ntaHandle = TbeginNestedTopAction(xid, OPERATION_ALLOC_REGION, (const byte*)&arg, sizeof(regionAllocArg));
|
|
|
|
|
|
|
|
TregionAllocHelper(xid, pageid, pageCount, allocationManager);
|
|
|
|
|
|
|
|
TendNestedTopAction(xid, ntaHandle);
|
|
|
|
|
2006-08-10 23:57:49 +00:00
|
|
|
holding_mutex = 0;
|
2006-07-27 00:15:29 +00:00
|
|
|
pthread_mutex_unlock(®ion_mutex);
|
|
|
|
|
|
|
|
return pageid+1;
|
|
|
|
}
|
|
|
|
|
2006-06-22 19:10:02 +00:00
|
|
|
|
2006-07-18 23:59:00 +00:00
|
|
|
Operation getAllocBoundaryTag() {
|
|
|
|
Operation o = {
|
|
|
|
OPERATION_ALLOC_BOUNDARY_TAG,
|
2006-07-20 01:29:39 +00:00
|
|
|
sizeof(boundary_tag),
|
2006-07-18 23:59:00 +00:00
|
|
|
OPERATION_NOOP,
|
|
|
|
&operate_alloc_boundary_tag
|
|
|
|
};
|
|
|
|
return o;
|
2006-06-22 19:10:02 +00:00
|
|
|
}
|
|
|
|
|
2006-07-25 00:56:50 +00:00
|
|
|
Operation getAllocRegion() {
|
|
|
|
Operation o = {
|
|
|
|
OPERATION_ALLOC_REGION,
|
|
|
|
sizeof(regionAllocArg),
|
|
|
|
OPERATION_DEALLOC_REGION,
|
|
|
|
&operate_alloc_region
|
|
|
|
};
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
Operation getDeallocRegion() {
|
|
|
|
Operation o = {
|
|
|
|
OPERATION_DEALLOC_REGION,
|
|
|
|
sizeof(regionAllocArg),
|
|
|
|
OPERATION_ALLOC_REGION,
|
|
|
|
&operate_dealloc_region
|
|
|
|
};
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2006-07-20 01:29:39 +00:00
|
|
|
void TregionFindNthActive(int xid, unsigned int regionNumber, unsigned int * firstPage, unsigned int * size) {
|
|
|
|
boundary_tag t;
|
|
|
|
recordid rid = {0, 0, sizeof(boundary_tag)};
|
2006-08-11 02:25:17 +00:00
|
|
|
pthread_mutex_lock(®ion_mutex);
|
|
|
|
holding_mutex = pthread_self();
|
2006-07-20 01:29:39 +00:00
|
|
|
Tread(xid, rid, &t);
|
|
|
|
unsigned int prevSize = 0;
|
|
|
|
while(t.status == REGION_VACANT) {
|
|
|
|
rid.page += (t.size + 1);
|
|
|
|
Tread(xid, rid, &t);
|
|
|
|
assert(t.size != UINT_MAX);
|
|
|
|
assert(t.prev_size != UINT_MAX);
|
|
|
|
assert(prevSize == t.prev_size || !prevSize);
|
|
|
|
prevSize = t.size;
|
|
|
|
}
|
|
|
|
for(int i = 0; i < regionNumber; i++) {
|
|
|
|
rid.page += (t.size + 1);
|
|
|
|
Tread(xid, rid, &t);
|
|
|
|
if(t.status == REGION_VACANT) { i--; }
|
|
|
|
assert(t.size != UINT_MAX);
|
|
|
|
assert(t.prev_size != UINT_MAX || i == 0);
|
|
|
|
assert(prevSize == t.prev_size || !prevSize);
|
|
|
|
prevSize = t.size;
|
|
|
|
}
|
|
|
|
*firstPage = rid.page+1;
|
|
|
|
*size = t.size;
|
2006-08-11 02:25:17 +00:00
|
|
|
holding_mutex = 0;
|
|
|
|
pthread_mutex_unlock(®ion_mutex);
|
2006-07-20 01:29:39 +00:00
|
|
|
}
|
|
|
|
|