rocksdb/port/win/port_win.cc
Dmitri Smirnov d8586ab22b All of these are in the new code added past 3.10
1) Crash in env_win.cc that prevented db_test run to completion and some new tests
     2) Fix new corruption tests in DBTest by allowing a shared trunction of files. Note that this is generally needed ONLY for tests.
     3) Close database so WAL is closed prior to inducing corruption similar to what we did within Corruption tests.
2015-07-08 16:56:45 -07:00

331 lines
6.4 KiB
C++

// Copyright (c) 2013, 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 = secNow.count();
tv->tv_usec = usNow.count() - duration_cast<microseconds>(secNow).count();
}
Mutex::Mutex(bool adaptive) : lock(m_mutex, std::defer_lock) {
}
Mutex::~Mutex() {
}
void Mutex::Lock() {
lock.lock();
#ifndef NDEBUG
locked_ = true;
#endif
}
void Mutex::Unlock() {
#ifndef NDEBUG
locked_ = false;
#endif
lock.unlock();
}
void Mutex::AssertHeld() {
#ifndef NDEBUG
assert(locked_);
#endif
}
CondVar::CondVar(Mutex* mu) : mu_(mu) {
}
CondVar::~CondVar() {
}
void CondVar::Wait() {
#ifndef NDEBUG
mu_->locked_ = false;
#endif
cv_.wait(mu_->getLock());
#ifndef NDEBUG
mu_->locked_ = true;
#endif
}
bool CondVar::TimedWait(uint64_t abs_time_us) {
#ifndef NDEBUG
mu_->locked_ = false;
#endif
using namespace std::chrono;
microseconds usAbsTime(abs_time_us);
microseconds usNow(duration_cast<microseconds>(system_clock::now().time_since_epoch()));
microseconds relTimeUs = (usAbsTime > usNow) ? (usAbsTime - usNow) : microseconds::zero();
std::_Cv_status cvStatus = cv_.wait_for(mu_->getLock(), relTimeUs);
#ifndef NDEBUG
mu_->locked_ = true;
#endif
if (cvStatus == std::cv_status::timeout) {
return true;
}
return false;
}
void CondVar::Signal() {
cv_.notify_one();
}
void CondVar::SignalAll() {
cv_.notify_all ();
}
void InitOnce(OnceType* once, void (*initializer)()) {
std::call_once(*once, 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;
}
} // namespace port
} // namespace rocksdb
#ifdef JEMALLOC
#include "jemalloc/jemalloc.h"
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"
// 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