add support for fallocate(); enable it by default if it is available at build time.

This commit is contained in:
Sears Russell 2011-08-25 21:29:51 +00:00
parent 9083bca1c3
commit 08c8be07b1
17 changed files with 107 additions and 11 deletions

View file

@ -64,6 +64,7 @@ endif(NOT HAVE_FUSE)
INCLUDE(CheckFunctionExists) INCLUDE(CheckFunctionExists)
INCLUDE(CheckCSourceCompiles) INCLUDE(CheckCSourceCompiles)
CHECK_FUNCTION_EXISTS(sync_file_range HAVE_SYNC_FILE_RANGE) CHECK_FUNCTION_EXISTS(sync_file_range HAVE_SYNC_FILE_RANGE)
CHECK_FUNCTION_EXISTS(posix_fallocate HAVE_POSIX_FALLOCATE)
CHECK_FUNCTION_EXISTS(fdatasync HAVE_FDATASYNC) CHECK_FUNCTION_EXISTS(fdatasync HAVE_FDATASYNC)
CHECK_FUNCTION_EXISTS(tdestroy HAVE_TDESTROY) CHECK_FUNCTION_EXISTS(tdestroy HAVE_TDESTROY)

View file

@ -1,5 +1,6 @@
#define __USE_GNU #define __USE_GNU
#define _GNU_SOURCE #define _GNU_SOURCE
#cmakedefine HAVE_POSIX_FALLOCATE
#cmakedefine HAVE_FDATASYNC #cmakedefine HAVE_FDATASYNC
#cmakedefine HAVE_SYNC_FILE_RANGE #cmakedefine HAVE_SYNC_FILE_RANGE
#cmakedefine HAVE_O_DIRECT #cmakedefine HAVE_O_DIRECT

View file

