aboutsummaryrefslogtreecommitdiff
path: root/src/leveldb
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2012-12-13 02:21:49 +0100
committerGavin Andresen <gavinandresen@gmail.com>2013-01-23 10:41:44 -0500
commit21f2ae7563c8892cbb634ece6911de38dc7dff7c (patch)
tree0cff518435e4494e2db9cdcbfca844ff850f181b /src/leveldb
parent00abfccc5d726b64c69bfb5e3607e2b18d14d14e (diff)
Native Windows LevelDB port
Import native Windows LevelDB port by Hiram Chirino. Extracted from from https://github.com/chirino/leveldb.git using git diff dd0d562..aea83b7
Diffstat (limited to 'src/leveldb')
-rw-r--r--src/leveldb/.gitignore4
-rw-r--r--src/leveldb/WINDOWS.md39
-rw-r--r--src/leveldb/port/port.h2
-rw-r--r--src/leveldb/port/port_win.cc154
-rw-r--r--src/leveldb/port/port_win.h154
-rw-r--r--src/leveldb/util/env_win.cc1017
-rw-r--r--src/leveldb/util/posix_logger.h2
7 files changed, 1371 insertions, 1 deletions
diff --git a/src/leveldb/.gitignore b/src/leveldb/.gitignore
index f030430565..55ba072e0e 100644
--- a/src/leveldb/.gitignore
+++ b/src/leveldb/.gitignore
@@ -6,3 +6,7 @@ build_config.mk
*.so.*
*_test
db_bench
+Release
+Debug
+Benchmark
+vs2010.*
diff --git a/src/leveldb/WINDOWS.md b/src/leveldb/WINDOWS.md
new file mode 100644
index 0000000000..5b76c2448f
--- /dev/null
+++ b/src/leveldb/WINDOWS.md
@@ -0,0 +1,39 @@
+# Building LevelDB On Windows
+
+## Prereqs
+
+Install the [Windows Software Development Kit version 7.1](http://www.microsoft.com/downloads/dlx/en-us/listdetailsview.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b).
+
+Download and extract the [Snappy source distribution](http://snappy.googlecode.com/files/snappy-1.0.5.tar.gz)
+
+1. Open the "Windows SDK 7.1 Command Prompt" :
+ Start Menu -> "Microsoft Windows SDK v7.1" > "Windows SDK 7.1 Command Prompt"
+2. Change the directory to the leveldb project
+
+## Building the Static lib
+
+* 32 bit Version
+
+ setenv /x86
+ msbuild.exe /p:Configuration=Release /p:Platform=Win32 /p:Snappy=..\snappy-1.0.5
+
+* 64 bit Version
+
+ setenv /x64
+ msbuild.exe /p:Configuration=Release /p:Platform=x64 /p:Snappy=..\snappy-1.0.5
+
+
+## Building and Running the Benchmark app
+
+* 32 bit Version
+
+ setenv /x86
+ msbuild.exe /p:Configuration=Benchmark /p:Platform=Win32 /p:Snappy=..\snappy-1.0.5
+ Benchmark\leveldb.exe
+
+* 64 bit Version
+
+ setenv /x64
+ msbuild.exe /p:Configuration=Benchmark /p:Platform=x64 /p:Snappy=..\snappy-1.0.5
+ x64\Benchmark\leveldb.exe
+
diff --git a/src/leveldb/port/port.h b/src/leveldb/port/port.h
index e667db40d0..4baafa8e22 100644
--- a/src/leveldb/port/port.h
+++ b/src/leveldb/port/port.h
@@ -14,6 +14,8 @@
# include "port/port_posix.h"
#elif defined(LEVELDB_PLATFORM_CHROMIUM)
# include "port/port_chromium.h"
+#elif defined(LEVELDB_PLATFORM_WINDOWS)
+# include "port/port_win.h"
#endif
#endif // STORAGE_LEVELDB_PORT_PORT_H_
diff --git a/src/leveldb/port/port_win.cc b/src/leveldb/port/port_win.cc
new file mode 100644
index 0000000000..7cf9537937
--- /dev/null
+++ b/src/leveldb/port/port_win.cc
@@ -0,0 +1,154 @@
+// LevelDB 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.
+
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of the University of California, Berkeley nor the
+// names of its contributors may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "port/port_win.h"
+
+#include <windows.h>
+#include <cassert>
+
+namespace leveldb {
+namespace port {
+
+Mutex::Mutex() :
+ cs_(nullptr) {
+ assert(!cs_);
+ cs_ = static_cast<void *>(new CRITICAL_SECTION());
+ ::InitializeCriticalSection(static_cast<CRITICAL_SECTION *>(cs_));
+ assert(cs_);
+}
+
+Mutex::~Mutex() {
+ assert(cs_);
+ ::DeleteCriticalSection(static_cast<CRITICAL_SECTION *>(cs_));
+ delete static_cast<CRITICAL_SECTION *>(cs_);
+ cs_ = nullptr;
+ assert(!cs_);
+}
+
+void Mutex::Lock() {
+ assert(cs_);
+ ::EnterCriticalSection(static_cast<CRITICAL_SECTION *>(cs_));
+}
+
+void Mutex::Unlock() {
+ assert(cs_);
+ ::LeaveCriticalSection(static_cast<CRITICAL_SECTION *>(cs_));
+}
+
+void Mutex::AssertHeld() {
+ assert(cs_);
+ assert(1);
+}
+
+CondVar::CondVar(Mutex* mu) :
+ waiting_(0),
+ mu_(mu),
+ sem1_(::CreateSemaphore(NULL, 0, 10000, NULL)),
+ sem2_(::CreateSemaphore(NULL, 0, 10000, NULL)) {
+ assert(mu_);
+}
+
+CondVar::~CondVar() {
+ ::CloseHandle(sem1_);
+ ::CloseHandle(sem2_);
+}
+
+void CondVar::Wait() {
+ mu_->AssertHeld();
+
+ wait_mtx_.Lock();
+ ++waiting_;
+ wait_mtx_.Unlock();
+
+ mu_->Unlock();
+
+ // initiate handshake
+ ::WaitForSingleObject(sem1_, INFINITE);
+ ::ReleaseSemaphore(sem2_, 1, NULL);
+ mu_->Lock();
+}
+
+void CondVar::Signal() {
+ wait_mtx_.Lock();
+ if (waiting_ > 0) {
+ --waiting_;
+
+ // finalize handshake
+ ::ReleaseSemaphore(sem1_, 1, NULL);
+ ::WaitForSingleObject(sem2_, INFINITE);
+ }
+ wait_mtx_.Unlock();
+}
+
+void CondVar::SignalAll() {
+ wait_mtx_.Lock();
+ for(long i = 0; i < waiting_; ++i) {
+ ::ReleaseSemaphore(sem1_, 1, NULL);
+ while(waiting_ > 0) {
+ --waiting_;
+ ::WaitForSingleObject(sem2_, INFINITE);
+ }
+ }
+ wait_mtx_.Unlock();
+}
+
+AtomicPointer::AtomicPointer(void* v) {
+ Release_Store(v);
+}
+
+BOOL CALLBACK InitHandleFunction (PINIT_ONCE InitOnce, PVOID func, PVOID *lpContext) {
+ ((void (*)())func)();
+ return true;
+}
+
+void InitOnce(OnceType* once, void (*initializer)()) {
+ InitOnceExecuteOnce((PINIT_ONCE)once, InitHandleFunction, initializer, NULL);
+}
+
+void* AtomicPointer::Acquire_Load() const {
+ void * p = nullptr;
+ InterlockedExchangePointer(&p, rep_);
+ return p;
+}
+
+void AtomicPointer::Release_Store(void* v) {
+ InterlockedExchangePointer(&rep_, v);
+}
+
+void* AtomicPointer::NoBarrier_Load() const {
+ return rep_;
+}
+
+void AtomicPointer::NoBarrier_Store(void* v) {
+ rep_ = v;
+}
+
+}
+}
diff --git a/src/leveldb/port/port_win.h b/src/leveldb/port/port_win.h
new file mode 100644
index 0000000000..c9e1cdad60
--- /dev/null
+++ b/src/leveldb/port/port_win.h
@@ -0,0 +1,154 @@
+// LevelDB 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.
+
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of the University of California, Berkeley nor the
+// names of its contributors may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef STORAGE_LEVELDB_PORT_PORT_WIN_H_
+#define STORAGE_LEVELDB_PORT_PORT_WIN_H_
+
+#define snprintf _snprintf
+#define close _close
+#define fread_unlocked _fread_nolock
+
+#include <string>
+#include <stdint.h>
+#ifdef SNAPPY
+#include <snappy.h>
+#endif
+
+namespace leveldb {
+namespace port {
+
+// Windows is little endian (for now :p)
+static const bool kLittleEndian = true;
+
+class CondVar;
+
+class Mutex {
+ public:
+ Mutex();
+ ~Mutex();
+
+ void Lock();
+ void Unlock();
+ void AssertHeld();
+
+ private:
+ friend class CondVar;
+ // critical sections are more efficient than mutexes
+ // but they are not recursive and can only be used to synchronize threads within the same process
+ // we use opaque void * to avoid including windows.h in port_win.h
+ void * cs_;
+
+ // No copying
+ Mutex(const Mutex&);
+ void operator=(const Mutex&);
+};
+
+// the Win32 API offers a dependable condition variable mechanism, but only starting with
+// Windows 2008 and Vista
+// no matter what we will implement our own condition variable with a semaphore
+// implementation as described in a paper written by Andrew D. Birrell in 2003
+class CondVar {
+ public:
+ explicit CondVar(Mutex* mu);
+ ~CondVar();
+ void Wait();
+ void Signal();
+ void SignalAll();
+ private:
+ Mutex* mu_;
+
+ Mutex wait_mtx_;
+ long waiting_;
+
+ void * sem1_;
+ void * sem2_;
+
+
+};
+
+typedef void* OnceType;
+#define LEVELDB_ONCE_INIT 0
+extern void InitOnce(port::OnceType*, void (*initializer)());
+
+// Storage for a lock-free pointer
+class AtomicPointer {
+ private:
+ void * rep_;
+ public:
+ AtomicPointer() : rep_(nullptr) { }
+ explicit AtomicPointer(void* v);
+ void* Acquire_Load() const;
+
+ void Release_Store(void* v);
+
+ void* NoBarrier_Load() const;
+
+ void NoBarrier_Store(void* v);
+};
+
+inline bool Snappy_Compress(const char* input, size_t length,
+ ::std::string* output) {
+#ifdef SNAPPY
+ output->resize(snappy::MaxCompressedLength(length));
+ size_t outlen;
+ snappy::RawCompress(input, length, &(*output)[0], &outlen);
+ output->resize(outlen);
+ return true;
+#endif
+
+ return false;
+}
+
+inline bool Snappy_GetUncompressedLength(const char* input, size_t length,
+ size_t* result) {
+#ifdef SNAPPY
+ return snappy::GetUncompressedLength(input, length, result);
+#else
+ return false;
+#endif
+}
+
+inline bool Snappy_Uncompress(const char* input, size_t length,
+ char* output) {
+#ifdef SNAPPY
+ return snappy::RawUncompress(input, length, output);
+#else
+ return false;
+#endif
+}
+
+inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) {
+ return false;
+}
+
+}
+}
+
+#endif // STORAGE_LEVELDB_PORT_PORT_WIN_H_
diff --git a/src/leveldb/util/env_win.cc b/src/leveldb/util/env_win.cc
new file mode 100644
index 0000000000..384331aec5
--- /dev/null
+++ b/src/leveldb/util/env_win.cc
@@ -0,0 +1,1017 @@
+// 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 <dbghelp.h>
+#include <algorithm>
+#pragma comment(lib,"DbgHelp.lib")
+
+#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,0,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;
+ }
+ UnmapViewOfFile(_base);
+ CloseHandle(_base_handle);
+ _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);
+}
+
+Status Win32Env::CreateDir( const std::string& dirname )
+{
+ Status sRet;
+ std::string path = dirname;
+ if(path[path.length() - 1] != '\\'){
+ path += '\\';
+ }
+ ModifyPath(path);
+ if(!::MakeSureDirectoryPathExists( path.c_str() ) ){
+ sRet = Status::IOError(dirname, "Could not create directory.");
+ }
+ return sRet;
+}
+
+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,"Could not create random access file.");
+ }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)
diff --git a/src/leveldb/util/posix_logger.h b/src/leveldb/util/posix_logger.h
index 9741b1afad..c063c2b7cb 100644
--- a/src/leveldb/util/posix_logger.h
+++ b/src/leveldb/util/posix_logger.h
@@ -3,7 +3,7 @@
// found in the LICENSE file. See the AUTHORS file for names of contributors.
//
// Logger implementation that can be shared by all environments
-// where enough posix functionality is available.
+// where enough Posix functionality is available.
#ifndef STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_
#define STORAGE_LEVELDB_UTIL_POSIX_LOGGER_H_