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:
parent
48c468c22e
commit
9b0a32f802
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user