@ -26,22 +26,18 @@ namespace {
const size_t kSectorSize = 512 ;
inline
bool IsPowerOfTwo ( const size_t alignment ) {
inline bool IsPowerOfTwo ( const size_t alignment ) {
return ( ( alignment ) & ( alignment - 1 ) ) = = 0 ;
}
inline
bool IsSectorAligned ( const size_t off ) {
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 ;
}
}
} // namespace
std : : string GetWindowsErrSz ( DWORD err ) {
LPSTR lpMsgBuf ;
@ -69,18 +65,17 @@ std::string GetWindowsErrSz(DWORD err) {
// Because all the reads/writes happen by the specified offset, the caller in
// theory should not
// rely on the current file offset.
Status pwrite ( const WinFileData * file_data , const Slice & data ,
IO Status pwrite ( const WinFileData * file_data , const Slice & data ,
uint64_t offset , size_t & bytes_written ) {
Status s ;
IOStatus s ;
bytes_written = 0 ;
size_t num_bytes = data . size ( ) ;
if ( num_bytes > std : : numeric_limits < DWORD > : : max ( ) ) {
// May happen in 64-bit builds where size_t is 64-bits but
// long is still 32-bit, but that's the API here at the moment
return Status : : InvalidArgument ( " num_bytes is too large for a single write: " +
file_data - > GetName ( ) ) ;
return IO Status: : InvalidArgument (
" num_bytes is too large for a single write: " + file_data - > GetName ( ) ) ;
}
OVERLAPPED overlapped = { 0 } ;
@ -92,8 +87,9 @@ Status pwrite(const WinFileData* file_data, const Slice& data,
DWORD bytesWritten = 0 ;
if ( FALSE = = WriteFile ( file_data - > GetFileHandle ( ) , data . data ( ) , static_cast < DWORD > ( num_bytes ) ,
& bytesWritten , & overlapped ) ) {
if ( FALSE = = WriteFile ( file_data - > GetFileHandle ( ) , data . data ( ) ,
static_cast < DWORD > ( num_bytes ) , & bytesWritten ,
& overlapped ) ) {
auto lastError = GetLastError ( ) ;
s = IOErrorFromWindowsError ( " WriteFile failed: " + file_data - > GetName ( ) ,
lastError ) ;
@ -105,15 +101,14 @@ Status pwrite(const WinFileData* file_data, const Slice& data,
}
// See comments for pwrite above
Status pread ( const WinFileData * file_data , char * src , size_t num_bytes ,
IO Status pread ( const WinFileData * file_data , char * src , size_t num_bytes ,
uint64_t offset , size_t & bytes_read ) {
Status s ;
IOStatus s ;
bytes_read = 0 ;
if ( num_bytes > std : : numeric_limits < DWORD > : : max ( ) ) {
return Status : : InvalidArgument ( " num_bytes is too large for a single read: " +
file_data - > GetName ( ) ) ;
return IO Status: : InvalidArgument (
" num_bytes is too large for a single read: " + file_data - > GetName ( ) ) ;
}
OVERLAPPED overlapped = { 0 } ;
@ -125,8 +120,9 @@ Status pread(const WinFileData* file_data, char* src, size_t num_bytes,
DWORD bytesRead = 0 ;
if ( FALSE = = ReadFile ( file_data - > GetFileHandle ( ) , src , static_cast < DWORD > ( num_bytes ) ,
& bytesRead , & overlapped ) ) {
if ( FALSE = = ReadFile ( file_data - > GetFileHandle ( ) , src ,
static_cast < DWORD > ( num_bytes ) , & bytesRead ,
& overlapped ) ) {
auto lastError = GetLastError ( ) ;
// EOF is OK with zero bytes read
if ( lastError ! = ERROR_HANDLE_EOF ) {
@ -143,9 +139,9 @@ Status pread(const WinFileData* file_data, char* src, size_t num_bytes,
// SetFileInformationByHandle() is capable of fast pre-allocates.
// However, this does not change the file end position unless the file is
// truncated and the pre-allocated space is not considered filled with zeros.
Status fallocate ( const std : : string & filename , HANDLE hFile ,
IO Status fallocate ( const std : : string & filename , HANDLE hFile ,
uint64_t to_size ) {
Status status ;
IO Status status ;
FILE_ALLOCATION_INFO alloc_info ;
alloc_info . AllocationSize . QuadPart = to_size ;
@ -160,9 +156,8 @@ Status fallocate(const std::string& filename, HANDLE hFile,
return status ;
}
Status ftruncate ( const std : : string & filename , HANDLE hFile ,
uint64_t toSize ) {
Status status ;
IOStatus ftruncate ( const std : : string & filename , HANDLE hFile , uint64_t toSize ) {
IOStatus status ;
FILE_END_OF_FILE_INFO end_of_file ;
end_of_file . EndOfFile . QuadPart = toSize ;
@ -212,9 +207,11 @@ WinMmapReadableFile::~WinMmapReadableFile() {
assert ( ret ) ;
}
Status WinMmapReadableFile : : Read ( uint64_t offset , size_t n , Slice * result ,
char * scratch ) const {
Status s ;
IOStatus WinMmapReadableFile : : Read ( uint64_t offset , size_t n ,
const IOOptions & /*options*/ , Slice * result ,
char * scratch ,
IODebugContext * /*dbg*/ ) const {
IOStatus s ;
if ( offset > length_ ) {
* result = Slice ( ) ;
@ -222,13 +219,12 @@ Status WinMmapReadableFile::Read(uint64_t offset, size_t n, Slice* result,
} else if ( offset + n > length_ ) {
n = length_ - static_cast < size_t > ( offset ) ;
}
* result =
Slice ( reinterpret_cast < const char * > ( mapped_region_ ) + offset , n ) ;
* result = Slice ( reinterpret_cast < const char * > ( mapped_region_ ) + offset , n ) ;
return s ;
}
Status WinMmapReadableFile : : InvalidateCache ( size_t offset , size_t length ) {
return Status : : OK ( ) ;
IO Status WinMmapReadableFile : : InvalidateCache ( size_t offset , size_t length ) {
return IO Status: : OK ( ) ;
}
size_t WinMmapReadableFile : : GetUniqueId ( char * id , size_t max_size ) const {
@ -238,15 +234,14 @@ size_t WinMmapReadableFile::GetUniqueId(char* id, size_t max_size) const {
///////////////////////////////////////////////////////////////////////////////
/// WinMmapFile
// Can only truncate or reserve to a sector size aligned if
// used on files that are opened with Unbuffered I/O
Status WinMmapFile : : TruncateFile ( uint64_t toSize ) {
IO Status WinMmapFile : : TruncateFile ( uint64_t toSize ) {
return ftruncate ( filename_ , hFile_ , toSize ) ;
}
Status WinMmapFile : : UnmapCurrentRegion ( ) {
Status status ;
IO Status WinMmapFile : : UnmapCurrentRegion ( ) {
IO Status status ;
if ( mapped_begin_ ! = nullptr ) {
if ( ! : : UnmapViewOfFile ( mapped_begin_ ) ) {
@ -271,16 +266,16 @@ Status WinMmapFile::UnmapCurrentRegion() {
return status ;
}
Status WinMmapFile : : MapNewRegion ( ) {
Status status ;
IO Status WinMmapFile : : MapNewRegion ( const IOOptions & options ,
IODebugContext * dbg ) {
IO Status status ;
assert ( mapped_begin_ = = nullptr ) ;
size_t minDiskSize = static_cast < size_t > ( file_offset_ ) + view_size_ ;
if ( minDiskSize > reserved_size_ ) {
status = Allocate ( file_offset_ , view_size_ ) ;
status = Allocate ( file_offset_ , view_size_ , options , dbg ) ;
if ( ! status . ok ( ) ) {
return status ;
}
@ -288,7 +283,6 @@ Status WinMmapFile::MapNewRegion() {
// Need to remap
if ( hMap_ = = NULL | | reserved_size_ > mapping_size_ ) {
if ( hMap_ ! = NULL ) {
// Unmap the previous one
BOOL ret __attribute__ ( ( __unused__ ) ) ;
@ -339,15 +333,15 @@ Status WinMmapFile::MapNewRegion() {
return status ;
}
Status WinMmapFile : : PreallocateInternal ( uint64_t spaceToReserve ) {
IO Status WinMmapFile : : PreallocateInternal ( uint64_t spaceToReserve ) {
return fallocate ( filename_ , hFile_ , spaceToReserve ) ;
}
WinMmapFile : : WinMmapFile ( const std : : string & fname , HANDLE hFile ,
size_t page_size , size_t allocation_granularity ,
const Env Options& options )
const File Options& options )
: WinFileData ( fname , hFile , false ) ,
WritableFile ( options ) ,
FS WritableFile( options ) ,
hMap_ ( NULL ) ,
page_size_ ( page_size ) ,
allocation_granularity_ ( allocation_granularity ) ,
@ -373,17 +367,19 @@ WinMmapFile::WinMmapFile(const std::string& fname, HANDLE hFile,
// View size must be both the multiple of allocation_granularity AND the
// page size and the granularity is usually a multiple of a page size.
const size_t viewSize = 32 * 1024 ; // 32Kb similar to the Windows File Cache in buffered mode
const size_t viewSize =
32 * 1024 ; // 32Kb similar to the Windows File Cache in buffered mode
view_size_ = Roundup ( viewSize , allocation_granularity_ ) ;
}
WinMmapFile : : ~ WinMmapFile ( ) {
if ( hFile_ ) {
this - > Close ( ) ;
this - > Close ( IOOptions ( ) , nullptr ) ;
}
}
Status WinMmapFile : : Append ( const Slice & data ) {
IOStatus WinMmapFile : : Append ( const Slice & data , const IOOptions & options ,
IODebugContext * dbg ) {
const char * src = data . data ( ) ;
size_t left = data . size ( ) ;
@ -392,9 +388,9 @@ Status WinMmapFile::Append(const Slice& data) {
size_t avail = mapped_end_ - dst_ ;
if ( avail = = 0 ) {
Status s = UnmapCurrentRegion ( ) ;
IO Status s = UnmapCurrentRegion ( ) ;
if ( s . ok ( ) ) {
s = MapNewRegion ( ) ;
s = MapNewRegion ( options , dbg ) ;
}
if ( ! s . ok ( ) ) {
@ -416,30 +412,31 @@ Status WinMmapFile::Append(const Slice& data) {
memset ( dst_ , 0 , bytesToPad ) ;
}
return Status : : OK ( ) ;
return IO Status: : OK ( ) ;
}
// Means Close() will properly take care of truncate
// and it does not need any additional information
Status WinMmapFile : : Truncate ( uint64_t size ) {
return Status : : OK ( ) ;
IOStatus WinMmapFile : : Truncate ( uint64_t size , const IOOptions & /*options*/ ,
IODebugContext * /*dbg*/ ) {
return IOStatus : : OK ( ) ;
}
Status WinMmapFile : : Close ( ) {
Status s ;
IO Status WinMmapFile : : Close ( const IOOptions & options , IODebugContext * dbg ) {
IO Status s ;
assert ( NULL ! = hFile_ ) ;
// We truncate to the precise size so no
// uninitialized data at the end. SetEndOfFile
// which we use does not write zeros and it is good.
uint64_t targetSize = GetFileSize ( ) ;
uint64_t targetSize = GetFileSize ( options , dbg ) ;
if ( mapped_begin_ ! = nullptr ) {
// Sync before unmapping to make sure everything
// is on disk and there is not a lazy writing
// so we are deterministic with the tests
Sync ( ) ;
Sync ( options , dbg ) ;
s = UnmapCurrentRegion ( ) ;
}
@ -455,7 +452,6 @@ Status WinMmapFile::Close() {
}
if ( hFile_ ! = NULL ) {
TruncateFile ( targetSize ) ;
BOOL ret = : : CloseHandle ( hFile_ ) ;
@ -471,11 +467,15 @@ Status WinMmapFile::Close() {
return s ;
}
Status WinMmapFile : : Flush ( ) { return Status : : OK ( ) ; }
IOStatus WinMmapFile : : Flush ( const IOOptions & /*options*/ ,
IODebugContext * /*dbg*/ ) {
return IOStatus : : OK ( ) ;
}
// Flush only data
Status WinMmapFile : : Sync ( ) {
Status s ;
IOStatus WinMmapFile : : Sync ( const IOOptions & /*options*/ ,
IODebugContext * /*dbg*/ ) {
IOStatus s ;
// Some writes occurred since last sync
if ( dst_ > last_sync_ ) {
@ -505,8 +505,8 @@ Status WinMmapFile::Sync() {
/**
* Flush data as well as metadata to stable storage .
*/
Status WinMmapFile : : Fsync ( ) {
Status s = Sync ( ) ;
IO Status WinMmapFile : : Fsync ( const IOOptions & options , IODebugContext * dbg ) {
IO Status s = Sync ( options , dbg ) ;
// Flush metadata
if ( s . ok ( ) & & pending_sync_ ) {
@ -525,23 +525,27 @@ Status WinMmapFile::Fsync() {
* size that is returned from the filesystem because we use mmap
* to extend file by map_size every time .
*/
uint64_t WinMmapFile : : GetFileSize ( ) {
uint64_t WinMmapFile : : GetFileSize ( const IOOptions & /*options*/ ,
IODebugContext * /*dbg*/ ) {
size_t used = dst_ - mapped_begin_ ;
return file_offset_ + used ;
}
Status WinMmapFile : : InvalidateCache ( size_t offset , size_t length ) {
return Status : : OK ( ) ;
IO Status WinMmapFile : : InvalidateCache ( size_t offset , size_t length ) {
return IO Status: : OK ( ) ;
}
Status WinMmapFile : : Allocate ( uint64_t offset , uint64_t len ) {
Status status ;
IOStatus WinMmapFile : : Allocate ( uint64_t offset , uint64_t len ,
const IOOptions & /*options*/ ,
IODebugContext * /*dbg*/ ) {
IOStatus status ;
TEST_KILL_RANDOM ( " WinMmapFile::Allocate " , rocksdb_kill_odds ) ;
// Make sure that we reserve an aligned amount of space
// since the reservation block size is driven outside so we want
// to check if we are ok with reservation here
size_t spaceToReserve = Roundup ( static_cast < size_t > ( offset + len ) , view_size_ ) ;
size_t spaceToReserve =
Roundup ( static_cast < size_t > ( offset + len ) , view_size_ ) ;
// Nothing to do
if ( spaceToReserve < = reserved_size_ ) {
return status ;
@ -563,31 +567,34 @@ size_t WinMmapFile::GetUniqueId(char* id, size_t max_size) const {
// WinSequentialFile
WinSequentialFile : : WinSequentialFile ( const std : : string & fname , HANDLE f ,
const Env Options& options )
const File Options& options )
: WinFileData ( fname , f , options . use_direct_reads ) { }
WinSequentialFile : : ~ WinSequentialFile ( ) {
assert ( hFile_ ! = INVALID_HANDLE_VALUE ) ;
}
Status WinSequentialFile : : Read ( size_t n , Slice * result , char * scratch ) {
Status s ;
IOStatus WinSequentialFile : : Read ( size_t n , const IOOptions & /*opts*/ ,
Slice * result , char * scratch ,
IODebugContext * /*dbg*/ ) {
IOStatus s ;
size_t r = 0 ;
assert ( result ! = nullptr ) ;
if ( WinFileData : : use_direct_io ( ) ) {
return Status : : NotSupported ( " Read() does not support direct_io " ) ;
return IO Status: : NotSupported ( " Read() does not support direct_io " ) ;
}
// Windows ReadFile API accepts a DWORD.
// While it is possible to read in a loop if n is too big
// it is an unlikely case.
if ( n > std : : numeric_limits < DWORD > : : max ( ) ) {
return Status : : InvalidArgument ( " n is too big for a single ReadFile: "
+ filename_ ) ;
return IO Status: : InvalidArgument ( " n is too big for a single ReadFile: " +
filename_ ) ;
}
DWORD bytesToRead = static_cast < DWORD > ( n ) ; //cast is safe due to the check above
DWORD bytesToRead =
static_cast < DWORD > ( n ) ; // cast is safe due to the check above
DWORD bytesRead = 0 ;
BOOL ret = ReadFile ( hFile_ , scratch , bytesToRead , & bytesRead , NULL ) ;
if ( ret ! = FALSE ) {
@ -595,8 +602,7 @@ Status WinSequentialFile::Read(size_t n, Slice* result, char* scratch) {
} else {
auto lastError = GetLastError ( ) ;
if ( lastError ! = ERROR_HANDLE_EOF ) {
s = IOErrorFromWindowsError ( " ReadFile failed: " + filename_ ,
lastError ) ;
s = IOErrorFromWindowsError ( " ReadFile failed: " + filename_ , lastError ) ;
}
}
@ -604,99 +610,91 @@ Status WinSequentialFile::Read(size_t n, Slice* result, char* scratch) {
return s ;
}
Status WinSequentialFile : : PositionedReadInternal ( char * src , size_t numBytes ,
uint64_t offset , size_t & bytes_read ) const {
IOStatus WinSequentialFile : : PositionedReadInternal ( char * src , size_t numBytes ,
uint64_t offset ,
size_t & bytes_read ) const {
return pread ( this , src , numBytes , offset , bytes_read ) ;
}
Status WinSequentialFile : : PositionedRead ( uint64_t offset , size_t n , Slice * result ,
char * scratch ) {
Status s ;
IOStatus WinSequentialFile : : PositionedRead ( uint64_t offset , size_t n ,
const IOOptions & /*opts*/ ,
Slice * result , char * scratch ,
IODebugContext * /*dbg*/ ) {
if ( ! WinFileData : : use_direct_io ( ) ) {
return Status : : NotSupported ( " This function is only used for direct_io " ) ;
return IO Status: : NotSupported ( " This function is only used for direct_io " ) ;
}
if ( ! IsSectorAligned ( static_cast < size_t > ( offset ) ) | |
! IsSectorAligned ( n ) ) {
return Status : : InvalidArgument (
if ( ! IsSectorAligned ( static_cast < size_t > ( offset ) ) | | ! IsSectorAligned ( n ) ) {
return IOStatus : : InvalidArgument (
" WinSequentialFile::PositionedRead: offset is not properly aligned " ) ;
}
size_t bytes_read = 0 ; // out param
s = PositionedReadInternal ( scratch , static_cast < size_t > ( n ) , offset , bytes_read ) ;
IOStatus s = PositionedReadInternal ( scratch , static_cast < size_t > ( n ) , offset ,
bytes_read ) ;
* result = Slice ( scratch , bytes_read ) ;
return s ;
}
Status WinSequentialFile : : Skip ( uint64_t n ) {
// Can't handle more than signed max as SetFilePointerEx accepts a signed 64-bit
// integer. As such it is a highly unlikley case to have n so large.
IOStatus WinSequentialFile : : Skip ( uint64_t n ) {
// Can't handle more than signed max as SetFilePointerEx accepts a signed
// 64-bit integer. As such it is a highly unlikley case to have n so large.
if ( n > static_cast < uint64_t > ( std : : numeric_limits < LONGLONG > : : max ( ) ) ) {
return Status : : InvalidArgument ( " n is too large for a single SetFilePointerEx() call " +
filename_ ) ;
return IO Status: : InvalidArgument (
" n is too large for a single SetFilePointerEx() call " + filename_ ) ;
}
LARGE_INTEGER li ;
li . QuadPart = static_cast < LONGLONG > ( n ) ; //cast is safe due to the check above
li . QuadPart = static_cast < LONGLONG > ( n ) ; // cast is safe due to the check
// above
BOOL ret = SetFilePointerEx ( hFile_ , li , NULL , FILE_CURRENT ) ;
if ( ret = = FALSE ) {
auto lastError = GetLastError ( ) ;
return IOErrorFromWindowsError ( " Skip SetFilePointerEx(): " + filename_ ,
lastError ) ;
}
return Status : : OK ( ) ;
return IO Status: : OK ( ) ;
}
Status WinSequentialFile : : InvalidateCache ( size_t offset , size_t length ) {
return Status : : OK ( ) ;
IO Status WinSequentialFile : : InvalidateCache ( size_t offset , size_t length ) {
return IO Status: : OK ( ) ;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
/// WinRandomAccessBase
inline
Status WinRandomAccessImpl : : PositionedReadInternal ( char * src ,
size_t numBytes ,
uint64_t offset ,
size_t & bytes_read ) const {
inline IOStatus WinRandomAccessImpl : : PositionedReadInternal (
char * src , size_t numBytes , uint64_t offset , size_t & bytes_read ) const {
return pread ( file_base_ , src , numBytes , offset , bytes_read ) ;
}
inline
WinRandomAccessImpl : : WinRandomAccessImpl ( WinFileData * file_base ,
inline WinRandomAccessImpl : : WinRandomAccessImpl ( WinFileData * file_base ,
size_t alignment ,
const EnvOptions & options ) :
file_base_ ( file_base ) ,
alignment_ ( alignment ) {
const FileOptions & options )
: file_base_ ( file_base ) , alignment_ ( alignment ) {
assert ( ! options . use_mmap_reads ) ;
}
inline
Status WinRandomAccessImpl : : ReadImpl ( uint64_t offset , size_t n , Slice * result ,
inline IOStatus WinRandomAccessImpl : : ReadImpl ( uint64_t offset , size_t n ,
Slice * result ,
char * scratch ) const {
Status s ;
// Check buffer alignment
if ( file_base_ - > use_direct_io ( ) ) {
if ( ! IsSectorAligned ( static_cast < size_t > ( offset ) ) | |
! IsAligned ( alignment_ , scratch ) ) {
return Status : : InvalidArgument (
" WinRandomAccessImpl::ReadImpl: offset or scratch is not properly aligned " ) ;
return IOStatus : : InvalidArgument (
" WinRandomAccessImpl::ReadImpl: offset or scratch is not properly "
" aligned " ) ;
}
}
if ( n = = 0 ) {
* result = Slice ( scratch , 0 ) ;
return s ;
return IOStatu s: : OK ( ) ;
}
size_t bytes_read = 0 ;
s = PositionedReadInternal ( scratch , n , offset , bytes_read ) ;
IOStatus s = PositionedReadInternal ( scratch , n , offset , bytes_read ) ;
* result = Slice ( scratch , bytes_read ) ;
return s ;
}
@ -706,20 +704,21 @@ Status WinRandomAccessImpl::ReadImpl(uint64_t offset, size_t n, Slice* result,
WinRandomAccessFile : : WinRandomAccessFile ( const std : : string & fname , HANDLE hFile ,
size_t alignment ,
const Env Options& options )
const File Options& options )
: WinFileData ( fname , hFile , options . use_direct_reads ) ,
WinRandomAccessImpl ( this , alignment , options ) { }
WinRandomAccessFile : : ~ WinRandomAccessFile ( ) {
}
WinRandomAccessFile : : ~ WinRandomAccessFile ( ) { }
Status WinRandomAccessFile : : Read ( uint64_t offset , size_t n , Slice * result ,
char * scratch ) const {
IOStatus WinRandomAccessFile : : Read ( uint64_t offset , size_t n ,
const IOOptions & /*options*/ , Slice * result ,
char * scratch ,
IODebugContext * /*dbg*/ ) const {
return ReadImpl ( offset , n , result , scratch ) ;
}
Status WinRandomAccessFile : : InvalidateCache ( size_t offset , size_t length ) {
return Status : : OK ( ) ;
IO Status WinRandomAccessFile : : InvalidateCache ( size_t offset , size_t length ) {
return IO Status: : OK ( ) ;
}
size_t WinRandomAccessFile : : GetUniqueId ( char * id , size_t max_size ) const {
@ -734,18 +733,17 @@ size_t WinRandomAccessFile::GetRequiredBufferAlignment() const {
// WinWritableImpl
//
inline
Status WinWritableImpl : : PreallocateInternal ( uint64_t spaceToReserve ) {
return fallocate ( file_data_ - > GetName ( ) , file_data_ - > GetFileHandle ( ) , spaceToReserve ) ;
inline IOStatus WinWritableImpl : : PreallocateInternal ( uint64_t spaceToReserve ) {
return fallocate ( file_data_ - > GetName ( ) , file_data_ - > GetFileHandle ( ) ,
spaceToReserve ) ;
}
inline
WinWritableImpl : : WinWritableImpl ( WinFileData * file_data , size_t alignment )
inline WinWritableImpl : : WinWritableImpl ( WinFileData * file_data ,
size_t alignment )
: file_data_ ( file_data ) ,
alignment_ ( alignment ) ,
next_write_offset_ ( 0 ) ,
reservedsize_ ( 0 ) {
// Query current position in case ReopenWritableFile is called
// This position is only important for buffered writes
// for unbuffered writes we explicitely specify the position.
@ -763,13 +761,11 @@ WinWritableImpl::WinWritableImpl(WinFileData* file_data, size_t alignment)
}
}
inline
Status WinWritableImpl : : AppendImpl ( const Slice & data ) {
Status s ;
inline IOStatus WinWritableImpl : : AppendImpl ( const Slice & data ) {
IOStatus s ;
if ( data . size ( ) > std : : numeric_limits < DWORD > : : max ( ) ) {
return Status : : InvalidArgument ( " data is too long for a single write " +
return IO Status: : InvalidArgument ( " data is too long for a single write " +
file_data_ - > GetName ( ) ) ;
}
@ -781,20 +777,18 @@ Status WinWritableImpl::AppendImpl(const Slice& data) {
assert ( IsSectorAligned ( next_write_offset_ ) ) ;
if ( ! IsSectorAligned ( data . size ( ) ) | |
! IsAligned ( static_cast < size_t > ( GetAlignement ( ) ) , data . data ( ) ) ) {
s = Status : : InvalidArgument (
s = IO Status: : InvalidArgument (
" WriteData must be page aligned, size must be sector aligned " ) ;
} else {
s = pwrite ( file_data_ , data , next_write_offset_ , bytes_written ) ;
}
} else {
DWORD bytesWritten = 0 ;
if ( ! WriteFile ( file_data_ - > GetFileHandle ( ) , data . data ( ) ,
static_cast < DWORD > ( data . size ( ) ) , & bytesWritten , NULL ) ) {
auto lastError = GetLastError ( ) ;
s = IOErrorFromWindowsError (
" Failed to WriteFile: " + file_data_ - > GetName ( ) ,
lastError ) ;
" Failed to WriteFile: " + file_data_ - > GetName ( ) , lastError ) ;
} else {
bytes_written = bytesWritten ;
}
@ -807,7 +801,7 @@ Status WinWritableImpl::AppendImpl(const Slice& data) {
// is sector aligned
next_write_offset_ + = bytes_written ;
} else {
s = Status : : IOError ( " Failed to write all bytes: " +
s = IO Status: : IOError ( " Failed to write all bytes: " +
file_data_ - > GetName ( ) ) ;
}
}
@ -815,20 +809,19 @@ Status WinWritableImpl::AppendImpl(const Slice& data) {
return s ;
}
inline
Status WinWritableImpl : : PositionedAppendImpl ( const Slice & data , uint64_t offset ) {
inline IOStatus WinWritableImpl : : PositionedAppendImpl ( const Slice & data ,
uint64_t offset ) {
if ( file_data_ - > use_direct_io ( ) ) {
if ( ! IsSectorAligned ( static_cast < size_t > ( offset ) ) | |
! IsSectorAligned ( data . size ( ) ) | |
! IsAligned ( static_cast < size_t > ( GetAlignement ( ) ) , data . data ( ) ) ) {
return Status : : InvalidArgument (
return IO Status: : InvalidArgument (
" Data and offset must be page aligned, size must be sector aligned " ) ;
}
}
size_t bytes_written = 0 ;
Status s = pwrite ( file_data_ , data , offset , bytes_written ) ;
IO Status s = pwrite ( file_data_ , data , offset , bytes_written ) ;
if ( s . ok ( ) ) {
if ( bytes_written = = data . size ( ) ) {
@ -839,23 +832,21 @@ Status WinWritableImpl::PositionedAppendImpl(const Slice& data, uint64_t offset)
next_write_offset_ = write_end ;
}
} else {
s = Status : : IOError ( " Failed to write all of the requested data: " +
s = IO Status: : IOError ( " Failed to write all of the requested data: " +
file_data_ - > GetName ( ) ) ;
}
}
return s ;
}
inline
Status WinWritableImpl : : TruncateImpl ( uint64_t size ) {
inline IOStatus WinWritableImpl : : TruncateImpl ( uint64_t size ) {
// It is tempting to check for the size for sector alignment
// but truncation may come at the end and there is not a requirement
// for this to be sector aligned so long as we do not attempt to write
// after that. The interface docs state that the behavior is undefined
// in that case.
Status s = ftruncate ( file_data_ - > GetName ( ) , file_data_ - > GetFileHandle ( ) ,
size ) ;
IO Status s =
ftruncate ( file_data_ - > GetName ( ) , file_data_ - > GetFileHandle ( ) , size ) ;
if ( s . ok ( ) ) {
next_write_offset_ = size ;
@ -863,50 +854,48 @@ Status WinWritableImpl::TruncateImpl(uint64_t size) {
return s ;
}
inline
Status WinWritableImpl : : CloseImpl ( ) {
Status s ;
inline IOStatus WinWritableImpl : : CloseImpl ( ) {
IOStatus s ;
auto hFile = file_data_ - > GetFileHandle ( ) ;
assert ( INVALID_HANDLE_VALUE ! = hFile ) ;
if ( ! : : FlushFileBuffers ( hFile ) ) {
auto lastError = GetLastError ( ) ;
s = IOErrorFromWindowsError ( " FlushFileBuffers failed at Close() for: " +
file_data_ - > GetName ( ) ,
s = IOErrorFromWindowsError (
" FlushFileBuffers failed at Close() for: " + file_data_ - > GetName ( ) ,
lastError ) ;
}
if ( ! file_data_ - > CloseFile ( ) & & s . ok ( ) ) {
auto lastError = GetLastError ( ) ;
s = IOErrorFromWindowsError ( " CloseHandle failed for: " + file_data_ - > GetName ( ) ,
lastError ) ;
s = IOErrorFromWindowsError (
" CloseHandle failed for: " + file_data_ - > GetName ( ) , lastError ) ;
}
return s ;
}
inline
Status WinWritableImpl : : SyncImpl ( ) {
Status s ;
inline IOStatus WinWritableImpl : : SyncImpl ( const IOOptions & /*options*/ ,
IODebugContext * /*dbg*/ ) {
IO Status s ;
if ( ! : : FlushFileBuffers ( file_data_ - > GetFileHandle ( ) ) ) {
auto lastError = GetLastError ( ) ;
s = IOErrorFromWindowsError (
" FlushFileBuffers failed at Sync() for: " + file_data_ - > GetName ( ) , lastError ) ;
" FlushFileBuffers failed at Sync() for: " + file_data_ - > GetName ( ) ,
lastError ) ;
}
return s ;
}
inline
Status WinWritableImpl : : AllocateImpl ( uint64_t offset , uint64_t len ) {
Status status ;
inline IOStatus WinWritableImpl : : AllocateImpl ( uint64_t offset , uint64_t len ) {
IOStatus status ;
TEST_KILL_RANDOM ( " WinWritableFile::Allocate " , rocksdb_kill_odds ) ;
// Make sure that we reserve an aligned amount of space
// since the reservation block size is driven outside so we want
// to check if we are ok with reservation here
size_t spaceToReserve = Roundup ( static_cast < size_t > ( offset + len ) , static_cast < size_t > ( alignment_ ) ) ;
size_t spaceToReserve = Roundup ( static_cast < size_t > ( offset + len ) ,
static_cast < size_t > ( alignment_ ) ) ;
// Nothing to do
if ( spaceToReserve < = reservedsize_ ) {
return status ;
@ -920,66 +909,78 @@ Status WinWritableImpl::AllocateImpl(uint64_t offset, uint64_t len) {
return status ;
}
////////////////////////////////////////////////////////////////////////////////
/// WinWritableFile
WinWritableFile : : WinWritableFile ( const std : : string & fname , HANDLE hFile ,
size_t alignment , size_t /* capacity */ ,
const Env Options& options )
const File Options& options )
: WinFileData ( fname , hFile , options . use_direct_writes ) ,
WinWritableImpl ( this , alignment ) ,
WritableFile ( options ) {
FS WritableFile( options ) {
assert ( ! options . use_mmap_writes ) ;
}
WinWritableFile : : ~ WinWritableFile ( ) {
}
WinWritableFile : : ~ WinWritableFile ( ) { }
// Indicates if the class makes use of direct I/O
bool WinWritableFile : : use_direct_io ( ) const { return WinFileData : : use_direct_io ( ) ; }
bool WinWritableFile : : use_direct_io ( ) const {
return WinFileData : : use_direct_io ( ) ;
}
size_t WinWritableFile : : GetRequiredBufferAlignment ( ) const {
return static_cast < size_t > ( GetAlignement ( ) ) ;
}
Status WinWritableFile : : Append ( const Slice & data ) {
IOStatus WinWritableFile : : Append ( const Slice & data ,
const IOOptions & /*options*/ ,
IODebugContext * /*dbg*/ ) {
return AppendImpl ( data ) ;
}
Status WinWritableFile : : PositionedAppend ( const Slice & data , uint64_t offset ) {
IOStatus WinWritableFile : : PositionedAppend ( const Slice & data , uint64_t offset ,
const IOOptions & /*options*/ ,
IODebugContext * /*dbg*/ ) {
return PositionedAppendImpl ( data , offset ) ;
}
// Need to implement this so the file is truncated correctly
// when buffered and unbuffered mode
Status WinWritableFile : : Truncate ( uint64_t size ) {
IOStatus WinWritableFile : : Truncate ( uint64_t size , const IOOptions & /*options*/ ,
IODebugContext * /*dbg*/ ) {
return TruncateImpl ( size ) ;
}
Status WinWritableFile : : Close ( ) {
IOStatus WinWritableFile : : Close ( const IOOptions & /*options*/ ,
IODebugContext * /*dbg*/ ) {
return CloseImpl ( ) ;
}
// write out the cached data to the OS cache
// This is now taken care of the WritableFileWriter
Status WinWritableFile : : Flush ( ) {
return Status : : OK ( ) ;
IOStatus WinWritableFile : : Flush ( const IOOptions & /*options*/ ,
IODebugContext * /*dbg*/ ) {
return IOStatus : : OK ( ) ;
}
Status WinWritableFile : : Sync ( ) {
return SyncImpl ( ) ;
IO Status WinWritableFile : : Sync ( const IOOptions & options , IODebugContext * dbg ) {
return SyncImpl ( options , dbg ) ;
}
Status WinWritableFile : : Fsync ( ) { return SyncImpl ( ) ; }
IOStatus WinWritableFile : : Fsync ( const IOOptions & options , IODebugContext * dbg ) {
return SyncImpl ( options , dbg ) ;
}
bool WinWritableFile : : IsSyncThreadSafe ( ) const { return true ; }
uint64_t WinWritableFile : : GetFileSize ( ) {
uint64_t WinWritableFile : : GetFileSize ( const IOOptions & /*options*/ ,
IODebugContext * /*dbg*/ ) {
return GetFileNextWriteOffset ( ) ;
}
Status WinWritableFile : : Allocate ( uint64_t offset , uint64_t len ) {
IOStatus WinWritableFile : : Allocate ( uint64_t offset , uint64_t len ,
const IOOptions & /*options*/ ,
IODebugContext * /*dbg*/ ) {
return AllocateImpl ( offset , len ) ;
}
@ -991,36 +992,43 @@ size_t WinWritableFile::GetUniqueId(char* id, size_t max_size) const {
/// WinRandomRWFile
WinRandomRWFile : : WinRandomRWFile ( const std : : string & fname , HANDLE hFile ,
size_t alignment , const Env Options& options )
size_t alignment , const File Options& options )
: WinFileData ( fname , hFile ,
options . use_direct_reads & & options . use_direct_writes ) ,
WinRandomAccessImpl ( this , alignment , options ) ,
WinWritableImpl ( this , alignment ) { }
bool WinRandomRWFile : : use_direct_io ( ) const { return WinFileData : : use_direct_io ( ) ; }
bool WinRandomRWFile : : use_direct_io ( ) const {
return WinFileData : : use_direct_io ( ) ;
}
size_t WinRandomRWFile : : GetRequiredBufferAlignment ( ) const {
return static_cast < size_t > ( GetAlignement ( ) ) ;
}
Status WinRandomRWFile : : Write ( uint64_t offset , const Slice & data ) {
IOStatus WinRandomRWFile : : Write ( uint64_t offset , const Slice & data ,
const IOOptions & /*options*/ ,
IODebugContext * /*dbg*/ ) {
return PositionedAppendImpl ( data , offset ) ;
}
Status WinRandomRWFile : : Read ( uint64_t offset , size_t n , Slice * result ,
char * scratch ) const {
IOStatus WinRandomRWFile : : Read ( uint64_t offset , size_t n ,
const IOOptions & /*options*/ , Slice * result ,
char * scratch , IODebugContext * /*dbg*/ ) const {
return ReadImpl ( offset , n , result , scratch ) ;
}
Status WinRandomRWFile : : Flush ( ) {
return Status : : OK ( ) ;
IOStatus WinRandomRWFile : : Flush ( const IOOptions & /*options*/ ,
IODebugContext * /*dbg*/ ) {
return IOStatus : : OK ( ) ;
}
Status WinRandomRWFile : : Sync ( ) {
return SyncImpl ( ) ;
IO Status WinRandomRWFile : : Sync ( const IOOptions & options , IODebugContext * dbg ) {
return SyncImpl ( options , dbg ) ;
}
Status WinRandomRWFile : : Close ( ) {
IOStatus WinRandomRWFile : : Close ( const IOOptions & /*options*/ ,
IODebugContext * /*dbg*/ ) {
return CloseImpl ( ) ;
}
@ -1053,7 +1061,10 @@ WinMemoryMappedBuffer::~WinMemoryMappedBuffer() {
//////////////////////////////////////////////////////////////////////////
/// WinDirectory
Status WinDirectory : : Fsync ( ) { return Status : : OK ( ) ; }
IOStatus WinDirectory : : Fsync ( const IOOptions & /*options*/ ,
IODebugContext * /*dbg*/ ) {
return IOStatus : : OK ( ) ;
}
size_t WinDirectory : : GetUniqueId ( char * id , size_t max_size ) const {
return GetUniqueIdFromFile ( handle_ , id , max_size ) ;
@ -1067,7 +1078,7 @@ WinFileLock::~WinFileLock() {
assert ( ret ) ;
}
}
} // namespace port
} // namespace ROCKSDB_NAMESPACE
# endif