Skip to content

Commit 3f9c085

Browse files
JanSellnerFrancescAlted
authored andcommitted
flush modified pages only in write mode for mmap files
1 parent 94206bc commit 3f9c085

File tree

3 files changed

+54
-42
lines changed

3 files changed

+54
-42
lines changed

blosc/blosc2-stdio.c

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -466,17 +466,19 @@ int blosc2_stdio_mmap_destroy(void* params) {
466466
int err = 0;
467467

468468
#if defined(_WIN32)
469-
/* Ensure modified pages are written to disk */
470-
if (!FlushViewOfFile(mmap_file->addr, mmap_file->file_size)) {
471-
_print_last_error();
472-
BLOSC_TRACE_ERROR("Cannot flush the memory-mapped view to disk.");
473-
err = -1;
474-
}
475-
HANDLE file_handle = (HANDLE) _get_osfhandle(mmap_file->fd);
476-
if (!FlushFileBuffers(file_handle)) {
477-
_print_last_error();
478-
BLOSC_TRACE_ERROR("Cannot flush the memory-mapped file to disk.");
479-
err = -1;
469+
if (mmap_file->access_flags == PAGE_READWRITE) {
470+
/* Ensure modified pages are written to disk */
471+
if (!FlushViewOfFile(mmap_file->addr, mmap_file->file_size)) {
472+
_print_last_error();
473+
BLOSC_TRACE_ERROR("Cannot flush the memory-mapped view to disk.");
474+
err = -1;
475+
}
476+
HANDLE file_handle = (HANDLE) _get_osfhandle(mmap_file->fd);
477+
if (!FlushFileBuffers(file_handle)) {
478+
_print_last_error();
479+
BLOSC_TRACE_ERROR("Cannot flush the memory-mapped file to disk.");
480+
err = -1;
481+
}
480482
}
481483

482484
if (!UnmapViewOfFile(mmap_file->addr)) {
@@ -496,13 +498,15 @@ int blosc2_stdio_mmap_destroy(void* params) {
496498
err = -1;
497499
}
498500
#else
499-
/* Ensure modified pages are written to disk */
500-
/* This is important since not every munmap implementation flushes modified pages to disk
501-
(e.g.: https://nfs.sourceforge.net/#faq_d8) */
502-
int rc = msync(mmap_file->addr, mmap_file->file_size, MS_SYNC);
503-
if (rc < 0) {
504-
BLOSC_TRACE_ERROR("Cannot sync the memory-mapped file to disk (error: %s).", strerror(errno));
505-
err = -1;
501+
if ((mmap_file->access_flags & PROT_WRITE) && !mmap_file->is_memory_only) {
502+
/* Ensure modified pages are written to disk */
503+
/* This is important since not every munmap implementation flushes modified pages to disk
504+
(e.g.: https://nfs.sourceforge.net/#faq_d8) */
505+
int rc = msync(mmap_file->addr, mmap_file->file_size, MS_SYNC);
506+
if (rc < 0) {
507+
BLOSC_TRACE_ERROR("Cannot sync the memory-mapped file to disk (error: %s).", strerror(errno));
508+
err = -1;
509+
}
506510
}
507511

508512
if (munmap(mmap_file->addr, mmap_file->mapping_size) < 0) {

blosc/schunk.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,8 @@ int64_t blosc2_schunk_append_file(blosc2_schunk* schunk, const char* urlpath) {
484484

485485
/* Free all memory from a super-chunk. */
486486
int blosc2_schunk_free(blosc2_schunk *schunk) {
487+
int err = 0;
488+
487489
if (schunk->data != NULL) {
488490
for (int i = 0; i < schunk->nchunks; i++) {
489491
free(schunk->data[i]);
@@ -516,6 +518,7 @@ int blosc2_schunk_free(blosc2_schunk *schunk) {
516518
int rc = io_cb->destroy(schunk->storage->io->params);
517519
if (rc < 0) {
518520
BLOSC_TRACE_ERROR("Could not free the I/O resources.");
521+
err = 1;
519522
}
520523
}
521524

@@ -546,7 +549,7 @@ int blosc2_schunk_free(blosc2_schunk *schunk) {
546549

547550
free(schunk);
548551

549-
return 0;
552+
return err;
550553
}
551554

552555

tests/test_mmap.c

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -99,32 +99,37 @@ CUTEST_TEST_TEST(mmap) {
9999
cbytes = blosc2_schunk_append_buffer(schunk_write_mmap, data_buffer2, sizeof(data_buffer2));
100100
CUTEST_ASSERT("Could not write second chunk", cbytes > 0);
101101

102-
blosc2_schunk_free(schunk_write_default);
103-
blosc2_schunk_free(schunk_write_mmap);
102+
CUTEST_ASSERT("Could not free the schunk ressources", blosc2_schunk_free(schunk_write_default) == 0);
103+
CUTEST_ASSERT("Could not free the schunk ressources", blosc2_schunk_free(schunk_write_mmap) == 0);
104104

105105
/* The compressed file content should not depend on the I/O which created it */
106106
CUTEST_ASSERT("Files are not identical", are_files_identical(urlpath_default, urlpath_mmap));
107107

108108
/* Read the schunk data back again (using mmap) */
109-
mmap_file = BLOSC2_STDIO_MMAP_DEFAULTS;
110-
mmap_file.mode = "r";
111-
mmap_file.initial_mapping_size = initial_mapping_size;
112-
io.params = &mmap_file;
113-
blosc2_schunk* schunk_read = blosc2_schunk_open_udio(urlpath_mmap, &io);
114-
CUTEST_ASSERT("Mismatch in number of chunks", schunk_read->nchunks == 2);
115-
116-
float* chunk_data = (float*)malloc(schunk_read->chunksize);
117-
int dsize = blosc2_schunk_decompress_chunk(schunk_read, 0, chunk_data, schunk_read->chunksize);
118-
CUTEST_ASSERT("Size of decompressed chunk 1 does not match", dsize == sizeof(data_buffer));
119-
CUTEST_ASSERT("Value 1 of chunk 1 is wrong", fabs(chunk_data[0] - 0.1) < 1e-6);
120-
CUTEST_ASSERT("Value 2 of chunk 1 is wrong", fabs(chunk_data[1] - 0.2) < 1e-6);
121-
122-
dsize = blosc2_schunk_decompress_chunk(schunk_read, 1, chunk_data, schunk_read->chunksize);
123-
CUTEST_ASSERT("Size of decompressed chunk 1 does not match", dsize == sizeof(data_buffer2));
124-
CUTEST_ASSERT("Value 1 of chunk 2 is wrong", fabs(chunk_data[0] - 0.3) < 1e-6);
125-
CUTEST_ASSERT("Value 2 of chunk 2 is wrong", fabs(chunk_data[1] - 0.4) < 1e-6);
126-
127-
blosc2_schunk_free(schunk_read);
109+
int n_repeated_reads = 2; // Make sure reading the same file again does not lead to any problems
110+
int dsize;
111+
float* chunk_data;
112+
for (int i = 0; i < n_repeated_reads; i++) {
113+
mmap_file = BLOSC2_STDIO_MMAP_DEFAULTS;
114+
mmap_file.mode = "r";
115+
mmap_file.initial_mapping_size = initial_mapping_size;
116+
io.params = &mmap_file;
117+
blosc2_schunk* schunk_read = blosc2_schunk_open_udio(urlpath_mmap, &io);
118+
CUTEST_ASSERT("Mismatch in number of chunks", schunk_read->nchunks == 2);
119+
120+
chunk_data = (float*)malloc(schunk_read->chunksize);
121+
dsize = blosc2_schunk_decompress_chunk(schunk_read, 0, chunk_data, schunk_read->chunksize);
122+
CUTEST_ASSERT("Size of decompressed chunk 1 does not match", dsize == sizeof(data_buffer));
123+
CUTEST_ASSERT("Value 1 of chunk 1 is wrong", fabs(chunk_data[0] - 0.1) < 1e-6);
124+
CUTEST_ASSERT("Value 2 of chunk 1 is wrong", fabs(chunk_data[1] - 0.2) < 1e-6);
125+
126+
dsize = blosc2_schunk_decompress_chunk(schunk_read, 1, chunk_data, schunk_read->chunksize);
127+
CUTEST_ASSERT("Size of decompressed chunk 1 does not match", dsize == sizeof(data_buffer2));
128+
CUTEST_ASSERT("Value 1 of chunk 2 is wrong", fabs(chunk_data[0] - 0.3) < 1e-6);
129+
CUTEST_ASSERT("Value 2 of chunk 2 is wrong", fabs(chunk_data[1] - 0.4) < 1e-6);
130+
131+
CUTEST_ASSERT("Could not free the schunk ressources", blosc2_schunk_free(schunk_read) == 0);
132+
}
128133

129134
#if defined(__linux__)
130135
/* Append some data to the existing schunk in memory (does not work on Windows) */
@@ -148,7 +153,7 @@ CUTEST_TEST_TEST(mmap) {
148153
CUTEST_ASSERT("Value 1 of chunk 2 is wrong", fabs(chunk_data[0] - 0.5) < 1e-6);
149154
CUTEST_ASSERT("Value 2 of chunk 2 is wrong", fabs(chunk_data[1] - 0.6) < 1e-6);
150155

151-
blosc2_schunk_free(schunk_memory);
156+
CUTEST_ASSERT("Could not free the schunk ressources", blosc2_schunk_free(schunk_memory) == 0);
152157
CUTEST_ASSERT("Files are not identical", are_files_identical(urlpath_default, urlpath_mmap));
153158
#endif
154159

@@ -173,7 +178,7 @@ CUTEST_TEST_TEST(mmap) {
173178
CUTEST_ASSERT("Value 1 of chunk 2 is wrong", fabs(chunk_data[0] - 0.5) < 1e-6);
174179
CUTEST_ASSERT("Value 2 of chunk 2 is wrong", fabs(chunk_data[1] - 0.6) < 1e-6);
175180

176-
blosc2_schunk_free(schunk_append);
181+
CUTEST_ASSERT("Could not free the schunk ressources", blosc2_schunk_free(schunk_append) == 0);
177182
CUTEST_ASSERT("Files are identical", !are_files_identical(urlpath_default, urlpath_mmap));
178183

179184
free(chunk_data);

0 commit comments

Comments
 (0)