Created
November 8, 2016 20:57
-
-
Save edouarda/ddc5763bf87c88353458e4cea636ebbc to your computer and use it in GitHub Desktop.
quasardb's rocksdb win32 port
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. | |
// This source code is licensed under the BSD-style license found in the | |
// LICENSE file in the root directory of this source tree. An additional grant | |
// of patent rights can be found in the PATENTS file in the same 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. | |
#if !defined(OS_WIN) && !defined(WIN32) && !defined(_WIN32) | |
#error Windows Specific Code | |
#endif | |
#include "port/win/port_win.h" | |
#include <io.h> | |
#include "port/dirent.h" | |
#include "port/sys_time.h" | |
#include <cstdlib> | |
#include <stdio.h> | |
#include <assert.h> | |
#include <string.h> | |
#include <memory> | |
#include <exception> | |
#include <chrono> | |
#include "util/logging.h" | |
namespace rocksdb { | |
namespace port { | |
void gettimeofday(struct timeval* tv, struct timezone* /* tz */) { | |
using namespace std::chrono; | |
microseconds usNow( | |
duration_cast<microseconds>(system_clock::now().time_since_epoch())); | |
seconds secNow(duration_cast<seconds>(usNow)); | |
tv->tv_sec = static_cast<long>(secNow.count()); | |
tv->tv_usec = static_cast<long>(usNow.count() - | |
duration_cast<microseconds>(secNow).count()); | |
} | |
Mutex::Mutex(bool adaptive) | |
{ | |
::InitializeCriticalSection(§ion_); | |
} | |
Mutex::~Mutex() | |
{ | |
::DeleteCriticalSection(§ion_); | |
} | |
void Mutex::Lock() { | |
::EnterCriticalSection(§ion_); | |
#ifndef NDEBUG | |
locked_ = true; | |
#endif | |
} | |
void Mutex::Unlock() { | |
#ifndef NDEBUG | |
locked_ = false; | |
#endif | |
::LeaveCriticalSection(§ion_); | |
} | |
void Mutex::AssertHeld() { | |
#ifndef NDEBUG | |
assert(locked_); | |
#endif | |
} | |
CondVar::CondVar(Mutex* mu) : mu_(mu) | |
{ | |
::InitializeConditionVariable(&cv_); | |
} | |
CondVar::~CondVar() {} | |
void CondVar::Wait() { | |
#ifndef NDEBUG | |
mu_->locked_ = false; | |
#endif | |
::SleepConditionVariableCS(&cv_, &(mu_->section_), INFINITE); | |
#ifndef NDEBUG | |
mu_->locked_ = true; | |
#endif | |
} | |
bool CondVar::TimedWait(uint64_t abs_time_us) { | |
#ifndef NDEBUG | |
mu_->locked_ = false; | |
#endif | |
using namespace std::chrono; | |
// MSVC++ library implements wait_until in terms of wait_for so | |
// there is not an absolute wait anyway. | |
microseconds usAbsTime(abs_time_us); | |
microseconds usNow( | |
duration_cast<microseconds>(system_clock::now().time_since_epoch())); | |
microseconds relTimeUs = | |
(usAbsTime > usNow) ? (usAbsTime - usNow) : microseconds::zero(); | |
const BOOL cvStatus = | |
::SleepConditionVariableCS(&cv_, &(mu_->section_), duration_cast<milliseconds>(relTimeUs).count()); | |
#ifndef NDEBUG | |
mu_->locked_ = true; | |
#endif | |
if ((!cvStatus) && (GetLastError() == ERROR_TIMEOUT)) | |
{ | |
return true; | |
} | |
return false; | |
} | |
void CondVar::Signal() { ::WakeConditionVariable(&cv_); } | |
void CondVar::SignalAll() { WakeAllConditionVariable(&cv_); } | |
int PhysicalCoreID() { return GetCurrentProcessorNumber(); } | |
void InitOnce(OnceType* once, void (*initializer)()) { | |
std::call_once(once->flag_, initializer); | |
} | |
// Private structure, exposed only by pointer | |
struct DIR { | |
intptr_t handle_; | |
bool firstread_; | |
struct __finddata64_t data_; | |
dirent entry_; | |
DIR() : handle_(-1), firstread_(true) {} | |
DIR(const DIR&) = delete; | |
DIR& operator=(const DIR&) = delete; | |
~DIR() { | |
if (-1 != handle_) { | |
_findclose(handle_); | |
} | |
} | |
}; | |
DIR* opendir(const char* name) { | |
if (!name || *name == 0) { | |
errno = ENOENT; | |
return nullptr; | |
} | |
std::string pattern(name); | |
pattern.append("\\").append("*"); | |
std::unique_ptr<DIR> dir(new DIR); | |
dir->handle_ = _findfirst64(pattern.c_str(), &dir->data_); | |
if (dir->handle_ == -1) { | |
return nullptr; | |
} | |
strncpy_s(dir->entry_.d_name, dir->data_.name, strlen(dir->data_.name)); | |
return dir.release(); | |
} | |
struct dirent* readdir(DIR* dirp) { | |
if (!dirp || dirp->handle_ == -1) { | |
errno = EBADF; | |
return nullptr; | |
} | |
if (dirp->firstread_) { | |
dirp->firstread_ = false; | |
return &dirp->entry_; | |
} | |
auto ret = _findnext64(dirp->handle_, &dirp->data_); | |
if (ret != 0) { | |
return nullptr; | |
} | |
strncpy_s(dirp->entry_.d_name, dirp->data_.name, strlen(dirp->data_.name)); | |
return &dirp->entry_; | |
} | |
int closedir(DIR* dirp) { | |
delete dirp; | |
return 0; | |
} | |
int truncate(const char* path, int64_t len) { | |
if (path == nullptr) { | |
errno = EFAULT; | |
return -1; | |
} | |
if (len < 0) { | |
errno = EINVAL; | |
return -1; | |
} | |
HANDLE hFile = | |
CreateFile(path, GENERIC_READ | GENERIC_WRITE, | |
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | |
NULL, // Security attrs | |
OPEN_EXISTING, // Truncate existing file only | |
FILE_ATTRIBUTE_NORMAL, NULL); | |
if (INVALID_HANDLE_VALUE == hFile) { | |
auto lastError = GetLastError(); | |
if (lastError == ERROR_FILE_NOT_FOUND) { | |
errno = ENOENT; | |
} else if (lastError == ERROR_ACCESS_DENIED) { | |
errno = EACCES; | |
} else { | |
errno = EIO; | |
} | |
return -1; | |
} | |
int result = 0; | |
FILE_END_OF_FILE_INFO end_of_file; | |
end_of_file.EndOfFile.QuadPart = len; | |
if (!SetFileInformationByHandle(hFile, FileEndOfFileInfo, &end_of_file, | |
sizeof(FILE_END_OF_FILE_INFO))) { | |
errno = EIO; | |
result = -1; | |
} | |
CloseHandle(hFile); | |
return result; | |
} | |
void Crash(const std::string& srcfile, int srcline) { | |
fprintf(stdout, "Crashing at %s:%d\n", srcfile.c_str(), srcline); | |
fflush(stdout); | |
abort(); | |
} | |
int GetMaxOpenFiles() { return -1; } | |
} // namespace port | |
} // namespace rocksdb | |
#ifdef JEMALLOC | |
#include "jemalloc/jemalloc.h" | |
#ifndef JEMALLOC_NON_INIT | |
namespace rocksdb { | |
namespace port { | |
__declspec(noinline) void WINAPI InitializeJemalloc() { | |
je_init(); | |
atexit(je_uninit); | |
} | |
} // port | |
} // rocksdb | |
extern "C" { | |
#ifdef _WIN64 | |
#pragma comment(linker, "/INCLUDE:p_rocksdb_init_jemalloc") | |
typedef void(WINAPI* CRT_Startup_Routine)(void); | |
// .CRT section is merged with .rdata on x64 so it must be constant data. | |
// must be of external linkage | |
// We put this into XCT since we want to run this earlier than C++ static | |
// constructors | |
// which are placed into XCU | |
#pragma const_seg(".CRT$XCT") | |
extern const CRT_Startup_Routine p_rocksdb_init_jemalloc; | |
const CRT_Startup_Routine p_rocksdb_init_jemalloc = | |
rocksdb::port::InitializeJemalloc; | |
#pragma const_seg() | |
#else // _WIN64 | |
// x86 untested | |
#pragma comment(linker, "/INCLUDE:_p_rocksdb_init_jemalloc") | |
#pragma section(".CRT$XCT", read) | |
JEMALLOC_SECTION(".CRT$XCT") JEMALLOC_ATTR(used) static const void( | |
WINAPI* p_rocksdb_init_jemalloc)(void) = rocksdb::port::InitializeJemalloc; | |
#endif // _WIN64 | |
} // extern "C" | |
#endif // JEMALLOC_NON_INIT | |
// Global operators to be replaced by a linker | |
void* operator new(size_t size) { | |
void* p = je_malloc(size); | |
if (!p) { | |
throw std::bad_alloc(); | |
} | |
return p; | |
} | |
void* operator new[](size_t size) { | |
void* p = je_malloc(size); | |
if (!p) { | |
throw std::bad_alloc(); | |
} | |
return p; | |
} | |
void operator delete(void* p) { je_free(p); } | |
void operator delete[](void* p) { je_free(p); } | |
#endif // JEMALLOC |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. | |
// This source code is licensed under the BSD-style license found in the | |
// LICENSE file in the root directory of this source tree. An additional grant | |
// of patent rights can be found in the PATENTS file in the same 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. | |
// | |
// See port_example.h for documentation for the following types/functions. | |
#ifndef STORAGE_LEVELDB_PORT_PORT_WIN_H_ | |
#define STORAGE_LEVELDB_PORT_PORT_WIN_H_ | |
// Always want minimum headers | |
#ifndef WIN32_LEAN_AND_MEAN | |
#define WIN32_LEAN_AND_MEAN | |
#endif | |
// Assume that for everywhere | |
#undef PLATFORM_IS_LITTLE_ENDIAN | |
#define PLATFORM_IS_LITTLE_ENDIAN true | |
#include <windows.h> | |
#include <string> | |
#include <string.h> | |
#include <mutex> | |
#include <limits> | |
#include <condition_variable> | |
#include <stdint.h> | |
#include "rocksdb/options.h" | |
#undef min | |
#undef max | |
#undef DeleteFile | |
#undef GetCurrentTime | |
#ifndef strcasecmp | |
#define strcasecmp _stricmp | |
#endif | |
#undef GetCurrentTime | |
#undef DeleteFile | |
typedef SSIZE_T ssize_t; | |
// size_t printf formatting named in the manner of C99 standard formatting | |
// strings such as PRIu64 | |
// in fact, we could use that one | |
#ifndef ROCKSDB_PRIszt | |
#define ROCKSDB_PRIszt "Iu" | |
#endif | |
#define __attribute__(A) | |
// Thread local storage on Linux | |
// There is thread_local in C++11 | |
#ifndef __thread | |
#define __thread __declspec(thread) | |
#endif | |
#ifndef PLATFORM_IS_LITTLE_ENDIAN | |
#define PLATFORM_IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN) | |
#endif | |
namespace rocksdb { | |
#define PREFETCH(addr, rw, locality) | |
namespace port { | |
// VS 15 | |
#if (defined _MSC_VER) && (_MSC_VER >= 1900) | |
#define ROCKSDB_NOEXCEPT noexcept | |
// For use at db/file_indexer.h kLevelMaxIndex | |
const int kMaxInt32 = std::numeric_limits<int>::max(); | |
const uint64_t kMaxUint64 = std::numeric_limits<uint64_t>::max(); | |
const int64_t kMaxInt64 = std::numeric_limits<int64_t>::max(); | |
const size_t kMaxSizet = std::numeric_limits<size_t>::max(); | |
#else //_MSC_VER | |
// VS 15 has snprintf | |
#define snprintf _snprintf | |
#define ROCKSDB_NOEXCEPT | |
// std::numeric_limits<size_t>::max() is not constexpr just yet | |
// therefore, use the same limits | |
// For use at db/file_indexer.h kLevelMaxIndex | |
const int kMaxInt32 = INT32_MAX; | |
const int64_t kMaxInt64 = INT64_MAX; | |
const uint64_t kMaxUint64 = UINT64_MAX; | |
#ifdef _WIN64 | |
const size_t kMaxSizet = UINT64_MAX; | |
#else | |
const size_t kMaxSizet = UINT_MAX; | |
#endif | |
#endif //_MSC_VER | |
const bool kLittleEndian = true; | |
class CondVar; | |
class Mutex { | |
public: | |
/* implicit */ Mutex(bool adaptive = false); | |
~Mutex(); | |
void Lock(); | |
void Unlock(); | |
// this will assert if the mutex is not locked | |
// it does NOT verify that mutex is held by a calling thread | |
void AssertHeld(); | |
// Mutex is move only with lock ownership transfer | |
Mutex(const Mutex&) = delete; | |
void operator=(const Mutex&) = delete; | |
private: | |
friend class CondVar; | |
CRITICAL_SECTION section_; | |
#ifndef NDEBUG | |
bool locked_; | |
#endif | |
}; | |
class RWMutex { | |
public: | |
RWMutex() { InitializeSRWLock(&srwLock_); } | |
void ReadLock() { AcquireSRWLockShared(&srwLock_); } | |
void WriteLock() { AcquireSRWLockExclusive(&srwLock_); } | |
void ReadUnlock() { ReleaseSRWLockShared(&srwLock_); } | |
void WriteUnlock() { ReleaseSRWLockExclusive(&srwLock_); } | |
// Empty as in POSIX | |
void AssertHeld() {} | |
private: | |
SRWLOCK srwLock_; | |
// No copying allowed | |
RWMutex(const RWMutex&); | |
void operator=(const RWMutex&); | |
}; | |
class CondVar { | |
public: | |
explicit CondVar(Mutex* mu); | |
~CondVar(); | |
void Wait(); | |
bool TimedWait(uint64_t expiration_time); | |
void Signal(); | |
void SignalAll(); | |
private: | |
CONDITION_VARIABLE cv_; | |
Mutex* mu_; | |
}; | |
// OnceInit type helps emulate | |
// Posix semantics with initialization | |
// adopted in the project | |
struct OnceType { | |
struct Init {}; | |
OnceType() {} | |
OnceType(const Init&) {} | |
OnceType(const OnceType&) = delete; | |
OnceType& operator=(const OnceType&) = delete; | |
std::once_flag flag_; | |
}; | |
#define LEVELDB_ONCE_INIT port::OnceType::Init() | |
extern void InitOnce(OnceType* once, void (*initializer)()); | |
#define CACHE_LINE_SIZE 64U | |
static inline void AsmVolatilePause() { | |
#if defined(_M_IX86) || defined(_M_X64) | |
YieldProcessor(); | |
#endif | |
// it would be nice to get "wfe" on ARM here | |
} | |
extern int PhysicalCoreID(); | |
// For Thread Local Storage abstraction | |
typedef DWORD pthread_key_t; | |
inline int pthread_key_create(pthread_key_t* key, void (*destructor)(void*)) { | |
// Not used | |
(void)destructor; | |
pthread_key_t k = TlsAlloc(); | |
if (TLS_OUT_OF_INDEXES == k) { | |
return ENOMEM; | |
} | |
*key = k; | |
return 0; | |
} | |
inline int pthread_key_delete(pthread_key_t key) { | |
if (!TlsFree(key)) { | |
return EINVAL; | |
} | |
return 0; | |
} | |
inline int pthread_setspecific(pthread_key_t key, const void* value) { | |
if (!TlsSetValue(key, const_cast<void*>(value))) { | |
return ENOMEM; | |
} | |
return 0; | |
} | |
inline void* pthread_getspecific(pthread_key_t key) { | |
void* result = TlsGetValue(key); | |
if (!result) { | |
if (GetLastError() != ERROR_SUCCESS) { | |
errno = EINVAL; | |
} else { | |
errno = NOERROR; | |
} | |
} | |
return result; | |
} | |
// UNIX equiv although errno numbers will be off | |
// using C-runtime to implement. Note, this does not | |
// feel space with zeros in case the file is extended. | |
int truncate(const char* path, int64_t length); | |
void Crash(const std::string& srcfile, int srcline); | |
extern int GetMaxOpenFiles(); | |
} // namespace port | |
using port::pthread_key_t; | |
using port::pthread_key_create; | |
using port::pthread_key_delete; | |
using port::pthread_setspecific; | |
using port::pthread_getspecific; | |
using port::truncate; | |
} // namespace rocksdb | |
#endif // STORAGE_LEVELDB_PORT_PORT_WIN_H_ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment