} END_TEST START_TEST(regions_lockSmokeTest) { Tinit(); int xid = Tbegin(); pageid_t pageid = TregionAlloc(xid, 100,0); fsckRegions(xid); Tcommit(xid); xid = Tbegin(); int xid2 = Tbegin(); TregionDealloc(xid, pageid); for(int i = 0; i < 50; i++) { TregionAlloc(xid2, 1, 0); } fsckRegions(xid); Tabort(xid); fsckRegions(xid2); Tcommit(xid2); Tdeinit(); } END_TEST
}END_TEST /** @test More complicated case of log w/ hard bound; many xacts at a time. */ START_TEST(boundedLogConcurrentTest) { stasis_log_type = LOG_TO_MEMORY; stasis_log_in_memory_max_entries = 1000; stasis_log_softcommit = 1; Tinit(); int xid = Tbegin(); pageid_t region_start = TregionAlloc(xid, NUM_XACTS, 0); Tcommit(xid); for(int64_t i = 0; i < NUM_XACTS; i++) { int xids[NUM_CONCURRENT_XACTS]; for(int j = 0; j < NUM_CONCURRENT_XACTS; j++) { xids[j] = Tbegin(); } for(int j = 0; j < NUM_CONCURRENT_XACTS; j++) { TinitializeFixedPage(xids[j], region_start + i, sizeof(uint64_t)); recordid rid = {region_start + i, 0, sizeof(uint64_t)}; Tset(xids[j], rid, &i); i++; } for(int j = 0; j < NUM_CONCURRENT_XACTS; j++) { Tcommit(xids[j]); } } Tdeinit(); }END_TEST
} END_TEST START_TEST(regions_recoveryTest) { Tinit(); pageid_t pages[50]; int xid1 = Tbegin(); int xid2 = Tbegin(); for(int i = 0; i < 50; i+=2) { pages[i] = TregionAlloc(xid1, stasis_util_random64(4)+1, 0); pages[i+1] = TregionAlloc(xid2, stasis_util_random64(2)+1, 0); } fsckRegions(xid1); Tcommit(xid1); Tdeinit(); if(TdurabilityLevel() == VOLATILE) { return; } Tinit(); int xid = Tbegin(); fsckRegions(xid); for(int i = 0; i < 50; i+=2) { TregionDealloc(xid, pages[i]); } fsckRegions(xid); Tabort(xid); fsckRegions(Tbegin()); Tdeinit(); Tinit(); fsckRegions(Tbegin()); Tdeinit(); } END_TEST
static void stasis_alloc_reserve_new_region(stasis_alloc_t* alloc, int xid) { void* nta = TbeginNestedTopAction(xid, OPERATION_NOOP, 0,0); pageid_t firstPage = TregionAlloc(xid, TALLOC_REGION_SIZE, STORAGE_MANAGER_TALLOC); int initialFreespace = -1; for(pageid_t i = 0; i < TALLOC_REGION_SIZE; i++) { TinitializeSlottedPage(xid, firstPage + i); if(initialFreespace == -1) { Page * p = loadPage(xid, firstPage); readlock(p->rwlatch,0); initialFreespace = stasis_record_freespace(xid, p); unlock(p->rwlatch); releasePage(p); } stasis_allocation_policy_register_new_page(alloc->allocPolicy, firstPage + i, initialFreespace); } TendNestedTopAction(xid, nta); }
} END_TEST START_TEST(regions_lockRandomizedTest) { Tinit(); const int NUM_XACTS = 100; const int NUM_OPS = 10000; const int FUDGE = 10; int xids[NUM_XACTS]; pageid_t * xidRegions[NUM_XACTS + FUDGE]; int xidRegionCounts[NUM_XACTS + FUDGE]; int longXid = Tbegin(); time_t seed = time(0); printf("\nSeed = %ld\n", seed); srandom(seed); for(int i = 0; i < NUM_XACTS; i++) { xids[i] = Tbegin(); assert(xids[i] < NUM_XACTS + FUDGE); xidRegions[xids[i]] = stasis_malloc(NUM_OPS, pageid_t); xidRegionCounts[xids[i]] = 0; } int activeXacts = NUM_XACTS; for(int i = 0; i < NUM_OPS; i++) { pageid_t j; if(!(i % (NUM_OPS/NUM_XACTS))) { // abort or commit one transaction randomly. activeXacts --; j = stasis_util_random64(activeXacts); if(stasis_util_random64(2)) { Tcommit(xids[j]); } else { Tabort(xids[j]); } if(activeXacts == 0) { break; } for(; j < activeXacts; j++) { xids[j] = xids[j+1]; } fsckRegions(longXid); } j = stasis_util_random64(activeXacts); if(stasis_util_random64(2)) { // alloc xidRegions[xids[j]][xidRegionCounts[xids[j]]] = TregionAlloc(xids[j], stasis_util_random64(100), 0); xidRegionCounts[xids[j]]++; } else { // free if(xidRegionCounts[xids[j]]) { pageid_t k = stasis_util_random64(xidRegionCounts[xids[j]]); TregionDealloc(xids[j], xidRegions[xids[j]][k]); xidRegionCounts[xids[j]]--; for(; k < xidRegionCounts[xids[j]]; k++) { xidRegions[xids[j]][k] = xidRegions[xids[j]][k+1]; } } } } for(int i = 0; i < activeXacts; i++) { Tabort(i); fsckRegions(longXid); } Tcommit(longXid); Tdeinit(); } END_TEST
END_TEST START_TEST(regions_randomizedTest) { Tinit(); time_t seed = time(0); printf("Seed = %ld: ", seed); srandom(seed); int xid = Tbegin(); pageid_t pagesAlloced = 0; pageid_t regionsAlloced = 0; double max_blowup = 0; pageid_t max_region_count = 0; pageid_t max_waste = 0; pageid_t max_size = 0; pageid_t max_ideal_size = 0; for(int i = 0; i < 10000; i++) { if(!(i % 100)) { Tcommit(xid); xid = Tbegin(); } if(!(i % 100)) { fsckRegions(xid); } if(stasis_util_random64(2)) { unsigned int size = stasis_util_random64(100); TregionAlloc(xid, size, 0); pagesAlloced += size; regionsAlloced ++; } else { if(regionsAlloced) { pageid_t victim = stasis_util_random64(regionsAlloced); pageid_t victimSize; pageid_t victimPage; TregionFindNthActive(xid, victim, &victimPage, &victimSize); TregionDealloc(xid, victimPage); pagesAlloced -= victimSize; regionsAlloced --; } else { i--; } } if(regionsAlloced) { pageid_t lastRegionStart; pageid_t lastRegionSize; TregionFindNthActive(xid, regionsAlloced-1, &lastRegionStart, &lastRegionSize); pageid_t length = lastRegionStart + lastRegionSize+1; pageid_t ideal = pagesAlloced + regionsAlloced + 1; double blowup = (double)length/(double)ideal; unsigned long long bytes_wasted = length - ideal; // printf("Region count = %d, blowup = %d / %d = %5.2f\n", regionsAlloced, length, ideal, blowup); if(max_blowup < blowup) { max_blowup = blowup; } if(max_waste < bytes_wasted) { max_waste = bytes_wasted; } if(max_size < length) { max_size = length; } if(max_ideal_size < ideal) { max_ideal_size = ideal; } if(max_region_count < regionsAlloced) { max_region_count = regionsAlloced; } } } fsckRegions(xid); Tcommit(xid); Tdeinit(); 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, ((double)max_size * PAGE_SIZE)/(1024.0*1024.0), ((double)max_ideal_size * PAGE_SIZE)/(1024.0*1024.0), (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