Support dynamic sector size in alignment validation for Windows. (#8613)

Summary:
- Use dynamic section size when calling IsSectorAligned()
- Support relative path for GetSectorSize().
- Move buffer and sector alignment check to assert for better retail performance.
- Typo fixes.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/8613

Reviewed By: ajkr

Differential Revision: D30136082

Pulled By: mrambacher

fbshipit-source-id: e8cb849befdcae4fea99de5ed5dd6565e612425f
This commit is contained in:
Burton Li 2021-08-16 07:30:57 -07:00 committed by Facebook GitHub Bot
parent 48c468c22e
commit 9b0a32f802
3 changed files with 56 additions and 47 deletions

View File

@ -347,8 +347,7 @@ IOStatus WinFileSystem::NewRandomAccessFile(
fileGuard.release(); fileGuard.release();
} }
} else { } else {
result->reset(new WinRandomAccessFile( result->reset(new WinRandomAccessFile(fname, hFile, page_size_, options));
fname, hFile, std::max(GetSectorSize(fname), page_size_), options));
fileGuard.release(); fileGuard.release();
} }
return s; return s;
@ -433,9 +432,8 @@ IOStatus WinFileSystem::OpenWritableFile(
} else { } else {
// Here we want the buffer allocation to be aligned by the SSD page size // Here we want the buffer allocation to be aligned by the SSD page size
// and to be a multiple of it // and to be a multiple of it
result->reset(new WinWritableFile( result->reset(new WinWritableFile(fname, hFile, GetPageSize(),
fname, hFile, std::max(GetSectorSize(fname), GetPageSize()), c_BufferCapacity, local_options));
c_BufferCapacity, local_options));
} }
return s; return s;
} }
@ -487,8 +485,7 @@ IOStatus WinFileSystem::NewRandomRWFile(const std::string& fname,
} }
UniqueCloseHandlePtr fileGuard(hFile, CloseHandleFunc); UniqueCloseHandlePtr fileGuard(hFile, CloseHandleFunc);
result->reset(new WinRandomRWFile( result->reset(new WinRandomRWFile(fname, hFile, GetPageSize(), options));
fname, hFile, std::max(GetSectorSize(fname), GetPageSize()), options));
fileGuard.release(); fileGuard.release();
return s; return s;
@ -1183,13 +1180,23 @@ bool WinFileSystem::DirExists(const std::string& dname) {
size_t WinFileSystem::GetSectorSize(const std::string& fname) { size_t WinFileSystem::GetSectorSize(const std::string& fname) {
size_t sector_size = kSectorSize; size_t sector_size = kSectorSize;
if (RX_PathIsRelative(RX_FN(fname).c_str())) {
return sector_size;
}
// obtain device handle // obtain device handle
char devicename[7] = "\\\\.\\"; char devicename[7] = "\\\\.\\";
int erresult = strncat_s(devicename, sizeof(devicename), fname.c_str(), 2); int erresult = 0;
if (RX_PathIsRelative(RX_FN(fname).c_str())) {
RX_FILESTRING rx_current_dir;
rx_current_dir.resize(MAX_PATH);
DWORD len = RX_GetCurrentDirectory(MAX_PATH, &rx_current_dir[0]);
if (len == 0) {
return sector_size;
}
rx_current_dir.resize(len);
std::string current_dir = FN_TO_RX(rx_current_dir);
erresult =
strncat_s(devicename, sizeof(devicename), current_dir.c_str(), 2);
} else {
erresult = strncat_s(devicename, sizeof(devicename), fname.c_str(), 2);
}
if (erresult) { if (erresult) {
assert(false); assert(false);

View File

@ -11,6 +11,7 @@
#include "port/win/io_win.h" #include "port/win/io_win.h"
#include "env_win.h"
#include "monitoring/iostats_context_imp.h" #include "monitoring/iostats_context_imp.h"
#include "test_util/sync_point.h" #include "test_util/sync_point.h"
#include "util/aligned_buffer.h" #include "util/aligned_buffer.h"
@ -30,10 +31,6 @@ inline bool IsPowerOfTwo(const size_t alignment) {
return ((alignment) & (alignment - 1)) == 0; return ((alignment) & (alignment - 1)) == 0;
} }
inline bool IsSectorAligned(const size_t off) {
return (off & (kSectorSize - 1)) == 0;
}
inline bool IsAligned(size_t alignment, const void* ptr) { inline bool IsAligned(size_t alignment, const void* ptr) {
return ((uintptr_t(ptr)) & (alignment - 1)) == 0; return ((uintptr_t(ptr)) & (alignment - 1)) == 0;
} }
@ -186,6 +183,17 @@ size_t GetUniqueIdFromFile(HANDLE /*hFile*/, char* /*id*/,
return 0; return 0;
} }
WinFileData::WinFileData(const std::string& filename, HANDLE hFile,
bool direct_io)
: filename_(filename),
hFile_(hFile),
use_direct_io_(direct_io),
sector_size_(WinFileSystem::GetSectorSize(filename)) {}
bool WinFileData::IsSectorAligned(const size_t off) const {
return (off & (sector_size_ - 1)) == 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// WinMmapReadableFile // WinMmapReadableFile
@ -624,10 +632,8 @@ IOStatus WinSequentialFile::PositionedRead(uint64_t offset, size_t n,
return IOStatus::NotSupported("This function is only used for direct_io"); return IOStatus::NotSupported("This function is only used for direct_io");
} }
if (!IsSectorAligned(static_cast<size_t>(offset)) || !IsSectorAligned(n)) { assert(IsSectorAligned(static_cast<size_t>(offset)));
return IOStatus::InvalidArgument( assert(IsSectorAligned(static_cast<size_t>(n)));
"WinSequentialFile::PositionedRead: offset is not properly aligned");
}
size_t bytes_read = 0; // out param size_t bytes_read = 0; // out param
IOStatus s = PositionedReadInternal(scratch, static_cast<size_t>(n), offset, IOStatus s = PositionedReadInternal(scratch, static_cast<size_t>(n), offset,
@ -671,7 +677,8 @@ inline IOStatus WinRandomAccessImpl::PositionedReadInternal(
inline WinRandomAccessImpl::WinRandomAccessImpl(WinFileData* file_base, inline WinRandomAccessImpl::WinRandomAccessImpl(WinFileData* file_base,
size_t alignment, size_t alignment,
const FileOptions& options) const FileOptions& options)
: file_base_(file_base), alignment_(alignment) { : file_base_(file_base),
alignment_(std::max(alignment, file_base->GetSectorSize())) {
assert(!options.use_mmap_reads); assert(!options.use_mmap_reads);
} }
@ -680,12 +687,8 @@ inline IOStatus WinRandomAccessImpl::ReadImpl(uint64_t offset, size_t n,
char* scratch) const { char* scratch) const {
// Check buffer alignment // Check buffer alignment
if (file_base_->use_direct_io()) { if (file_base_->use_direct_io()) {
if (!IsSectorAligned(static_cast<size_t>(offset)) || assert(file_base_->IsSectorAligned(static_cast<size_t>(offset)));
!IsAligned(alignment_, scratch)) { assert(IsAligned(alignment_, scratch));
return IOStatus::InvalidArgument(
"WinRandomAccessImpl::ReadImpl: offset or scratch is not properly "
"aligned");
}
} }
if (n == 0) { if (n == 0) {
@ -741,7 +744,7 @@ inline IOStatus WinWritableImpl::PreallocateInternal(uint64_t spaceToReserve) {
inline WinWritableImpl::WinWritableImpl(WinFileData* file_data, inline WinWritableImpl::WinWritableImpl(WinFileData* file_data,
size_t alignment) size_t alignment)
: file_data_(file_data), : file_data_(file_data),
alignment_(alignment), alignment_(std::max(alignment, file_data->GetSectorSize())),
next_write_offset_(0), next_write_offset_(0),
reservedsize_(0) { reservedsize_(0) {
// Query current position in case ReopenWritableFile is called // Query current position in case ReopenWritableFile is called
@ -774,14 +777,10 @@ inline IOStatus WinWritableImpl::AppendImpl(const Slice& data) {
if (file_data_->use_direct_io()) { if (file_data_->use_direct_io()) {
// With no offset specified we are appending // With no offset specified we are appending
// to the end of the file // to the end of the file
assert(IsSectorAligned(next_write_offset_)); assert(file_data_->IsSectorAligned(next_write_offset_));
if (!IsSectorAligned(data.size()) || assert(file_data_->IsSectorAligned(data.size()));
!IsAligned(static_cast<size_t>(GetAlignement()), data.data())) { assert(IsAligned(static_cast<size_t>(GetAlignment()), data.data()));
s = IOStatus::InvalidArgument( s = pwrite(file_data_, data, next_write_offset_, bytes_written);
"WriteData must be page aligned, size must be sector aligned");
} else {
s = pwrite(file_data_, data, next_write_offset_, bytes_written);
}
} else { } else {
DWORD bytesWritten = 0; DWORD bytesWritten = 0;
if (!WriteFile(file_data_->GetFileHandle(), data.data(), if (!WriteFile(file_data_->GetFileHandle(), data.data(),
@ -812,12 +811,9 @@ inline IOStatus WinWritableImpl::AppendImpl(const Slice& data) {
inline IOStatus WinWritableImpl::PositionedAppendImpl(const Slice& data, inline IOStatus WinWritableImpl::PositionedAppendImpl(const Slice& data,
uint64_t offset) { uint64_t offset) {
if (file_data_->use_direct_io()) { if (file_data_->use_direct_io()) {
if (!IsSectorAligned(static_cast<size_t>(offset)) || assert(file_data_->IsSectorAligned(static_cast<size_t>(offset)));
!IsSectorAligned(data.size()) || assert(file_data_->IsSectorAligned(data.size()));
!IsAligned(static_cast<size_t>(GetAlignement()), data.data())) { assert(IsAligned(static_cast<size_t>(GetAlignment()), data.data()));
return IOStatus::InvalidArgument(
"Data and offset must be page aligned, size must be sector aligned");
}
} }
size_t bytes_written = 0; size_t bytes_written = 0;
@ -929,7 +925,7 @@ bool WinWritableFile::use_direct_io() const {
} }
size_t WinWritableFile::GetRequiredBufferAlignment() const { size_t WinWritableFile::GetRequiredBufferAlignment() const {
return static_cast<size_t>(GetAlignement()); return static_cast<size_t>(GetAlignment());
} }
IOStatus WinWritableFile::Append(const Slice& data, IOStatus WinWritableFile::Append(const Slice& data,
@ -1003,7 +999,9 @@ bool WinRandomRWFile::use_direct_io() const {
} }
size_t WinRandomRWFile::GetRequiredBufferAlignment() const { size_t WinRandomRWFile::GetRequiredBufferAlignment() const {
return static_cast<size_t>(GetAlignement()); assert(WinRandomAccessImpl::GetAlignment() ==
WinWritableImpl::GetAlignment());
return static_cast<size_t>(WinRandomAccessImpl::GetAlignment());
} }
IOStatus WinRandomRWFile::Write(uint64_t offset, const Slice& data, IOStatus WinRandomRWFile::Write(uint64_t offset, const Slice& data,

View File

@ -67,12 +67,12 @@ class WinFileData {
// will need to be aligned (not sure there is a guarantee that the buffer // will need to be aligned (not sure there is a guarantee that the buffer
// passed in is aligned). // passed in is aligned).
const bool use_direct_io_; const bool use_direct_io_;
const size_t sector_size_;
public: public:
// We want this class be usable both for inheritance (prive // We want this class be usable both for inheritance (prive
// or protected) and for containment so __ctor and __dtor public // or protected) and for containment so __ctor and __dtor public
WinFileData(const std::string& filename, HANDLE hFile, bool direct_io) WinFileData(const std::string& filename, HANDLE hFile, bool direct_io);
: filename_(filename), hFile_(hFile), use_direct_io_(direct_io) {}
virtual ~WinFileData() { this->CloseFile(); } virtual ~WinFileData() { this->CloseFile(); }
@ -93,6 +93,10 @@ class WinFileData {
bool use_direct_io() const { return use_direct_io_; } bool use_direct_io() const { return use_direct_io_; }
size_t GetSectorSize() const { return sector_size_; }
bool IsSectorAligned(const size_t off) const;
WinFileData(const WinFileData&) = delete; WinFileData(const WinFileData&) = delete;
WinFileData& operator=(const WinFileData&) = delete; WinFileData& operator=(const WinFileData&) = delete;
}; };
@ -321,7 +325,7 @@ class WinWritableImpl {
~WinWritableImpl() {} ~WinWritableImpl() {}
uint64_t GetAlignement() const { return alignment_; } uint64_t GetAlignment() const { return alignment_; }
IOStatus AppendImpl(const Slice& data); IOStatus AppendImpl(const Slice& data);