@ -202,6 +202,27 @@ void prefetchPages(pageid_t pageid, pageid_t count) {
if(bm->prefetchPages != NULL) { bm->prefetchPages(bm, pageid, count); } if(bm->prefetchPages != NULL) { bm->prefetchPages(bm, pageid, count); }
} }
int preallocatePages(pageid_t pageid, pageid_t count) {
stasis_buffer_manager_t * bm = stasis_runtime_buffer_manager();
// This is just a performance hint; and is an optional method.
if(stasis_buffer_manager_preallocate_mode == STASIS_BUFFER_MANAGER_PREALLOCATE_LEGACY) {
// Legacy option (ext3): pre-fill the stasis buffer manager with dirty zeros.
for(pageid_t i = 0; i < count; i++) {
Page * p = loadUninitializedPage(-1, pageid+i);
stasis_dirty_page_table_set_dirty(stasis_runtime_dirty_page_table(), p);
releasePage(p);
}
} else if(stasis_buffer_manager_preallocate_mode == STASIS_BUFFER_MANAGER_PREALLOCATE_DEFAULT) {
if(bm->preallocatePages != NULL) { return bm->preallocatePages(bm, pageid, count); }
} else if(stasis_buffer_manager_preallocate_mode == STASIS_BUFFER_MANAGER_PREALLOCATE_DISABLED) {
} else {
fprintf(stderr, "Configuration error. Unknown preallocation mode: %d\n",
stasis_buffer_manager_preallocate_mode);
abort();
}
return 0;
}
Page * getCachedPage(int xid, pageid_t pageid) { Page * getCachedPage(int xid, pageid_t pageid) {
stasis_buffer_manager_t * bm = stasis_runtime_buffer_manager(); stasis_buffer_manager_t * bm = stasis_runtime_buffer_manager();
return bm->getCachedPageImpl(bm, xid, pageid); return bm->getCachedPageImpl(bm, xid, pageid);

View file

@ -370,6 +370,12 @@ void bhPrefetchPagesImpl(stasis_buffer_manager_t *bm, pageid_t pageid, pageid_t
} }
static int bhPreallocatePages(stasis_buffer_manager_t * bm, pageid_t start, pageid_t count) {
stasis_buffer_hash_t * bh = bm->impl;
return bh->page_handle->preallocate_range(bh->page_handle, start, count);
}
static void bhReleasePage(stasis_buffer_manager_t * bm, Page * p) { static void bhReleasePage(stasis_buffer_manager_t * bm, Page * p) {
DEBUG("releasePage(%lld) (rwlatch = %llx)\n", p->id, (long long)p->rwlatch); DEBUG("releasePage(%lld) (rwlatch = %llx)\n", p->id, (long long)p->rwlatch);
stasis_buffer_hash_t * bh = bm->impl; stasis_buffer_hash_t * bh = bm->impl;
@ -503,6 +509,7 @@ stasis_buffer_manager_t* stasis_buffer_manager_hash_open(stasis_page_handle_t *
bm->loadPageImpl = bhLoadPageImpl; bm->loadPageImpl = bhLoadPageImpl;
bm->loadUninitPageImpl = bhLoadUninitPageImpl; bm->loadUninitPageImpl = bhLoadUninitPageImpl;
bm->prefetchPages = bhPrefetchPagesImpl; bm->prefetchPages = bhPrefetchPagesImpl;
bm->preallocatePages = bhPreallocatePages;
bm->getCachedPageImpl = bhGetCachedPage; bm->getCachedPageImpl = bhGetCachedPage;
bm->releasePageImpl = bhReleasePage; bm->releasePageImpl = bhReleasePage;
bm->writeBackPage = bhWriteBackPage; bm->writeBackPage = bhWriteBackPage;

View file

@ -370,6 +370,10 @@ static void chForcePageRange(stasis_buffer_manager_t *bm, stasis_buffer_manager_
stasis_buffer_concurrent_hash_t * ch = bm->impl; stasis_buffer_concurrent_hash_t * ch = bm->impl;
ch->page_handle->force_range(ch->page_handle, start, stop); ch->page_handle->force_range(ch->page_handle, start, stop);
} }
static int chPreallocatePages(stasis_buffer_manager_t * bm, pageid_t start, pageid_t count) {
stasis_buffer_concurrent_hash_t * ch = bm->impl;
return ch->page_handle->preallocate_range(ch->page_handle, start, count);
}
static void chBufDeinitHelper(stasis_buffer_manager_t * bm, int crash) { static void chBufDeinitHelper(stasis_buffer_manager_t * bm, int crash) {
stasis_buffer_concurrent_hash_t *ch = bm->impl; stasis_buffer_concurrent_hash_t *ch = bm->impl;
ch->running = 0; ch->running = 0;
@ -411,6 +415,7 @@ stasis_buffer_manager_t* stasis_buffer_manager_concurrent_hash_open(stasis_page_
bm->loadPageImpl = chLoadPageImpl; bm->loadPageImpl = chLoadPageImpl;
bm->loadUninitPageImpl = chLoadUninitPageImpl; bm->loadUninitPageImpl = chLoadUninitPageImpl;
bm->prefetchPages = NULL; bm->prefetchPages = NULL;
bm->preallocatePages = chPreallocatePages;
bm->getCachedPageImpl = chGetCachedPage; bm->getCachedPageImpl = chGetCachedPage;
bm->releasePageImpl = chReleasePage; bm->releasePageImpl = chReleasePage;
bm->writeBackPage = chWriteBackPage; bm->writeBackPage = chWriteBackPage;

View file

@ -61,6 +61,7 @@ stasis_buffer_manager_t* stasis_buffer_manager_deprecated_open(stasis_page_handl
bm->loadPageImpl = bufManLoadPage; bm->loadPageImpl = bufManLoadPage;
bm->loadUninitPageImpl = bufManLoadUninitPage; bm->loadUninitPageImpl = bufManLoadUninitPage;
bm->prefetchPages = NULL; bm->prefetchPages = NULL;
bm->preallocatePages = NULL;
bm->getCachedPageImpl = bufManGetCachedPage; bm->getCachedPageImpl = bufManGetCachedPage;
bm->writeBackPage = pageWrite_legacyWrapper; bm->writeBackPage = pageWrite_legacyWrapper;
bm->forcePages = forcePageFile_legacyWrapper; bm->forcePages = forcePageFile_legacyWrapper;

View file

@ -90,6 +90,7 @@ stasis_buffer_manager_t * stasis_buffer_manager_mem_array_open () {
bm->loadPageImpl = paLoadPage; bm->loadPageImpl = paLoadPage;
bm->loadUninitPageImpl = paLoadUninitPage; bm->loadUninitPageImpl = paLoadUninitPage;
bm->prefetchPages = NULL; bm->prefetchPages = NULL;
bm->preallocatePages = NULL;
bm->getCachedPageImpl = paGetCachedPage; bm->getCachedPageImpl = paGetCachedPage;
bm->writeBackPage = paWriteBackPage; bm->writeBackPage = paWriteBackPage;
bm->tryToWriteBackPage = paWriteBackPage; bm->tryToWriteBackPage = paWriteBackPage;

View file

@ -33,6 +33,17 @@ int stasis_buffer_manager_io_handle_flags =
O_NOATIME; O_NOATIME;
#endif #endif
int stasis_buffer_manager_preallocate_mode =
#ifdef STASIS_BUFFER_MANAGER_PREALLOCATE_MODE
STASIS_BUFFER_MANAGER_PREALLOCATE_MODE;
#else
#ifdef HAVE_POSIX_FALLOCATE
STASIS_BUFFER_MANAGER_PREALLOCATE_DEFAULT;
#else
STASIS_BUFFER_MANAGER_PREALLOCATE_LEGACY;
#endif
#endif
#ifdef STASIS_BUFFER_MANAGER_SIZE #ifdef STASIS_BUFFER_MANAGER_SIZE
pageid_t stasis_buffer_manager_size = STASIS_BUFFER_MANAGER_SIZE; pageid_t stasis_buffer_manager_size = STASIS_BUFFER_MANAGER_SIZE;
#else // STASIS_BUFFER_MANAGER_SIZE #else // STASIS_BUFFER_MANAGER_SIZE

View file

@ -410,6 +410,16 @@ static int file_force_range(stasis_handle_t *h, lsn_t start, lsn_t stop) {
} }
return ret; return ret;
} }
static int file_fallocate(struct stasis_handle_t* h, lsn_t off, lsn_t len) {
file_impl * impl = h->impl;
#ifdef HAVE_POSIX_FALLOCATE
return posix_fallocate(impl->fd, off, len);
#else
(void)impl;
fprintf(stderr, "file.c: fallocate called, but not supported by this build.\n");
return -1;
#endif
}
struct stasis_handle_t file_func = { struct stasis_handle_t file_func = {
.num_copies = file_num_copies, .num_copies = file_num_copies,
@ -426,6 +436,7 @@ struct stasis_handle_t file_func = {
.release_read_buffer = file_release_read_buffer, .release_read_buffer = file_release_read_buffer,
.force = file_force, .force = file_force,
.force_range = file_force_range, .force_range = file_force_range,
.fallocate = file_fallocate,
.error = 0 .error = 0
}; };

View file

@ -342,7 +342,16 @@ static int pfile_force_range(stasis_handle_t *h, lsn_t start, lsn_t stop) {
TOCK(force_range_hist); TOCK(force_range_hist);
return ret; return ret;
} }
static int pfile_fallocate(struct stasis_handle_t* h, lsn_t off, lsn_t len) {
pfile_impl * impl = h->impl;
#ifdef HAVE_POSIX_FALLOCATE
return posix_fallocate(impl->fd, off, len);
#else
(void)impl;
fprintf(stderr, "pfile.c: fallocate called, but not supported by this build.\n");
return -1;
#endif
}
static struct stasis_handle_t pfile_func = { static struct stasis_handle_t pfile_func = {
.num_copies = pfile_num_copies, .num_copies = pfile_num_copies,
.num_copies_buffer = pfile_num_copies_buffer, .num_copies_buffer = pfile_num_copies_buffer,
@ -358,6 +367,7 @@ static struct stasis_handle_t pfile_func = {
.release_read_buffer = pfile_release_read_buffer, .release_read_buffer = pfile_release_read_buffer,
.force = pfile_force, .force = pfile_force,
.force_range = pfile_force_range, .force_range = pfile_force_range,
.fallocate = pfile_fallocate,
.error = 0 .error = 0
}; };

View file

@ -270,16 +270,18 @@ static void TregionAllocHelper(int xid, pageid_t page, pageid_t pageCount, int a
new_tag.size = PAGEID_T_MAX; new_tag.size = PAGEID_T_MAX;
// We're extending the page file, so pre-fill the stasis buffer manager with dirty zeros. This // We're extending the page file, and need to prevent it from
// prevents the file from becoming sparse. // becoming sparse.
for(pageid_t i = page+1; i < newPageid; i++) {
Page * p = loadUninitializedPage(xid, i);
writelock(p->rwlatch, 0);
stasis_dirty_page_table_set_dirty(stasis_runtime_dirty_page_table(), p);
unlock(p->rwlatch);
releasePage(p);
}
int preallocation_error
= preallocatePages(page+1, newPageid - page);
if(preallocation_error) {
if(preallocation_error == -1) {
fprintf(stderr, "Note, errno is -1, which usually means that there was a build problem.\n");
}
perror("Could not preallocate after end of file.\n");
abort();
}
} }
new_tag.prev_size = pageCount; new_tag.prev_size = pageCount;
// Create the new region, and disassociate it from this transaction immediately. // Create the new region, and disassociate it from this transaction immediately.

View file

@ -52,6 +52,12 @@ static void phPrefetchRange(stasis_page_handle_t *ph, pageid_t pageid, pageid_t
free(buf); free(buf);
} }
static int phPreallocateRange(stasis_page_handle_t * ph, pageid_t pageid, pageid_t count) {
lsn_t off = pageid * PAGE_SIZE;
lsn_t len = count * PAGE_SIZE;
return ((stasis_handle_t*)ph->impl)->fallocate(ph->impl, off, len);
}
static void phForce(stasis_page_handle_t * ph) { static void phForce(stasis_page_handle_t * ph) {
int err = ((stasis_handle_t*)ph->impl)->force(ph->impl); int err = ((stasis_handle_t*)ph->impl)->force(ph->impl);
assert(!err); assert(!err);
@ -91,6 +97,7 @@ stasis_page_handle_t * stasis_page_handle_open(stasis_handle_t * handle,
ret->write = phWrite; ret->write = phWrite;
ret->read = phRead; ret->read = phRead;
ret->prefetch_range = phPrefetchRange; ret->prefetch_range = phPrefetchRange;
ret->preallocate_range = phPreallocateRange;
ret->force_file = phForce; ret->force_file = phForce;
ret->force_range = phForceRange; ret->force_range = phForceRange;
ret->close = phClose; ret->close = phClose;

View file

@ -99,7 +99,7 @@ Page * loadUninitializedPage(int xid, pageid_t pageid);
Page * loadPageForOperation(int xid, pageid_t pageid, int op); Page * loadPageForOperation(int xid, pageid_t pageid, int op);
void prefetchPages(pageid_t pageid, pageid_t count); void prefetchPages(pageid_t pageid, pageid_t count);
int preallocatePages(pageid_t pageid, pageid_t count);
/** /**
Get a page from cache. This function should never block on I/O. Get a page from cache. This function should never block on I/O.
@ -126,6 +126,7 @@ struct stasis_buffer_manager_t {
Page * (*loadPageImpl)(stasis_buffer_manager_t*, stasis_buffer_manager_handle_t* h, int xid, pageid_t pageid, pagetype_t type); Page * (*loadPageImpl)(stasis_buffer_manager_t*, stasis_buffer_manager_handle_t* h, int xid, pageid_t pageid, pagetype_t type);
Page * (*loadUninitPageImpl)(stasis_buffer_manager_t*, int xid, pageid_t pageid); Page * (*loadUninitPageImpl)(stasis_buffer_manager_t*, int xid, pageid_t pageid);
void (*prefetchPages)(stasis_buffer_manager_t*, pageid_t pageid, pageid_t count); void (*prefetchPages)(stasis_buffer_manager_t*, pageid_t pageid, pageid_t count);
int (*preallocatePages)(stasis_buffer_manager_t*, pageid_t pageid, pageid_t count);
Page * (*getCachedPageImpl)(stasis_buffer_manager_t*, int xid, const pageid_t pageid); Page * (*getCachedPageImpl)(stasis_buffer_manager_t*, int xid, const pageid_t pageid);
void (*releasePageImpl)(stasis_buffer_manager_t*, Page * p); void (*releasePageImpl)(stasis_buffer_manager_t*, Page * p);
/** /**

View file

@ -81,6 +81,10 @@ terms specified in this license.
#define PERSISTENT 1 #define PERSISTENT 1
#define DURABLE 2 #define DURABLE 2
#define STASIS_BUFFER_MANAGER_PREALLOCATE_DEFAULT 1
#define STASIS_BUFFER_MANAGER_PREALLOCATE_DISABLED 2
#define STASIS_BUFFER_MANAGER_PREALLOCATE_LEGACY 3
#define STASIS_REPLACEMENT_POLICY_THREADSAFE_LRU 1 #define STASIS_REPLACEMENT_POLICY_THREADSAFE_LRU 1
#define STASIS_REPLACEMENT_POLICY_CONCURRENT_LRU 2 #define STASIS_REPLACEMENT_POLICY_CONCURRENT_LRU 2
#define STASIS_REPLACEMENT_POLICY_CLOCK 3 #define STASIS_REPLACEMENT_POLICY_CLOCK 3

View file

@ -84,6 +84,15 @@ extern stasis_handle_t* (*stasis_non_blocking_handle_file_factory)(const char* f
defining STASIS_BUFFER_MANAGER_IO_HANDLE_FLAGS. defining STASIS_BUFFER_MANAGER_IO_HANDLE_FLAGS.
*/ */
extern int stasis_buffer_manager_io_handle_flags; extern int stasis_buffer_manager_io_handle_flags;
/**
How should stasis grow the page file? Valid options are:
* STASIS_BUFFER_MANAGER_PREALLOCATE_DISABLED, which avoids any explicit preallocation. (This can cause terrible fragmentation on filesystems that support large files.),
* STASIS_BUFFER_MANAGER_PREALLCOATE_LEGACY, which placed dirty zero filled pages in the buffer cache. (This can cause double writes if the extended region does not fit in RAM, and unnecessarily evicts stuff.)
* STASIS_BUFFER_MANAGER_PREALLOCATE_DEFAULT, the recommended mode, which currently calls posix_fallocate(). This is not supported by old versions of Linux, so we attempt to fallback on the legacy mode at compile time.
*/
extern int stasis_buffer_manager_preallocate_mode;
/** /**
The default replacement policy. The default replacement policy.

View file

@ -184,6 +184,7 @@ typedef struct stasis_handle_t {
*/ */
int (*force)(struct stasis_handle_t * h); int (*force)(struct stasis_handle_t * h);
int (*force_range)(struct stasis_handle_t * h, lsn_t start, lsn_t stop); int (*force_range)(struct stasis_handle_t * h, lsn_t start, lsn_t stop);
int (*fallocate)(struct stasis_handle_t * h, lsn_t off, lsn_t len);
/** /**
The handle's error flag; this passes errors to the caller when The handle's error flag; this passes errors to the caller when
they can't be returned directly. they can't be returned directly.

View file

@ -68,8 +68,11 @@ struct stasis_page_handle_t {
/** /**
* @param start the pageid of the first page to be forced to disk. * @param start the pageid of the first page to be forced to disk.
* @param stop the pageid of the page after the last page to be forced to disk. * @param stop the pageid of the page after the last page to be forced to disk.
*
* @todo force_range takes a start and a stop page, but the others in pageHandle take an offset and count.
*/ */
void (*force_range)(struct stasis_page_handle_t* ph, lsn_t start, lsn_t stop); void (*force_range)(struct stasis_page_handle_t* ph, lsn_t start, lsn_t stop);
int (*preallocate_range)(struct stasis_page_handle_t* ph, lsn_t pageid, lsn_t count);
/** /**
Force the page file to disk, then close it. Force the page file to disk, then close it.
*/ */