added dup method to io handles
This commit is contained in:
parent
ff2f2e9e1e
commit
7c5eb2a7e9
7 changed files with 101 additions and 24 deletions
|
@ -35,6 +35,15 @@ static int debug_close(stasis_handle_t * h) {
|
|||
free(h);
|
||||
return ret;
|
||||
}
|
||||
static stasis_handle_t * debug_dup(stasis_handle_t * h) {
|
||||
stasis_handle_t * hh = ((debug_impl*)h->impl)->h;
|
||||
printf("tid=%9ld call dup(%lx)\n", (long)(intptr_t)pthread_self(), (unsigned long)hh); fflush(stdout);
|
||||
stasis_handle_t * ret = hh->dup(hh);
|
||||
printf("tid=%9ld retn dup(%lx) = %lx\n", (long)(intptr_t)pthread_self(), (unsigned long)hh, (unsigned long)ret); fflush(stdout);
|
||||
free(h->impl);
|
||||
free(h);
|
||||
return ret;
|
||||
}
|
||||
static lsn_t debug_start_position(stasis_handle_t *h) {
|
||||
stasis_handle_t * hh = ((debug_impl*)h->impl)->h;
|
||||
printf("tid=%9ld call start_position(%lx)\n", (long)(intptr_t)pthread_self(), (unsigned long)hh); fflush(stdout);
|
||||
|
@ -170,6 +179,7 @@ struct stasis_handle_t debug_func = {
|
|||
.num_copies = debug_num_copies,
|
||||
.num_copies_buffer = debug_num_copies_buffer,
|
||||
.close = debug_close,
|
||||
.dup = debug_dup,
|
||||
.start_position = debug_start_position,
|
||||
.end_position = debug_end_position,
|
||||
.write = debug_write,
|
||||
|
|
|
@ -46,6 +46,11 @@ static int file_close(stasis_handle_t * h) {
|
|||
if(!ret) return 0;
|
||||
else return errno;
|
||||
}
|
||||
static stasis_handle_t* file_dup(stasis_handle_t * h) {
|
||||
file_impl * impl = h->impl;
|
||||
return stasis_handle_open_file(impl->start_pos, impl->filename, impl->file_flags, impl->file_mode);
|
||||
}
|
||||
|
||||
static lsn_t file_start_position(stasis_handle_t *h) {
|
||||
file_impl * impl = (file_impl*)h->impl;
|
||||
pthread_mutex_lock(&(impl->mut));
|
||||
|
@ -548,6 +553,7 @@ struct stasis_handle_t file_func = {
|
|||
.num_copies = file_num_copies,
|
||||
.num_copies_buffer = file_num_copies_buffer,
|
||||
.close = file_close,
|
||||
.dup = file_dup,
|
||||
.start_position = file_start_position,
|
||||
.end_position = file_end_position,
|
||||
.write = file_write,
|
||||
|
|
|
@ -6,18 +6,28 @@ typedef struct mem_impl {
|
|||
lsn_t start_pos;
|
||||
lsn_t end_pos;
|
||||
byte * buf;
|
||||
int refcount;
|
||||
} mem_impl;
|
||||
|
||||
static int mem_num_copies(stasis_handle_t * h) { return 1; }
|
||||
static int mem_num_copies_buffer(stasis_handle_t * h) { return 0; }
|
||||
|
||||
static int mem_close(stasis_handle_t * h) {
|
||||
free(((mem_impl*)h->impl)->buf);
|
||||
pthread_mutex_destroy(&(((mem_impl*)h->impl)->mut));
|
||||
mem_impl *impl = h->impl;
|
||||
(impl->refcount)--;
|
||||
if(impl->refcount) { return 0; }
|
||||
|
||||
free(impl->buf);
|
||||
pthread_mutex_destroy(&(impl->mut));
|
||||
free(h->impl);
|
||||
free(h);
|
||||
return 0;
|
||||
}
|
||||
static stasis_handle_t * mem_dup(stasis_handle_t *h) {
|
||||
mem_impl *impl = h->impl;
|
||||
(impl->refcount)++;
|
||||
return h;
|
||||
}
|
||||
static lsn_t mem_start_position(stasis_handle_t *h) {
|
||||
lsn_t ret;
|
||||
mem_impl* impl = (mem_impl*)(h->impl);
|
||||
|
@ -243,6 +253,7 @@ struct stasis_handle_t mem_func = {
|
|||
.num_copies = mem_num_copies,
|
||||
.num_copies_buffer = mem_num_copies_buffer,
|
||||
.close = mem_close,
|
||||
.dup = mem_dup,
|
||||
.start_position = mem_start_position,
|
||||
.end_position = mem_end_position,
|
||||
.write = mem_write,
|
||||
|
@ -270,6 +281,7 @@ stasis_handle_t * stasis_handle(open_memory)(lsn_t start_offset) {
|
|||
impl->start_pos = start_offset;
|
||||
impl->end_pos = start_offset;
|
||||
impl->buf = malloc(0);
|
||||
impl->refcount = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -179,6 +179,7 @@ typedef struct nbw_impl {
|
|||
pthread_cond_t force_completed_cond;
|
||||
pthread_cond_t pending_writes_cond;
|
||||
int still_open;
|
||||
int refcount;
|
||||
} nbw_impl;
|
||||
|
||||
static inline void freeFastHandle(nbw_impl * impl, const tree_node * n);
|
||||
|
@ -332,6 +333,12 @@ static int nbw_close(stasis_handle_t * h) {
|
|||
nbw_impl * impl = h->impl;
|
||||
|
||||
pthread_mutex_lock(&impl->mut);
|
||||
|
||||
(impl->refcount)--;
|
||||
if(impl->refcount) {
|
||||
pthread_mutex_unlock(&impl->mut);
|
||||
return 0;
|
||||
}
|
||||
impl->still_open = 0;
|
||||
pthread_mutex_unlock(&impl->mut);
|
||||
pthread_cond_broadcast(&impl->pending_writes_cond);
|
||||
|
@ -374,6 +381,11 @@ static int nbw_close(stasis_handle_t * h) {
|
|||
free(h);
|
||||
return ret;
|
||||
}
|
||||
static stasis_handle_t * nbw_dup(stasis_handle_t *h) {
|
||||
nbw_impl * impl = h->impl;
|
||||
(impl->refcount)++;
|
||||
return h;
|
||||
}
|
||||
static lsn_t nbw_start_position(stasis_handle_t *h) {
|
||||
nbw_impl * impl = h->impl;
|
||||
pthread_mutex_lock(&impl->mut);
|
||||
|
@ -614,6 +626,7 @@ struct stasis_handle_t nbw_func = {
|
|||
.num_copies = nbw_num_copies,
|
||||
.num_copies_buffer = nbw_num_copies_buffer,
|
||||
.close = nbw_close,
|
||||
.dup = nbw_dup,
|
||||
.start_position = nbw_start_position,
|
||||
.end_position = nbw_end_position,
|
||||
.write = nbw_write,
|
||||
|
@ -830,6 +843,7 @@ stasis_handle_t * stasis_handle(open_non_blocking)
|
|||
pthread_cond_init(&impl->force_completed_cond, 0);
|
||||
|
||||
impl->still_open = 1;
|
||||
impl->refcount++;
|
||||
|
||||
stasis_handle_t *h = malloc(sizeof(stasis_handle_t));
|
||||
*h = nbw_func;
|
||||
|
|
|
@ -74,6 +74,11 @@ static int pfile_close(stasis_handle_t *h) {
|
|||
else return errno;
|
||||
}
|
||||
|
||||
static stasis_handle_t * pfile_dup(stasis_handle_t *h) {
|
||||
pfile_impl *impl = h->impl;
|
||||
return stasis_handle_open_pfile(impl->start_pos, impl->filename, impl->file_flags, impl->file_mode);
|
||||
}
|
||||
|
||||
static lsn_t pfile_start_position(stasis_handle_t *h) {
|
||||
pfile_impl *impl = (pfile_impl*)h->impl;
|
||||
return impl->start_pos;
|
||||
|
@ -415,6 +420,7 @@ struct stasis_handle_t pfile_func = {
|
|||
.num_copies = pfile_num_copies,
|
||||
.num_copies_buffer = pfile_num_copies_buffer,
|
||||
.close = pfile_close,
|
||||
.dup = pfile_dup,
|
||||
.start_position = pfile_start_position,
|
||||
.end_position = pfile_end_position,
|
||||
.write = pfile_write,
|
||||
|
|
|
@ -104,6 +104,15 @@ typedef struct stasis_handle_t {
|
|||
/** Close this handle, and release any associated resources. */
|
||||
int (*close)(struct stasis_handle_t *);
|
||||
|
||||
/** Duplicate this handle. This is useful for performance hinting;
|
||||
* sending sequential disk operations to different handles than random
|
||||
* operations allows the kernel's prefetch algorithm to kick in.
|
||||
*
|
||||
* XXX calling dup on a handle, then calling truncate or append on the resulting handles has undefined semantics.
|
||||
*
|
||||
* @return a stasis_handle_t that should eventually have close() called on it.
|
||||
*/
|
||||
struct stasis_handle_t * (*dup)(struct stasis_handle_t *h);
|
||||
/** The offset of the handle's first byte */
|
||||
lsn_t (*start_position)(struct stasis_handle_t * h);
|
||||
|
||||
|
|
|
@ -129,10 +129,15 @@ void load_handle(thread_arg* t) {
|
|||
|
||||
stasis_handle_t * h = t->h;
|
||||
|
||||
if(handle_truncate_is_supported) {
|
||||
for(int i = 0; i < t->count; i++) {
|
||||
offsets[i] = -1;
|
||||
}
|
||||
|
||||
} else {
|
||||
for(int i = 0; i < t->count; i++) {
|
||||
offsets[i] = i * sizeof(int);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < OPS_PER_THREAD; i++) {
|
||||
int val = myrandom(t->count);
|
||||
|
||||
|
@ -178,11 +183,14 @@ void load_handle(thread_arg* t) {
|
|||
}
|
||||
} break;
|
||||
case 2: { // append
|
||||
if(handle_truncate_is_supported) {
|
||||
lsn_t oldend = h->end_position(h);
|
||||
int ret = h->append(h, &(offsets[val]), (const byte*)&(t->values[val]), sizeof(int));
|
||||
assert(!ret || oldend < h->start_position(h));
|
||||
}
|
||||
} break;
|
||||
case 3: { // append_buffer
|
||||
if(handle_truncate_is_supported) {
|
||||
lsn_t oldend = h->end_position(h);
|
||||
stasis_write_buffer_t * w = h->append_buffer(h, sizeof(int));
|
||||
if(!w->error) {
|
||||
|
@ -193,6 +201,7 @@ void load_handle(thread_arg* t) {
|
|||
assert(oldend < h->start_position(h));
|
||||
}
|
||||
w->h->release_write_buffer(w);
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
abort();
|
||||
|
@ -219,6 +228,7 @@ void load_handle(thread_arg* t) {
|
|||
assert(j == t->values[val]);
|
||||
} else {
|
||||
assert(ret == EDOM);
|
||||
if(handle_truncate_is_supported)
|
||||
assert(h->start_position(h) > offsets[val]);
|
||||
}
|
||||
} break;
|
||||
|
@ -231,6 +241,7 @@ void load_handle(thread_arg* t) {
|
|||
} else {
|
||||
assert(r->error == EDOM);
|
||||
r->h->release_read_buffer(r);
|
||||
if(handle_truncate_is_supported)
|
||||
assert(h->start_position(h) > offsets[val]);
|
||||
}
|
||||
} break;
|
||||
|
@ -287,7 +298,7 @@ void handle_sequentialtest(stasis_handle_t * h) {
|
|||
void handle_concurrencytest(stasis_handle_t * h) {
|
||||
int vc = myrandom(VALUE_COUNT) + 10;
|
||||
|
||||
printf("Running concurrency test with %d values", vc); fflush(stdout);
|
||||
printf("Running concurrency test with %d values\n", vc); fflush(stdout);
|
||||
|
||||
int * values = malloc(vc * sizeof(int));
|
||||
|
||||
|
@ -297,12 +308,17 @@ void handle_concurrencytest(stasis_handle_t * h) {
|
|||
|
||||
thread_arg * args = malloc(THREAD_COUNT * sizeof(thread_arg));
|
||||
pthread_t * threads = malloc(THREAD_COUNT * sizeof(pthread_t));
|
||||
stasis_handle_t ** handles = malloc(THREAD_COUNT / 2 * sizeof(*handles));
|
||||
|
||||
int val_per_thread = vc / THREAD_COUNT;
|
||||
trunc_val = 0;
|
||||
for(int i = 0; i < THREAD_COUNT; i++) {
|
||||
args[i].values = &(values[i * val_per_thread]);
|
||||
args[i].count = val_per_thread;
|
||||
if(!(i % 2)) {
|
||||
handles[i/2] = h->dup(h);
|
||||
h = handles[i/2];
|
||||
}
|
||||
args[i].h = h;
|
||||
pthread_create(&threads[i], 0, (void*(*)(void*))load_handle, &args[i]);
|
||||
}
|
||||
|
@ -310,9 +326,13 @@ void handle_concurrencytest(stasis_handle_t * h) {
|
|||
for(int i = 0; i < THREAD_COUNT; i++) {
|
||||
pthread_join(threads[i], 0);
|
||||
}
|
||||
for(int i = 0; i < THREAD_COUNT / 2; i++) {
|
||||
handles[i]->close(handles[i]);
|
||||
}
|
||||
free(values);
|
||||
free(args);
|
||||
free(threads);
|
||||
free(handles);
|
||||
}
|
||||
/**
|
||||
@test
|
||||
|
@ -353,7 +373,7 @@ START_TEST(io_fileTest) {
|
|||
unlink("logfile.txt");
|
||||
|
||||
h = stasis_handle(open_file)(0, "logfile.txt", O_CREAT | O_RDWR, FILE_PERM);
|
||||
//handle_concurrencytest(h);
|
||||
// handle_concurrencytest(h); // fails by design
|
||||
h->close(h);
|
||||
|
||||
unlink("logfile.txt");
|
||||
|
@ -390,7 +410,7 @@ START_TEST(io_pfileTest) {
|
|||
unlink("logfile.txt");
|
||||
|
||||
h = stasis_handle(open_pfile)(0, "logfile.txt", O_CREAT | O_RDWR, FILE_PERM);
|
||||
//handle_concurrencytest(h);
|
||||
handle_concurrencytest(h);
|
||||
h->close(h);
|
||||
|
||||
unlink("logfile.txt");
|
||||
|
|
Loading…
Reference in a new issue