Add new IO window advise modes

This commit is contained in:
Andrea Mazzoleni 2016-05-17 23:34:47 +02:00
parent 4298a238e9
commit 397c58c41e
5 changed files with 104 additions and 107 deletions

11
HISTORY
View file

@ -15,13 +15,12 @@ SnapRAID HISTORY
'\'.
* Added test options for selecting the file advise mode to use:
--test-io-advise-none for standard mode
--test-io-advise-sequential advise sequential operations (Linux/Windows)
--test-io-advise-flush flush data after every operation (Linux)
--test-io-advise-sequential advise sequential access (Linux/Windows)
--test-io-advise-flush flush cache after every operation (Linux)
--test-io-advise-flush-window flush cache every 8 MB (Linux)
--test-io-advise-discard discard cache after every operation (Linux)
--test-io-advise-discard-2 discard cache every 2 MB (Linux)
--test-io-advise-discard-8 discard cache every 8 MB (Linux)
--test-io-advise-discard-32 discard cache every 32 MB (Linux)
--test-io-advise-direct use direct mode (Linux/Windows)
--test-io-advise-discard-window discard cache every 8 MB (Linux)
--test-io-advise-direct use direct/unbuffered mode (Linux/Windows)
* Fixed running in Windows platforms that miss the RtlGenRandom
function.
* Added a new 'hashsize' configuration option. It could be useful in

View file

@ -439,8 +439,8 @@ endif
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) status
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-io-advise-none -c $(PAR1) sync -F
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-io-advise-sequential -c $(PAR1) sync -F
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-io-advise-flush -c $(PAR1) sync -F
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-io-advise-discard -c $(PAR1) sync -F
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-io-advise-flush-window -c $(PAR1) sync -F
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-io-advise-discard-window -c $(PAR1) sync -F
#### CHANGE LINKS ####
# Use a different size ("22" instead of "1") to ensure to recognize the file different
# even if it gets the same timestamp in case subsecond timestamp is no available

View file

