Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(372)

Unified Diff: third_party/leveldatabase/env_chromium.cc

Issue 7522008: Move chromium-specific files from leveldb to chromium. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: change parameter to const ref Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/leveldatabase/README.chromium ('k') | third_party/leveldatabase/leveldatabase.gyp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/leveldatabase/env_chromium.cc
diff --git a/third_party/leveldatabase/env_chromium.cc b/third_party/leveldatabase/env_chromium.cc
new file mode 100644
index 0000000000000000000000000000000000000000..905c0df1588dbd5d27eb75c76488c26eca4096e8
--- /dev/null
+++ b/third_party/leveldatabase/env_chromium.cc
@@ -0,0 +1,543 @@
+// 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 <deque>
+#include <errno.h>
+#include <stdio.h>
+#include "base/at_exit.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop.h"
+#include "base/platform_file.h"
+#include "base/process_util.h"
+#include "base/stringprintf.h"
+#include "base/synchronization/lock.h"
+#include "base/sys_info.h"
+#include "base/task.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "base/utf_string_conversions.h"
+#include "leveldb/env.h"
+#include "leveldb/slice.h"
+#include "port/port.h"
+#include "util/logging.h"
+
+#if defined(OS_WIN)
+#include <io.h>
+#include "base/win/win_util.h"
+#endif
+
+#if defined(OS_MACOSX) || defined(OS_WIN)
+// The following are glibc-specific
+namespace {
+
+size_t fread_unlocked(void *ptr, size_t size, size_t n, FILE *file) {
+ return fread(ptr, size, n, file);
+}
+
+size_t fwrite_unlocked(const void *ptr, size_t size, size_t n, FILE *file) {
+ return fwrite(ptr, size, n, file);
+}
+
+int fflush_unlocked(FILE *file) {
+ return fflush(file);
+}
+
+int fdatasync(int fildes) {
+#if defined(OS_WIN)
+ return _commit(fildes);
+#else
+ return fsync(fildes);
+#endif
+}
+
+}
+#endif
+
+namespace leveldb {
+
+namespace {
+
+class Thread;
+
+static const ::FilePath::CharType kLevelDBTestDirectoryPrefix[]
+ = FILE_PATH_LITERAL("leveldb-test-");
+
+::FilePath CreateFilePath(const std::string& file_path) {
+#if defined(OS_WIN)
+ return FilePath(UTF8ToUTF16(file_path));
+#else
+ return FilePath(file_path);
+#endif
+}
+
+std::string FilePathToString(const ::FilePath& file_path) {
+#if defined(OS_WIN)
+ return UTF16ToUTF8(file_path.value());
+#else
+ return file_path.value();
+#endif
+}
+
+// TODO(jorlow): This should be moved into Chromium's base.
+const char* PlatformFileErrorString(const ::base::PlatformFileError& error) {
+ switch (error) {
+ case ::base::PLATFORM_FILE_ERROR_FAILED:
+ return "Opening file failed.";
+ case ::base::PLATFORM_FILE_ERROR_IN_USE:
+ return "File currently in use.";
+ case ::base::PLATFORM_FILE_ERROR_EXISTS:
+ return "File already exists.";
+ case ::base::PLATFORM_FILE_ERROR_NOT_FOUND:
+ return "File not found.";
+ case ::base::PLATFORM_FILE_ERROR_ACCESS_DENIED:
+ return "Access denied.";
+ case ::base::PLATFORM_FILE_ERROR_TOO_MANY_OPENED:
+ return "Too many files open.";
+ case ::base::PLATFORM_FILE_ERROR_NO_MEMORY:
+ return "Out of memory.";
+ case ::base::PLATFORM_FILE_ERROR_NO_SPACE:
+ return "No space left on drive.";
+ case ::base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY:
+ return "Not a directory.";
+ case ::base::PLATFORM_FILE_ERROR_INVALID_OPERATION:
+ return "Invalid operation.";
+ case ::base::PLATFORM_FILE_ERROR_SECURITY:
+ return "Security error.";
+ case ::base::PLATFORM_FILE_ERROR_ABORT:
+ return "File operation aborted.";
+ case ::base::PLATFORM_FILE_ERROR_NOT_A_FILE:
+ return "The supplied path was not a file.";
+ case ::base::PLATFORM_FILE_ERROR_NOT_EMPTY:
+ return "The file was not empty.";
+ case ::base::PLATFORM_FILE_ERROR_INVALID_URL:
+ return "Invalid URL.";
+ case ::base::PLATFORM_FILE_OK:
+ return "OK.";
+ }
+ NOTIMPLEMENTED();
+ return "Unknown error.";
+}
+
+class ChromiumSequentialFile: public SequentialFile {
+ private:
+ std::string filename_;
+ FILE* file_;
+
+ public:
+ ChromiumSequentialFile(const std::string& fname, FILE* f)
+ : filename_(fname), file_(f) { }
+ virtual ~ChromiumSequentialFile() { fclose(file_); }
+
+ virtual Status Read(size_t n, Slice* result, char* scratch) {
+ Status s;
+ size_t r = fread_unlocked(scratch, 1, n, file_);
+ *result = Slice(scratch, r);
+ if (r < n) {
+ if (feof(file_)) {
+ // We leave status as ok if we hit the end of the file
+ } else {
+ // A partial read with an error: return a non-ok status
+ s = Status::IOError(filename_, strerror(errno));
+ }
+ }
+ return s;
+ }
+
+ virtual Status Skip(uint64_t n) {
+ if (fseek(file_, n, SEEK_CUR)) {
+ return Status::IOError(filename_, strerror(errno));
+ }
+ return Status::OK();
+ }
+};
+
+class ChromiumRandomAccessFile: public RandomAccessFile {
+ private:
+ std::string filename_;
+ ::base::PlatformFile file_;
+
+ public:
+ ChromiumRandomAccessFile(const std::string& fname, ::base::PlatformFile file)
+ : filename_(fname), file_(file) { }
+ virtual ~ChromiumRandomAccessFile() { ::base::ClosePlatformFile(file_); }
+
+ virtual Status Read(uint64_t offset, size_t n, Slice* result,
+ char* scratch) const {
+ Status s;
+ int r = ::base::ReadPlatformFile(file_, offset, scratch, n);
+ *result = Slice(scratch, (r < 0) ? 0 : r);
+ if (r < 0) {
+ // An error: return a non-ok status
+ s = Status::IOError(filename_, "Could not preform read");
+ }
+ return s;
+ }
+};
+
+class ChromiumWritableFile : public WritableFile {
+ private:
+ std::string filename_;
+ FILE* file_;
+
+ public:
+ ChromiumWritableFile(const std::string& fname, FILE* f)
+ : filename_(fname), file_(f) { }
+
+ ~ChromiumWritableFile() {
+ if (file_ != NULL) {
+ // Ignoring any potential errors
+ fclose(file_);
+ }
+ }
+
+ virtual Status Append(const Slice& data) {
+ size_t r = fwrite_unlocked(data.data(), 1, data.size(), file_);
+ Status result;
+ if (r != data.size()) {
+ result = Status::IOError(filename_, strerror(errno));
+ }
+ return result;
+ }
+
+ virtual Status Close() {
+ Status result;
+ if (fclose(file_) != 0) {
+ result = Status::IOError(filename_, strerror(errno));
+ }
+ file_ = NULL;
+ return result;
+ }
+
+ virtual Status Flush() {
+ Status result;
+ if (fflush_unlocked(file_) != 0) {
+ result = Status::IOError(filename_, strerror(errno));
+ }
+ return result;
+ }
+
+ virtual Status Sync() {
+ Status result;
+ if ((fflush_unlocked(file_) != 0) ||
+ (fdatasync(fileno(file_)) != 0)) {
+ result = Status::IOError(filename_, strerror(errno));
+ }
+ return result;
+ }
+};
+
+class ChromiumFileLock : public FileLock {
+ public:
+ ::base::PlatformFile file_;
+};
+
+class ChromiumEnv : public Env {
+ public:
+ ChromiumEnv();
+ virtual ~ChromiumEnv() {
+ fprintf(stderr, "Destroying Env::Default()\n");
+ exit(1);
+ }
+
+ virtual Status NewSequentialFile(const std::string& fname,
+ SequentialFile** result) {
+ FILE* f = fopen(fname.c_str(), "rb");
+ if (f == NULL) {
+ *result = NULL;
+ return Status::IOError(fname, strerror(errno));
+ } else {
+ *result = new ChromiumSequentialFile(fname, f);
+ return Status::OK();
+ }
+ }
+
+ virtual Status NewRandomAccessFile(const std::string& fname,
+ RandomAccessFile** result) {
+ int flags = ::base::PLATFORM_FILE_READ | ::base::PLATFORM_FILE_OPEN;
+ bool created;
+ ::base::PlatformFileError error_code;
+ ::base::PlatformFile file = ::base::CreatePlatformFile(
+ CreateFilePath(fname), flags, &created, &error_code);
+ if (error_code != ::base::PLATFORM_FILE_OK) {
+ *result = NULL;
+ return Status::IOError(fname, PlatformFileErrorString(error_code));
+ }
+ *result = new ChromiumRandomAccessFile(fname, file);
+ return Status::OK();
+ }
+
+ virtual Status NewWritableFile(const std::string& fname,
+ WritableFile** result) {
+ *result = NULL;
+ FILE* f = fopen(fname.c_str(), "wb");
+ if (f == NULL) {
+ return Status::IOError(fname, strerror(errno));
+ } else {
+ *result = new ChromiumWritableFile(fname, f);
+ return Status::OK();
+ }
+ }
+
+ virtual bool FileExists(const std::string& fname) {
+ return ::file_util::PathExists(CreateFilePath(fname));
+ }
+
+ virtual Status GetChildren(const std::string& dir,
+ std::vector<std::string>* result) {
+ result->clear();
+ ::file_util::FileEnumerator iter(
+ CreateFilePath(dir), false, ::file_util::FileEnumerator::FILES);
+ ::FilePath current = iter.Next();
+ while (!current.empty()) {
+ result->push_back(FilePathToString(current.BaseName()));
+ current = iter.Next();
+ }
+ // TODO(jorlow): Unfortunately, the FileEnumerator swallows errors, so
+ // we'll always return OK. Maybe manually check for error
+ // conditions like the file not existing?
+ return Status::OK();
+ }
+
+ virtual Status DeleteFile(const std::string& fname) {
+ Status result;
+ // TODO(jorlow): Should we assert this is a file?
+ if (!::file_util::Delete(CreateFilePath(fname), false)) {
+ result = Status::IOError(fname, "Could not delete file.");
+ }
+ return result;
+ };
+
+ virtual Status CreateDir(const std::string& name) {
+ Status result;
+ if (!::file_util::CreateDirectory(CreateFilePath(name))) {
+ result = Status::IOError(name, "Could not create directory.");
+ }
+ return result;
+ };
+
+ virtual Status DeleteDir(const std::string& name) {
+ Status result;
+ // TODO(jorlow): Should we assert this is a directory?
+ if (!::file_util::Delete(CreateFilePath(name), false)) {
+ result = Status::IOError(name, "Could not delete directory.");
+ }
+ return result;
+ };
+
+ virtual Status GetFileSize(const std::string& fname, uint64_t* size) {
+ Status s;
+ int64_t signed_size;
+ if (!::file_util::GetFileSize(CreateFilePath(fname), &signed_size)) {
+ *size = 0;
+ s = Status::IOError(fname, "Could not determine file size.");
+ } else {
+ *size = static_cast<uint64_t>(signed_size);
+ }
+ return s;
+ }
+
+ virtual Status RenameFile(const std::string& src, const std::string& dst) {
+ Status result;
+ if (!::file_util::ReplaceFile(CreateFilePath(src), CreateFilePath(dst))) {
+ result = Status::IOError(src, "Could not rename file.");
+ }
+ return result;
+ }
+
+ virtual Status LockFile(const std::string& fname, FileLock** lock) {
+ *lock = NULL;
+ Status result;
+ int flags = ::base::PLATFORM_FILE_OPEN_ALWAYS |
+ ::base::PLATFORM_FILE_READ |
+ ::base::PLATFORM_FILE_WRITE |
+ ::base::PLATFORM_FILE_EXCLUSIVE_READ |
+ ::base::PLATFORM_FILE_EXCLUSIVE_WRITE;
+ bool created;
+ ::base::PlatformFileError error_code;
+ ::base::PlatformFile file = ::base::CreatePlatformFile(
+ CreateFilePath(fname), flags, &created, &error_code);
+ if (error_code != ::base::PLATFORM_FILE_OK) {
+ result = Status::IOError(fname, PlatformFileErrorString(error_code));
+ } else {
+ ChromiumFileLock* my_lock = new ChromiumFileLock;
+ my_lock->file_ = file;
+ *lock = my_lock;
+ }
+ return result;
+ }
+
+ virtual Status UnlockFile(FileLock* lock) {
+ ChromiumFileLock* my_lock = reinterpret_cast<ChromiumFileLock*>(lock);
+ Status result;
+ if (!::base::ClosePlatformFile(my_lock->file_)) {
+ result = Status::IOError("Could not close lock file.");
+ }
+ delete my_lock;
+ return result;
+ }
+
+ virtual void Schedule(void (*function)(void*), void* arg);
+
+ virtual void StartThread(void (*function)(void* arg), void* arg);
+
+ virtual std::string UserIdentifier() {
+#if defined(OS_WIN)
+ std::wstring user_sid;
+ bool ret = ::base::win::GetUserSidString(&user_sid);
+ DCHECK(ret);
+ return UTF16ToUTF8(user_sid);
+#else
+ char buf[100];
+ snprintf(buf, sizeof(buf), "%d", int(geteuid()));
+ return buf;
+#endif
+ }
+
+ virtual Status GetTestDirectory(std::string* path) {
+ mu_.Acquire();
+ if (test_directory_.empty()) {
+ if (!::file_util::CreateNewTempDirectory(kLevelDBTestDirectoryPrefix,
+ &test_directory_)) {
+ mu_.Release();
+ return Status::IOError("Could not create temp directory.");
+ }
+ }
+ *path = FilePathToString(test_directory_);
+ mu_.Release();
+ return Status::OK();
+ }
+
+ class ChromiumLogger : public Logger {
+ public:
+ ChromiumLogger(const std::string& filename) : filename_(filename) {
+ }
+
+ virtual void Logv(const char* format, va_list ap) {
+ VLOG(5) << "LevelDB: " << filename_ << " " << StringPrintf(format, ap);
+ }
+
+ private:
+ std::string filename_;
+ };
+
+ virtual Status NewLogger(const std::string& fname, Logger** result) {
+ *result = new ChromiumLogger(fname);
+ return Status::OK();
+ }
+
+ virtual uint64_t NowMicros() {
+ return ::base::TimeTicks::HighResNow().ToInternalValue();
+ }
+
+ virtual void SleepForMicroseconds(int micros) {
+ // Round up to the next millisecond.
+ ::base::PlatformThread::Sleep((micros + 999) / 1000);
+ }
+
+ private:
+ // BGThread() is the body of the background thread
+ void BGThread();
+ static void BGThreadWrapper(void* arg) {
+ reinterpret_cast<ChromiumEnv*>(arg)->BGThread();
+ }
+
+ FilePath test_directory_;
+
+ size_t page_size_;
+ ::base::Lock mu_;
+ ::base::ConditionVariable bgsignal_;
+ bool started_bgthread_;
+
+ // Entry per Schedule() call
+ struct BGItem { void* arg; void (*function)(void*); };
+ typedef std::deque<BGItem> BGQueue;
+ BGQueue queue_;
+};
+
+ChromiumEnv::ChromiumEnv()
+ : page_size_(::base::SysInfo::VMAllocationGranularity()),
+ bgsignal_(&mu_),
+ started_bgthread_(false) {
+#if defined(OS_MACOSX)
+ ::base::EnableTerminationOnHeapCorruption();
+ ::base::EnableTerminationOnOutOfMemory();
+#endif // OS_MACOSX
+}
+
+class Thread : public ::base::PlatformThread::Delegate {
+ public:
+ Thread(void (*function)(void* arg), void* arg)
+ : function_(function), arg_(arg) {
+ ::base::PlatformThreadHandle handle;
+ bool success = ::base::PlatformThread::Create(0, this, &handle);
+ DCHECK(success);
+ }
+ virtual ~Thread() {}
+ virtual void ThreadMain() {
+ (*function_)(arg_);
+ delete this;
+ }
+
+ private:
+ void (*function_)(void* arg);
+ void* arg_;
+};
+
+void ChromiumEnv::Schedule(void (*function)(void*), void* arg) {
+ mu_.Acquire();
+
+ // Start background thread if necessary
+ if (!started_bgthread_) {
+ started_bgthread_ = true;
+ StartThread(&ChromiumEnv::BGThreadWrapper, this);
+ }
+
+ // If the queue is currently empty, the background thread may currently be
+ // waiting.
+ if (queue_.empty()) {
+ bgsignal_.Signal();
+ }
+
+ // Add to priority queue
+ queue_.push_back(BGItem());
+ queue_.back().function = function;
+ queue_.back().arg = arg;
+
+ mu_.Release();
+}
+
+void ChromiumEnv::BGThread() {
+ while (true) {
+ // Wait until there is an item that is ready to run
+ mu_.Acquire();
+ while (queue_.empty()) {
+ bgsignal_.Wait();
+ }
+
+ void (*function)(void*) = queue_.front().function;
+ void* arg = queue_.front().arg;
+ queue_.pop_front();
+
+ mu_.Release();
+ (*function)(arg);
+ }
+}
+
+void ChromiumEnv::StartThread(void (*function)(void* arg), void* arg) {
+ new Thread(function, arg); // Will self-delete.
+}
+
+::base::LazyInstance<ChromiumEnv, ::base::LeakyLazyInstanceTraits<ChromiumEnv> >
+ default_env(::base::LINKER_INITIALIZED);
+
+}
+
+Env* Env::Default() {
+ return default_env.Pointer();
+}
+
+}
« no previous file with comments | « third_party/leveldatabase/README.chromium ('k') | third_party/leveldatabase/leveldatabase.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698