Skip to content

Commit 4e3352a

Browse files
committed
Invalidate Linux page cache before mmap to prevent stale reads after ZFS rollback
After a ZFS/LVM snapshot rollback, the Linux page cache may retain pre-rollback data for mmap'd files. When chainbase opens shared_memory.bin via boost::interprocess::managed_mapped_file, it can read stale LIB values from the page cache instead of the rolled-back data on disk. Meanwhile, RocksDB uses pread() and reads correct post-rollback data, causing a LIB mismatch assertion failure on startup. Add posix_fadvise(POSIX_FADV_DONTNEED) before the mmap open to evict any cached pages, ensuring fresh data is read from disk. The call has negligible overhead (<0.01ms for a 7GB file). Also improve the RocksDB LIB mismatch error message to explain the likely cause and suggest remediation steps.
1 parent a394359 commit 4e3352a

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

libraries/chain/external_storage/rocksdb_storage_provider.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,11 @@ void rocksdb_storage_provider::load_lib()
312312

313313
uint32_t lib = lib_slice_t::unpackSlice( _value );
314314

315-
FC_ASSERT( lib == _cached_irreversible_block, "Inconsistency in last irreversible block - expected ${c}, stored ${s}",
315+
FC_ASSERT( lib == _cached_irreversible_block,
316+
"Inconsistency in last irreversible block - expected ${c} (from shared_memory), stored ${s} (from RocksDB). "
317+
"If this occurs after a ZFS/LVM snapshot rollback, it may be caused by stale data in the Linux page cache. "
318+
"Try: echo 3 > /proc/sys/vm/drop_caches, then restart. "
319+
"Or use the rollback_zfs_datasets.sh script which handles cache invalidation automatically.",
316320
( "c", static_cast< uint32_t >( _cached_irreversible_block ) )( "s", lib ) );
317321

318322
ilog( "`${name}` RocksDB database LIB loaded with value ${l}.", ("name", name)( "l", lib ) );

libraries/chainbase/src/chainbase.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77

88
#include <filesystem>
99

10+
#ifdef __linux__
11+
#include <fcntl.h>
12+
#include <unistd.h>
13+
#endif
14+
1015
namespace chainbase {
1116

1217
size_t snapshot_base_serializer::worker_common_base::get_serialized_object_cache_max_size() const
@@ -225,6 +230,21 @@ size_t snapshot_base_serializer::worker_common_base::get_serialized_object_cache
225230
_file_size = shared_file_size;
226231
}
227232

233+
#ifdef __linux__
234+
// Evict any stale pages from the Linux page cache before mmap.
235+
// After a ZFS/LVM snapshot rollback, the page cache may still contain
236+
// pre-rollback data. Without this, mmap can return stale pages instead
237+
// of reading the rolled-back data from disk.
238+
{
239+
int fd = ::open( abs_path.generic_string().c_str(), O_RDONLY );
240+
if( fd >= 0 )
241+
{
242+
posix_fadvise( fd, 0, 0, POSIX_FADV_DONTNEED );
243+
::close( fd );
244+
}
245+
}
246+
#endif
247+
228248
_segment.reset( new bip::managed_mapped_file( bip::open_only,
229249
abs_path.generic_string().c_str()
230250
) );

0 commit comments

Comments
 (0)