diff --git a/src/leveldb/db/c.cc b/src/leveldb/db/c.cc index 08ff0ad90a..b23e3dcc9d 100644 --- a/src/leveldb/db/c.cc +++ b/src/leveldb/db/c.cc @@ -1,595 +1,597 @@ // 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. #include "leveldb/c.h" #include +#ifndef WIN32 #include +#endif #include "leveldb/cache.h" #include "leveldb/comparator.h" #include "leveldb/db.h" #include "leveldb/env.h" #include "leveldb/filter_policy.h" #include "leveldb/iterator.h" #include "leveldb/options.h" #include "leveldb/status.h" #include "leveldb/write_batch.h" using leveldb::Cache; using leveldb::Comparator; using leveldb::CompressionType; using leveldb::DB; using leveldb::Env; using leveldb::FileLock; using leveldb::FilterPolicy; using leveldb::Iterator; using leveldb::kMajorVersion; using leveldb::kMinorVersion; using leveldb::Logger; using leveldb::NewBloomFilterPolicy; using leveldb::NewLRUCache; using leveldb::Options; using leveldb::RandomAccessFile; using leveldb::Range; using leveldb::ReadOptions; using leveldb::SequentialFile; using leveldb::Slice; using leveldb::Snapshot; using leveldb::Status; using leveldb::WritableFile; using leveldb::WriteBatch; using leveldb::WriteOptions; extern "C" { struct leveldb_t { DB* rep; }; struct leveldb_iterator_t { Iterator* rep; }; struct leveldb_writebatch_t { WriteBatch rep; }; struct leveldb_snapshot_t { const Snapshot* rep; }; struct leveldb_readoptions_t { ReadOptions rep; }; struct leveldb_writeoptions_t { WriteOptions rep; }; struct leveldb_options_t { Options rep; }; struct leveldb_cache_t { Cache* rep; }; struct leveldb_seqfile_t { SequentialFile* rep; }; struct leveldb_randomfile_t { RandomAccessFile* rep; }; struct leveldb_writablefile_t { WritableFile* rep; }; struct leveldb_logger_t { Logger* rep; }; struct leveldb_filelock_t { FileLock* rep; }; struct leveldb_comparator_t : public Comparator { void* state_; void (*destructor_)(void*); int (*compare_)( void*, const char* a, size_t alen, const char* b, size_t blen); const char* (*name_)(void*); virtual ~leveldb_comparator_t() { (*destructor_)(state_); } virtual int Compare(const Slice& a, const Slice& b) const { return (*compare_)(state_, a.data(), a.size(), b.data(), b.size()); } virtual const char* Name() const { return (*name_)(state_); } // No-ops since the C binding does not support key shortening methods. virtual void FindShortestSeparator(std::string*, const Slice&) const { } virtual void FindShortSuccessor(std::string* key) const { } }; struct leveldb_filterpolicy_t : public FilterPolicy { void* state_; void (*destructor_)(void*); const char* (*name_)(void*); char* (*create_)( void*, const char* const* key_array, const size_t* key_length_array, int num_keys, size_t* filter_length); unsigned char (*key_match_)( void*, const char* key, size_t length, const char* filter, size_t filter_length); virtual ~leveldb_filterpolicy_t() { (*destructor_)(state_); } virtual const char* Name() const { return (*name_)(state_); } virtual void CreateFilter(const Slice* keys, int n, std::string* dst) const { std::vector key_pointers(n); std::vector key_sizes(n); for (int i = 0; i < n; i++) { key_pointers[i] = keys[i].data(); key_sizes[i] = keys[i].size(); } size_t len; char* filter = (*create_)(state_, &key_pointers[0], &key_sizes[0], n, &len); dst->append(filter, len); free(filter); } virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const { return (*key_match_)(state_, key.data(), key.size(), filter.data(), filter.size()); } }; struct leveldb_env_t { Env* rep; bool is_default; }; static bool SaveError(char** errptr, const Status& s) { assert(errptr != NULL); if (s.ok()) { return false; } else if (*errptr == NULL) { *errptr = strdup(s.ToString().c_str()); } else { // TODO(sanjay): Merge with existing error? free(*errptr); *errptr = strdup(s.ToString().c_str()); } return true; } static char* CopyString(const std::string& str) { char* result = reinterpret_cast(malloc(sizeof(char) * str.size())); memcpy(result, str.data(), sizeof(char) * str.size()); return result; } leveldb_t* leveldb_open( const leveldb_options_t* options, const char* name, char** errptr) { DB* db; if (SaveError(errptr, DB::Open(options->rep, std::string(name), &db))) { return NULL; } leveldb_t* result = new leveldb_t; result->rep = db; return result; } void leveldb_close(leveldb_t* db) { delete db->rep; delete db; } void leveldb_put( leveldb_t* db, const leveldb_writeoptions_t* options, const char* key, size_t keylen, const char* val, size_t vallen, char** errptr) { SaveError(errptr, db->rep->Put(options->rep, Slice(key, keylen), Slice(val, vallen))); } void leveldb_delete( leveldb_t* db, const leveldb_writeoptions_t* options, const char* key, size_t keylen, char** errptr) { SaveError(errptr, db->rep->Delete(options->rep, Slice(key, keylen))); } void leveldb_write( leveldb_t* db, const leveldb_writeoptions_t* options, leveldb_writebatch_t* batch, char** errptr) { SaveError(errptr, db->rep->Write(options->rep, &batch->rep)); } char* leveldb_get( leveldb_t* db, const leveldb_readoptions_t* options, const char* key, size_t keylen, size_t* vallen, char** errptr) { char* result = NULL; std::string tmp; Status s = db->rep->Get(options->rep, Slice(key, keylen), &tmp); if (s.ok()) { *vallen = tmp.size(); result = CopyString(tmp); } else { *vallen = 0; if (!s.IsNotFound()) { SaveError(errptr, s); } } return result; } leveldb_iterator_t* leveldb_create_iterator( leveldb_t* db, const leveldb_readoptions_t* options) { leveldb_iterator_t* result = new leveldb_iterator_t; result->rep = db->rep->NewIterator(options->rep); return result; } const leveldb_snapshot_t* leveldb_create_snapshot( leveldb_t* db) { leveldb_snapshot_t* result = new leveldb_snapshot_t; result->rep = db->rep->GetSnapshot(); return result; } void leveldb_release_snapshot( leveldb_t* db, const leveldb_snapshot_t* snapshot) { db->rep->ReleaseSnapshot(snapshot->rep); delete snapshot; } char* leveldb_property_value( leveldb_t* db, const char* propname) { std::string tmp; if (db->rep->GetProperty(Slice(propname), &tmp)) { // We use strdup() since we expect human readable output. return strdup(tmp.c_str()); } else { return NULL; } } void leveldb_approximate_sizes( leveldb_t* db, int num_ranges, const char* const* range_start_key, const size_t* range_start_key_len, const char* const* range_limit_key, const size_t* range_limit_key_len, uint64_t* sizes) { Range* ranges = new Range[num_ranges]; for (int i = 0; i < num_ranges; i++) { ranges[i].start = Slice(range_start_key[i], range_start_key_len[i]); ranges[i].limit = Slice(range_limit_key[i], range_limit_key_len[i]); } db->rep->GetApproximateSizes(ranges, num_ranges, sizes); delete[] ranges; } void leveldb_compact_range( leveldb_t* db, const char* start_key, size_t start_key_len, const char* limit_key, size_t limit_key_len) { Slice a, b; db->rep->CompactRange( // Pass NULL Slice if corresponding "const char*" is NULL (start_key ? (a = Slice(start_key, start_key_len), &a) : NULL), (limit_key ? (b = Slice(limit_key, limit_key_len), &b) : NULL)); } void leveldb_destroy_db( const leveldb_options_t* options, const char* name, char** errptr) { SaveError(errptr, DestroyDB(name, options->rep)); } void leveldb_repair_db( const leveldb_options_t* options, const char* name, char** errptr) { SaveError(errptr, RepairDB(name, options->rep)); } void leveldb_iter_destroy(leveldb_iterator_t* iter) { delete iter->rep; delete iter; } unsigned char leveldb_iter_valid(const leveldb_iterator_t* iter) { return iter->rep->Valid(); } void leveldb_iter_seek_to_first(leveldb_iterator_t* iter) { iter->rep->SeekToFirst(); } void leveldb_iter_seek_to_last(leveldb_iterator_t* iter) { iter->rep->SeekToLast(); } void leveldb_iter_seek(leveldb_iterator_t* iter, const char* k, size_t klen) { iter->rep->Seek(Slice(k, klen)); } void leveldb_iter_next(leveldb_iterator_t* iter) { iter->rep->Next(); } void leveldb_iter_prev(leveldb_iterator_t* iter) { iter->rep->Prev(); } const char* leveldb_iter_key(const leveldb_iterator_t* iter, size_t* klen) { Slice s = iter->rep->key(); *klen = s.size(); return s.data(); } const char* leveldb_iter_value(const leveldb_iterator_t* iter, size_t* vlen) { Slice s = iter->rep->value(); *vlen = s.size(); return s.data(); } void leveldb_iter_get_error(const leveldb_iterator_t* iter, char** errptr) { SaveError(errptr, iter->rep->status()); } leveldb_writebatch_t* leveldb_writebatch_create() { return new leveldb_writebatch_t; } void leveldb_writebatch_destroy(leveldb_writebatch_t* b) { delete b; } void leveldb_writebatch_clear(leveldb_writebatch_t* b) { b->rep.Clear(); } void leveldb_writebatch_put( leveldb_writebatch_t* b, const char* key, size_t klen, const char* val, size_t vlen) { b->rep.Put(Slice(key, klen), Slice(val, vlen)); } void leveldb_writebatch_delete( leveldb_writebatch_t* b, const char* key, size_t klen) { b->rep.Delete(Slice(key, klen)); } void leveldb_writebatch_iterate( leveldb_writebatch_t* b, void* state, void (*put)(void*, const char* k, size_t klen, const char* v, size_t vlen), void (*deleted)(void*, const char* k, size_t klen)) { class H : public WriteBatch::Handler { public: void* state_; void (*put_)(void*, const char* k, size_t klen, const char* v, size_t vlen); void (*deleted_)(void*, const char* k, size_t klen); virtual void Put(const Slice& key, const Slice& value) { (*put_)(state_, key.data(), key.size(), value.data(), value.size()); } virtual void Delete(const Slice& key) { (*deleted_)(state_, key.data(), key.size()); } }; H handler; handler.state_ = state; handler.put_ = put; handler.deleted_ = deleted; b->rep.Iterate(&handler); } leveldb_options_t* leveldb_options_create() { return new leveldb_options_t; } void leveldb_options_destroy(leveldb_options_t* options) { delete options; } void leveldb_options_set_comparator( leveldb_options_t* opt, leveldb_comparator_t* cmp) { opt->rep.comparator = cmp; } void leveldb_options_set_filter_policy( leveldb_options_t* opt, leveldb_filterpolicy_t* policy) { opt->rep.filter_policy = policy; } void leveldb_options_set_create_if_missing( leveldb_options_t* opt, unsigned char v) { opt->rep.create_if_missing = v; } void leveldb_options_set_error_if_exists( leveldb_options_t* opt, unsigned char v) { opt->rep.error_if_exists = v; } void leveldb_options_set_paranoid_checks( leveldb_options_t* opt, unsigned char v) { opt->rep.paranoid_checks = v; } void leveldb_options_set_env(leveldb_options_t* opt, leveldb_env_t* env) { opt->rep.env = (env ? env->rep : NULL); } void leveldb_options_set_info_log(leveldb_options_t* opt, leveldb_logger_t* l) { opt->rep.info_log = (l ? l->rep : NULL); } void leveldb_options_set_write_buffer_size(leveldb_options_t* opt, size_t s) { opt->rep.write_buffer_size = s; } void leveldb_options_set_max_open_files(leveldb_options_t* opt, int n) { opt->rep.max_open_files = n; } void leveldb_options_set_cache(leveldb_options_t* opt, leveldb_cache_t* c) { opt->rep.block_cache = c->rep; } void leveldb_options_set_block_size(leveldb_options_t* opt, size_t s) { opt->rep.block_size = s; } void leveldb_options_set_block_restart_interval(leveldb_options_t* opt, int n) { opt->rep.block_restart_interval = n; } void leveldb_options_set_compression(leveldb_options_t* opt, int t) { opt->rep.compression = static_cast(t); } leveldb_comparator_t* leveldb_comparator_create( void* state, void (*destructor)(void*), int (*compare)( void*, const char* a, size_t alen, const char* b, size_t blen), const char* (*name)(void*)) { leveldb_comparator_t* result = new leveldb_comparator_t; result->state_ = state; result->destructor_ = destructor; result->compare_ = compare; result->name_ = name; return result; } void leveldb_comparator_destroy(leveldb_comparator_t* cmp) { delete cmp; } leveldb_filterpolicy_t* leveldb_filterpolicy_create( void* state, void (*destructor)(void*), char* (*create_filter)( void*, const char* const* key_array, const size_t* key_length_array, int num_keys, size_t* filter_length), unsigned char (*key_may_match)( void*, const char* key, size_t length, const char* filter, size_t filter_length), const char* (*name)(void*)) { leveldb_filterpolicy_t* result = new leveldb_filterpolicy_t; result->state_ = state; result->destructor_ = destructor; result->create_ = create_filter; result->key_match_ = key_may_match; result->name_ = name; return result; } void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t* filter) { delete filter; } leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom(int bits_per_key) { // Make a leveldb_filterpolicy_t, but override all of its methods so // they delegate to a NewBloomFilterPolicy() instead of user // supplied C functions. struct Wrapper : public leveldb_filterpolicy_t { const FilterPolicy* rep_; ~Wrapper() { delete rep_; } const char* Name() const { return rep_->Name(); } void CreateFilter(const Slice* keys, int n, std::string* dst) const { return rep_->CreateFilter(keys, n, dst); } bool KeyMayMatch(const Slice& key, const Slice& filter) const { return rep_->KeyMayMatch(key, filter); } static void DoNothing(void*) { } }; Wrapper* wrapper = new Wrapper; wrapper->rep_ = NewBloomFilterPolicy(bits_per_key); wrapper->state_ = NULL; wrapper->destructor_ = &Wrapper::DoNothing; return wrapper; } leveldb_readoptions_t* leveldb_readoptions_create() { return new leveldb_readoptions_t; } void leveldb_readoptions_destroy(leveldb_readoptions_t* opt) { delete opt; } void leveldb_readoptions_set_verify_checksums( leveldb_readoptions_t* opt, unsigned char v) { opt->rep.verify_checksums = v; } void leveldb_readoptions_set_fill_cache( leveldb_readoptions_t* opt, unsigned char v) { opt->rep.fill_cache = v; } void leveldb_readoptions_set_snapshot( leveldb_readoptions_t* opt, const leveldb_snapshot_t* snap) { opt->rep.snapshot = (snap ? snap->rep : NULL); } leveldb_writeoptions_t* leveldb_writeoptions_create() { return new leveldb_writeoptions_t; } void leveldb_writeoptions_destroy(leveldb_writeoptions_t* opt) { delete opt; } void leveldb_writeoptions_set_sync( leveldb_writeoptions_t* opt, unsigned char v) { opt->rep.sync = v; } leveldb_cache_t* leveldb_cache_create_lru(size_t capacity) { leveldb_cache_t* c = new leveldb_cache_t; c->rep = NewLRUCache(capacity); return c; } void leveldb_cache_destroy(leveldb_cache_t* cache) { delete cache->rep; delete cache; } leveldb_env_t* leveldb_create_default_env() { leveldb_env_t* result = new leveldb_env_t; result->rep = Env::Default(); result->is_default = true; return result; } void leveldb_env_destroy(leveldb_env_t* env) { if (!env->is_default) delete env->rep; delete env; } void leveldb_free(void* ptr) { free(ptr); } int leveldb_major_version() { return kMajorVersion; } int leveldb_minor_version() { return kMinorVersion; } } // end extern "C" diff --git a/src/leveldb/port/port_win.h b/src/leveldb/port/port_win.h index e8bf46ef27..989c15cd91 100644 --- a/src/leveldb/port/port_win.h +++ b/src/leveldb/port/port_win.h @@ -1,177 +1,184 @@ // 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_ #ifdef _MSC_VER +#if !(_MSC_VER >= 1900) #define snprintf _snprintf +#endif #define close _close #define fread_unlocked _fread_nolock +#ifdef _WIN64 +#define ssize_t int64_t +#else +#define ssize_t int32_t +#endif #endif #include #include #ifdef SNAPPY #include #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_; }; class OnceType { public: // OnceType() : init_(false) {} OnceType(const OnceType &once) : init_(once.init_) {} OnceType(bool f) : init_(f) {} void InitOnce(void (*initializer)()) { mutex_.Lock(); if (!init_) { init_ = true; initializer(); } mutex_.Unlock(); } private: bool init_; Mutex mutex_; }; #define LEVELDB_ONCE_INIT false extern void InitOnce(port::OnceType*, void (*initializer)()); // Storage for a lock-free pointer class AtomicPointer { private: void * rep_; public: AtomicPointer() : rep_(NULL) { } 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; } bool HasAcceleratedCRC32C(); uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size); } } #endif // STORAGE_LEVELDB_PORT_PORT_WIN_H_ diff --git a/src/leveldb/util/env_win.cc b/src/leveldb/util/env_win.cc index 81380216bb..830332abe9 100644 --- a/src/leveldb/util/env_win.cc +++ b/src/leveldb/util/env_win.cc @@ -1,901 +1,902 @@ // 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 don't have any explicit 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 #include "leveldb/env.h" #include "port/port.h" #include "leveldb/slice.h" #include "util/logging.h" #include #include #include #include #include #include #include #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(); virtual std::string GetName() const { return _filename; } 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(); virtual std::string GetName() const { return _filename; } private: BOOL _Init(LPCWSTR path); void _CleanUp(); Win32RandomAccessFile(const std::string& fname); HANDLE _hFile; const std::string _filename; DISALLOW_COPY_AND_ASSIGN(Win32RandomAccessFile); }; class Win32WritableFile : public WritableFile { public: Win32WritableFile(const std::string& fname, bool append); ~Win32WritableFile(); virtual Status Append(const Slice& data); virtual Status Close(); virtual Status Flush(); virtual Status Sync(); BOOL isEnable(); virtual std::string GetName() const { return filename_; } private: std::string filename_; ::HANDLE _hFile; }; 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 Status NewAppendableFile(const std::string& fname, WritableFile** result); virtual bool FileExists(const std::string& fname); virtual Status GetChildren(const std::string& dir, std::vector* 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); + MultiByteToWideChar(CP_UTF8, 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); + WideCharToMultiByte(CP_UTF8, 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 GetCurrentDir() +{ + std::string path; + ToNarrowPath(GetCurrentDirW(), path); + return 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(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 | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (_hFile == INVALID_HANDLE_VALUE) _hFile = 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|FILE_SHARE_WRITE,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; } } Win32WritableFile::Win32WritableFile(const std::string& fname, bool append) : filename_(fname) { std::wstring path; ToWidePath(fname, path); // NewAppendableFile: append to an existing file, or create a new one // if none exists - this is OPEN_ALWAYS behavior, with // FILE_APPEND_DATA to avoid having to manually position the file // pointer at the end of the file. // NewWritableFile: create a new file, delete if it exists - this is // CREATE_ALWAYS behavior. This file is used for writing only so // use GENERIC_WRITE. _hFile = CreateFileW(path.c_str(), append ? FILE_APPEND_DATA : GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE, NULL, append ? OPEN_ALWAYS : CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); // CreateFileW returns INVALID_HANDLE_VALUE in case of error, always check isEnable() before use } Win32WritableFile::~Win32WritableFile() { if (_hFile != INVALID_HANDLE_VALUE) Close(); } Status Win32WritableFile::Append(const Slice& data) { DWORD r = 0; if (!WriteFile(_hFile, data.data(), data.size(), &r, NULL) || r != data.size()) { return Status::IOError("Win32WritableFile.Append::WriteFile: "+filename_, Win32::GetLastErrSz()); } return Status::OK(); } Status Win32WritableFile::Close() { if (!CloseHandle(_hFile)) { return Status::IOError("Win32WritableFile.Close::CloseHandle: "+filename_, Win32::GetLastErrSz()); } _hFile = INVALID_HANDLE_VALUE; return Status::OK(); } Status Win32WritableFile::Flush() { // Nothing to do here, there are no application-side buffers return Status::OK(); } Status Win32WritableFile::Sync() { if (!FlushFileBuffers(_hFile)) { return Status::IOError("Win32WritableFile.Sync::FlushFileBuffers "+filename_, Win32::GetLastErrSz()); } return Status::OK(); } BOOL Win32WritableFile::isEnable() { return _hFile != INVALID_HANDLE_VALUE; } 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(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* 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|FILE_SHARE_WRITE,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()); + std::wstring dirnameW; + ToWidePath(dirname, dirnameW); + DWORD attr = ::GetFileAttributesW(dirnameW.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); + BOOL result = ::CreateDirectoryW(dirnameW.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; // Logs are opened with write semantics, not with append semantics // (see PosixEnv::NewLogger) Win32WritableFile* pMapFile = new Win32WritableFile(ModifyPath(path), false); 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; Win32WritableFile* pFile = new Win32WritableFile(ModifyPath(path), false); if(!pFile->isEnable()){ *result = NULL; sRet = Status::IOError(fname,Win32::GetLastErrSz()); }else *result = pFile; return sRet; } Status Win32Env::NewAppendableFile( const std::string& fname, WritableFile** result ) { Status sRet; std::string path = fname; Win32WritableFile* pFile = new Win32WritableFile(ModifyPath(path), true); 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)