support for lsn-free writeback; partial benchmark code for submission
This commit is contained in:
parent
b1f44ab005
commit
d413bb27f3
14 changed files with 565 additions and 23 deletions
|
@ -24,7 +24,8 @@ CREATE_EXECUTABLE(linearHashNTAWriteRequests)
|
||||||
CREATE_EXECUTABLE(transitiveClosure)
|
CREATE_EXECUTABLE(transitiveClosure)
|
||||||
CREATE_EXECUTABLE(zeroCopy)
|
CREATE_EXECUTABLE(zeroCopy)
|
||||||
CREATE_EXECUTABLE(sequentialThroughput)
|
CREATE_EXECUTABLE(sequentialThroughput)
|
||||||
|
CREATE_EXECUTABLE(qos)
|
||||||
|
CREATE_EXECUTABLE(writeBack)
|
||||||
IF(CHECK_LIBRARY)
|
IF(CHECK_LIBRARY)
|
||||||
ADD_TEST(rose rose)
|
ADD_TEST(rose rose)
|
||||||
ENDIF(CHECK_LIBRARY)
|
ENDIF(CHECK_LIBRARY)
|
||||||
|
|
|
@ -10,7 +10,7 @@ noinst_PROGRAMS=lhtableThreaded naiveHash \
|
||||||
naiveMultiThreaded rawSet arrayListSet \
|
naiveMultiThreaded rawSet arrayListSet \
|
||||||
linearHashNTA linkedListNTA pageOrientedListNTA \
|
linearHashNTA linkedListNTA pageOrientedListNTA \
|
||||||
linearHashNTAThreaded linearHashNTAMultiReader linearHashNTAWriteRequests \
|
linearHashNTAThreaded linearHashNTAMultiReader linearHashNTAWriteRequests \
|
||||||
transitiveClosure zeroCopy sequentialThroughput rose roseTable
|
transitiveClosure zeroCopy sequentialThroughput rose roseTable qos writeBack
|
||||||
endif
|
endif
|
||||||
AM_CFLAGS=${GLOBAL_CFLAGS}
|
AM_CFLAGS=${GLOBAL_CFLAGS}
|
||||||
AM_CXXFLAGS=${GLOBAL_CXXFLAGS} -I ${top_builddir}/src
|
AM_CXXFLAGS=${GLOBAL_CXXFLAGS} -I ${top_builddir}/src
|
||||||
|
|
248
benchmarks/qos.c
Normal file
248
benchmarks/qos.c
Normal file
|
@ -0,0 +1,248 @@
|
||||||
|
#include <stasis/transactional.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
void alloc_rids(long long num_rids, recordid ** slow, recordid ** fast) {
|
||||||
|
*slow = malloc(num_rids * sizeof(**slow));
|
||||||
|
*fast = malloc((num_rids / 10) * sizeof(**fast));
|
||||||
|
|
||||||
|
int xid = Tbegin();
|
||||||
|
|
||||||
|
byte * old = malloc(PAGE_SIZE);
|
||||||
|
byte * new = malloc(PAGE_SIZE);
|
||||||
|
|
||||||
|
for(long long i = 0; i < num_rids; ) {
|
||||||
|
pageid_t pid = TpageAlloc(xid);
|
||||||
|
Page * p = loadPage(xid, pid);
|
||||||
|
writelock(p->rwlatch,0);
|
||||||
|
memcpy(old, p->memAddr, PAGE_SIZE);
|
||||||
|
stasis_slotted_lsn_free_initialize_page(p);
|
||||||
|
while(i < num_rids &&
|
||||||
|
(
|
||||||
|
((*slow)[i] = stasis_record_alloc_begin(xid, p, sizeof(int))).size
|
||||||
|
== sizeof(int)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
stasis_record_alloc_done(xid, p, (*slow)[i]);
|
||||||
|
if(!(i%10)) {
|
||||||
|
(*fast)[i/10] = stasis_record_alloc_begin(xid, p, sizeof(int));
|
||||||
|
if((*fast)[i/10].size!=sizeof(int)) {
|
||||||
|
break; // don't increment i
|
||||||
|
}
|
||||||
|
stasis_record_alloc_done(xid, p, (*fast)[i/10]);
|
||||||
|
}
|
||||||
|
assert((*slow)[i].size != -1);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
memcpy(new, p->memAddr, PAGE_SIZE);
|
||||||
|
memcpy(p->memAddr, old, PAGE_SIZE);
|
||||||
|
unlock(p->rwlatch);
|
||||||
|
releasePage(p);
|
||||||
|
TpageSet(xid, pid, new);
|
||||||
|
}
|
||||||
|
free(old);
|
||||||
|
free(new);
|
||||||
|
|
||||||
|
Tcommit(xid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
long long num_rids;
|
||||||
|
long long rid_per_xact;
|
||||||
|
recordid * rids;
|
||||||
|
int done;
|
||||||
|
pthread_mutex_t mut;
|
||||||
|
} bulk_worker_args;
|
||||||
|
|
||||||
|
static int (*original_write_entry) (struct stasis_log_t* log, LogEntry * e);
|
||||||
|
|
||||||
|
static int net_latency = 2;
|
||||||
|
|
||||||
|
|
||||||
|
int my_write_entry(struct stasis_log_t* log, LogEntry *e) {
|
||||||
|
usleep(net_latency * 1000);
|
||||||
|
return original_write_entry(log,e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* normal_worker(void * ap) {
|
||||||
|
bulk_worker_args * a = ap;
|
||||||
|
pthread_mutex_lock(&a->mut);
|
||||||
|
for(int i = 0; !a->done; i++) {
|
||||||
|
pthread_mutex_unlock(&a->mut);
|
||||||
|
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, 0);
|
||||||
|
long long start = tv.tv_usec + tv.tv_sec * 1000000;
|
||||||
|
|
||||||
|
int xid = Tbegin();
|
||||||
|
for(int j = 0; j < a->rid_per_xact; j++) {
|
||||||
|
int val = i * a->rid_per_xact + j;
|
||||||
|
Tset(xid, a->rids[j%a->num_rids], &val);
|
||||||
|
}
|
||||||
|
Tcommit(xid);
|
||||||
|
|
||||||
|
gettimeofday(&tv, 0);
|
||||||
|
long long stop = tv.tv_usec + tv.tv_sec * 1000000;
|
||||||
|
printf("low(ms),%lld\n", stop-start);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&a->mut);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&a->mut);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
typedef struct {
|
||||||
|
int xid;
|
||||||
|
int n; // which worker am i?
|
||||||
|
int i; // which iteration is this?
|
||||||
|
int divisor;
|
||||||
|
bulk_worker_args * a;
|
||||||
|
} unit_of_work_arg;
|
||||||
|
void * bg_unit_of_work(void * ap) {
|
||||||
|
unit_of_work_arg * ua = ap;
|
||||||
|
bulk_worker_args * a = ua->a;
|
||||||
|
|
||||||
|
stasis_log_reordering_handle_t * rh
|
||||||
|
= stasis_log_reordering_handle_open(&XactionTable[ua->xid%MAX_TRANSACTIONS],
|
||||||
|
stasis_log_file,
|
||||||
|
(stasis_log_write_buffer_size * 0.25)/ua->divisor,
|
||||||
|
//512*1024/ua->divisor, // 0.5 mb in log tail at once
|
||||||
|
1000000/ua->divisor, // max num outstanding requests
|
||||||
|
(50 * 1024 * 1024)/ua->divisor // max backlog in bytes
|
||||||
|
);
|
||||||
|
for(int j = 0; j < a->rid_per_xact/ua->divisor; j++) {
|
||||||
|
int val = ua->i * (a->rid_per_xact/ua->divisor) + j;
|
||||||
|
TsetReorderable(ua->xid, rh, a->rids[(j*ua->divisor+ua->n)%a->num_rids], &val);
|
||||||
|
}
|
||||||
|
stasis_log_reordering_handle_close(rh);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* bg_worker(void * ap) {
|
||||||
|
bulk_worker_args * a = ap;
|
||||||
|
pthread_mutex_lock(&a->mut);
|
||||||
|
for(int i = 0; !a->done; i++) {
|
||||||
|
pthread_mutex_unlock(&a->mut);
|
||||||
|
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, 0);
|
||||||
|
long long start = tv.tv_usec + tv.tv_sec * 1000000;
|
||||||
|
|
||||||
|
int xid = Tbegin();
|
||||||
|
if(stasis_log_file->write_entry == my_write_entry) {
|
||||||
|
// based on tweaking; also, normal-net is ~ 100x slower than nromal
|
||||||
|
int num_worker = 100;
|
||||||
|
pthread_t workers[num_worker];
|
||||||
|
unit_of_work_arg args[num_worker];
|
||||||
|
for(int w = 0; w < num_worker; w++) {
|
||||||
|
args[i].xid = xid;
|
||||||
|
args[i].n = w;
|
||||||
|
args[i].i = i;
|
||||||
|
args[i].divisor = num_worker;
|
||||||
|
args[i].a = a;
|
||||||
|
pthread_create(&workers[w], 0, bg_unit_of_work, &(args[i]));
|
||||||
|
}
|
||||||
|
for(int w = 0; w < num_worker; w++) {
|
||||||
|
pthread_join(workers[w], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
unit_of_work_arg unit_arg = {
|
||||||
|
xid,
|
||||||
|
0,
|
||||||
|
i,
|
||||||
|
1,
|
||||||
|
ap
|
||||||
|
};
|
||||||
|
bg_unit_of_work(&unit_arg);
|
||||||
|
}
|
||||||
|
Tcommit(xid);
|
||||||
|
|
||||||
|
gettimeofday(&tv, 0);
|
||||||
|
long long stop = tv.tv_usec + tv.tv_sec * 1000000;
|
||||||
|
printf("low(ms),%lld\n", stop-start);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&a->mut);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&a->mut);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
char * mode = argv[1];
|
||||||
|
bulk_worker_args a;
|
||||||
|
a.num_rids = atoll(argv[2]);
|
||||||
|
a.rid_per_xact = atoll(argv[3]);
|
||||||
|
|
||||||
|
a.done = 0;
|
||||||
|
pthread_mutex_init(&a.mut,0);
|
||||||
|
unlink("storefile.txt");
|
||||||
|
unlink("logfile.txt");
|
||||||
|
|
||||||
|
// disable truncation, as it interferes w/ the benchmark.
|
||||||
|
|
||||||
|
stasis_truncation_automatic = 0;
|
||||||
|
// XXX instead of overriding this, set tail of priority log to 80%
|
||||||
|
// stasis log buf or something...
|
||||||
|
|
||||||
|
stasis_log_write_buffer_size = 50 * 1024 * 1024;
|
||||||
|
|
||||||
|
printf("%s %s %s %s %lld\n", argv[0], argv[1], argv[2], argv[3],
|
||||||
|
stasis_log_write_buffer_size);
|
||||||
|
|
||||||
|
Tinit();
|
||||||
|
|
||||||
|
// 10% as big as slow rids; interspersed
|
||||||
|
recordid * fast_rids;
|
||||||
|
|
||||||
|
alloc_rids(a.num_rids, &a.rids, &fast_rids);
|
||||||
|
pthread_t worker;
|
||||||
|
if(!strcmp(mode, "none")) {
|
||||||
|
// nop
|
||||||
|
} else if (!strcmp(mode, "normal")) {
|
||||||
|
pthread_create(&worker, 0, normal_worker, &a);
|
||||||
|
} else if (!strcmp(mode, "normal-net")) {
|
||||||
|
original_write_entry = stasis_log_file->write_entry;
|
||||||
|
stasis_log_file->write_entry = my_write_entry;
|
||||||
|
pthread_create(&worker, 0, normal_worker, &a);
|
||||||
|
} else if (!strcmp(mode, "bg-net")) {
|
||||||
|
original_write_entry = stasis_log_file->write_entry;
|
||||||
|
stasis_log_file->write_entry = my_write_entry;
|
||||||
|
pthread_create(&worker, 0, bg_worker, &a);
|
||||||
|
} else {
|
||||||
|
assert(!strcmp(mode, "bg"));
|
||||||
|
pthread_create(&worker, 0, bg_worker, &a);
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(10);
|
||||||
|
// sleep 10 (reach steady state)
|
||||||
|
|
||||||
|
// run benchmark here
|
||||||
|
for(int i = 0; i < 60; i++) {
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, 0);
|
||||||
|
long long start = tv.tv_usec + tv.tv_sec * 1000000;
|
||||||
|
int xid = Tbegin();
|
||||||
|
TsetLsnFree(xid, fast_rids[i % (a.num_rids/10)], &i);
|
||||||
|
Tcommit(xid);
|
||||||
|
gettimeofday(&tv, 0);
|
||||||
|
long long stop = tv.tv_usec + tv.tv_sec * 1000000;
|
||||||
|
|
||||||
|
printf("high(ms),%lld\n", stop-start);
|
||||||
|
fflush(stdout);
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pthread_mutex_lock(&a.mut);
|
||||||
|
a.done = 1;
|
||||||
|
pthread_mutex_unlock(&a.mut);
|
||||||
|
|
||||||
|
pthread_join(worker, 0);
|
||||||
|
Tdeinit();
|
||||||
|
|
||||||
|
}
|
147
benchmarks/writeBack.c
Normal file
147
benchmarks/writeBack.c
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
#include <stasis/transactional.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
void alloc_rids(long long num_rids, recordid ** slow, recordid ** fast) {
|
||||||
|
*slow = malloc(num_rids * sizeof(**slow));
|
||||||
|
*fast = malloc((num_rids / 10) * sizeof(**fast));
|
||||||
|
|
||||||
|
int xid = Tbegin();
|
||||||
|
|
||||||
|
byte * old = malloc(PAGE_SIZE);
|
||||||
|
byte * new = malloc(PAGE_SIZE);
|
||||||
|
|
||||||
|
for(long long i = 0; i < num_rids; ) {
|
||||||
|
pageid_t pid = TpageAlloc(xid);
|
||||||
|
Page * p = loadPage(xid, pid);
|
||||||
|
writelock(p->rwlatch,0);
|
||||||
|
memcpy(old, p->memAddr, PAGE_SIZE);
|
||||||
|
stasis_slotted_lsn_free_initialize_page(p);
|
||||||
|
while(i < num_rids &&
|
||||||
|
(
|
||||||
|
((*slow)[i] = stasis_record_alloc_begin(xid, p, sizeof(int))).size
|
||||||
|
== sizeof(int)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
stasis_record_alloc_done(xid, p, (*slow)[i]);
|
||||||
|
if(!(i%10)) {
|
||||||
|
(*fast)[i/10] = stasis_record_alloc_begin(xid, p, sizeof(int));
|
||||||
|
if((*fast)[i/10].size!=sizeof(int)) {
|
||||||
|
break; // don't increment i
|
||||||
|
}
|
||||||
|
stasis_record_alloc_done(xid, p, (*fast)[i/10]);
|
||||||
|
}
|
||||||
|
assert((*slow)[i].size != -1);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
memcpy(new, p->memAddr, PAGE_SIZE);
|
||||||
|
memcpy(p->memAddr, old, PAGE_SIZE);
|
||||||
|
unlock(p->rwlatch);
|
||||||
|
releasePage(p);
|
||||||
|
TpageSet(xid, pid, new);
|
||||||
|
}
|
||||||
|
free(old);
|
||||||
|
free(new);
|
||||||
|
|
||||||
|
Tcommit(xid);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
pageid_t pid;
|
||||||
|
pageoff_t off;
|
||||||
|
pageoff_t len;
|
||||||
|
int val;
|
||||||
|
} cached_addr;
|
||||||
|
|
||||||
|
void build_cache(recordid * rids, cached_addr** cache, long long count) {
|
||||||
|
*cache = malloc (sizeof(**cache) * count);
|
||||||
|
lsn_t log_trunc = stasis_log_file->truncation_point(stasis_log_file);
|
||||||
|
for(long long i = 0; i < count; i++) {
|
||||||
|
(*cache)[i].pid = rids[i].page;
|
||||||
|
|
||||||
|
Page * p = loadPage(-1, (*cache)[i].pid);
|
||||||
|
readlock(p->rwlatch,0);
|
||||||
|
byte * b = stasis_record_write_begin(-1, p, rids[i]);
|
||||||
|
(*cache)[i].off = b - p->memAddr;
|
||||||
|
stasis_record_write_done(-1, p, rids[i], b);
|
||||||
|
stasis_page_lsn_write(-1, p, log_trunc);
|
||||||
|
(*cache)[i].len = stasis_record_type_to_size(rids[i].size);
|
||||||
|
(*cache)[i].val = 0;
|
||||||
|
unlock(p->rwlatch);
|
||||||
|
// releasePage(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int net_latency = 2;
|
||||||
|
static byte * (*origWrite)(int xid, Page *p, recordid rid);
|
||||||
|
static byte * slowWrite(int xid, Page *p, recordid rid) {
|
||||||
|
usleep(net_latency * 1000);
|
||||||
|
return origWrite(xid,p,rid);
|
||||||
|
}
|
||||||
|
static const byte * (*origRead)(int xid, Page *p, recordid rid);
|
||||||
|
static const byte * slowRead(int xid, Page *p, recordid rid) {
|
||||||
|
usleep(net_latency * 1000);
|
||||||
|
return origRead(xid,p,rid);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char ** argv) {
|
||||||
|
unlink("storefile.txt");
|
||||||
|
unlink("logfile.txt");
|
||||||
|
char * mode = argv[1];
|
||||||
|
long long num_rids = atoll(argv[2]);
|
||||||
|
long long num_xacts = atoll(argv[3]);
|
||||||
|
long long writes_per_xact = atoll(argv[4]);
|
||||||
|
recordid * rids;
|
||||||
|
recordid * fast;
|
||||||
|
cached_addr * cache;
|
||||||
|
int writeback = !(strcmp(mode, "writeback")&&strcmp(mode,"writeback-net"));
|
||||||
|
// stasis_truncation_automatic = 0;
|
||||||
|
Tinit();
|
||||||
|
|
||||||
|
alloc_rids(num_rids,&rids,&fast);
|
||||||
|
if(writeback) {
|
||||||
|
build_cache(rids,&cache,num_rids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(strcmp(mode, "normal-net")&&strcmp(mode,"writeback-net"))) {
|
||||||
|
origWrite = stasis_page_impl_get(SLOTTED_LSN_FREE_PAGE)->recordWrite;
|
||||||
|
origRead = stasis_page_impl_get(SLOTTED_LSN_FREE_PAGE)->recordRead;
|
||||||
|
|
||||||
|
// xxx a bit of cheating; don't pay latency for lsn write
|
||||||
|
// (could amortize w/ recordWrite)
|
||||||
|
|
||||||
|
stasis_page_impl_get(SLOTTED_LSN_FREE_PAGE)->recordWrite = slowWrite;
|
||||||
|
stasis_page_impl_get(SLOTTED_LSN_FREE_PAGE)->recordRead = slowRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lsn_t last_lsn = 0;
|
||||||
|
for(long long i = 0; i < num_xacts; i++) {
|
||||||
|
int xid = Tbegin();
|
||||||
|
|
||||||
|
for(long long j = 0; j < writes_per_xact; j++) {
|
||||||
|
long long idx = ((i*writes_per_xact)+j)%num_rids;
|
||||||
|
|
||||||
|
if(!(strcmp(mode, "normal")&&strcmp(mode, "normal-net"))) {
|
||||||
|
TsetLsnFree(xid, rids[idx], &j);
|
||||||
|
} else {
|
||||||
|
assert(writeback);
|
||||||
|
int old = cache[idx].val;
|
||||||
|
cache[idx].val = j;
|
||||||
|
last_lsn = TsetWriteBack(xid, cache[idx].pid,cache[idx].off,
|
||||||
|
cache[idx].len,&j,&old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Tcommit(xid);
|
||||||
|
}
|
||||||
|
// XXX hack; really, want to register upcall in buffermanager...
|
||||||
|
if(writeback) {
|
||||||
|
for(long long i = 0; i < num_rids; i++) {
|
||||||
|
Page *p = loadPage(-1, rids[i].page);
|
||||||
|
writelock(p->rwlatch,0);
|
||||||
|
stasis_record_write(-1, p, last_lsn, rids[i], (byte*)&cache[i].val);
|
||||||
|
unlock(p->rwlatch);
|
||||||
|
releasePage(p);
|
||||||
|
releasePage(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Tdeinit();
|
||||||
|
}
|
43
benchmarks/writeback.sh
Normal file
43
benchmarks/writeback.sh
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
echo w1
|
||||||
|
time ./writeBack writeback 100 1 1000000
|
||||||
|
|
||||||
|
echo n1
|
||||||
|
time ./writeBack normal 100 1 1000000
|
||||||
|
|
||||||
|
echo w10
|
||||||
|
time ./writeBack writeback 100 10 100000
|
||||||
|
|
||||||
|
echo n10
|
||||||
|
time ./writeBack normal 100 10 100000
|
||||||
|
|
||||||
|
echo w100
|
||||||
|
time ./writeBack writeback 100 100 10000
|
||||||
|
|
||||||
|
echo n100
|
||||||
|
time ./writeBack normal 100 100 10000
|
||||||
|
|
||||||
|
echo w1000
|
||||||
|
time ./writeBack writeback 100 1000 1000
|
||||||
|
|
||||||
|
echo n1000
|
||||||
|
time ./writeBack normal 100 1000 1000
|
||||||
|
|
||||||
|
echo w10000
|
||||||
|
time ./writeBack writeback 100 10000 100
|
||||||
|
|
||||||
|
echo n10000
|
||||||
|
time ./writeBack normal 100 10000 100
|
||||||
|
|
||||||
|
#echo w100000
|
||||||
|
#time ./writeBack writeback 100 100000 10
|
||||||
|
|
||||||
|
#echo n100000
|
||||||
|
#time ./writeBack normal 100 100000 10
|
||||||
|
|
||||||
|
#echo w1000000
|
||||||
|
#time ./writeBack writeback 100 1000000 1
|
||||||
|
|
||||||
|
#echo n1000000
|
||||||
|
#time ./writeBack normal 100 1000000 1
|
||||||
|
|
||||||
|
|
|
@ -16,15 +16,20 @@ static void* stasis_log_reordering_handle_worker(void * a) {
|
||||||
h->queue[h->cur_off].arg_size);
|
h->queue[h->cur_off].arg_size);
|
||||||
assert(e->xid != INVALID_XID);
|
assert(e->xid != INVALID_XID);
|
||||||
chunk_len += sizeofLogEntry(e);
|
chunk_len += sizeofLogEntry(e);
|
||||||
Page * p = h->queue[h->cur_off].p;
|
|
||||||
|
|
||||||
h->cur_len--;
|
h->cur_len--;
|
||||||
|
h->phys_size -= sizeofLogEntry(e);
|
||||||
h->cur_off = (h->cur_off+1)%h->max_len;
|
h->cur_off = (h->cur_off+1)%h->max_len;
|
||||||
|
|
||||||
|
if(h->queue[h->cur_off].p) {
|
||||||
|
Page * p = h->queue[h->cur_off].p;
|
||||||
writelock(p->rwlatch,0);
|
writelock(p->rwlatch,0);
|
||||||
stasis_page_lsn_write(e->xid, p, e->LSN);
|
stasis_page_lsn_write(e->xid, p, e->LSN);
|
||||||
unlock(p->rwlatch);
|
unlock(p->rwlatch);
|
||||||
releasePage(p);
|
releasePage(p);
|
||||||
|
} /*
|
||||||
|
else it's the caller's problem; flush(), and checking the
|
||||||
|
xaction table for prevLSN is their friend. */
|
||||||
}
|
}
|
||||||
if(chunk_len > 0) {
|
if(chunk_len > 0) {
|
||||||
lsn_t to_force = h->l->prevLSN;
|
lsn_t to_force = h->l->prevLSN;
|
||||||
|
@ -64,7 +69,8 @@ stasis_log_reordering_handle_t *
|
||||||
stasis_log_reordering_handle_open(TransactionLog * l,
|
stasis_log_reordering_handle_open(TransactionLog * l,
|
||||||
stasis_log_t* log,
|
stasis_log_t* log,
|
||||||
size_t chunk_len,
|
size_t chunk_len,
|
||||||
size_t max_len) {
|
size_t max_len,
|
||||||
|
size_t max_size) {
|
||||||
stasis_log_reordering_handle_t * ret = malloc(sizeof(*ret));
|
stasis_log_reordering_handle_t * ret = malloc(sizeof(*ret));
|
||||||
|
|
||||||
ret->l = l;
|
ret->l = l;
|
||||||
|
@ -78,18 +84,32 @@ stasis_log_reordering_handle_open(TransactionLog * l,
|
||||||
ret->max_len = max_len;
|
ret->max_len = max_len;
|
||||||
ret->cur_off = 0;
|
ret->cur_off = 0;
|
||||||
ret->cur_len = 0;
|
ret->cur_len = 0;
|
||||||
|
ret->phys_size = 0;
|
||||||
|
ret->max_size = max_size;
|
||||||
pthread_create(&ret->worker,0,stasis_log_reordering_handle_worker,ret);
|
pthread_create(&ret->worker,0,stasis_log_reordering_handle_worker,ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
void stasis_log_reordering_handle_append(stasis_log_reordering_handle_t * h,
|
static int AskedForBump = 0;
|
||||||
|
size_t stasis_log_reordering_handle_append(stasis_log_reordering_handle_t * h,
|
||||||
Page * p,
|
Page * p,
|
||||||
unsigned int op,
|
unsigned int op,
|
||||||
const byte * arg,
|
const byte * arg,
|
||||||
size_t arg_size
|
size_t arg_size,
|
||||||
|
size_t phys_size
|
||||||
) {
|
) {
|
||||||
while(h->cur_len == h->max_len) {
|
while(h->phys_size >= h->max_size) {
|
||||||
pthread_cond_wait(&h->done, &h->mut);
|
pthread_cond_wait(&h->done, &h->mut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while(h->cur_len == h->max_len) {
|
||||||
|
if(!AskedForBump) {
|
||||||
|
printf("Warning: bump max_len\n"); fflush(stdout);
|
||||||
|
AskedForBump = 1;
|
||||||
|
}
|
||||||
|
pthread_cond_wait(&h->done, &h->mut);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
intptr_t idx = (h->cur_off+h->cur_len)%h->max_len;
|
intptr_t idx = (h->cur_off+h->cur_len)%h->max_len;
|
||||||
h->queue[idx].p = p;
|
h->queue[idx].p = p;
|
||||||
h->queue[idx].op = op;
|
h->queue[idx].op = op;
|
||||||
|
@ -97,5 +117,7 @@ void stasis_log_reordering_handle_append(stasis_log_reordering_handle_t * h,
|
||||||
memcpy(h->queue[idx].arg,arg,arg_size);
|
memcpy(h->queue[idx].arg,arg,arg_size);
|
||||||
h->queue[idx].arg_size = arg_size;
|
h->queue[idx].arg_size = arg_size;
|
||||||
h->cur_len++;
|
h->cur_len++;
|
||||||
|
h->phys_size += phys_size;
|
||||||
pthread_cond_signal(&h->ready);
|
pthread_cond_signal(&h->ready);
|
||||||
|
return h->phys_size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ static int op_lsn_free_unset(const LogEntry *e, Page *p) {
|
||||||
memcpy(p->memAddr + a[0], b+a[1], a[1]);
|
memcpy(p->memAddr + a[0], b+a[1], a[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int TsetLsnFreeReorderable(int xid, stasis_log_reordering_handle_t * h,
|
int TsetReorderable(int xid, stasis_log_reordering_handle_t * h,
|
||||||
recordid rid, const void * dat) {
|
recordid rid, const void * dat) {
|
||||||
Page * p = loadPage(xid, rid.page);
|
Page * p = loadPage(xid, rid.page);
|
||||||
readlock(p->rwlatch,0);
|
readlock(p->rwlatch,0);
|
||||||
|
@ -63,7 +63,29 @@ int TsetLsnFreeReorderable(int xid, stasis_log_reordering_handle_t * h,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int TsetLsnFree(int xid, recordid rid, const void * dat) {
|
int TsetLsnFree(int xid, recordid rid, const void * dat) {
|
||||||
return TsetLsnFreeReorderable(xid, 0, rid, dat);
|
return TsetReorderable(xid, 0, rid, dat);
|
||||||
|
}
|
||||||
|
int TsetReorderableWriteBack(int xid, stasis_log_reordering_handle_t * h,
|
||||||
|
pageid_t page, pageoff_t off, pageoff_t len,
|
||||||
|
const void * dat, const void * olddat) {
|
||||||
|
intptr_t sz = 2 * (sizeof(pageoff_t) + len);
|
||||||
|
byte * buf = calloc(sz,1);
|
||||||
|
pageoff_t * a = (pageoff_t*)buf;
|
||||||
|
a[0] = off;
|
||||||
|
a[1] = len;
|
||||||
|
byte * b = (byte*)&a[2];
|
||||||
|
memcpy(b,dat,len);
|
||||||
|
memcpy(b+len,dat,len);
|
||||||
|
if(!h) {
|
||||||
|
TwritebackUpdate(xid,page,buf,sz,OPERATION_SET_LSN_FREE);
|
||||||
|
} else {
|
||||||
|
TreorderableWritebackUpdate(xid,h,page,buf,sz,OPERATION_SET_LSN_FREE);
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int TsetWriteBack(int xid, pageid_t page, pageoff_t off, pageoff_t len, const void * dat, const void * olddat) {
|
||||||
|
return TsetReorderableWriteBack(xid,0,page,off,len,dat,olddat);
|
||||||
}
|
}
|
||||||
|
|
||||||
Operation getSetLsnFree() {
|
Operation getSetLsnFree() {
|
||||||
|
|
|
@ -145,6 +145,10 @@ int stasis_page_impl_register(page_impl p) {
|
||||||
page_impls[p.page_type] = p;
|
page_impls[p.page_type] = p;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
page_impl * stasis_page_impl_get(int id) {
|
||||||
|
assert(page_impls[id].page_type == id);
|
||||||
|
return & page_impls[id];
|
||||||
|
}
|
||||||
void stasis_record_write(int xid, Page * p, lsn_t lsn, recordid rid, const byte *dat) {
|
void stasis_record_write(int xid, Page * p, lsn_t lsn, recordid rid, const byte *dat) {
|
||||||
assertlocked(p->rwlatch);
|
assertlocked(p->rwlatch);
|
||||||
assert( (p->id == rid.page) && (p->memAddr != NULL) );
|
assert( (p->id == rid.page) && (p->memAddr != NULL) );
|
||||||
|
|
|
@ -325,13 +325,12 @@ void TreorderableUpdate(int xid, void * hp, pageid_t page,
|
||||||
|
|
||||||
pthread_mutex_lock(&h->mut);
|
pthread_mutex_lock(&h->mut);
|
||||||
|
|
||||||
// e = LogUpdate(stasis_log_file, &XactionTable[xid % MAX_TRANSACTIONS],
|
|
||||||
// p, op, dat, datlen);
|
|
||||||
stasis_log_reordering_handle_append(h, p, op, dat, datlen);
|
|
||||||
|
|
||||||
LogEntry * e = allocUpdateLogEntry(-1, h->l->xid, op,
|
LogEntry * e = allocUpdateLogEntry(-1, h->l->xid, op,
|
||||||
p ? p->id : INVALID_PAGE,
|
p ? p->id : INVALID_PAGE,
|
||||||
dat, datlen);
|
dat, datlen);
|
||||||
|
|
||||||
|
stasis_log_reordering_handle_append(h, p, op, dat, datlen, sizeofLogEntry(e));
|
||||||
|
|
||||||
e->LSN = 0;
|
e->LSN = 0;
|
||||||
writelock(p->rwlatch,0);
|
writelock(p->rwlatch,0);
|
||||||
doUpdate(e, p);
|
doUpdate(e, p);
|
||||||
|
@ -340,7 +339,32 @@ void TreorderableUpdate(int xid, void * hp, pageid_t page,
|
||||||
releasePage(p);
|
releasePage(p);
|
||||||
freeLogEntry(e);
|
freeLogEntry(e);
|
||||||
}
|
}
|
||||||
|
lsn_t TwritebackUpdate(int xid, pageid_t page,
|
||||||
|
const void *dat, size_t datlen, int op) {
|
||||||
|
assert(xid >= 0 && XactionTable[xid % MAX_TRANSACTIONS].xid == xid);
|
||||||
|
LogEntry * e = allocUpdateLogEntry(-1, xid, op, page, dat, datlen);
|
||||||
|
TransactionLog* l = &XactionTable[xid % MAX_TRANSACTIONS];
|
||||||
|
stasis_log_file->write_entry(stasis_log_file, e);
|
||||||
|
|
||||||
|
if(l->prevLSN == -1) { l->recLSN = e->LSN; }
|
||||||
|
l->prevLSN = e->LSN;
|
||||||
|
|
||||||
|
freeLogEntry(e);
|
||||||
|
return l->prevLSN;
|
||||||
|
}
|
||||||
|
/** DANGER: you need to set the LSN's on the pages that you want to write back,
|
||||||
|
this method doesn't let you do that, so the only option is to pin until
|
||||||
|
commit, then set a conservative (too high) lsn */
|
||||||
|
void TreorderableWritebackUpdate(int xid, void* hp,
|
||||||
|
pageid_t page, const void * dat,
|
||||||
|
size_t datlen, int op) {
|
||||||
|
stasis_log_reordering_handle_t* h = hp;
|
||||||
|
assert(xid >= 0 && XactionTable[xid % MAX_TRANSACTIONS].xid == xid);
|
||||||
|
pthread_mutex_lock(&h->mut);
|
||||||
|
LogEntry * e = allocUpdateLogEntry(-1, xid, op, page, dat, datlen);
|
||||||
|
stasis_log_reordering_handle_append(h, 0, op, dat, datlen, sizeofLogEntry(e));
|
||||||
|
|
||||||
|
}
|
||||||
compensated_function void TupdateStr(int xid, pageid_t page,
|
compensated_function void TupdateStr(int xid, pageid_t page,
|
||||||
const char *dat, size_t datlen, int op) {
|
const char *dat, size_t datlen, int op) {
|
||||||
Tupdate(xid, page, dat, datlen, op);
|
Tupdate(xid, page, dat, datlen, op);
|
||||||
|
|
|
@ -23,6 +23,8 @@ typedef struct stasis_log_reordering_handle_t {
|
||||||
size_t max_len;
|
size_t max_len;
|
||||||
size_t cur_off;
|
size_t cur_off;
|
||||||
size_t cur_len;
|
size_t cur_len;
|
||||||
|
size_t max_size;
|
||||||
|
size_t phys_size;
|
||||||
} stasis_log_reordering_handle_t;
|
} stasis_log_reordering_handle_t;
|
||||||
|
|
||||||
#include <stasis/page.h>
|
#include <stasis/page.h>
|
||||||
|
@ -33,11 +35,14 @@ stasis_log_reordering_handle_t *
|
||||||
stasis_log_reordering_handle_open(TransactionLog * l,
|
stasis_log_reordering_handle_open(TransactionLog * l,
|
||||||
stasis_log_t* log,
|
stasis_log_t* log,
|
||||||
size_t chunk_len,
|
size_t chunk_len,
|
||||||
size_t max_len);
|
size_t max_len,
|
||||||
void stasis_log_reordering_handle_append(stasis_log_reordering_handle_t * h,
|
size_t max_size);
|
||||||
|
size_t stasis_log_reordering_handle_append(stasis_log_reordering_handle_t * h,
|
||||||
Page * p,
|
Page * p,
|
||||||
unsigned int op,
|
unsigned int op,
|
||||||
const byte * arg,
|
const byte * arg,
|
||||||
size_t arg_size);
|
size_t arg_size,
|
||||||
|
size_t phys_size
|
||||||
|
);
|
||||||
|
|
||||||
#endif //__STASIS_LOG_REORDERING_HANDLE_H
|
#endif //__STASIS_LOG_REORDERING_HANDLE_H
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
Operation getSetLsnFree();
|
Operation getSetLsnFree();
|
||||||
Operation getSetLsnFreeInverse();
|
Operation getSetLsnFreeInverse();
|
||||||
int TsetLsnFree(int xid, recordid rid, const void *dat);
|
int TsetLsnFree(int xid, recordid rid, const void *dat);
|
||||||
int TsetLsnReorderable(int xid, stasis_log_reordering_handle_t * h,
|
int TsetReorderable(int xid, stasis_log_reordering_handle_t * h,
|
||||||
recordid rid, const void *dat);
|
recordid rid, const void *dat);
|
||||||
|
int TsetWriteBack(int xid, pageid_t page, pageoff_t off, pageoff_t len,
|
||||||
|
const void * dat, const void * olddat);
|
||||||
#endif //__LSN_FREE_SET_H
|
#endif //__LSN_FREE_SET_H
|
||||||
|
|
|
@ -865,6 +865,16 @@ typedef struct page_impl {
|
||||||
*/
|
*/
|
||||||
int stasis_page_impl_register(page_impl impl);
|
int stasis_page_impl_register(page_impl impl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get the page_impl for a particular page type. This isn't set
|
||||||
|
const, so you can write to the function pointers. However, no
|
||||||
|
attempt has been made to make such things thread safe, so stasis'
|
||||||
|
worker threads can cause all sorts of undefined trouble if you poke
|
||||||
|
this.
|
||||||
|
*/
|
||||||
|
page_impl* stasis_page_impl_get(int id);
|
||||||
|
|
||||||
|
|
||||||
// -------------------- Page specific, general purpose methods
|
// -------------------- Page specific, general purpose methods
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -617,6 +617,19 @@ compensated_function void TupdateStr(int xid, pageid_t page,
|
||||||
|
|
||||||
void TreorderableUpdate(int xid, void * h, pageid_t page,
|
void TreorderableUpdate(int xid, void * h, pageid_t page,
|
||||||
const void * dat, size_t datlen, int op);
|
const void * dat, size_t datlen, int op);
|
||||||
|
/** Note; it is *your* responsibility to set the lsn on the page; this
|
||||||
|
function returns a plausible value */
|
||||||
|
lsn_t TwritebackUpdate(int xid, pageid_t page,
|
||||||
|
const void * dat, size_t datlen, int op);
|
||||||
|
|
||||||
|
|
||||||
|
/** DANGER: you need to set the LSN's on the pages that you want to write back,
|
||||||
|
this method doesn't help you do that, so the only option is to pin until
|
||||||
|
commit, then set a conservative (too high) lsn */
|
||||||
|
void TreorderableWritebackUpdate(int xid, void* h,
|
||||||
|
pageid_t page, const void * dat,
|
||||||
|
size_t datlen, int op);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the value of a record.
|
* Read the value of a record.
|
||||||
*
|
*
|
||||||
|
|
|
@ -655,7 +655,8 @@ START_TEST(operation_reorderable) {
|
||||||
&XactionTable[xid[0]% MAX_TRANSACTIONS],
|
&XactionTable[xid[0]% MAX_TRANSACTIONS],
|
||||||
stasis_log_file,
|
stasis_log_file,
|
||||||
100, // bytes (far too low!)
|
100, // bytes (far too low!)
|
||||||
5 // log entries
|
10, // log entries
|
||||||
|
500 // max byte size
|
||||||
);
|
);
|
||||||
for(int i = 0; i < 100; i++) {
|
for(int i = 0; i < 100; i++) {
|
||||||
int foo;
|
int foo;
|
||||||
|
@ -664,7 +665,7 @@ START_TEST(operation_reorderable) {
|
||||||
if(i%2) {
|
if(i%2) {
|
||||||
TsetLsnFree(xid[i%2], rid[i], &i);
|
TsetLsnFree(xid[i%2], rid[i], &i);
|
||||||
} else {
|
} else {
|
||||||
TsetLsnFreeReorderable(xid[i%2], rh, rid[i], &i);
|
TsetReorderable(xid[i%2], rh, rid[i], &i);
|
||||||
}
|
}
|
||||||
Tread(xid[i%2],rid[i], &foo);
|
Tread(xid[i%2],rid[i], &foo);
|
||||||
assert(foo == i);
|
assert(foo == i);
|
||||||
|
|
Loading…
Reference in a new issue