You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1031 lines
25 KiB
1031 lines
25 KiB
// This file contains source that originates from: |
|
// http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/env_win32.h |
|
// http://code.google.com/p/leveldbwin/source/browse/trunk/win32_impl_src/port_win32.cc |
|
// Those files dont' have any explict license headers but the |
|
// project (http://code.google.com/p/leveldbwin/) lists the 'New BSD License' |
|
// as the license. |
|
#if defined(LEVELDB_PLATFORM_WINDOWS) |
|
#include <map> |
|
|
|
|
|
#include "leveldb/env.h" |
|
|
|
#include "port/port.h" |
|
#include "leveldb/slice.h" |
|
#include "util/logging.h" |
|
|
|
#include <shlwapi.h> |
|
#include <process.h> |
|
#include <cstring> |
|
#include <stdio.h> |
|
#include <errno.h> |
|
#include <io.h> |
|
#include <algorithm> |
|
|
|
#ifdef max |
|
#undef max |
|
#endif |
|
|
|
#ifndef va_copy |
|
#define va_copy(d,s) ((d) = (s)) |
|
#endif |
|
|
|
#if defined DeleteFile |
|
#undef DeleteFile |
|
#endif |
|
|
|
//Declarations |
|
namespace leveldb |
|
{ |
|
|
|
namespace Win32 |
|
{ |
|
|
|
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ |
|
TypeName(const TypeName&); \ |
|
void operator=(const TypeName&) |
|
|
|
std::string GetCurrentDir(); |
|
std::wstring GetCurrentDirW(); |
|
|
|
static const std::string CurrentDir = GetCurrentDir(); |
|
static const std::wstring CurrentDirW = GetCurrentDirW(); |
|
|
|
std::string& ModifyPath(std::string& path); |
|
std::wstring& ModifyPath(std::wstring& path); |
|
|
|
std::string GetLastErrSz(); |
|
std::wstring GetLastErrSzW(); |
|
|
|
size_t GetPageSize(); |
|
|
|
typedef void (*ScheduleProc)(void*) ; |
|
|
|
struct WorkItemWrapper |
|
{ |
|
WorkItemWrapper(ScheduleProc proc_,void* content_); |
|
ScheduleProc proc; |
|
void* pContent; |
|
}; |
|
|
|
DWORD WINAPI WorkItemWrapperProc(LPVOID pContent); |
|
|
|
class Win32SequentialFile : public SequentialFile |
|
{ |
|
public: |
|
friend class Win32Env; |
|
virtual ~Win32SequentialFile(); |
|
virtual Status Read(size_t n, Slice* result, char* scratch); |
|
virtual Status Skip(uint64_t n); |
|
BOOL isEnable(); |
|
private: |
|
BOOL _Init(); |
|
void _CleanUp(); |
|
Win32SequentialFile(const std::string& fname); |
|
std::string _filename; |
|
::HANDLE _hFile; |
|
DISALLOW_COPY_AND_ASSIGN(Win32SequentialFile); |
|
}; |
|
|
|
class Win32RandomAccessFile : public RandomAccessFile |
|
{ |
|
public: |
|
friend class Win32Env; |
|
virtual ~Win32RandomAccessFile(); |
|
virtual Status Read(uint64_t offset, size_t n, Slice* result,char* scratch) const; |
|
BOOL isEnable(); |
|
private: |
|
BOOL _Init(LPCWSTR path); |
|
void _CleanUp(); |
|
Win32RandomAccessFile(const std::string& fname); |
|
HANDLE _hFile; |
|
const std::string _filename; |
|
DISALLOW_COPY_AND_ASSIGN(Win32RandomAccessFile); |
|
}; |
|
|
|
class Win32MapFile : public WritableFile |
|
{ |
|
public: |
|
Win32MapFile(const std::string& fname); |
|
|
|
~Win32MapFile(); |
|
virtual Status Append(const Slice& data); |
|
virtual Status Close(); |
|
virtual Status Flush(); |
|
virtual Status Sync(); |
|
BOOL isEnable(); |
|
private: |
|
std::string _filename; |
|
HANDLE _hFile; |
|
size_t _page_size; |
|
size_t _map_size; // How much extra memory to map at a time |
|
char* _base; // The mapped region |
|
HANDLE _base_handle; |
|
char* _limit; // Limit of the mapped region |
|
char* _dst; // Where to write next (in range [base_,limit_]) |
|
char* _last_sync; // Where have we synced up to |
|
uint64_t _file_offset; // Offset of base_ in file |
|
//LARGE_INTEGER file_offset_; |
|
// Have we done an munmap of unsynced data? |
|
bool _pending_sync; |
|
|
|
// Roundup x to a multiple of y |
|
static size_t _Roundup(size_t x, size_t y); |
|
size_t _TruncateToPageBoundary(size_t s); |
|
bool _UnmapCurrentRegion(); |
|
bool _MapNewRegion(); |
|
DISALLOW_COPY_AND_ASSIGN(Win32MapFile); |
|
BOOL _Init(LPCWSTR Path); |
|
}; |
|
|
|
class Win32FileLock : public FileLock |
|
{ |
|
public: |
|
friend class Win32Env; |
|
virtual ~Win32FileLock(); |
|
BOOL isEnable(); |
|
private: |
|
BOOL _Init(LPCWSTR path); |
|
void _CleanUp(); |
|
Win32FileLock(const std::string& fname); |
|
HANDLE _hFile; |
|
std::string _filename; |
|
DISALLOW_COPY_AND_ASSIGN(Win32FileLock); |
|
}; |
|
|
|
class Win32Logger : public Logger |
|
{ |
|
public: |
|
friend class Win32Env; |
|
virtual ~Win32Logger(); |
|
virtual void Logv(const char* format, va_list ap); |
|
private: |
|
explicit Win32Logger(WritableFile* pFile); |
|
WritableFile* _pFileProxy; |
|
DISALLOW_COPY_AND_ASSIGN(Win32Logger); |
|
}; |
|
|
|
class Win32Env : public Env |
|
{ |
|
public: |
|
Win32Env(); |
|
virtual ~Win32Env(); |
|
virtual Status NewSequentialFile(const std::string& fname, |
|
SequentialFile** result); |
|
|
|
virtual Status NewRandomAccessFile(const std::string& fname, |
|
RandomAccessFile** result); |
|
virtual Status NewWritableFile(const std::string& fname, |
|
WritableFile** result); |
|
|
|
virtual bool FileExists(const std::string& fname); |
|
|
|
virtual Status GetChildren(const std::string& dir, |
|
std::vector<std::string>* result); |
|
|
|
virtual Status DeleteFile(const std::string& fname); |
|
|
|
virtual Status CreateDir(const std::string& dirname); |
|
|
|
virtual Status DeleteDir(const std::string& dirname); |
|
|
|
virtual Status GetFileSize(const std::string& fname, uint64_t* file_size); |
|
|
|
virtual Status RenameFile(const std::string& src, |
|
const std::string& target); |
|
|
|
virtual Status LockFile(const std::string& fname, FileLock** lock); |
|
|
|
virtual Status UnlockFile(FileLock* lock); |
|
|
|
virtual void Schedule( |
|
void (*function)(void* arg), |
|
void* arg); |
|
|
|
virtual void StartThread(void (*function)(void* arg), void* arg); |
|
|
|
virtual Status GetTestDirectory(std::string* path); |
|
|
|
//virtual void Logv(WritableFile* log, const char* format, va_list ap); |
|
|
|
virtual Status NewLogger(const std::string& fname, Logger** result); |
|
|
|
virtual uint64_t NowMicros(); |
|
|
|
virtual void SleepForMicroseconds(int micros); |
|
}; |
|
|
|
void ToWidePath(const std::string& value, std::wstring& target) { |
|
wchar_t buffer[MAX_PATH]; |
|
MultiByteToWideChar(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH); |
|
target = buffer; |
|
} |
|
|
|
void ToNarrowPath(const std::wstring& value, std::string& target) { |
|
char buffer[MAX_PATH]; |
|
WideCharToMultiByte(CP_ACP, 0, value.c_str(), -1, buffer, MAX_PATH, NULL, NULL); |
|
target = buffer; |
|
} |
|
|
|
std::string GetCurrentDir() |
|
{ |
|
CHAR path[MAX_PATH]; |
|
::GetModuleFileNameA(::GetModuleHandleA(NULL),path,MAX_PATH); |
|
*strrchr(path,'\\') = 0; |
|
return std::string(path); |
|
} |
|
|
|
std::wstring GetCurrentDirW() |
|
{ |
|
WCHAR path[MAX_PATH]; |
|
::GetModuleFileNameW(::GetModuleHandleW(NULL),path,MAX_PATH); |
|
*wcsrchr(path,L'\\') = 0; |
|
return std::wstring(path); |
|
} |
|
|
|
std::string& ModifyPath(std::string& path) |
|
{ |
|
if(path[0] == '/' || path[0] == '\\'){ |
|
path = CurrentDir + path; |
|
} |
|
std::replace(path.begin(),path.end(),'/','\\'); |
|
|
|
return path; |
|
} |
|
|
|
std::wstring& ModifyPath(std::wstring& path) |
|
{ |
|
if(path[0] == L'/' || path[0] == L'\\'){ |
|
path = CurrentDirW + path; |
|
} |
|
std::replace(path.begin(),path.end(),L'/',L'\\'); |
|
return path; |
|
} |
|
|
|
std::string GetLastErrSz() |
|
{ |
|
LPWSTR lpMsgBuf; |
|
FormatMessageW( |
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | |
|
FORMAT_MESSAGE_FROM_SYSTEM | |
|
FORMAT_MESSAGE_IGNORE_INSERTS, |
|
NULL, |
|
GetLastError(), |
|
0, // Default language |
|
(LPWSTR) &lpMsgBuf, |
|
0, |
|
NULL |
|
); |
|
std::string Err; |
|
ToNarrowPath(lpMsgBuf, Err); |
|
LocalFree( lpMsgBuf ); |
|
return Err; |
|
} |
|
|
|
std::wstring GetLastErrSzW() |
|
{ |
|
LPVOID lpMsgBuf; |
|
FormatMessageW( |
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | |
|
FORMAT_MESSAGE_FROM_SYSTEM | |
|
FORMAT_MESSAGE_IGNORE_INSERTS, |
|
NULL, |
|
GetLastError(), |
|
0, // Default language |
|
(LPWSTR) &lpMsgBuf, |
|
0, |
|
NULL |
|
); |
|
std::wstring Err = (LPCWSTR)lpMsgBuf; |
|
LocalFree(lpMsgBuf); |
|
return Err; |
|
} |
|
|
|
WorkItemWrapper::WorkItemWrapper( ScheduleProc proc_,void* content_ ) : |
|
proc(proc_),pContent(content_) |
|
{ |
|
|
|
} |
|
|
|
DWORD WINAPI WorkItemWrapperProc(LPVOID pContent) |
|
{ |
|
WorkItemWrapper* item = static_cast<WorkItemWrapper*>(pContent); |
|
ScheduleProc TempProc = item->proc; |
|
void* arg = item->pContent; |
|
delete item; |
|
TempProc(arg); |
|
return 0; |
|
} |
|
|
|
size_t GetPageSize() |
|
{ |
|
SYSTEM_INFO si; |
|
GetSystemInfo(&si); |
|
return std::max(si.dwPageSize,si.dwAllocationGranularity); |
|
} |
|
|
|
const size_t g_PageSize = GetPageSize(); |
|
|
|
|
|
Win32SequentialFile::Win32SequentialFile( const std::string& fname ) : |
|
_filename(fname),_hFile(NULL) |
|
{ |
|
_Init(); |
|
} |
|
|
|
Win32SequentialFile::~Win32SequentialFile() |
|
{ |
|
_CleanUp(); |
|
} |
|
|
|
Status Win32SequentialFile::Read( size_t n, Slice* result, char* scratch ) |
|
{ |
|
Status sRet; |
|
DWORD hasRead = 0; |
|
if(_hFile && ReadFile(_hFile,scratch,n,&hasRead,NULL) ){ |
|
*result = Slice(scratch,hasRead); |
|
} else { |
|
sRet = Status::IOError(_filename, Win32::GetLastErrSz() ); |
|
} |
|
return sRet; |
|
} |
|
|
|
Status Win32SequentialFile::Skip( uint64_t n ) |
|
{ |
|
Status sRet; |
|
LARGE_INTEGER Move,NowPointer; |
|
Move.QuadPart = n; |
|
if(!SetFilePointerEx(_hFile,Move,&NowPointer,FILE_CURRENT)){ |
|
sRet = Status::IOError(_filename,Win32::GetLastErrSz()); |
|
} |
|
return sRet; |
|
} |
|
|
|
BOOL Win32SequentialFile::isEnable() |
|
{ |
|
return _hFile ? TRUE : FALSE; |
|
} |
|
|
|
BOOL Win32SequentialFile::_Init() |
|
{ |
|
std::wstring path; |
|
ToWidePath(_filename, path); |
|
_hFile = CreateFileW(path.c_str(), |
|
GENERIC_READ, |
|
FILE_SHARE_READ, |
|
NULL, |
|
OPEN_EXISTING, |
|
FILE_ATTRIBUTE_NORMAL, |
|
NULL); |
|
return _hFile ? TRUE : FALSE; |
|
} |
|
|
|
void Win32SequentialFile::_CleanUp() |
|
{ |
|
if(_hFile){ |
|
CloseHandle(_hFile); |
|
_hFile = NULL; |
|
} |
|
} |
|
|
|
Win32RandomAccessFile::Win32RandomAccessFile( const std::string& fname ) : |
|
_filename(fname),_hFile(NULL) |
|
{ |
|
std::wstring path; |
|
ToWidePath(fname, path); |
|
_Init( path.c_str() ); |
|
} |
|
|
|
Win32RandomAccessFile::~Win32RandomAccessFile() |
|
{ |
|
_CleanUp(); |
|
} |
|
|
|
Status Win32RandomAccessFile::Read(uint64_t offset,size_t n,Slice* result,char* scratch) const |
|
{ |
|
Status sRet; |
|
OVERLAPPED ol = {0}; |
|
ZeroMemory(&ol,sizeof(ol)); |
|
ol.Offset = (DWORD)offset; |
|
ol.OffsetHigh = (DWORD)(offset >> 32); |
|
DWORD hasRead = 0; |
|
if(!ReadFile(_hFile,scratch,n,&hasRead,&ol)) |
|
sRet = Status::IOError(_filename,Win32::GetLastErrSz()); |
|
else |
|
*result = Slice(scratch,hasRead); |
|
return sRet; |
|
} |
|
|
|
BOOL Win32RandomAccessFile::_Init( LPCWSTR path ) |
|
{ |
|
BOOL bRet = FALSE; |
|
if(!_hFile) |
|
_hFile = ::CreateFileW(path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING, |
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,NULL); |
|
if(!_hFile || _hFile == INVALID_HANDLE_VALUE ) |
|
_hFile = NULL; |
|
else |
|
bRet = TRUE; |
|
return bRet; |
|
} |
|
|
|
BOOL Win32RandomAccessFile::isEnable() |
|
{ |
|
return _hFile ? TRUE : FALSE; |
|
} |
|
|
|
void Win32RandomAccessFile::_CleanUp() |
|
{ |
|
if(_hFile){ |
|
::CloseHandle(_hFile); |
|
_hFile = NULL; |
|
} |
|
} |
|
|
|
size_t Win32MapFile::_Roundup( size_t x, size_t y ) |
|
{ |
|
return ((x + y - 1) / y) * y; |
|
} |
|
|
|
size_t Win32MapFile::_TruncateToPageBoundary( size_t s ) |
|
{ |
|
s -= (s & (_page_size - 1)); |
|
assert((s % _page_size) == 0); |
|
return s; |
|
} |
|
|
|
bool Win32MapFile::_UnmapCurrentRegion() |
|
{ |
|
bool result = true; |
|
if (_base != NULL) { |
|
if (_last_sync < _limit) { |
|
// Defer syncing this data until next Sync() call, if any |
|
_pending_sync = true; |
|
} |
|
if (!UnmapViewOfFile(_base) || !CloseHandle(_base_handle)) |
|
result = false; |
|
_file_offset += _limit - _base; |
|
_base = NULL; |
|
_base_handle = NULL; |
|
_limit = NULL; |
|
_last_sync = NULL; |
|
_dst = NULL; |
|
// Increase the amount we map the next time, but capped at 1MB |
|
if (_map_size < (1<<20)) { |
|
_map_size *= 2; |
|
} |
|
} |
|
return result; |
|
} |
|
|
|
bool Win32MapFile::_MapNewRegion() |
|
{ |
|
assert(_base == NULL); |
|
//LONG newSizeHigh = (LONG)((file_offset_ + map_size_) >> 32); |
|
//LONG newSizeLow = (LONG)((file_offset_ + map_size_) & 0xFFFFFFFF); |
|
DWORD off_hi = (DWORD)(_file_offset >> 32); |
|
DWORD off_lo = (DWORD)(_file_offset & 0xFFFFFFFF); |
|
LARGE_INTEGER newSize; |
|
newSize.QuadPart = _file_offset + _map_size; |
|
SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN); |
|
SetEndOfFile(_hFile); |
|
|
|
_base_handle = CreateFileMappingA( |
|
_hFile, |
|
NULL, |
|
PAGE_READWRITE, |
|
0, |
|
0, |
|
0); |
|
if (_base_handle != NULL) { |
|
_base = (char*) MapViewOfFile(_base_handle, |
|
FILE_MAP_ALL_ACCESS, |
|
off_hi, |
|
off_lo, |
|
_map_size); |
|
if (_base != NULL) { |
|
_limit = _base + _map_size; |
|
_dst = _base; |
|
_last_sync = _base; |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
Win32MapFile::Win32MapFile( const std::string& fname) : |
|
_filename(fname), |
|
_hFile(NULL), |
|
_page_size(Win32::g_PageSize), |
|
_map_size(_Roundup(65536, Win32::g_PageSize)), |
|
_base(NULL), |
|
_base_handle(NULL), |
|
_limit(NULL), |
|
_dst(NULL), |
|
_last_sync(NULL), |
|
_file_offset(0), |
|
_pending_sync(false) |
|
{ |
|
std::wstring path; |
|
ToWidePath(fname, path); |
|
_Init(path.c_str()); |
|
assert((Win32::g_PageSize & (Win32::g_PageSize - 1)) == 0); |
|
} |
|
|
|
Status Win32MapFile::Append( const Slice& data ) |
|
{ |
|
const char* src = data.data(); |
|
size_t left = data.size(); |
|
Status s; |
|
while (left > 0) { |
|
assert(_base <= _dst); |
|
assert(_dst <= _limit); |
|
size_t avail = _limit - _dst; |
|
if (avail == 0) { |
|
if (!_UnmapCurrentRegion() || |
|
!_MapNewRegion()) { |
|
return Status::IOError("WinMmapFile.Append::UnmapCurrentRegion or MapNewRegion: ", Win32::GetLastErrSz()); |
|
} |
|
} |
|
size_t n = (left <= avail) ? left : avail; |
|
memcpy(_dst, src, n); |
|
_dst += n; |
|
src += n; |
|
left -= n; |
|
} |
|
return s; |
|
} |
|
|
|
Status Win32MapFile::Close() |
|
{ |
|
Status s; |
|
size_t unused = _limit - _dst; |
|
if (!_UnmapCurrentRegion()) { |
|
s = Status::IOError("WinMmapFile.Close::UnmapCurrentRegion: ",Win32::GetLastErrSz()); |
|
} else if (unused > 0) { |
|
// Trim the extra space at the end of the file |
|
LARGE_INTEGER newSize; |
|
newSize.QuadPart = _file_offset - unused; |
|
if (!SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN)) { |
|
s = Status::IOError("WinMmapFile.Close::SetFilePointer: ",Win32::GetLastErrSz()); |
|
} else |
|
SetEndOfFile(_hFile); |
|
} |
|
if (!CloseHandle(_hFile)) { |
|
if (s.ok()) { |
|
s = Status::IOError("WinMmapFile.Close::CloseHandle: ", Win32::GetLastErrSz()); |
|
} |
|
} |
|
_hFile = INVALID_HANDLE_VALUE; |
|
_base = NULL; |
|
_base_handle = NULL; |
|
_limit = NULL; |
|
|
|
return s; |
|
} |
|
|
|
Status Win32MapFile::Sync() |
|
{ |
|
Status s; |
|
if (_pending_sync) { |
|
// Some unmapped data was not synced |
|
_pending_sync = false; |
|
if (!FlushFileBuffers(_hFile)) { |
|
s = Status::IOError("WinMmapFile.Sync::FlushFileBuffers: ",Win32::GetLastErrSz()); |
|
} |
|
} |
|
if (_dst > _last_sync) { |
|
// Find the beginnings of the pages that contain the first and last |
|
// bytes to be synced. |
|
size_t p1 = _TruncateToPageBoundary(_last_sync - _base); |
|
size_t p2 = _TruncateToPageBoundary(_dst - _base - 1); |
|
_last_sync = _dst; |
|
if (!FlushViewOfFile(_base + p1, p2 - p1 + _page_size)) { |
|
s = Status::IOError("WinMmapFile.Sync::FlushViewOfFile: ",Win32::GetLastErrSz()); |
|
} |
|
} |
|
return s; |
|
} |
|
|
|
Status Win32MapFile::Flush() |
|
{ |
|
return Status::OK(); |
|
} |
|
|
|
Win32MapFile::~Win32MapFile() |
|
{ |
|
if (_hFile != INVALID_HANDLE_VALUE) { |
|
Win32MapFile::Close(); |
|
} |
|
} |
|
|
|
BOOL Win32MapFile::_Init( LPCWSTR Path ) |
|
{ |
|
DWORD Flag = PathFileExistsW(Path) ? OPEN_EXISTING : CREATE_ALWAYS; |
|
_hFile = CreateFileW(Path, |
|
GENERIC_READ | GENERIC_WRITE, |
|
FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE, |
|
NULL, |
|
Flag, |
|
FILE_ATTRIBUTE_NORMAL, |
|
NULL); |
|
if(!_hFile || _hFile == INVALID_HANDLE_VALUE) |
|
return FALSE; |
|
else |
|
return TRUE; |
|
} |
|
|
|
BOOL Win32MapFile::isEnable() |
|
{ |
|
return _hFile ? TRUE : FALSE; |
|
} |
|
|
|
Win32FileLock::Win32FileLock( const std::string& fname ) : |
|
_hFile(NULL),_filename(fname) |
|
{ |
|
std::wstring path; |
|
ToWidePath(fname, path); |
|
_Init(path.c_str()); |
|
} |
|
|
|
Win32FileLock::~Win32FileLock() |
|
{ |
|
_CleanUp(); |
|
} |
|
|
|
BOOL Win32FileLock::_Init( LPCWSTR path ) |
|
{ |
|
BOOL bRet = FALSE; |
|
if(!_hFile) |
|
_hFile = ::CreateFileW(path,0,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); |
|
if(!_hFile || _hFile == INVALID_HANDLE_VALUE ){ |
|
_hFile = NULL; |
|
} |
|
else |
|
bRet = TRUE; |
|
return bRet; |
|
} |
|
|
|
void Win32FileLock::_CleanUp() |
|
{ |
|
::CloseHandle(_hFile); |
|
_hFile = NULL; |
|
} |
|
|
|
BOOL Win32FileLock::isEnable() |
|
{ |
|
return _hFile ? TRUE : FALSE; |
|
} |
|
|
|
Win32Logger::Win32Logger(WritableFile* pFile) : _pFileProxy(pFile) |
|
{ |
|
assert(_pFileProxy); |
|
} |
|
|
|
Win32Logger::~Win32Logger() |
|
{ |
|
if(_pFileProxy) |
|
delete _pFileProxy; |
|
} |
|
|
|
void Win32Logger::Logv( const char* format, va_list ap ) |
|
{ |
|
uint64_t thread_id = ::GetCurrentThreadId(); |
|
|
|
// We try twice: the first time with a fixed-size stack allocated buffer, |
|
// and the second time with a much larger dynamically allocated buffer. |
|
char buffer[500]; |
|
for (int iter = 0; iter < 2; iter++) { |
|
char* base; |
|
int bufsize; |
|
if (iter == 0) { |
|
bufsize = sizeof(buffer); |
|
base = buffer; |
|
} else { |
|
bufsize = 30000; |
|
base = new char[bufsize]; |
|
} |
|
char* p = base; |
|
char* limit = base + bufsize; |
|
|
|
SYSTEMTIME st; |
|
GetLocalTime(&st); |
|
p += snprintf(p, limit - p, |
|
"%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ", |
|
int(st.wYear), |
|
int(st.wMonth), |
|
int(st.wDay), |
|
int(st.wHour), |
|
int(st.wMinute), |
|
int(st.wMinute), |
|
int(st.wMilliseconds), |
|
static_cast<long long unsigned int>(thread_id)); |
|
|
|
// Print the message |
|
if (p < limit) { |
|
va_list backup_ap; |
|
va_copy(backup_ap, ap); |
|
p += vsnprintf(p, limit - p, format, backup_ap); |
|
va_end(backup_ap); |
|
} |
|
|
|
// Truncate to available space if necessary |
|
if (p >= limit) { |
|
if (iter == 0) { |
|
continue; // Try again with larger buffer |
|
} else { |
|
p = limit - 1; |
|
} |
|
} |
|
|
|
// Add newline if necessary |
|
if (p == base || p[-1] != '\n') { |
|
*p++ = '\n'; |
|
} |
|
|
|
assert(p <= limit); |
|
DWORD hasWritten = 0; |
|
if(_pFileProxy){ |
|
_pFileProxy->Append(Slice(base, p - base)); |
|
_pFileProxy->Flush(); |
|
} |
|
if (base != buffer) { |
|
delete[] base; |
|
} |
|
break; |
|
} |
|
} |
|
|
|
bool Win32Env::FileExists(const std::string& fname) |
|
{ |
|
std::string path = fname; |
|
std::wstring wpath; |
|
ToWidePath(ModifyPath(path), wpath); |
|
return ::PathFileExistsW(wpath.c_str()) ? true : false; |
|
} |
|
|
|
Status Win32Env::GetChildren(const std::string& dir, std::vector<std::string>* result) |
|
{ |
|
Status sRet; |
|
::WIN32_FIND_DATAW wfd; |
|
std::string path = dir; |
|
ModifyPath(path); |
|
path += "\\*.*"; |
|
std::wstring wpath; |
|
ToWidePath(path, wpath); |
|
|
|
::HANDLE hFind = ::FindFirstFileW(wpath.c_str() ,&wfd); |
|
if(hFind && hFind != INVALID_HANDLE_VALUE){ |
|
BOOL hasNext = TRUE; |
|
std::string child; |
|
while(hasNext){ |
|
ToNarrowPath(wfd.cFileName, child); |
|
if(child != ".." && child != ".") { |
|
result->push_back(child); |
|
} |
|
hasNext = ::FindNextFileW(hFind,&wfd); |
|
} |
|
::FindClose(hFind); |
|
} |
|
else |
|
sRet = Status::IOError(dir,"Could not get children."); |
|
return sRet; |
|
} |
|
|
|
void Win32Env::SleepForMicroseconds( int micros ) |
|
{ |
|
::Sleep((micros + 999) /1000); |
|
} |
|
|
|
|
|
Status Win32Env::DeleteFile( const std::string& fname ) |
|
{ |
|
Status sRet; |
|
std::string path = fname; |
|
std::wstring wpath; |
|
ToWidePath(ModifyPath(path), wpath); |
|
|
|
if(!::DeleteFileW(wpath.c_str())) { |
|
sRet = Status::IOError(path, "Could not delete file."); |
|
} |
|
return sRet; |
|
} |
|
|
|
Status Win32Env::GetFileSize( const std::string& fname, uint64_t* file_size ) |
|
{ |
|
Status sRet; |
|
std::string path = fname; |
|
std::wstring wpath; |
|
ToWidePath(ModifyPath(path), wpath); |
|
|
|
HANDLE file = ::CreateFileW(wpath.c_str(), |
|
GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); |
|
LARGE_INTEGER li; |
|
if(::GetFileSizeEx(file,&li)){ |
|
*file_size = (uint64_t)li.QuadPart; |
|
}else |
|
sRet = Status::IOError(path,"Could not get the file size."); |
|
CloseHandle(file); |
|
return sRet; |
|
} |
|
|
|
Status Win32Env::RenameFile( const std::string& src, const std::string& target ) |
|
{ |
|
Status sRet; |
|
std::string src_path = src; |
|
std::wstring wsrc_path; |
|
ToWidePath(ModifyPath(src_path), wsrc_path); |
|
std::string target_path = target; |
|
std::wstring wtarget_path; |
|
ToWidePath(ModifyPath(target_path), wtarget_path); |
|
|
|
if(!MoveFileW(wsrc_path.c_str(), wtarget_path.c_str() ) ){ |
|
DWORD err = GetLastError(); |
|
if(err == 0x000000b7){ |
|
if(!::DeleteFileW(wtarget_path.c_str() ) ) |
|
sRet = Status::IOError(src, "Could not rename file."); |
|
else if(!::MoveFileW(wsrc_path.c_str(), |
|
wtarget_path.c_str() ) ) |
|
sRet = Status::IOError(src, "Could not rename file."); |
|
} |
|
} |
|
return sRet; |
|
} |
|
|
|
Status Win32Env::LockFile( const std::string& fname, FileLock** lock ) |
|
{ |
|
Status sRet; |
|
std::string path = fname; |
|
ModifyPath(path); |
|
Win32FileLock* _lock = new Win32FileLock(path); |
|
if(!_lock->isEnable()){ |
|
delete _lock; |
|
*lock = NULL; |
|
sRet = Status::IOError(path, "Could not lock file."); |
|
} |
|
else |
|
*lock = _lock; |
|
return sRet; |
|
} |
|
|
|
Status Win32Env::UnlockFile( FileLock* lock ) |
|
{ |
|
Status sRet; |
|
delete lock; |
|
return sRet; |
|
} |
|
|
|
void Win32Env::Schedule( void (*function)(void* arg), void* arg ) |
|
{ |
|
QueueUserWorkItem(Win32::WorkItemWrapperProc, |
|
new Win32::WorkItemWrapper(function,arg), |
|
WT_EXECUTEDEFAULT); |
|
} |
|
|
|
void Win32Env::StartThread( void (*function)(void* arg), void* arg ) |
|
{ |
|
::_beginthread(function,0,arg); |
|
} |
|
|
|
Status Win32Env::GetTestDirectory( std::string* path ) |
|
{ |
|
Status sRet; |
|
WCHAR TempPath[MAX_PATH]; |
|
::GetTempPathW(MAX_PATH,TempPath); |
|
ToNarrowPath(TempPath, *path); |
|
path->append("leveldb\\test\\"); |
|
ModifyPath(*path); |
|
return sRet; |
|
} |
|
|
|
uint64_t Win32Env::NowMicros() |
|
{ |
|
#ifndef USE_VISTA_API |
|
#define GetTickCount64 GetTickCount |
|
#endif |
|
return (uint64_t)(GetTickCount64()*1000); |
|
} |
|
|
|
static Status CreateDirInner( const std::string& dirname ) |
|
{ |
|
Status sRet; |
|
DWORD attr = ::GetFileAttributes(dirname.c_str()); |
|
if (attr == INVALID_FILE_ATTRIBUTES) { // doesn't exist: |
|
std::size_t slash = dirname.find_last_of("\\"); |
|
if (slash != std::string::npos){ |
|
sRet = CreateDirInner(dirname.substr(0, slash)); |
|
if (!sRet.ok()) return sRet; |
|
} |
|
BOOL result = ::CreateDirectory(dirname.c_str(), NULL); |
|
if (result == FALSE) { |
|
sRet = Status::IOError(dirname, "Could not create directory."); |
|
return sRet; |
|
} |
|
} |
|
return sRet; |
|
} |
|
|
|
Status Win32Env::CreateDir( const std::string& dirname ) |
|
{ |
|
std::string path = dirname; |
|
if(path[path.length() - 1] != '\\'){ |
|
path += '\\'; |
|
} |
|
ModifyPath(path); |
|
|
|
return CreateDirInner(path); |
|
} |
|
|
|
Status Win32Env::DeleteDir( const std::string& dirname ) |
|
{ |
|
Status sRet; |
|
std::wstring path; |
|
ToWidePath(dirname, path); |
|
ModifyPath(path); |
|
if(!::RemoveDirectoryW( path.c_str() ) ){ |
|
sRet = Status::IOError(dirname, "Could not delete directory."); |
|
} |
|
return sRet; |
|
} |
|
|
|
Status Win32Env::NewSequentialFile( const std::string& fname, SequentialFile** result ) |
|
{ |
|
Status sRet; |
|
std::string path = fname; |
|
ModifyPath(path); |
|
Win32SequentialFile* pFile = new Win32SequentialFile(path); |
|
if(pFile->isEnable()){ |
|
*result = pFile; |
|
}else { |
|
delete pFile; |
|
sRet = Status::IOError(path, Win32::GetLastErrSz()); |
|
} |
|
return sRet; |
|
} |
|
|
|
Status Win32Env::NewRandomAccessFile( const std::string& fname, RandomAccessFile** result ) |
|
{ |
|
Status sRet; |
|
std::string path = fname; |
|
Win32RandomAccessFile* pFile = new Win32RandomAccessFile(ModifyPath(path)); |
|
if(!pFile->isEnable()){ |
|
delete pFile; |
|
*result = NULL; |
|
sRet = Status::IOError(path, Win32::GetLastErrSz()); |
|
}else |
|
*result = pFile; |
|
return sRet; |
|
} |
|
|
|
Status Win32Env::NewLogger( const std::string& fname, Logger** result ) |
|
{ |
|
Status sRet; |
|
std::string path = fname; |
|
Win32MapFile* pMapFile = new Win32MapFile(ModifyPath(path)); |
|
if(!pMapFile->isEnable()){ |
|
delete pMapFile; |
|
*result = NULL; |
|
sRet = Status::IOError(path,"could not create a logger."); |
|
}else |
|
*result = new Win32Logger(pMapFile); |
|
return sRet; |
|
} |
|
|
|
Status Win32Env::NewWritableFile( const std::string& fname, WritableFile** result ) |
|
{ |
|
Status sRet; |
|
std::string path = fname; |
|
Win32MapFile* pFile = new Win32MapFile(ModifyPath(path)); |
|
if(!pFile->isEnable()){ |
|
*result = NULL; |
|
sRet = Status::IOError(fname,Win32::GetLastErrSz()); |
|
}else |
|
*result = pFile; |
|
return sRet; |
|
} |
|
|
|
Win32Env::Win32Env() |
|
{ |
|
|
|
} |
|
|
|
Win32Env::~Win32Env() |
|
{ |
|
|
|
} |
|
|
|
|
|
} // Win32 namespace |
|
|
|
static port::OnceType once = LEVELDB_ONCE_INIT; |
|
static Env* default_env; |
|
static void InitDefaultEnv() { default_env = new Win32::Win32Env(); } |
|
|
|
Env* Env::Default() { |
|
port::InitOnce(&once, InitDefaultEnv); |
|
return default_env; |
|
} |
|
|
|
} // namespace leveldb |
|
|
|
#endif // defined(LEVELDB_PLATFORM_WINDOWS)
|
|
|