MDEV-13852 - redefine WinWriteableFile such as IsSyncThreadSafe()
is set to true, as it should. Copy and modify original io_win.h header file to a different location (as we cannot patch anything in submodule). Make sure modified header is used.
This commit is contained in:
parent
842dce378a
commit
689168be12
@ -11,6 +11,11 @@ INCLUDE_DIRECTORIES(
|
||||
${ROCKSDB_SOURCE_DIR}/third-party/gtest-1.7.0/fused-src
|
||||
)
|
||||
|
||||
IF(WIN32)
|
||||
INCLUDE_DIRECTORIES(BEFORE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/patch)
|
||||
ENDIF()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${ROCKSDB_SOURCE_DIR}/cmake/modules/")
|
||||
|
||||
if(WIN32)
|
||||
|
@ -23,7 +23,6 @@ $ENV{MARIAROCKS_SST_DUMP}="$sst_dump";
|
||||
# Temporarily disable testing under valgrind, due to MDEV-12439
|
||||
return "RocksDB tests disabled under valgrind" if ($::opt_valgrind);
|
||||
|
||||
return "Temporarily disabled on Windows due to MDEV-13852" if (My::SysInfo::IS_WINDOWS);
|
||||
|
||||
bless { };
|
||||
|
||||
|
446
storage/rocksdb/patch/port/win/io_win.h
Normal file
446
storage/rocksdb/patch/port/win/io_win.h
Normal file
@ -0,0 +1,446 @@
|
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under both the GPLv2 (found in the
|
||||
// COPYING file in the root directory) and Apache 2.0 License
|
||||
// (found in the LICENSE.Apache file in the root directory).
|
||||
//
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include "rocksdb/status.h"
|
||||
#include "rocksdb/env.h"
|
||||
#include "util/aligned_buffer.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
namespace rocksdb {
|
||||
namespace port {
|
||||
|
||||
std::string GetWindowsErrSz(DWORD err);
|
||||
|
||||
inline Status IOErrorFromWindowsError(const std::string& context, DWORD err) {
|
||||
return ((err == ERROR_HANDLE_DISK_FULL) || (err == ERROR_DISK_FULL))
|
||||
? Status::NoSpace(context, GetWindowsErrSz(err))
|
||||
: Status::IOError(context, GetWindowsErrSz(err));
|
||||
}
|
||||
|
||||
inline Status IOErrorFromLastWindowsError(const std::string& context) {
|
||||
return IOErrorFromWindowsError(context, GetLastError());
|
||||
}
|
||||
|
||||
inline Status IOError(const std::string& context, int err_number) {
|
||||
return (err_number == ENOSPC)
|
||||
? Status::NoSpace(context, strerror(err_number))
|
||||
: Status::IOError(context, strerror(err_number));
|
||||
}
|
||||
|
||||
// Note the below two do not set errno because they are used only here in this
|
||||
// file
|
||||
// on a Windows handle and, therefore, not necessary. Translating GetLastError()
|
||||
// to errno
|
||||
// is a sad business
|
||||
inline int fsync(HANDLE hFile) {
|
||||
if (!FlushFileBuffers(hFile)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SSIZE_T pwrite(HANDLE hFile, const char* src, size_t numBytes, uint64_t offset);
|
||||
|
||||
SSIZE_T pread(HANDLE hFile, char* src, size_t numBytes, uint64_t offset);
|
||||
|
||||
Status fallocate(const std::string& filename, HANDLE hFile, uint64_t to_size);
|
||||
|
||||
Status ftruncate(const std::string& filename, HANDLE hFile, uint64_t toSize);
|
||||
|
||||
size_t GetUniqueIdFromFile(HANDLE hFile, char* id, size_t max_size);
|
||||
|
||||
class WinFileData {
|
||||
protected:
|
||||
const std::string filename_;
|
||||
HANDLE hFile_;
|
||||
// If ture, the I/O issued would be direct I/O which the buffer
|
||||
// will need to be aligned (not sure there is a guarantee that the buffer
|
||||
// passed in is aligned).
|
||||
const bool use_direct_io_;
|
||||
|
||||
public:
|
||||
// We want this class be usable both for inheritance (prive
|
||||
// or protected) and for containment so __ctor and __dtor public
|
||||
WinFileData(const std::string& filename, HANDLE hFile, bool direct_io)
|
||||
: filename_(filename), hFile_(hFile), use_direct_io_(direct_io) {}
|
||||
|
||||
virtual ~WinFileData() { this->CloseFile(); }
|
||||
|
||||
bool CloseFile() {
|
||||
bool result = true;
|
||||
|
||||
if (hFile_ != NULL && hFile_ != INVALID_HANDLE_VALUE) {
|
||||
result = ::CloseHandle(hFile_);
|
||||
assert(result);
|
||||
hFile_ = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::string& GetName() const { return filename_; }
|
||||
|
||||
HANDLE GetFileHandle() const { return hFile_; }
|
||||
|
||||
bool use_direct_io() const { return use_direct_io_; }
|
||||
|
||||
WinFileData(const WinFileData&) = delete;
|
||||
WinFileData& operator=(const WinFileData&) = delete;
|
||||
};
|
||||
|
||||
class WinSequentialFile : protected WinFileData, public SequentialFile {
|
||||
|
||||
// Override for behavior change when creating a custom env
|
||||
virtual SSIZE_T PositionedReadInternal(char* src, size_t numBytes,
|
||||
uint64_t offset) const;
|
||||
|
||||
public:
|
||||
WinSequentialFile(const std::string& fname, HANDLE f,
|
||||
const EnvOptions& options);
|
||||
|
||||
~WinSequentialFile();
|
||||
|
||||
WinSequentialFile(const WinSequentialFile&) = delete;
|
||||
WinSequentialFile& operator=(const WinSequentialFile&) = delete;
|
||||
|
||||
virtual Status Read(size_t n, Slice* result, char* scratch) override;
|
||||
virtual Status PositionedRead(uint64_t offset, size_t n, Slice* result,
|
||||
char* scratch) override;
|
||||
|
||||
virtual Status Skip(uint64_t n) override;
|
||||
|
||||
virtual Status InvalidateCache(size_t offset, size_t length) override;
|
||||
|
||||
virtual bool use_direct_io() const override { return WinFileData::use_direct_io(); }
|
||||
};
|
||||
|
||||
// mmap() based random-access
|
||||
class WinMmapReadableFile : private WinFileData, public RandomAccessFile {
|
||||
HANDLE hMap_;
|
||||
|
||||
const void* mapped_region_;
|
||||
const size_t length_;
|
||||
|
||||
public:
|
||||
// mapped_region_[0,length-1] contains the mmapped contents of the file.
|
||||
WinMmapReadableFile(const std::string& fileName, HANDLE hFile, HANDLE hMap,
|
||||
const void* mapped_region, size_t length);
|
||||
|
||||
~WinMmapReadableFile();
|
||||
|
||||
WinMmapReadableFile(const WinMmapReadableFile&) = delete;
|
||||
WinMmapReadableFile& operator=(const WinMmapReadableFile&) = delete;
|
||||
|
||||
virtual Status Read(uint64_t offset, size_t n, Slice* result,
|
||||
char* scratch) const override;
|
||||
|
||||
virtual Status InvalidateCache(size_t offset, size_t length) override;
|
||||
|
||||
virtual size_t GetUniqueId(char* id, size_t max_size) const override;
|
||||
};
|
||||
|
||||
// We preallocate and use memcpy to append new
|
||||
// data to the file. This is safe since we either properly close the
|
||||
// file before reading from it, or for log files, the reading code
|
||||
// knows enough to skip zero suffixes.
|
||||
class WinMmapFile : private WinFileData, public WritableFile {
|
||||
private:
|
||||
HANDLE hMap_;
|
||||
|
||||
const size_t page_size_; // We flush the mapping view in page_size
|
||||
// increments. We may decide if this is a memory
|
||||
// page size or SSD page size
|
||||
const size_t
|
||||
allocation_granularity_; // View must start at such a granularity
|
||||
|
||||
size_t reserved_size_; // Preallocated size
|
||||
|
||||
size_t mapping_size_; // The max size of the mapping object
|
||||
// we want to guess the final file size to minimize the remapping
|
||||
size_t view_size_; // How much memory to map into a view at a time
|
||||
|
||||
char* mapped_begin_; // Must begin at the file offset that is aligned with
|
||||
// allocation_granularity_
|
||||
char* mapped_end_;
|
||||
char* dst_; // Where to write next (in range [mapped_begin_,mapped_end_])
|
||||
char* last_sync_; // Where have we synced up to
|
||||
|
||||
uint64_t file_offset_; // Offset of mapped_begin_ in file
|
||||
|
||||
// Do we have unsynced writes?
|
||||
bool pending_sync_;
|
||||
|
||||
// Can only truncate or reserve to a sector size aligned if
|
||||
// used on files that are opened with Unbuffered I/O
|
||||
Status TruncateFile(uint64_t toSize);
|
||||
|
||||
Status UnmapCurrentRegion();
|
||||
|
||||
Status MapNewRegion();
|
||||
|
||||
virtual Status PreallocateInternal(uint64_t spaceToReserve);
|
||||
|
||||
public:
|
||||
WinMmapFile(const std::string& fname, HANDLE hFile, size_t page_size,
|
||||
size_t allocation_granularity, const EnvOptions& options);
|
||||
|
||||
~WinMmapFile();
|
||||
|
||||
WinMmapFile(const WinMmapFile&) = delete;
|
||||
WinMmapFile& operator=(const WinMmapFile&) = delete;
|
||||
|
||||
virtual Status Append(const Slice& data) override;
|
||||
|
||||
// Means Close() will properly take care of truncate
|
||||
// and it does not need any additional information
|
||||
virtual Status Truncate(uint64_t size) override;
|
||||
|
||||
virtual Status Close() override;
|
||||
|
||||
virtual Status Flush() override;
|
||||
|
||||
// Flush only data
|
||||
virtual Status Sync() override;
|
||||
|
||||
/**
|
||||
* Flush data as well as metadata to stable storage.
|
||||
*/
|
||||
virtual Status Fsync() override;
|
||||
|
||||
/**
|
||||
* Get the size of valid data in the file. This will not match the
|
||||
* size that is returned from the filesystem because we use mmap
|
||||
* to extend file by map_size every time.
|
||||
*/
|
||||
virtual uint64_t GetFileSize() override;
|
||||
|
||||
virtual Status InvalidateCache(size_t offset, size_t length) override;
|
||||
|
||||
virtual Status Allocate(uint64_t offset, uint64_t len) override;
|
||||
|
||||
virtual size_t GetUniqueId(char* id, size_t max_size) const override;
|
||||
};
|
||||
|
||||
class WinRandomAccessImpl {
|
||||
protected:
|
||||
WinFileData* file_base_;
|
||||
size_t alignment_;
|
||||
|
||||
// Override for behavior change when creating a custom env
|
||||
virtual SSIZE_T PositionedReadInternal(char* src, size_t numBytes,
|
||||
uint64_t offset) const;
|
||||
|
||||
WinRandomAccessImpl(WinFileData* file_base, size_t alignment,
|
||||
const EnvOptions& options);
|
||||
|
||||
virtual ~WinRandomAccessImpl() {}
|
||||
|
||||
Status ReadImpl(uint64_t offset, size_t n, Slice* result,
|
||||
char* scratch) const;
|
||||
|
||||
size_t GetAlignment() const { return alignment_; }
|
||||
|
||||
public:
|
||||
|
||||
WinRandomAccessImpl(const WinRandomAccessImpl&) = delete;
|
||||
WinRandomAccessImpl& operator=(const WinRandomAccessImpl&) = delete;
|
||||
};
|
||||
|
||||
// pread() based random-access
|
||||
class WinRandomAccessFile
|
||||
: private WinFileData,
|
||||
protected WinRandomAccessImpl, // Want to be able to override
|
||||
// PositionedReadInternal
|
||||
public RandomAccessFile {
|
||||
public:
|
||||
WinRandomAccessFile(const std::string& fname, HANDLE hFile, size_t alignment,
|
||||
const EnvOptions& options);
|
||||
|
||||
~WinRandomAccessFile();
|
||||
|
||||
virtual Status Read(uint64_t offset, size_t n, Slice* result,
|
||||
char* scratch) const override;
|
||||
|
||||
virtual size_t GetUniqueId(char* id, size_t max_size) const override;
|
||||
|
||||
virtual bool use_direct_io() const override { return WinFileData::use_direct_io(); }
|
||||
|
||||
virtual Status InvalidateCache(size_t offset, size_t length) override;
|
||||
|
||||
virtual size_t GetRequiredBufferAlignment() const override;
|
||||
};
|
||||
|
||||
// This is a sequential write class. It has been mimicked (as others) after
|
||||
// the original Posix class. We add support for unbuffered I/O on windows as
|
||||
// well
|
||||
// we utilize the original buffer as an alignment buffer to write directly to
|
||||
// file with no buffering.
|
||||
// No buffering requires that the provided buffer is aligned to the physical
|
||||
// sector size (SSD page size) and
|
||||
// that all SetFilePointer() operations to occur with such an alignment.
|
||||
// We thus always write in sector/page size increments to the drive and leave
|
||||
// the tail for the next write OR for Close() at which point we pad with zeros.
|
||||
// No padding is required for
|
||||
// buffered access.
|
||||
class WinWritableImpl {
|
||||
protected:
|
||||
WinFileData* file_data_;
|
||||
const uint64_t alignment_;
|
||||
uint64_t next_write_offset_; // Needed because Windows does not support O_APPEND
|
||||
uint64_t reservedsize_; // how far we have reserved space
|
||||
|
||||
virtual Status PreallocateInternal(uint64_t spaceToReserve);
|
||||
|
||||
WinWritableImpl(WinFileData* file_data, size_t alignment);
|
||||
|
||||
~WinWritableImpl() {}
|
||||
|
||||
|
||||
uint64_t GetAlignement() const { return alignment_; }
|
||||
|
||||
Status AppendImpl(const Slice& data);
|
||||
|
||||
// Requires that the data is aligned as specified by
|
||||
// GetRequiredBufferAlignment()
|
||||
Status PositionedAppendImpl(const Slice& data, uint64_t offset);
|
||||
|
||||
Status TruncateImpl(uint64_t size);
|
||||
|
||||
Status CloseImpl();
|
||||
|
||||
Status SyncImpl();
|
||||
|
||||
uint64_t GetFileNextWriteOffset() {
|
||||
// Double accounting now here with WritableFileWriter
|
||||
// and this size will be wrong when unbuffered access is used
|
||||
// but tests implement their own writable files and do not use
|
||||
// WritableFileWrapper
|
||||
// so we need to squeeze a square peg through
|
||||
// a round hole here.
|
||||
return next_write_offset_;
|
||||
}
|
||||
|
||||
Status AllocateImpl(uint64_t offset, uint64_t len);
|
||||
|
||||
public:
|
||||
WinWritableImpl(const WinWritableImpl&) = delete;
|
||||
WinWritableImpl& operator=(const WinWritableImpl&) = delete;
|
||||
};
|
||||
|
||||
class WinWritableFile : private WinFileData,
|
||||
protected WinWritableImpl,
|
||||
public WritableFile {
|
||||
public:
|
||||
WinWritableFile(const std::string& fname, HANDLE hFile, size_t alignment,
|
||||
size_t capacity, const EnvOptions& options);
|
||||
|
||||
~WinWritableFile();
|
||||
|
||||
bool IsSyncThreadSafe() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual Status Append(const Slice& data) override;
|
||||
|
||||
// Requires that the data is aligned as specified by
|
||||
// GetRequiredBufferAlignment()
|
||||
virtual Status PositionedAppend(const Slice& data, uint64_t offset) override;
|
||||
|
||||
// Need to implement this so the file is truncated correctly
|
||||
// when buffered and unbuffered mode
|
||||
virtual Status Truncate(uint64_t size) override;
|
||||
|
||||
virtual Status Close() override;
|
||||
|
||||
// write out the cached data to the OS cache
|
||||
// This is now taken care of the WritableFileWriter
|
||||
virtual Status Flush() override;
|
||||
|
||||
virtual Status Sync() override;
|
||||
|
||||
virtual Status Fsync() override;
|
||||
|
||||
// Indicates if the class makes use of direct I/O
|
||||
// Use PositionedAppend
|
||||
virtual bool use_direct_io() const override;
|
||||
|
||||
virtual size_t GetRequiredBufferAlignment() const override;
|
||||
|
||||
virtual uint64_t GetFileSize() override;
|
||||
|
||||
virtual Status Allocate(uint64_t offset, uint64_t len) override;
|
||||
|
||||
virtual size_t GetUniqueId(char* id, size_t max_size) const override;
|
||||
};
|
||||
|
||||
class WinRandomRWFile : private WinFileData,
|
||||
protected WinRandomAccessImpl,
|
||||
protected WinWritableImpl,
|
||||
public RandomRWFile {
|
||||
public:
|
||||
WinRandomRWFile(const std::string& fname, HANDLE hFile, size_t alignment,
|
||||
const EnvOptions& options);
|
||||
|
||||
~WinRandomRWFile() {}
|
||||
|
||||
// Indicates if the class makes use of direct I/O
|
||||
// If false you must pass aligned buffer to Write()
|
||||
virtual bool use_direct_io() const override;
|
||||
|
||||
// Use the returned alignment value to allocate aligned
|
||||
// buffer for Write() when use_direct_io() returns true
|
||||
virtual size_t GetRequiredBufferAlignment() const override;
|
||||
|
||||
// Write bytes in `data` at offset `offset`, Returns Status::OK() on success.
|
||||
// Pass aligned buffer when use_direct_io() returns true.
|
||||
virtual Status Write(uint64_t offset, const Slice& data) override;
|
||||
|
||||
// Read up to `n` bytes starting from offset `offset` and store them in
|
||||
// result, provided `scratch` size should be at least `n`.
|
||||
// Returns Status::OK() on success.
|
||||
virtual Status Read(uint64_t offset, size_t n, Slice* result,
|
||||
char* scratch) const override;
|
||||
|
||||
virtual Status Flush() override;
|
||||
|
||||
virtual Status Sync() override;
|
||||
|
||||
virtual Status Fsync() { return Sync(); }
|
||||
|
||||
virtual Status Close() override;
|
||||
};
|
||||
|
||||
class WinDirectory : public Directory {
|
||||
public:
|
||||
WinDirectory() {}
|
||||
|
||||
virtual Status Fsync() override;
|
||||
};
|
||||
|
||||
class WinFileLock : public FileLock {
|
||||
public:
|
||||
explicit WinFileLock(HANDLE hFile) : hFile_(hFile) {
|
||||
assert(hFile != NULL);
|
||||
assert(hFile != INVALID_HANDLE_VALUE);
|
||||
}
|
||||
|
||||
~WinFileLock();
|
||||
|
||||
private:
|
||||
HANDLE hFile_;
|
||||
};
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user