Reimplemented allocationPolicy.c; updated API + added more cases to the unit tests.

This commit is contained in:
Sears Russell 2009-08-05 06:35:11 +00:00
parent beb14ec917
commit 5b10bcc63b
4 changed files with 527 additions and 509 deletions

View file

@ -36,371 +36,456 @@
#include <assert.h>
#include <stdio.h>
#define ALLOCATION_POLICY_SANITY_CHECKS
/**
* Allocation Policy maintains the following tables:
*
* AllPages: _pageid_, freespace, key1: pageid
*
* XidAlloced: _xid, pageid_ key1: xid,pageid, key2: pageid,xid
* XidDealloced: _xid, pageid_: key1: xid,pageid, key2: pageid,xid
*
* And the following views:
*
* AvailablePages: (_pageid_, freespace) The rows of AllPages with no entries in xidAllloced or xidDealloced. key1: pageid, key2: freespace, pageid
* PageOwners: (xid, freespace, _pageid_) The rows of AllPages with an entry in xidAlloced, and at most one entry in xidDealloced, key1: pageid, key2 = xid, freespace, pageid
*/
// Tables:
typedef struct {
pageid_t pageid;
size_t freespace;
} allPages_pageid_freespace;
typedef struct {
int xid;
pageid_t pageid;
} xidAllocedDealloced_xid_pageid;
// Each availablePage should either be in availablePages, or in
// xidAlloced and pageOwners. If a transaction allocs and
// deallocs from the same page, then it only has an entry for that
// page in xidAlloced.
//
// xidAlloced is an lhtable of type (int xid) -> (rbtree of availablePage*)
// xidDealloced is an lhtable of type (int xid) -> (lhtable of int pageid -> availablePage *)
// pageOwners is an lhtable of type (int pageid) -> (int xid)
// availablePages is a rbtree of availablePage*.
// Views:
struct allocationPolicy {
struct LH_ENTRY(table) * xidAlloced;
struct LH_ENTRY(table) * xidDealloced;
struct RB_ENTRY(tree) * availablePages;
struct LH_ENTRY(table) * pageOwners;
struct LH_ENTRY(table) * allPages;
typedef struct {
pageid_t pageid;
size_t freespace;
} availablePages_pageid_freespace;
typedef struct {
int xid;
size_t freespace;
pageid_t pageid;
} pageOwners_xid_freespace_pageid;
struct stasis_allocation_policy_t {
// views
struct rbtree * availablePages_key_pageid;
struct rbtree * availablePages_key_freespace_pageid;
struct rbtree * pageOwners_key_pageid;
struct rbtree * pageOwners_key_xid_freespace_pageid;
// tables
struct rbtree * allPages_key_pageid;
struct rbtree * xidAlloced_key_xid_pageid;
struct rbtree * xidAlloced_key_pageid_xid;
struct rbtree * xidDealloced_key_xid_pageid;
struct rbtree * xidDealloced_key_pageid_xid;
// flags
char reuseWithinXact;
};
inline static int cmpPageid(const void * ap, const void * bp, const void * param) {
const availablePage * a = (const availablePage *)ap;
const availablePage * b = (const availablePage *)bp;
// View maintenance functions. Called by the table insertion functions.
if(a->pageid < b->pageid) {
return -1;
} else if (a->pageid > b->pageid) {
// ######## Helpers ###############
static int void_single_add(void * val, struct rbtree * a) {
const void * old = rbdelete(val, a);
rbsearch(val, a);
int found = (old != 0);
if(found) { free((void*)old); }
return found;
}
static int void_single_remove(void * val, struct rbtree * a) {
const void * old = rbdelete(val, a);
int found = (old != 0);
if(found) { free((void*)old); }
return found;
}
static int void_double_add(void * val, struct rbtree * a, struct rbtree * b) {
const void *old1, *old2 ;
old1 = rbdelete(val, a);
rbsearch(val, a);
int found1 = (old1 != 0);
old2 = rbdelete(val, b);
rbsearch(val,b);
assert(old1 == old2);
if(found1) { free((void*)old1); }
return found1;
}
static int void_double_remove(const void * val, struct rbtree * primary, struct rbtree * secondary) {
const void * fullTuple= rbdelete(val, primary);
int found1 = (fullTuple != 0);
if(found1) {
const void * old = rbdelete(fullTuple, secondary);
assert(old == fullTuple);
free((void*)fullTuple);
return 1;
} else {
return 0;
}
}
// ######## AvailablePages ###########
static int availablePages_remove(stasis_allocation_policy_t *ap, pageid_t pageid);
static int availablePages_add(stasis_allocation_policy_t *ap, pageid_t pageid, size_t freespace) {
int ret = availablePages_remove(ap, pageid);
availablePages_pageid_freespace* tup= malloc(sizeof(*tup));
tup->pageid = pageid;
tup->freespace = freespace;
void_double_add(tup, ap->availablePages_key_pageid, ap->availablePages_key_freespace_pageid);
return ret;
}
static int availablePages_remove(stasis_allocation_policy_t *ap, pageid_t pageid) {
availablePages_pageid_freespace tup = {pageid, -1};
return void_double_remove(&tup, ap->availablePages_key_pageid, ap->availablePages_key_freespace_pageid);
}
// ######## PageOwners ###########
static int pageOwners_remove(stasis_allocation_policy_t *ap, pageid_t pageid);
static int pageOwners_add(stasis_allocation_policy_t *ap, int xid, size_t freespace, pageid_t pageid) {
int ret = pageOwners_remove(ap, pageid);
pageOwners_xid_freespace_pageid * tup = malloc(sizeof(*tup));
tup->xid = xid;
tup->freespace = freespace;
tup->pageid = pageid;
void_double_add(tup, ap->pageOwners_key_pageid, ap->pageOwners_key_xid_freespace_pageid);
return ret;
}
static int pageOwners_remove(stasis_allocation_policy_t *ap, pageid_t pageid) {
pageOwners_xid_freespace_pageid tup = { INVALID_XID, -1, pageid };
return void_double_remove(&tup, ap->pageOwners_key_pageid, ap->pageOwners_key_xid_freespace_pageid);
}
int pageOwners_lookup_by_xid_freespace(stasis_allocation_policy_t *ap, int xid, size_t freespace, pageid_t* pageid) {
pageOwners_xid_freespace_pageid query = { xid, freespace, 0 };
// find lowest numbered page w/ enough freespace.
const pageOwners_xid_freespace_pageid *tup = rblookup(RB_LUGTEQ, &query, ap->pageOwners_key_xid_freespace_pageid);
if(tup && tup->xid == xid) {
assert(tup->freespace >= freespace);
*pageid = tup->pageid;
return 1;
} else {
return 0;
}
}
int pageOwners_lookup_by_pageid(stasis_allocation_policy_t* ap, pageid_t pageid, int *xid, size_t *freespace) {
const pageOwners_xid_freespace_pageid query = { 0, 0, pageid };
const pageOwners_xid_freespace_pageid *tup = rbfind(&query, ap->pageOwners_key_pageid);
if(tup) {
*xid = tup->xid;
*freespace = tup->freespace;
return 1;
} else {
return 0;
}
}
/// TABLE METHODS FOLLOW. These functions perform view maintenance.
// ######## AllPages #############
static int allPages_lookup_by_pageid(stasis_allocation_policy_t *ap, pageid_t pageid, size_t *freespace) {
allPages_pageid_freespace query = {pageid, 0};
const allPages_pageid_freespace * tup = rbfind(&query, ap->allPages_key_pageid);
if(tup) {
assert(tup->pageid == pageid);
*freespace = tup->freespace;
return 1;
} else {
return 0;
}
}
static int allPages_add(stasis_allocation_policy_t *ap, pageid_t pageid, size_t freespace) {
allPages_pageid_freespace * tup = malloc(sizeof(*tup));
tup->pageid = pageid;
tup->freespace = freespace;
int ret = void_single_add(tup, ap->allPages_key_pageid);
if(!ret) {
int ret2 = availablePages_add(ap, pageid, freespace);
assert(!ret2);
} else {
// page may or may not be in availablePages...
}
return ret;
}
/** Assumes that the page is not in use by an outstanding xact */
static int allPages_remove(stasis_allocation_policy_t *ap, pageid_t pageid) {
allPages_pageid_freespace tup = { pageid, -1 };
int found = void_single_remove(&tup, ap->allPages_key_pageid);
int found2 = availablePages_remove(ap, pageid);
assert(found == found2);
return found;
}
static void allPages_removeAll(stasis_allocation_policy_t *ap) {
const allPages_pageid_freespace * tup;
while((tup = rbmin(ap->allPages_key_pageid))) {
allPages_remove(ap, tup->pageid);
}
}
static void allPages_set_freespace(stasis_allocation_policy_t *ap, pageid_t pageid, size_t freespace) {
allPages_pageid_freespace * tup = malloc(sizeof(*tup));
tup->pageid = pageid;
tup->freespace = freespace;
int existed = void_single_add(tup, ap->allPages_key_pageid);
assert(existed);
int availableExisted = availablePages_remove(ap, pageid);
if(availableExisted) {
availablePages_add(ap, pageid, freespace);
}
int xid;
size_t oldfreespace;
int ownerExisted = pageOwners_lookup_by_pageid(ap, pageid, &xid, &oldfreespace);
if(ownerExisted) {
pageOwners_add(ap, xid, freespace, pageid);
}
assert(!(ownerExisted && availableExisted));
}
static int xidAllocedDealloced_helper_lookup_by_xid(struct rbtree *t, int xid, pageid_t **pages, size_t*count) {
xidAllocedDealloced_xid_pageid query = {xid, -1};
const xidAllocedDealloced_xid_pageid *tup = rblookup(RB_LUGTEQ, &query, t);
int ret = 0;
*pages = 0;
*count = 0;
while(tup && tup->xid == xid) {
ret = 1;
// add pageid to ret value
(*count)++;
*pages = realloc(*pages, *count * sizeof(*pages[0]));
// printf("pages %x count %x *pages %x len %lld \n", pages, count, *pages, *count * sizeof(*pages[0]));
fflush(stdout);
(*pages)[(*count) - 1] = tup->pageid;
tup = rblookup(RB_LUGREAT, tup, t);
}
return ret;
}
static int xidAllocedDealloced_helper_lookup_by_pageid(struct rbtree *t, pageid_t pageid, int ** xids, size_t * count) {
xidAllocedDealloced_xid_pageid query = {-1, pageid};
const xidAllocedDealloced_xid_pageid *tup = rblookup(RB_LUGTEQ, &query, t);
int ret = 0;
*xids = 0;
*count = 0;
while (tup && tup->pageid == pageid) {
ret = 1;
// add xid to ret value.
(*count)++;
*xids = realloc(*xids, *count * sizeof(*xids[0]));
(*xids)[(*count) - 1] = tup->xid;
tup = rblookup(RB_LUGREAT, tup, t);
}
return ret;
}
static int xidAlloced_lookup_by_pageid(stasis_allocation_policy_t *ap, pageid_t pageid, int **xids, size_t * count);
static int xidDealloced_lookup_by_pageid(stasis_allocation_policy_t *ap, pageid_t pageid, int **xids, size_t * count);
static int update_views_for_page(stasis_allocation_policy_t *ap, pageid_t pageid) {
size_t xidAllocCount;
size_t xidDeallocCount;
int ret = 0;
int * allocXids;
int * deallocXids;
size_t freespace;
int inAllPages = allPages_lookup_by_pageid(ap, pageid, &freespace);
assert(inAllPages);
int inXidAlloced = xidAlloced_lookup_by_pageid(ap, pageid, &allocXids, &xidAllocCount);
int inXidDealloced = xidDealloced_lookup_by_pageid(ap, pageid, &deallocXids, &xidDeallocCount);
if(! inXidAlloced) { xidAllocCount = 0; allocXids = 0;}
if(! inXidDealloced) { xidDeallocCount = 0; deallocXids = 0; }
if(xidAllocCount == 0 && xidDeallocCount == 0) {
pageOwners_remove(ap, pageid);
availablePages_add(ap, pageid, freespace);
} else if ((xidAllocCount == 1 && xidDeallocCount == 0)
|| (xidAllocCount == 1 && xidDeallocCount == 1 && ap->reuseWithinXact && (allocXids[0] == deallocXids[0]))) {
pageOwners_add(ap, allocXids[0], freespace, pageid);
availablePages_remove(ap, pageid);
} else {
pageOwners_remove(ap, pageid);
availablePages_remove(ap, pageid);
}
if(allocXids) { free(allocXids); }
if(deallocXids) { free(deallocXids); }
return ret;
}
static int xidAllocedDealloced_helper_add(stasis_allocation_policy_t *ap, struct rbtree *first, struct rbtree* second, int xid, pageid_t pageid) {
xidAllocedDealloced_xid_pageid * tup = malloc(sizeof(*tup));
tup->xid = xid;
tup->pageid = pageid;
int existed = void_double_add(tup, first, second);
if(!existed) {
update_views_for_page(ap, pageid);
}
return existed;
}
static int xidAllocedDealloced_helper_remove(stasis_allocation_policy_t *ap, struct rbtree *first, struct rbtree*second, int xid, pageid_t pageid) {
xidAllocedDealloced_xid_pageid query = { xid, pageid };
int existed = void_double_remove(&query, first, second);
if(existed) {
update_views_for_page(ap, pageid);
}
return existed;
}
static int xidAlloced_lookup_by_xid(stasis_allocation_policy_t *ap, int xid, pageid_t ** pages, size_t * count) {
return xidAllocedDealloced_helper_lookup_by_xid(ap->xidAlloced_key_xid_pageid, xid, pages, count);
}
static int xidAlloced_lookup_by_pageid(stasis_allocation_policy_t *ap, pageid_t pageid, int **xids, size_t * count) {
return xidAllocedDealloced_helper_lookup_by_pageid(ap->xidAlloced_key_pageid_xid, pageid, xids, count);
}
static int xidAlloced_add(stasis_allocation_policy_t * ap, int xid, pageid_t pageid) {
return xidAllocedDealloced_helper_add(ap, ap->xidAlloced_key_pageid_xid, ap->xidAlloced_key_xid_pageid, xid, pageid);
}
static int xidAlloced_remove(stasis_allocation_policy_t * ap, int xid, pageid_t pageid) {
return xidAllocedDealloced_helper_remove(ap, ap->xidAlloced_key_pageid_xid, ap->xidAlloced_key_xid_pageid, xid, pageid);
}
static int xidDealloced_lookup_by_xid(stasis_allocation_policy_t *ap, int xid, pageid_t ** pages, size_t * count) {
return xidAllocedDealloced_helper_lookup_by_xid(ap->xidDealloced_key_xid_pageid, xid, pages, count);
}
static int xidDealloced_lookup_by_pageid(stasis_allocation_policy_t *ap, pageid_t pageid, int **xids, size_t * count) {
return xidAllocedDealloced_helper_lookup_by_pageid(ap->xidDealloced_key_pageid_xid, pageid, xids, count);
}
static int xidDealloced_add(stasis_allocation_policy_t * ap, int xid, pageid_t pageid) {
return xidAllocedDealloced_helper_add(ap, ap->xidDealloced_key_pageid_xid, ap->xidDealloced_key_xid_pageid, xid, pageid);
}
static int xidDealloced_remove(stasis_allocation_policy_t * ap, int xid, pageid_t pageid) {
return xidAllocedDealloced_helper_remove(ap, ap->xidDealloced_key_pageid_xid, ap->xidDealloced_key_xid_pageid, xid, pageid);
}
static int availablePages_cmp_pageid(const void *ap, const void *bp, const void* ign) {
const availablePages_pageid_freespace *a = ap, *b = bp;
return a->pageid < b->pageid ? -1 : a->pageid > b->pageid ? 1 : 0;
}
static int availablePages_cmp_freespace_pageid(const void *ap, const void *bp, const void* ign) {
const availablePages_pageid_freespace *a = ap, *b = bp;
return a->freespace < b->freespace ? -1 : a->freespace > b->freespace ? 1 : a->pageid < b->pageid ? -1 : a->pageid > b->pageid ? 1 : 0;
}
int availablePages_lookup_by_freespace(stasis_allocation_policy_t *ap, size_t freespace, pageid_t *pageid) {
const availablePages_pageid_freespace query = { 0, freespace };
const availablePages_pageid_freespace *tup = rblookup(RB_LUGTEQ, &query, ap->availablePages_key_freespace_pageid);
if(tup && tup->freespace >= freespace ) {
*pageid = tup->pageid;
return 1;
} else {
return 0;
}
}
static int cmpFreespace(const void * ap, const void * bp, const void * param) {
const availablePage * a = (const availablePage *) ap;
const availablePage * b = (const availablePage *) bp;
if(a->freespace < b->freespace) {
return -1;
} else if (a->freespace > b->freespace) {
return 1;
} else {
return cmpPageid(ap,bp,param);
}
static int pageOwners_cmp_pageid(const void *ap, const void *bp, const void* ign) {
const pageOwners_xid_freespace_pageid *a = ap, *b = bp;
return a->pageid < b->pageid ? -1 : a->pageid > b->pageid ? 1 : 0;
}
inline static availablePage* getAvailablePage(stasis_allocation_policy_t * ap, pageid_t pageid) {
return (availablePage*) LH_ENTRY(find)(ap->allPages, &pageid, sizeof(pageid));
static int pageOwners_cmp_xid_freespace_pageid(const void *ap, const void *bp, const void* ign) {
const pageOwners_xid_freespace_pageid *a = ap, *b = bp;
return a->xid < b->xid ? -1 : a->xid > b->xid ? 1 : a->freespace < b->freespace ? -1 : a->freespace > b->freespace ? 1 : a->pageid < b->pageid ? -1 : a->pageid > b->pageid ? 1 : 0;
}
inline static void insert_xidAlloced(stasis_allocation_policy_t * ap, int xid, availablePage * p) {
struct RB_ENTRY(tree) * pages = LH_ENTRY(find)(ap->xidAlloced, &xid, sizeof(xid));
if(!pages) {
pages = RB_ENTRY(init)(cmpFreespace, 0);
LH_ENTRY(insert)(ap->xidAlloced, &xid, sizeof(xid), pages);
}
const availablePage * check = RB_ENTRY(search)(p, pages);
assert(check == p);
static int allPages_cmp_pageid(const void *ap, const void *bp, const void* ign) {
const allPages_pageid_freespace *a = ap, *b = bp;
return a->pageid < b->pageid ? -1 : a->pageid > b->pageid ? 1 : 0;
}
inline static void remove_xidAlloced(stasis_allocation_policy_t * ap, int xid, availablePage * p) {
assert(p->lockCount);
struct RB_ENTRY(tree) * pages = LH_ENTRY(find)(ap->xidAlloced, &xid, sizeof(xid));
assert(pages);
const availablePage * check = RB_ENTRY(delete)(p, pages);
assert(check == p); // sometimes fails
static int xidAllocedDealloced_cmp_pageid_xid(const void *ap, const void *bp, const void* ign) {
const xidAllocedDealloced_xid_pageid *a = ap, *b = bp;
return a->pageid < b->pageid ? -1 : a->pageid > b->pageid ? 1 : a->xid < b->xid ? -1 : a->xid > b->xid ? 1 : 0;
}
inline static void insert_xidDealloced(stasis_allocation_policy_t * ap, int xid, availablePage * p) {
struct RB_ENTRY(tree) * pages = LH_ENTRY(find)(ap->xidDealloced, &xid, sizeof(xid));
if(!pages) {
pages = RB_ENTRY(init)(cmpPageid, 0);
LH_ENTRY(insert)(ap->xidDealloced, &xid, sizeof(xid), pages);
}
assert(pages);
const availablePage * check = RB_ENTRY(search)(p, pages);
// XXX Assert that the page wasn't already there?
assert(check);
}
inline static void remove_xidDealloced(stasis_allocation_policy_t * ap, int xid, availablePage * p) {
struct RB_ENTRY(tree) * pages = LH_ENTRY(find)(ap->xidDealloced, &xid, sizeof(xid));
assert(pages);
const availablePage * check = RB_ENTRY(delete)(p, pages);
assert(check == p);
}
inline static int find_xidDealloced(stasis_allocation_policy_t * ap, int xid, availablePage * p) {
struct RB_ENTRY(tree) * pages = LH_ENTRY(find)(ap->xidDealloced, &xid, sizeof(xid));
if(!pages) { return 0; }
const availablePage * check = RB_ENTRY(find)(p, pages);
if(check) {
return 1;
} else {
return 0;
}
}
inline static void lockAlloced(stasis_allocation_policy_t * ap, int xid, availablePage * p) {
const availablePage * check = RB_ENTRY(delete)(p, ap->availablePages);
assert(check == p);
assert(p->lockCount == 0);
p->lockCount = 1;
int * xidp = malloc(sizeof(int));
*xidp = xid;
LH_ENTRY(insert)(ap->pageOwners, &(p->pageid), sizeof(p->pageid), xidp);
insert_xidAlloced(ap, xid, p);
}
inline static void unlockAlloced(stasis_allocation_policy_t * ap, int xid, availablePage * p) {
remove_xidAlloced(ap, xid, p);
p->lockCount--;
// assert(p->lockCount == 1);
// p->lockCount = 0;
if(!p->lockCount) {
const availablePage * check = RB_ENTRY(search)(p, ap->availablePages);
assert(check == p);
}
int * xidp = LH_ENTRY(remove)(ap->pageOwners, &(p->pageid), sizeof(p->pageid));
//assert(*xidp == xid);
if(xidp) { free(xidp); }
}
inline static void lockDealloced(stasis_allocation_policy_t * ap, int xid, availablePage * p) {
if(p->lockCount == 0) {
// xid should own it
lockAlloced(ap, xid, p);
} else if(p->lockCount == 1) {
int * xidp = LH_ENTRY(find)(ap->pageOwners, &(p->pageid), sizeof(p->pageid));
if(!xidp) {
// The only active transaction that touched this page deallocated from it,
// so just add the page to our dealloced table.
p->lockCount++;
insert_xidDealloced(ap, xid, p);
} else if(*xidp != xid) {
// Remove from the other transaction's "alloced" table.
remove_xidAlloced(ap, *xidp, p);
assert(p->lockCount == 1);
// Place in other transaction's "dealloced" table.
insert_xidDealloced(ap, *xidp, p);
// This page no longer has an owner
LH_ENTRY(remove)(ap->pageOwners, &(p->pageid), sizeof(p->pageid));
free(xidp);
// Add to our "dealloced" table, increment lockCount.
p->lockCount++;
insert_xidDealloced(ap, xid, p);
}
} else {
// not owned by anyone... is it already in this xid's Dealloced table?
if(!find_xidDealloced(ap, xid, p)) {
p->lockCount++;
insert_xidDealloced(ap, xid, p);
}
}
}
inline static void unlockDealloced(stasis_allocation_policy_t * ap, int xid, availablePage * p) {
assert(p->lockCount > 0);
p->lockCount--;
remove_xidDealloced(ap, xid, p);
if(!p->lockCount) {
// put it back into available pages.
LH_ENTRY(remove)(ap->pageOwners, &(p->pageid), sizeof(p->pageid)); // XXX new feb-29
const availablePage * check = RB_ENTRY(search)(p, ap->availablePages);
assert(check == p);
}
static int xidAllocedDealloced_cmp_xid_pageid(const void *ap, const void *bp, const void* ign) {
const xidAllocedDealloced_xid_pageid *a = ap, *b = bp;
return a->xid < b->xid ? -1 : a->xid > b->xid ? 1 : a->pageid < b->pageid ? -1 : a->pageid > b->pageid ? 1 : 0;
}
stasis_allocation_policy_t * stasis_allocation_policy_init() {
stasis_allocation_policy_t * ap = malloc(sizeof(stasis_allocation_policy_t));
ap->xidAlloced = LH_ENTRY(create)(10);
ap->xidDealloced = LH_ENTRY(create)(10);
ap->availablePages = RB_ENTRY(init)(cmpFreespace, 0);
ap->pageOwners = LH_ENTRY(create)(10);
ap->allPages = LH_ENTRY(create)(10);
stasis_allocation_policy_t * ap = malloc(sizeof(*ap));
ap->availablePages_key_pageid = rbinit(availablePages_cmp_pageid, 0);
ap->availablePages_key_freespace_pageid = rbinit(availablePages_cmp_freespace_pageid, 0);
ap->pageOwners_key_pageid = rbinit(pageOwners_cmp_pageid, 0);
ap->pageOwners_key_xid_freespace_pageid = rbinit(pageOwners_cmp_xid_freespace_pageid, 0);
ap->allPages_key_pageid = rbinit(allPages_cmp_pageid, 0);
ap->xidAlloced_key_pageid_xid = rbinit(xidAllocedDealloced_cmp_pageid_xid, 0);
ap->xidAlloced_key_xid_pageid = rbinit(xidAllocedDealloced_cmp_xid_pageid, 0);
ap->xidDealloced_key_pageid_xid = rbinit(xidAllocedDealloced_cmp_pageid_xid, 0);
ap->xidDealloced_key_xid_pageid = rbinit(xidAllocedDealloced_cmp_xid_pageid, 0);
ap->reuseWithinXact = 0;
return ap;
}
void stasis_allocation_policy_deinit(stasis_allocation_policy_t * ap) {
const availablePage * next;
while(( next = RB_ENTRY(min)(ap->availablePages) )) {
RB_ENTRY(delete)(next, ap->availablePages);
free((void*)next);
}
LH_ENTRY(destroy)(ap->xidAlloced);
LH_ENTRY(destroy)(ap->xidDealloced);
RB_ENTRY(destroy)(ap->availablePages);
LH_ENTRY(destroy)(ap->pageOwners);
LH_ENTRY(destroy)(ap->allPages);
allPages_removeAll(ap); // frees entries in availablePages, asserts that all pages are available.
rbdestroy(ap->availablePages_key_pageid);
rbdestroy(ap->availablePages_key_freespace_pageid);
rbdestroy(ap->pageOwners_key_pageid);
rbdestroy(ap->pageOwners_key_xid_freespace_pageid);
rbdestroy(ap->allPages_key_pageid);
rbdestroy(ap->xidAlloced_key_pageid_xid);
rbdestroy(ap->xidAlloced_key_xid_pageid);
rbdestroy(ap->xidDealloced_key_pageid_xid);
rbdestroy(ap->xidDealloced_key_xid_pageid);
free(ap);
}
void stasis_allocation_policy_register_new_pages(stasis_allocation_policy_t * ap, availablePage** newPages) {
for(int i = 0; newPages[i] != 0; i++) {
const availablePage * ret = RB_ENTRY(search)(newPages[i], ap->availablePages);
assert(ret == newPages[i]);
LH_ENTRY(insert)(ap->allPages, &(newPages[i]->pageid), sizeof(newPages[i]->pageid), newPages[i]);
}
void stasis_allocation_policy_register_new_page(stasis_allocation_policy_t * ap, pageid_t pageid, size_t freespace) {
int existed = allPages_add(ap,pageid,freespace);
assert(!existed);
}
/// XXX need updateAlloced, updateFree, which remove a page, change
/// its freespace / lockCount, and then re-insert them into the tree.
availablePage * stasis_allocation_policy_pick_suitable_page(stasis_allocation_policy_t * ap, int xid, int freespace) {
// For the best fit amongst the pages in availablePages, call:
//
// rblookup(RB_LUGREAT, key, availablePages)
//
// For the page with the most freespace, call:
//
// rbmax(availablePages);
//
availablePage tmp = { .freespace = freespace, .pageid = 0, .lockCount = 0 };
struct RB_ENTRY(tree) * locks;
// If we haven't heard of this transaction yet, then create an entry
// for it.
if(0 == (locks = LH_ENTRY(find)(ap->xidAlloced, &xid, sizeof(xid)))) {
// Since this is cmpPageid, we can change the amount of freespace
// without modifying the tree.
locks = RB_ENTRY(init)(cmpFreespace, 0);
LH_ENTRY(insert)(ap->xidAlloced, &xid, sizeof(xid), locks);
}
const availablePage *ret;
// Does this transaction already have an appropriate page?
if(!(ret = RB_ENTRY(lookup)(RB_LUGREAT, &tmp, locks))) {
// No; get a page from the availablePages.
ret = RB_ENTRY(lookup)(RB_LUGREAT, &tmp, ap->availablePages);
/*if(ret) {
assert(ret->lockCount == 0);
lockAlloced(ap, xid, (availablePage*) ret);
} */
}
// Done. (If ret is null, then it's the caller's problem.)
return (availablePage*) ret;
}
int stasis_allocation_policy_can_xid_alloc_from_page(stasis_allocation_policy_t *ap, int xid, pageid_t page) {
availablePage * p = getAvailablePage(ap, page);
const availablePage * check1 = RB_ENTRY(find)(p, ap->availablePages);
int * xidp = LH_ENTRY(find)(ap->pageOwners, &(page), sizeof(page));
if(!(xidp || check1)) {
// the page is not available, and not owned.
return 0; // can't safely alloc from page
}
if(check1) {
// the page is available and unlocked
return 1; // can safely alloc from page
pageid_t stasis_allocation_policy_pick_suitable_page(stasis_allocation_policy_t * ap, int xid, size_t freespace) {
// does the xid have a suitable page?
pageid_t pageid;
int found = pageOwners_lookup_by_xid_freespace(ap, xid, freespace, &pageid);
if(found) { return pageid; }
// pick one from global pool.
found = availablePages_lookup_by_freespace(ap, freespace, &pageid);
if(found) {
return pageid;
} else {
// someone owns the page. Is it this xid?
return (*xidp == xid);
return INVALID_PAGE;
}
}
void stasis_allocation_policy_transaction_completed(stasis_allocation_policy_t * ap, int xid) {
pageid_t *allocPages;
pageid_t *deallocPages;
size_t allocCount;
size_t deallocCount;
int alloced = xidAlloced_lookup_by_xid(ap, xid, &allocPages, &allocCount);
int dealloced = xidDealloced_lookup_by_xid(ap, xid, &deallocPages, &deallocCount);
void stasis_allocation_policy_alloced_from_page(stasis_allocation_policy_t *ap, int xid, pageid_t page) {
availablePage * p = getAvailablePage(ap, page);
const availablePage * check1 = RB_ENTRY(find)(p, ap->availablePages);
int * xidp = LH_ENTRY(find)(ap->pageOwners, &(page), sizeof(page));
if(!(xidp || check1)) {
// the page is not available, and is not owned.
// this can happen if more than one transaction deallocs from the same page
assert(p->lockCount);
printf("Two transactions concurrently dealloced from page; now a "
"transaction has alloced from it. This leads to unrecoverable "
"schedules. Refusing to continue.");
fflush(stdout);
if(alloced) {
for(size_t i = 0; i < allocCount; i++) {
xidAlloced_remove(ap, xid, allocPages[i]);
}
free(allocPages);
}
if(dealloced) {
for(size_t i = 0; i < deallocCount; i++) {
xidDealloced_remove(ap, xid, deallocPages[i]);
}
free(deallocPages);
}
}
void stasis_allocation_policy_update_freespace(stasis_allocation_policy_t *ap, pageid_t pageid, size_t freespace) {
allPages_set_freespace(ap, pageid, freespace);
}
void stasis_allocation_policy_dealloced_from_page(stasis_allocation_policy_t *ap, int xid, pageid_t pageid) {
xidDealloced_add(ap, xid, pageid);
}
void stasis_allocation_policy_alloced_from_page(stasis_allocation_policy_t * ap, int xid, pageid_t pageid) {
if(!stasis_allocation_policy_can_xid_alloc_from_page(ap, xid, pageid)) {
fprintf(stderr, "A transaction allocated space from a page that contains records deallocated by another active transaction. "
"This leads to unrecoverable schedules. Refusing to continue.");
fflush(stderr);
abort();
}
if(check1) {
assert(p->lockCount == 0);
lockAlloced(ap, xid, (availablePage*)p);
} else {
// new: this xact is allocing on a page that an active xact alloced on.
// perhaps this is safe, but it's spooky.
assert(*xidp == xid);
xidAlloced_add(ap, xid, pageid);
}
int stasis_allocation_policy_can_xid_alloc_from_page(stasis_allocation_policy_t * ap, int xid, pageid_t pageid) {
int *xids;
size_t count;
int ret = 1;
int existed = xidDealloced_lookup_by_pageid(ap, pageid, &xids, &count);
if(!existed) { count = 0; xids = 0;}
for(size_t i = 0; i < count ; i++) {
if(xids[i] != xid) { ret = 0; }
}
}
void stasis_allocation_policy_lock_page(stasis_allocation_policy_t *ap, int xid, pageid_t page) {
availablePage * p = getAvailablePage(ap, page);
lockDealloced(ap, xid, p);
}
void stasis_allocation_policy_transaction_completed(stasis_allocation_policy_t * ap, int xid) {
struct RB_ENTRY(tree) * locks = LH_ENTRY(find)(ap->xidAlloced, &xid, sizeof(xid));
if(locks) {
availablePage * next;
while(( next = (void*)RB_ENTRY(min)(locks) )) {
unlockAlloced(ap, xid, (next)); // This is really inefficient. (We're wasting hashtable lookups. Also, an iterator would be faster.)
}
LH_ENTRY(remove)(ap->xidAlloced, &xid, sizeof(xid));
RB_ENTRY(destroy)(locks);
}
locks = LH_ENTRY(find)(ap->xidDealloced, &xid, sizeof(xid));
if(locks) {
availablePage * next;
while(( next = (void*)RB_ENTRY(min)(locks) )) {
unlockDealloced(ap, xid, (availablePage*)next); // This is really inefficient. (We're wasting hashtable lookups. Also, an iterator would be faster.)
}
LH_ENTRY(remove)(ap->xidDealloced, &xid, sizeof(xid));
RB_ENTRY(destroy)(locks);
}
}
void stasis_allocation_policy_update_freespace_unlocked_page(stasis_allocation_policy_t * ap, availablePage * key, int newFree) {
availablePage * p = (availablePage*) RB_ENTRY(delete)(key, ap->availablePages);
assert(key == p);
p->freespace = newFree;
const availablePage * ret = RB_ENTRY(search)(p, ap->availablePages);
assert(ret == p);
}
void stasis_allocation_policy_update_freespace_locked_page(stasis_allocation_policy_t * ap, int xid, availablePage * key, int newFree) {
struct RB_ENTRY(tree) * locks = LH_ENTRY(find)(ap->xidAlloced, &xid, sizeof(xid));
assert(key);
availablePage * p = (availablePage*) RB_ENTRY(delete)(key, locks);
assert(p); // sometimes fails
p->freespace = newFree;
key->freespace = newFree;
const availablePage * ret = RB_ENTRY(search)(p, locks);
assert(ret == p);
assert(p->lockCount == 1);
if(xids) { free(xids); }
return ret;
}

View file

@ -222,26 +222,18 @@ static void stasis_alloc_register_old_regions() {
do {
DEBUG("boundary tag %lld type %d\n", boundary, t.allocation_manager);
if(t.allocation_manager == STORAGE_MANAGER_TALLOC) {
availablePage ** newPages = malloc(sizeof(availablePage*)*(t.size+1));
for(pageid_t i = 0; i < t.size; i++) {
Page * p = loadPage(-1, boundary + i);
readlock(p->rwlatch,0);
if(p->pageType == SLOTTED_PAGE) {
availablePage * next = malloc(sizeof(availablePage));
next->pageid = boundary+i;
next->freespace = stasis_record_freespace(-1, p);
next->lockCount = 0;
newPages[i] = next;
DEBUG("registered page %lld\n", boundary+i);
} else {
abort();
}
unlock(p->rwlatch);
releasePage(p);
}
newPages[t.size]=0;
stasis_allocation_policy_register_new_pages(allocPolicy, newPages);
free(newPages);
for(pageid_t i = 0; i < t.size; i++) {
Page * p = loadPage(-1, boundary + i);
readlock(p->rwlatch,0);
if(p->pageType == SLOTTED_PAGE) {
stasis_allocation_policy_register_new_page(allocPolicy, p->id, stasis_record_freespace(-1, p));
DEBUG("registered page %lld\n", boundary+i);
} else {
abort();
}
unlock(p->rwlatch);
releasePage(p);
}
}
} while(TregionNextBoundaryTag(-1, &boundary, &t, 0)); //STORAGE_MANAGER_TALLOC)) {
}
@ -253,11 +245,7 @@ static void stasis_alloc_reserve_new_region(int xid) {
pageid_t firstPage = TregionAlloc(xid, TALLOC_REGION_SIZE, STORAGE_MANAGER_TALLOC);
int initialFreespace = -1;
availablePage ** newPages = malloc(sizeof(availablePage*)*(TALLOC_REGION_SIZE+1));
for(pageid_t i = 0; i < TALLOC_REGION_SIZE; i++) {
availablePage * next = malloc(sizeof(availablePage)); // * TALLOC_REGION_SIZE);
TinitializeSlottedPage(xid, firstPage + i);
if(initialFreespace == -1) {
Page * p = loadPage(xid, firstPage);
@ -266,17 +254,10 @@ static void stasis_alloc_reserve_new_region(int xid) {
unlock(p->rwlatch);
releasePage(p);
}
next->pageid = firstPage + i;
next->freespace = initialFreespace;
next->lockCount = 0;
newPages[i] = next;
stasis_allocation_policy_register_new_page(allocPolicy, firstPage + i, initialFreespace);
}
newPages[TALLOC_REGION_SIZE]= 0;
stasis_allocation_policy_register_new_pages(allocPolicy, newPages);
free(newPages); // Don't free the structs it points to; they are in use by the allocation policy.
TendNestedTopAction(xid, nta);
}
compensated_function recordid Talloc(int xid, unsigned long size) {
@ -293,16 +274,16 @@ compensated_function recordid Talloc(int xid, unsigned long size) {
begin_action_ret(pthread_mutex_unlock, &talloc_mutex, NULLRID) {
pthread_mutex_lock(&talloc_mutex);
availablePage * ap =
pageid_t pageid =
stasis_allocation_policy_pick_suitable_page(allocPolicy, xid,
stasis_record_type_to_size(type));
if(!ap) {
if(pageid == INVALID_PAGE) {
stasis_alloc_reserve_new_region(xid);
ap = stasis_allocation_policy_pick_suitable_page(allocPolicy, xid,
pageid = stasis_allocation_policy_pick_suitable_page(allocPolicy, xid,
stasis_record_type_to_size(type));
}
lastFreepage = ap->pageid;
lastFreepage = pageid;
Page * p = loadPage(xid, lastFreepage);
@ -316,25 +297,19 @@ compensated_function recordid Talloc(int xid, unsigned long size) {
}
unlock(p->rwlatch);
if(!ap->lockCount) {
stasis_allocation_policy_update_freespace_unlocked_page(allocPolicy, ap,
newFreespace);
} else {
stasis_allocation_policy_update_freespace_locked_page(allocPolicy, xid, ap,
newFreespace);
}
stasis_allocation_policy_update_freespace(allocPolicy, pageid, newFreespace);
releasePage(p);
ap = stasis_allocation_policy_pick_suitable_page(allocPolicy, xid,
pageid = stasis_allocation_policy_pick_suitable_page(allocPolicy, xid,
stasis_record_type_to_size(type));
if(!ap) {
if(pageid == INVALID_PAGE) {
stasis_alloc_reserve_new_region(xid);
ap = stasis_allocation_policy_pick_suitable_page(allocPolicy, xid,
pageid = stasis_allocation_policy_pick_suitable_page(allocPolicy, xid,
stasis_record_type_to_size(type));
}
lastFreepage = ap->pageid;
lastFreepage = pageid;
p = loadPage(xid, lastFreepage);
writelock(p->rwlatch, 0);
@ -346,8 +321,8 @@ compensated_function recordid Talloc(int xid, unsigned long size) {
stasis_record_alloc_done(xid, p, rid);
int newFreespace = stasis_record_freespace(xid, p);
stasis_allocation_policy_alloced_from_page(allocPolicy, xid, ap->pageid);
stasis_allocation_policy_update_freespace_locked_page(allocPolicy, xid, ap, newFreespace);
stasis_allocation_policy_alloced_from_page(allocPolicy, xid, pageid);
stasis_allocation_policy_update_freespace(allocPolicy, pageid, newFreespace);
unlock(p->rwlatch);
alloc_arg a = { rid.slot, type };
@ -431,7 +406,7 @@ compensated_function void Tdealloc(int xid, recordid rid) {
readlock(p->rwlatch,0);
recordid newrid = stasis_record_dereference(xid, p, rid);
stasis_allocation_policy_lock_page(allocPolicy, xid, newrid.page);
stasis_allocation_policy_dealloced_from_page(allocPolicy, xid, newrid.page);
int64_t size = stasis_record_length_read(xid,p,rid);
int64_t type = stasis_record_type_read(xid,p,rid);

View file

@ -3,23 +3,16 @@
#include <stasis/common.h>
struct allocationPolicy;
typedef struct allocationPolicy stasis_allocation_policy_t;
typedef struct availablePage {
int freespace;
pageid_t pageid;
int lockCount; // Number of active transactions that have alloced or dealloced from this page.
} availablePage;
struct stasis_allocation_policy_t;
typedef struct stasis_allocation_policy_t stasis_allocation_policy_t;
stasis_allocation_policy_t * stasis_allocation_policy_init();
void stasis_allocation_policy_deinit(stasis_allocation_policy_t * ap);
void stasis_allocation_policy_register_new_pages(stasis_allocation_policy_t * ap, availablePage** newPages);
availablePage * stasis_allocation_policy_pick_suitable_page(stasis_allocation_policy_t * ap, int xid, int freespace);
void stasis_allocation_policy_register_new_page(stasis_allocation_policy_t * ap, pageid_t page, size_t freespace); //availablePage** newPages);
pageid_t stasis_allocation_policy_pick_suitable_page(stasis_allocation_policy_t * ap, int xid, size_t freespace);
void stasis_allocation_policy_transaction_completed(stasis_allocation_policy_t * ap, int xid);
void stasis_allocation_policy_update_freespace_unlocked_page(stasis_allocation_policy_t * ap, availablePage * key, int newFree);
void stasis_allocation_policy_update_freespace_locked_page(stasis_allocation_policy_t * ap, int xid, availablePage * key, int newFree);
void stasis_allocation_policy_lock_page(stasis_allocation_policy_t * ap, int xid, pageid_t page);
void stasis_allocation_policy_update_freespace(stasis_allocation_policy_t * ap, pageid_t pageid, size_t freespace);
void stasis_allocation_policy_dealloced_from_page(stasis_allocation_policy_t * ap, int xid, pageid_t page);
void stasis_allocation_policy_alloced_from_page(stasis_allocation_policy_t * ap, int xid, pageid_t page);
/**
Check to see if it is safe to allocate from a particular page.

View file

@ -44,6 +44,7 @@ terms specified in this license.
#include <stasis/allocationPolicy.h>
#include <stasis/common.h>
#include <stasis/constants.h>
#include <sys/time.h>
#include <time.h>
@ -58,89 +59,61 @@ terms specified in this license.
START_TEST(allocationPolicy_smokeTest)
{
availablePage ** pages = malloc(5 * sizeof(availablePage*));
for(int i = 0; i < 4; i++) {
pages[i] = malloc(sizeof(availablePage));
}
availablePage p;
p.pageid = 0;
p.freespace = 100;
p.lockCount = 0;
(*pages[0]) = p;
p.pageid = 1;
p.freespace = 100;
(*pages[1]) = p;
p.pageid = 2;
p.freespace = 50;
(*pages[2]) = p;
p.pageid = 3;
p.freespace = 25;
(*pages[3]) = p;
pages[4] = 0;
stasis_allocation_policy_t * ap = stasis_allocation_policy_init();
stasis_allocation_policy_register_new_pages(ap, pages);
stasis_allocation_policy_register_new_page(ap, 0, 100);
stasis_allocation_policy_register_new_page(ap, 1, 100);
stasis_allocation_policy_register_new_page(ap, 2, 50);
stasis_allocation_policy_register_new_page(ap, 3, 25);
availablePage * p1 = stasis_allocation_policy_pick_suitable_page(ap, 1, 51);
stasis_allocation_policy_alloced_from_page(ap, 1, p1->pageid);
pageid_t pageid1 = stasis_allocation_policy_pick_suitable_page(ap, 1, 51);
assert(pageid1 != INVALID_PAGE);
stasis_allocation_policy_alloced_from_page(ap, 1, pageid1);
assert(pageid1 == 0 || pageid1 == 1);
stasis_allocation_policy_update_freespace(ap, pageid1, 0);
assert(p1);
assert(p1->pageid == 0 || p1->pageid == 1);
stasis_allocation_policy_update_freespace_locked_page(ap, 1, p1, 0);
pageid_t pageid2 = stasis_allocation_policy_pick_suitable_page(ap, 1, 21);
assert(pageid2 != INVALID_PAGE);
stasis_allocation_policy_alloced_from_page(ap, 1, pageid2);
assert(pageid2 == 3);
stasis_allocation_policy_update_freespace(ap, pageid2, 0);
availablePage * p2 = stasis_allocation_policy_pick_suitable_page(ap, 1, 21);
stasis_allocation_policy_alloced_from_page(ap, 1, p2->pageid);
pageid_t pageid3 = stasis_allocation_policy_pick_suitable_page(ap, 2, 51);
stasis_allocation_policy_alloced_from_page(ap, 2, pageid3);
assert(pageid1 != pageid3);
stasis_allocation_policy_update_freespace(ap, pageid3, 0);
assert(p2->pageid == 3);
stasis_allocation_policy_update_freespace_locked_page(ap, 1, p2, 0);
pageid_t pageid4 = stasis_allocation_policy_pick_suitable_page(ap, 2, 51);
assert(pageid4 == INVALID_PAGE);
availablePage * p3 = stasis_allocation_policy_pick_suitable_page(ap, 2, 51);
stasis_allocation_policy_alloced_from_page(ap, 2, p3->pageid);
assert(p1->pageid != p3->pageid);
stasis_allocation_policy_update_freespace_locked_page(ap, 2, p3, 0);
pageid_t pageid5 = stasis_allocation_policy_pick_suitable_page(ap, 2, 50);
stasis_allocation_policy_alloced_from_page(ap, 2, pageid5);
assert(pageid5== 2);
stasis_allocation_policy_update_freespace(ap, pageid5, 0);
availablePage * p4 = stasis_allocation_policy_pick_suitable_page(ap, 2, 51);
assert(!p4);
availablePage * p5 = stasis_allocation_policy_pick_suitable_page(ap, 2, 50);
stasis_allocation_policy_alloced_from_page(ap, 2, p5->pageid);
assert(p5 && p5->pageid == 2);
stasis_allocation_policy_update_freespace_locked_page(ap, 2, p5, 0);
stasis_allocation_policy_update_freespace_locked_page(ap, 1, p1, 100);
stasis_allocation_policy_update_freespace(ap, pageid1, 100);
stasis_allocation_policy_transaction_completed(ap, 1);
stasis_allocation_policy_update_freespace_unlocked_page(ap, p2, 25);
stasis_allocation_policy_update_freespace(ap, pageid2, 25);
availablePage * p6 = stasis_allocation_policy_pick_suitable_page(ap, 2, 50);
stasis_allocation_policy_alloced_from_page(ap, 2, p6->pageid);
assert(p6->pageid == 1 || p6->pageid == 0);
stasis_allocation_policy_update_freespace_locked_page(ap, 2, p6, 0);
pageid_t pageid6 = stasis_allocation_policy_pick_suitable_page(ap, 2, 50);
stasis_allocation_policy_alloced_from_page(ap, 2, pageid6);
assert(pageid6 == 1 || pageid6 == 0);
stasis_allocation_policy_update_freespace(ap, pageid6, 0);
availablePage * p7 = stasis_allocation_policy_pick_suitable_page(ap, 2, 50);
assert(!p7);
pageid_t pageid7 = stasis_allocation_policy_pick_suitable_page(ap, 2, 50);
assert(pageid7 == INVALID_PAGE);
stasis_allocation_policy_update_freespace_unlocked_page(ap, pages[3], 51);
stasis_allocation_policy_update_freespace(ap, 3, 51);
availablePage * p8 =stasis_allocation_policy_pick_suitable_page(ap, 2, 51);
assert(p8->pageid == 3);
stasis_allocation_policy_alloced_from_page(ap, 2, p8->pageid);
pageid_t pageid8 =stasis_allocation_policy_pick_suitable_page(ap, 2, 51);
assert(pageid8 == 3);
stasis_allocation_policy_alloced_from_page(ap, 2, pageid8);
stasis_allocation_policy_update_freespace_locked_page(ap, 2, p8, 0);
stasis_allocation_policy_update_freespace(ap, pageid8, 0);
stasis_allocation_policy_transaction_completed(ap, 2);
stasis_allocation_policy_deinit(ap);
free(pages);
} END_TEST
#define AVAILABLE_PAGE_COUNT_A 1000
@ -155,8 +128,8 @@ static const int MAX_DESIRED_FREESPACE =
static int nextxid = 0;
int activexidcount = 0;
static void takeRandomAction(stasis_allocation_policy_t * ap, int * xids,
availablePage ** pages1, availablePage ** pages2) {
switch(myrandom(6)) {
pageid_t * pages1, pageid_t * pages2) {
switch(myrandom(5)) {
case 0 : { // find page
int thexid = myrandom(XACT_COUNT);
if(xids[thexid] == -1) {
@ -166,9 +139,9 @@ static void takeRandomAction(stasis_allocation_policy_t * ap, int * xids,
DEBUG("xid begins\n");
}
int thefreespace = myrandom(MAX_DESIRED_FREESPACE);
availablePage * p =
pageid_t p =
stasis_allocation_policy_pick_suitable_page(ap, xids[thexid], thefreespace);
if(p) {
if(p != INVALID_PAGE) {
DEBUG("alloc succeeds\n");
// xxx validate returned value...
} else {
@ -185,7 +158,7 @@ static void takeRandomAction(stasis_allocation_policy_t * ap, int * xids,
DEBUG("complete");
} break;
case 2 : { // update freespace unlocked
int thespacediff = myrandom(MAX_DESIRED_FREESPACE/2) - (MAX_DESIRED_FREESPACE/2);
int thespacediff = myrandom(MAX_DESIRED_FREESPACE) - (MAX_DESIRED_FREESPACE/2);
int thexid;
if(!activexidcount) { break; }
while(xids[thexid = myrandom(XACT_COUNT)] == -1) { }
@ -195,33 +168,32 @@ static void takeRandomAction(stasis_allocation_policy_t * ap, int * xids,
} else {
minfreespace = 0;
}
availablePage * p = stasis_allocation_policy_pick_suitable_page(ap, xids[thexid],
pageid_t p = stasis_allocation_policy_pick_suitable_page(ap, xids[thexid],
minfreespace);
if(p && p->lockCount == 0) {
int thenewfreespace = p->freespace+thespacediff;
stasis_allocation_policy_update_freespace_unlocked_page(ap, p, thenewfreespace);
if(p != INVALID_PAGE) {
int thenewfreespace = myrandom(MAX_DESIRED_FREESPACE/2)+thespacediff;
stasis_allocation_policy_update_freespace(ap, p, thenewfreespace);
// printf("updated freespace unlocked");
}
} break;
case 3 : { // update freespace locked
} break;
case 4 : { // lock page
} break;
case 5 : { // alloced from page
// xxx this case is nonsense. we pick a random page, alloc from it, and allocation policy correctly sees that we're violating protocol, and cores...
// xxx write better one..
/* int thexid;
case 3 : { // dealloc from page
int thexid;
if(!activexidcount) { break; }
while(xids[thexid = myrandom(XACT_COUNT)] == -1) { }
pageid_t thepage=myrandom(AVAILABLE_PAGE_COUNT_A + pages2?AVAILABLE_PAGE_COUNT_B:0);
stasis_allocation_policy_alloced_from_page(ap,thexid,thepage); */
while(xids[thexid = myrandom(XACT_COUNT)] == -1) {}
pageid_t p = pages1[myrandom(AVAILABLE_PAGE_COUNT_A)];
stasis_allocation_policy_dealloced_from_page(ap, xids[thexid], p);
} break;
case 4 : { // alloced from page
int thexid;
if(!activexidcount) { break; }
while(xids[thexid = myrandom(XACT_COUNT)] == -1) {}
pageid_t p = pages1[myrandom(AVAILABLE_PAGE_COUNT_A)];
if(stasis_allocation_policy_can_xid_alloc_from_page(ap, xids[thexid], p)) {
stasis_allocation_policy_alloced_from_page(ap, xids[thexid], p);
}
} break;
default: abort();
}
}
START_TEST(allocationPolicy_randomTest) {
@ -232,10 +204,8 @@ START_TEST(allocationPolicy_randomTest) {
printf("\nSeed = %ld\n", seed);
srandom(seed);
availablePage ** pages1 =
malloc((1+AVAILABLE_PAGE_COUNT_A) * sizeof(availablePage *));
availablePage ** pages2 =
malloc((1+AVAILABLE_PAGE_COUNT_B) * sizeof(availablePage *));
pageid_t * pages1 = malloc(AVAILABLE_PAGE_COUNT_A * sizeof(pageid_t));
pageid_t * pages2 = malloc(AVAILABLE_PAGE_COUNT_B * sizeof(pageid_t));
int * xids = malloc(sizeof(int) * XACT_COUNT);
@ -243,35 +213,30 @@ START_TEST(allocationPolicy_randomTest) {
xids[i] = -1;
}
for(int i = 0; i < AVAILABLE_PAGE_COUNT_A; i++) {
pages1[i] = malloc(sizeof(availablePage));
pages1[i]->pageid = i;
pages1[i]->freespace = i * FREE_MUL;
pages1[i]->lockCount = 0;
}
pages1[AVAILABLE_PAGE_COUNT_A] = 0;
for(int i = 0 ; i < AVAILABLE_PAGE_COUNT_B; i++) {
pages2[i] = malloc(sizeof(availablePage));
pages2[i]->pageid = AVAILABLE_PAGE_COUNT_A + i;
pages2[i]->freespace = (AVAILABLE_PAGE_COUNT_A + i) * FREE_MUL;
pages2[i]->lockCount = 0;
}
pages2[AVAILABLE_PAGE_COUNT_B] = 0;
stasis_allocation_policy_t * ap = stasis_allocation_policy_init();
stasis_allocation_policy_register_new_pages(ap, pages1);
for(int i = 0; i < AVAILABLE_PAGE_COUNT_A; i++) {
pages1[i] = i;
stasis_allocation_policy_register_new_page(ap, i, i * FREE_MUL);
}
for(int k = 0; k < PHASE_ONE_COUNT; k++) {
// Don't pass in pages2; ap doesn't know about them yet!
takeRandomAction(ap, xids, pages1, 0);
}
stasis_allocation_policy_register_new_pages(ap, pages2);
for(int i = 0 ; i < AVAILABLE_PAGE_COUNT_B; i++) {
pages2[i] = AVAILABLE_PAGE_COUNT_A + i;
stasis_allocation_policy_register_new_page(ap, pages2[i], (AVAILABLE_PAGE_COUNT_A + i) * FREE_MUL);
}
for(int k = 0; k < PHASE_TWO_COUNT; k++) {
takeRandomAction(ap, xids, pages1, pages2);
}
for(int i = 0; i < XACT_COUNT; i++) {
if(xids[i] != INVALID_XID) { stasis_allocation_policy_transaction_completed(ap, xids[i]); }
}
stasis_allocation_policy_deinit(ap);