diff --git a/src/stasis/operations/regions.c b/src/stasis/operations/regions.c index 8c04b78..5bd8460 100644 --- a/src/stasis/operations/regions.c +++ b/src/stasis/operations/regions.c @@ -59,7 +59,8 @@ static int operate_dealloc_region_unlocked(int xid, const regionAllocArg *dat) { assert(ret); t.status = REGION_VACANT; - t.region_xid = xid; + int err = TgetTransactionFingerprint(xid, &t.region_xid_fp); + assert(!err); TsetBoundaryTag(xid, firstPage -1, &t); @@ -132,7 +133,8 @@ static void TdeallocBoundaryTag(int xid, pageid_t page) { int ret = readBoundaryTag(xid, page, &t); assert(ret); t.status = REGION_CONDEMNED; - t.region_xid = xid; + int err = TgetTransactionFingerprint(xid, &t.region_xid_fp); + assert(!err); TsetBoundaryTag(xid, page, &t); } @@ -146,7 +148,7 @@ void regionsInit(stasis_log_t *log) { t.size = PAGEID_T_MAX; t.prev_size = PAGEID_T_MAX; t.status = REGION_VACANT; - t.region_xid = INVALID_XID; + TgetTransactionFingerprint(INVALID_XID, &t.region_xid_fp); t.allocation_manager = 0; // This does what TallocBoundaryTag(-1, 0, &t); would do, but it @@ -285,7 +287,7 @@ static void TregionAllocHelper(int xid, pageid_t page, pageid_t pageCount, int a // - 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; + TgetTransactionFingerprint(INVALID_XID, &new_tag.region_xid_fp); new_tag.allocation_manager = 0; TallocBoundaryTag(xid, newPageid, &new_tag); @@ -293,7 +295,8 @@ static void TregionAllocHelper(int xid, pageid_t page, pageid_t pageCount, int a } t.status = REGION_ZONED; - t.region_xid = xid; + int err = TgetTransactionFingerprint(xid, &t.region_xid_fp); + assert(!err); t.allocation_manager = allocationManager; t.size = pageCount; @@ -303,7 +306,7 @@ static void TregionAllocHelper(int xid, pageid_t page, pageid_t pageCount, int a static void consolidateRegions(int xid, pageid_t * firstPage, boundary_tag *t) { - if(t->status != REGION_VACANT || TisActiveTransaction(t->region_xid)) { return; } + if(t->status != REGION_VACANT || TisActiveTransaction(&t->region_xid_fp)) { return; } // (*firstPage)++; @@ -324,7 +327,7 @@ static void consolidateRegions(int xid, pageid_t * firstPage, boundary_tag *t) // TODO: Truncate page file. TdeallocBoundaryTag(xid, succ_page); mustWriteOriginalTag = 1; - } else if(succ_tag.status == REGION_VACANT && (!TisActiveTransaction(succ_tag.region_xid))) { + } else if(succ_tag.status == REGION_VACANT && (!TisActiveTransaction(&succ_tag.region_xid_fp))) { t->size = t->size + succ_tag.size + 1; pageid_t succ_succ_page = succ_page + succ_tag.size + 1; @@ -357,7 +360,7 @@ static void consolidateRegions(int xid, pageid_t * firstPage, boundary_tag *t) int ret = readBoundaryTag(xid, pred_page, &pred_tag); assert(ret); - if(pred_tag.status == REGION_VACANT && (!TisActiveTransaction(pred_tag.region_xid))) { + if(pred_tag.status == REGION_VACANT && (!TisActiveTransaction(&pred_tag.region_xid_fp))) { TdeallocBoundaryTag(xid, *firstPage); @@ -452,7 +455,7 @@ pageid_t TregionAlloc(int xid, pageid_t pageCount, int allocationManager) { // 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)) { + while(t.status != REGION_VACANT || t.size < pageCount || TisActiveTransaction(&t.region_xid_fp)) { // 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); diff --git a/src/stasis/transactional2.c b/src/stasis/transactional2.c index b028fc5..62c77dd 100644 --- a/src/stasis/transactional2.c +++ b/src/stasis/transactional2.c @@ -444,8 +444,27 @@ int TactiveThreadCount(void) { int* TlistActiveTransactions(int *count) { return stasis_transaction_table_list_active(stasis_transaction_table, count); } -int TisActiveTransaction(int xid) { - return stasis_transaction_table_is_active(stasis_transaction_table, xid); +int TgetTransactionFingerprint(int xid, stasis_transaction_fingerprint_t * fp) { + if(stasis_transaction_table_is_active(stasis_transaction_table, xid)) { + lsn_t rec_lsn = stasis_transaction_table_get(stasis_transaction_table, xid)->recLSN; + if(rec_lsn == INVALID_LSN) { // Generate a dummy entry. + Tupdate(xid,0,0,0,OPERATION_NOOP); + } + fp->xid = xid; + rec_lsn = stasis_transaction_table_get(stasis_transaction_table, xid)->recLSN; + fp->rec_lsn = rec_lsn; + return 0; + } else if(xid == INVALID_XID) { + fp->xid = INVALID_XID; + fp->rec_lsn = INVALID_LSN; + } else { + return ENOENT; + } +} +int TisActiveTransaction(stasis_transaction_fingerprint_t * fp) { + // stasis_transaction_table_is_active returns false for INVALID_XID, which is what we want. + return stasis_transaction_table_is_active(stasis_transaction_table, fp->xid) + && stasis_transaction_table_get(stasis_transaction_table, fp->xid)->recLSN == fp->rec_lsn; } diff --git a/stasis/operations/regions.h b/stasis/operations/regions.h index d1e7bd9..1cf11c5 100644 --- a/stasis/operations/regions.h +++ b/stasis/operations/regions.h @@ -16,7 +16,7 @@ typedef struct boundary_tag { pageid_t size; pageid_t prev_size; int status; - int region_xid; + stasis_transaction_fingerprint_t region_xid_fp; int allocation_manager; } boundary_tag; diff --git a/stasis/transactional.h b/stasis/transactional.h index f08a897..7d6367e 100644 --- a/stasis/transactional.h +++ b/stasis/transactional.h @@ -727,13 +727,25 @@ lsn_t TendNestedTopAction(int xid, void * handle); */ int* TlistActiveTransactions(int *count); +/** + * A unique (for all time) transaction descriptor. + * + * Unlike xids, fingerprints are not reused. + * + */ +typedef struct stasis_transaction_fingerprint_t { + lsn_t rec_lsn; // The lsn of the first entry in the transaction + int xid; // The transaction id. Lets us look up the rec_lsn in the transaction table. +} stasis_transaction_fingerprint_t; + +int TgetTransactionFingerprint(int xid, stasis_transaction_fingerprint_t * fp); /** * Checks to see if a transaction is still active. * * @param xid The transaction id to be tested. * @return true if the transaction is still running, false otherwise. */ -int TisActiveTransaction(int xid); +int TisActiveTransaction(stasis_transaction_fingerprint_t* fp); /* * @return the number of currently active transactions. */ diff --git a/test/stasis/check_regions.c b/test/stasis/check_regions.c index 2b3faa0..a247972 100644 --- a/test/stasis/check_regions.c +++ b/test/stasis/check_regions.c @@ -186,12 +186,6 @@ START_TEST(regions_randomizedTest) { Tcommit(xid); Tdeinit(); - if((double)max_size/(double)max_ideal_size > 5) { - // max_blowup isn't what we want here; it measures the peak - // percentage of the file that is unused. Instead, we want to - // measure the actual and ideal page file sizes for this run. - printf("WARNING: Excessive blowup "); - } printf("Max # of regions = %lld, page file size = %5.2fM, ideal page file size = %5.2fM, (blowup = %5.2f)\n", //peak bytes wasted = %5.2fM, blowup = %3.2f\n", max_region_count, @@ -200,6 +194,13 @@ START_TEST(regions_randomizedTest) { (double)max_size/(double)max_ideal_size); // ((double)max_waste * PAGE_SIZE)/(1024.0*1024.0), // max_blowup); + if((double)max_size/(double)max_ideal_size > 5) { + // max_blowup isn't what we want here; it measures the peak + // percentage of the file that is unused. Instead, we want to + // measure the actual and ideal page file sizes for this run. + printf("ERROR: Excessive blowup (max allowable is 5)\n"); + abort(); + } } END_TEST