@ -285,11 +285,10 @@ void config(char* conf, size_t conf_size, const char* argv0)
#define OPT_TEST_IO_ADVISE_NONE 293
#define OPT_TEST_IO_ADVISE_SEQUENTIAL 294
#define OPT_TEST_IO_ADVISE_FLUSH 295
#define OPT_TEST_IO_ADVISE_DISCARD 296
#define OPT_TEST_IO_ADVISE_DISCARD_2 297
#define OPT_TEST_IO_ADVISE_DISCARD_8 298
#define OPT_TEST_IO_ADVISE_DISCARD_32 299
#define OPT_TEST_IO_ADVISE_DIRECT 300
#define OPT_TEST_IO_ADVISE_FLUSH_WINDOW 296
#define OPT_TEST_IO_ADVISE_DISCARD 297
#define OPT_TEST_IO_ADVISE_DISCARD_WINDOW 298
#define OPT_TEST_IO_ADVISE_DIRECT 299
#define OPT_TEST_PARITY_LIMIT 301
#define OPT_TEST_SKIP_CONTENT_WRITE 302
@ -434,17 +433,14 @@ struct option long_options[] = {
/* Set the io advise to flush */
{ "test-io-advise-flush", 0, 0, OPT_TEST_IO_ADVISE_FLUSH },
/* Set the io advise to flush window */
{ "test-io-advise-flush-window", 0, 0, OPT_TEST_IO_ADVISE_FLUSH_WINDOW },
/* Set the io advise to discard */
{ "test-io-advise-discard", 0, 0, OPT_TEST_IO_ADVISE_DISCARD },
/* Set the io advise to discard */
{ "test-io-advise-discard-2", 0, 0, OPT_TEST_IO_ADVISE_DISCARD_2 },
/* Set the io advise to discard */
{ "test-io-advise-discard-8", 0, 0, OPT_TEST_IO_ADVISE_DISCARD_8 },
/* Set the io advise to discard */
{ "test-io-advise-discard-32", 0, 0, OPT_TEST_IO_ADVISE_DISCARD_32 },
/* Set the io advise to discard window */
{ "test-io-advise-discard-window", 0, 0, OPT_TEST_IO_ADVISE_DISCARD_WINDOW },
/* Set the io advise to direct */
{ "test-io-advise-direct", 0, 0, OPT_TEST_IO_ADVISE_DIRECT },
@ -860,17 +856,14 @@ int main(int argc, char* argv[])
case OPT_TEST_IO_ADVISE_FLUSH :
opt.file_mode = ADVISE_FLUSH;
break;
case OPT_TEST_IO_ADVISE_FLUSH_WINDOW :
opt.file_mode = ADVISE_FLUSH_WINDOW;
break;
case OPT_TEST_IO_ADVISE_DISCARD :
opt.file_mode = ADVISE_DISCARD;
break;
case OPT_TEST_IO_ADVISE_DISCARD_2 :
opt.file_mode = ADVISE_DISCARD_2;
break;
case OPT_TEST_IO_ADVISE_DISCARD_8 :
opt.file_mode = ADVISE_DISCARD_8;
break;
case OPT_TEST_IO_ADVISE_DISCARD_32 :
opt.file_mode = ADVISE_DISCARD_32;
case OPT_TEST_IO_ADVISE_DISCARD_WINDOW :
opt.file_mode = ADVISE_DISCARD_WINDOW;
break;
case OPT_TEST_IO_ADVISE_DIRECT :
opt.file_mode = ADVISE_DIRECT;

View file

@ -895,10 +895,9 @@ int advise_flags(struct advise_struct* advise)
if (advise->mode == ADVISE_SEQUENTIAL
|| advise->mode == ADVISE_FLUSH
|| advise->mode == ADVISE_FLUSH_WINDOW
|| advise->mode == ADVISE_DISCARD
|| advise->mode == ADVISE_DISCARD_2
|| advise->mode == ADVISE_DISCARD_8
|| advise->mode == ADVISE_DISCARD_32
|| advise->mode == ADVISE_DISCARD_WINDOW
)
flags |= O_SEQUENTIAL;
@ -918,10 +917,9 @@ int advise_open(struct advise_struct* advise, int f)
#if HAVE_POSIX_FADVISE
if (advise->mode == ADVISE_SEQUENTIAL
|| advise->mode == ADVISE_FLUSH
|| advise->mode == ADVISE_FLUSH_WINDOW
|| advise->mode == ADVISE_DISCARD
|| advise->mode == ADVISE_DISCARD_2
|| advise->mode == ADVISE_DISCARD_8
|| advise->mode == ADVISE_DISCARD_32
|| advise->mode == ADVISE_DISCARD_WINDOW
) {
int ret;
@ -939,26 +937,15 @@ int advise_open(struct advise_struct* advise, int f)
return 0;
}
int advise_write(struct advise_struct* advise, int f, size_t offset, size_t size)
int advise_write(struct advise_struct* advise, int f, uint64_t offset, uint64_t size)
{
(void)advise;
uint64_t handle_offset;
uint64_t handle_size;
(void)f;
(void)offset;
(void)size;
#if HAVE_SYNC_FILE_RANGE
if (advise->mode == ADVISE_FLUSH) {
int ret;
/* start writing immediately */
ret = sync_file_range(f, offset, size, SYNC_FILE_RANGE_WRITE);
if (ret != 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
}
#endif
handle_offset = 0;
handle_size = 0;
/*
* Follow Linus recommendations about fast writes.
@ -1013,54 +1000,74 @@ int advise_write(struct advise_struct* advise, int f, size_t offset, size_t size
* ---
*/
#if HAVE_SYNC_FILE_RANGE && HAVE_POSIX_FADVISE
if (advise->mode == ADVISE_DISCARD
|| advise->mode == ADVISE_DISCARD_2
|| advise->mode == ADVISE_DISCARD_8
|| advise->mode == ADVISE_DISCARD_32
) {
size_t dirty_offset = advise->dirty_begin;
size_t dirty_size = advise->dirty_end - advise->dirty_begin;
size_t limit;
if (advise->mode == ADVISE_FLUSH || advise->mode == ADVISE_DISCARD) {
handle_offset = offset;
handle_size = size;
}
switch (advise->mode) {
default:
case ADVISE_DISCARD : limit = 1; break;
case ADVISE_DISCARD_2 : limit = 2 * 1024 * 1024; break;
case ADVISE_DISCARD_8 : limit = 8 * 1024 * 1024; break;
case ADVISE_DISCARD_32 : limit = 32 * 1024 * 1024; break;
}
if (advise->mode == ADVISE_FLUSH_WINDOW || advise->mode == ADVISE_DISCARD_WINDOW) {
/* if the dirty range can be extended */
if (advise->dirty_end == offset) {
/* extent the dirty range */
advise->dirty_end += size;
/* if we have to discard */
if (dirty_size >= limit) {
int ret;
/* if we reached the double window size */
if (advise->dirty_end - advise->dirty_begin >= 2 * ADVISE_WINDOW_SIZE) {
/* handle the first window */
handle_offset = advise->dirty_begin;
handle_size = ADVISE_WINDOW_SIZE;
/* send the data to the disk and wait until it's written */
ret = sync_file_range(f, dirty_offset, dirty_size, SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE | SYNC_FILE_RANGE_WAIT_AFTER);
if (ret != 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
/* remove it from the dirty range */
advise->dirty_begin += ADVISE_WINDOW_SIZE;
}
} else {
/* otherwise flush the existing dirty */
handle_offset = advise->dirty_begin;
handle_size = advise->dirty_end - advise->dirty_begin;
/* flush the data from the cache */
ret = posix_fadvise(f, dirty_offset, dirty_size, POSIX_FADV_DONTNEED);
if (ret != 0) {
/* LCOV_EXCL_START */
errno = ret; /* posix_fadvise return the error code */
return -1;
/* LCOV_EXCL_STOP */
}
/* set the new dirty range */
/* and set the new range as dirty */
advise->dirty_begin = offset;
advise->dirty_end = offset + size;
} else {
/* extend the dirty range */
if (advise->dirty_begin > offset)
advise->dirty_begin = offset;
if (advise->dirty_end < offset + size)
advise->dirty_end = offset + size;
}
}
#if HAVE_SYNC_FILE_RANGE
if ((advise->mode == ADVISE_FLUSH || advise->mode == ADVISE_FLUSH_WINDOW)
&& handle_size != 0
) {
int ret;
/* start writing immediately */
ret = sync_file_range(f, handle_offset, handle_size, SYNC_FILE_RANGE_WRITE);
if (ret != 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
}
#endif
#if HAVE_SYNC_FILE_RANGE && HAVE_POSIX_FADVISE
if ((advise->mode == ADVISE_DISCARD || advise->mode == ADVISE_DISCARD_WINDOW)
&& handle_size != 0
) {
int ret;
/* send the data to the disk and wait until it's written */
ret = sync_file_range(f, handle_offset, handle_size, SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE | SYNC_FILE_RANGE_WAIT_AFTER);
if (ret != 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
/* flush the data from the cache */
ret = posix_fadvise(f, handle_offset, handle_size, POSIX_FADV_DONTNEED);
if (ret != 0) {
/* LCOV_EXCL_START */
errno = ret; /* posix_fadvise return the error code */
return -1;
/* LCOV_EXCL_STOP */
}
}
#endif
@ -1068,7 +1075,7 @@ int advise_write(struct advise_struct* advise, int f, size_t offset, size_t size
return 0;
}
int advise_read(struct advise_struct* advise, int f, size_t offset, size_t size)
int advise_read(struct advise_struct* advise, int f, uint64_t offset, uint64_t size)
{
(void)advise;
(void)f;
@ -1077,9 +1084,7 @@ int advise_read(struct advise_struct* advise, int f, size_t offset, size_t size)
#if HAVE_POSIX_FADVISE
if (advise->mode == ADVISE_DISCARD
|| advise->mode == ADVISE_DISCARD_2
|| advise->mode == ADVISE_DISCARD_8
|| advise->mode == ADVISE_DISCARD_32
|| advise->mode == ADVISE_DISCARD_WINDOW
) {
int ret;
@ -1143,7 +1148,6 @@ int advise_read(struct advise_struct* advise, int f, size_t offset, size_t size)
*/
static size_t mcounter;
size_t malloc_counter_get(void)
{
size_t ret;

View file

@ -332,23 +332,24 @@ int fmtime(int f, int64_t mtime_sec, int mtime_nsec);
#define ADVISE_NONE 1 /**< Bare read/write mode. */
#define ADVISE_SEQUENTIAL 2 /**< Sequential mode. */
#define ADVISE_FLUSH 3 /**< Flush mode. */
#define ADVISE_DISCARD 4 /**< Discard the cache after every operation. */
#define ADVISE_DISCARD_2 5 /**< Discard the cache every 2MB. */
#define ADVISE_DISCARD_8 6 /**< Discard the cache every 8MB. */
#define ADVISE_DISCARD_32 7 /**< Discard the cache every 32MB. */
#define ADVISE_DIRECT 8 /**< Direct mode. */
#define ADVISE_FLUSH_WINDOW 4 /**< Flush mode with a window of 8MB. */
#define ADVISE_DISCARD 5 /**< Discard the cache after every operation. */
#define ADVISE_DISCARD_WINDOW 6 /**< Discard the cache with a window of 8MB. */
#define ADVISE_DIRECT 7 /**< Direct mode. */
#define ADVISE_WINDOW_SIZE (8 * 1024 * 1024) /**< Window size. */
struct advise_struct {
int mode;
size_t dirty_begin;
size_t dirty_end;
uint64_t dirty_begin;
uint64_t dirty_end;
};
void advise_init(struct advise_struct* advise, int mode);
int advise_flags(struct advise_struct* advise);
int advise_open(struct advise_struct* advise, int f);
int advise_write(struct advise_struct* advise, int f, size_t offset, size_t size);
int advise_read(struct advise_struct* advise, int f, size_t offset, size_t size);
int advise_write(struct advise_struct* advise, int f, uint64_t offset, uint64_t size);
int advise_read(struct advise_struct* advise, int f, uint64_t offset, uint64_t size);
/****************************************************************************/
/* memory */