summaryrefslogtreecommitdiffstats
path: root/third_party/leveldatabase/env_chromium.cc
diff options
context:
space:
mode:
authordgrogan@chromium.org <dgrogan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-05 18:11:31 +0000
committerdgrogan@chromium.org <dgrogan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-05 18:11:31 +0000
commitf046c7e2e18496448b28adba7f4e1152067d5d25 (patch)
tree3f17470a31541991b2d440be817ced5cfe301578 /third_party/leveldatabase/env_chromium.cc
parent94b7dd2b59b1dfd0bce5083011248b6c2235be0e (diff)
downloadchromium_src-f046c7e2e18496448b28adba7f4e1152067d5d25.zip
chromium_src-f046c7e2e18496448b28adba7f4e1152067d5d25.tar.gz
chromium_src-f046c7e2e18496448b28adba7f4e1152067d5d25.tar.bz2
Put more declarations in env_chromium.h.
This will allow more unit testing of ChromiumEnv. See https://codereview.chromium.org/15843010 BUG=242269 R=jsbell@chromium.org Review URL: https://codereview.chromium.org/16399003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@204301 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/leveldatabase/env_chromium.cc')
-rw-r--r--third_party/leveldatabase/env_chromium.cc899
1 files changed, 412 insertions, 487 deletions
diff --git a/third_party/leveldatabase/env_chromium.cc b/third_party/leveldatabase/env_chromium.cc
index 066f34d..4d296fa 100644
--- a/third_party/leveldatabase/env_chromium.cc
+++ b/third_party/leveldatabase/env_chromium.cc
@@ -198,22 +198,6 @@ const char* MethodIDToString(MethodID method) {
return "Unknown";
}
-class UMALogger {
- public:
- virtual void RecordErrorAt(MethodID method) const = 0;
- virtual void RecordOSError(MethodID method, int saved_errno) const = 0;
- virtual void RecordOSError(MethodID method, base::PlatformFileError error)
- const = 0;
-};
-
-class RetrierProvider {
- public:
- virtual int MaxRetryTimeMillis() const = 0;
- virtual base::HistogramBase* GetRetryTimeHistogram(MethodID method) const = 0;
- virtual base::HistogramBase* GetRecoveredFromErrorHistogram(
- MethodID method) const = 0;
-};
-
static const base::FilePath::CharType kLevelDBTestDirectoryPrefix[]
= FILE_PATH_LITERAL("leveldb-test-");
@@ -325,459 +309,476 @@ class ChromiumRandomAccessFile: public RandomAccessFile {
}
};
-class ChromiumWritableFile : public WritableFile {
- private:
- std::string filename_;
- FILE* file_;
- const UMALogger* uma_logger_;
-
+class ChromiumFileLock : public FileLock {
public:
- ChromiumWritableFile(const std::string& fname, FILE* f,
- const UMALogger* uma_logger)
- : filename_(fname), file_(f), uma_logger_(uma_logger) { }
-
- ~ChromiumWritableFile() {
- if (file_ != NULL) {
- // Ignoring any potential errors
- fclose(file_);
- }
- }
-
- virtual Status Append(const Slice& data) {
- size_t r = fwrite_wrapper(data.data(), 1, data.size(), file_);
- Status result;
- if (r != data.size()) {
- uma_logger_->RecordOSError(kWritableFileAppend, errno);
- result =
- MakeIOError(filename_, strerror(errno), kWritableFileAppend, errno);
- }
- return result;
- }
+ ::base::PlatformFile file_;
+};
- virtual Status Close() {
- Status result;
- if (fclose(file_) != 0) {
- result =
- MakeIOError(filename_, strerror(errno), kWritableFileClose, errno);
- uma_logger_->RecordErrorAt(kWritableFileClose);
+class Retrier {
+ public:
+ Retrier(MethodID method, RetrierProvider* provider)
+ : start_(base::TimeTicks::Now()),
+ limit_(start_ + base::TimeDelta::FromMilliseconds(
+ provider->MaxRetryTimeMillis())),
+ last_(start_),
+ time_to_sleep_(base::TimeDelta::FromMilliseconds(10)),
+ success_(true),
+ method_(method),
+ last_error_(base::PLATFORM_FILE_OK),
+ provider_(provider) {}
+ ~Retrier() {
+ if (success_) {
+ provider_->GetRetryTimeHistogram(method_)->AddTime(last_ - start_);
+ if (last_error_ != base::PLATFORM_FILE_OK) {
+ DCHECK(last_error_ < 0);
+ provider_->GetRecoveredFromErrorHistogram(method_)->Add(-last_error_);
+ }
}
- file_ = NULL;
- return result;
}
-
- virtual Status Flush() {
- Status result;
- if (HANDLE_EINTR(fflush_wrapper(file_))) {
- int saved_errno = errno;
- result = MakeIOError(
- filename_, strerror(saved_errno), kWritableFileFlush, saved_errno);
- uma_logger_->RecordOSError(kWritableFileFlush, saved_errno);
+ bool ShouldKeepTrying(base::PlatformFileError last_error) {
+ DCHECK_NE(last_error, base::PLATFORM_FILE_OK);
+ last_error_ = last_error;
+ if (last_ < limit_) {
+ base::PlatformThread::Sleep(time_to_sleep_);
+ last_ = base::TimeTicks::Now();
+ return true;
}
- return result;
+ success_ = false;
+ return false;
}
- virtual Status Sync() {
- TRACE_EVENT0("leveldb", "ChromiumEnv::Sync");
- Status result;
- int error = 0;
-
- if (HANDLE_EINTR(fflush_wrapper(file_)))
- error = errno;
- // Sync even if fflush gave an error; perhaps the data actually got out,
- // even though something went wrong.
- if (fdatasync(fileno(file_)) && !error)
- error = errno;
- // Report the first error we found.
- if (error) {
- result =
- MakeIOError(filename_, strerror(error), kWritableFileSync, error);
- uma_logger_->RecordErrorAt(kWritableFileSync);
- }
- return result;
- }
+ private:
+ base::TimeTicks start_;
+ base::TimeTicks limit_;
+ base::TimeTicks last_;
+ base::TimeDelta time_to_sleep_;
+ bool success_;
+ MethodID method_;
+ base::PlatformFileError last_error_;
+ RetrierProvider* provider_;
};
-class ChromiumFileLock : public FileLock {
+class IDBEnv : public ChromiumEnv {
public:
- ::base::PlatformFile file_;
+ IDBEnv() : ChromiumEnv() { name_ = "LevelDBEnv.IDB"; }
};
-class ChromiumEnv : public Env, public UMALogger, public RetrierProvider {
- public:
- ChromiumEnv();
- virtual ~ChromiumEnv() {
- NOTREACHED();
- }
-
- virtual Status NewSequentialFile(const std::string& fname,
- SequentialFile** result) {
- FILE* f = fopen_internal(fname.c_str(), "rb");
- if (f == NULL) {
- *result = NULL;
- int saved_errno = errno;
- RecordOSError(kNewSequentialFile, saved_errno);
- return MakeIOError(
- fname, strerror(saved_errno), kNewSequentialFile, saved_errno);
- } else {
- *result = new ChromiumSequentialFile(fname, f, this);
- return Status::OK();
- }
- }
+::base::LazyInstance<IDBEnv>::Leaky idb_env = LAZY_INSTANCE_INITIALIZER;
- void RecordOpenFilesLimit(const std::string& type) {
-#if defined(OS_POSIX)
- struct rlimit nofile;
- if (getrlimit(RLIMIT_NOFILE, &nofile))
- return;
- GetMaxFDHistogram(type)->Add(nofile.rlim_cur);
-#endif
+::base::LazyInstance<ChromiumEnv>::Leaky default_env =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // unnamed namespace
+
+Status MakeIOError(Slice filename,
+ const char* message,
+ MethodID method,
+ int saved_errno) {
+ char buf[512];
+ snprintf(buf,
+ sizeof(buf),
+ "%s (ChromeMethodErrno: %d::%s::%d)",
+ message,
+ method,
+ MethodIDToString(method),
+ saved_errno);
+ return Status::IOError(filename, buf);
+}
+
+Status MakeIOError(Slice filename,
+ const char* message,
+ MethodID method,
+ base::PlatformFileError error) {
+ DCHECK(error < 0);
+ char buf[512];
+ snprintf(buf,
+ sizeof(buf),
+ "%s (ChromeMethodPFE: %d::%s::%d)",
+ message,
+ method,
+ MethodIDToString(method),
+ -error);
+ return Status::IOError(filename, buf);
+}
+
+Status MakeIOError(Slice filename, const char* message, MethodID method) {
+ char buf[512];
+ snprintf(buf,
+ sizeof(buf),
+ "%s (ChromeMethodOnly: %d::%s)",
+ message,
+ method,
+ MethodIDToString(method));
+ return Status::IOError(filename, buf);
+}
+
+bool ParseMethodAndError(const char* string, int* method, int* error) {
+ if (RE2::PartialMatch(string, "ChromeMethodOnly: (\\d+)", method))
+ return true;
+ if (RE2::PartialMatch(
+ string, "ChromeMethodPFE: (\\d+)::.*::(\\d+)", method, error)) {
+ *error = -*error;
+ return true;
+ }
+ if (RE2::PartialMatch(
+ string, "ChromeMethodErrno: (\\d+)::.*::(\\d+)", method, error)) {
+ return true;
}
+ return false;
+}
- 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 = new ChromiumRandomAccessFile(fname, file, this);
- RecordOpenFilesLimit("Success");
- return Status::OK();
- }
- if (error_code == ::base::PLATFORM_FILE_ERROR_TOO_MANY_OPENED)
- RecordOpenFilesLimit("TooManyOpened");
- else
- RecordOpenFilesLimit("OtherError");
- *result = NULL;
- RecordOSError(kNewRandomAccessFile, error_code);
- return MakeIOError(fname,
- PlatformFileErrorString(error_code),
- kNewRandomAccessFile,
- error_code);
+ChromiumWritableFile::ChromiumWritableFile(const std::string& fname,
+ FILE* f,
+ const UMALogger* uma_logger)
+ : filename_(fname), file_(f), uma_logger_(uma_logger) {}
+
+ChromiumWritableFile::~ChromiumWritableFile() {
+ if (file_ != NULL) {
+ // Ignoring any potential errors
+ fclose(file_);
}
+}
- virtual Status NewWritableFile(const std::string& fname,
- WritableFile** result) {
- *result = NULL;
- FILE* f = fopen_internal(fname.c_str(), "wb");
- if (f == NULL) {
- RecordErrorAt(kNewWritableFile);
- return MakeIOError(fname, strerror(errno), kNewWritableFile, errno);
- } else {
- if (!sync_parent(fname)) {
- fclose(f);
- RecordErrorAt(kNewWritableFile);
- return MakeIOError(fname, strerror(errno), kNewWritableFile, errno);
- }
- *result = new ChromiumWritableFile(fname, f, this);
- return Status::OK();
- }
+Status ChromiumWritableFile::Append(const Slice& data) {
+ size_t r = fwrite_wrapper(data.data(), 1, data.size(), file_);
+ Status result;
+ if (r != data.size()) {
+ uma_logger_->RecordOSError(kWritableFileAppend, errno);
+ result =
+ MakeIOError(filename_, strerror(errno), kWritableFileAppend, errno);
}
+ return result;
+}
- virtual bool FileExists(const std::string& fname) {
- return ::file_util::PathExists(CreateFilePath(fname));
+Status ChromiumWritableFile::Close() {
+ Status result;
+ if (fclose(file_) != 0) {
+ result = MakeIOError(filename_, strerror(errno), kWritableFileClose, errno);
+ uma_logger_->RecordErrorAt(kWritableFileClose);
}
+ file_ = NULL;
+ return result;
+}
- 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);
- base::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();
+Status ChromiumWritableFile::Flush() {
+ Status result;
+ if (HANDLE_EINTR(fflush_wrapper(file_))) {
+ int saved_errno = errno;
+ result = MakeIOError(
+ filename_, strerror(saved_errno), kWritableFileFlush, saved_errno);
+ uma_logger_->RecordOSError(kWritableFileFlush, saved_errno);
}
+ return result;
+}
- 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 = MakeIOError(fname, "Could not delete file.", kDeleteFile);
- RecordErrorAt(kDeleteFile);
- }
- return result;
- };
+Status ChromiumWritableFile::Sync() {
+ TRACE_EVENT0("leveldb", "ChromiumEnv::Sync");
+ Status result;
+ int error = 0;
+
+ if (HANDLE_EINTR(fflush_wrapper(file_)))
+ error = errno;
+ // Sync even if fflush gave an error; perhaps the data actually got out,
+ // even though something went wrong.
+ if (fdatasync(fileno(file_)) && !error)
+ error = errno;
+ // Report the first error we found.
+ if (error) {
+ result = MakeIOError(filename_, strerror(error), kWritableFileSync, error);
+ uma_logger_->RecordErrorAt(kWritableFileSync);
+ }
+ return result;
+}
- virtual Status CreateDir(const std::string& name) {
- Status result;
- if (!::file_util::CreateDirectory(CreateFilePath(name))) {
- result = MakeIOError(name, "Could not create directory.", kCreateDir);
- RecordErrorAt(kCreateDir);
- }
- 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 = MakeIOError(name, "Could not delete directory.", kDeleteDir);
- RecordErrorAt(kDeleteDir);
- }
- return result;
- };
+ChromiumEnv::ChromiumEnv()
+ : name_("LevelDBEnv"),
+ bgsignal_(&mu_),
+ started_bgthread_(false),
+ kMaxRetryTimeMillis(1000) {
+}
- 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 = MakeIOError(fname, "Could not determine file size.", kGetFileSize);
- RecordErrorAt(kGetFileSize);
- } else {
- *size = static_cast<uint64_t>(signed_size);
- }
- return s;
- }
+ChromiumEnv::~ChromiumEnv() { NOTREACHED(); }
- class Retrier {
- public:
- Retrier(MethodID method, RetrierProvider* provider)
- : start_(base::TimeTicks::Now()),
- limit_(start_ + base::TimeDelta::FromMilliseconds(
- provider->MaxRetryTimeMillis())),
- last_(start_),
- time_to_sleep_(base::TimeDelta::FromMilliseconds(10)),
- success_(true),
- method_(method),
- last_error_(base::PLATFORM_FILE_OK),
- provider_(provider) {}
- ~Retrier() {
- if (success_) {
- provider_->GetRetryTimeHistogram(method_)->AddTime(last_ - start_);
- if (last_error_ != base::PLATFORM_FILE_OK) {
- DCHECK(last_error_ < 0);
- provider_->GetRecoveredFromErrorHistogram(method_)->Add(-last_error_);
- }
- }
- }
- bool ShouldKeepTrying(base::PlatformFileError last_error) {
- DCHECK_NE(last_error, base::PLATFORM_FILE_OK);
- last_error_ = last_error;
- if (last_ < limit_) {
- base::PlatformThread::Sleep(time_to_sleep_);
- last_ = base::TimeTicks::Now();
- return true;
- }
- success_ = false;
- return false;
- }
- private:
- base::TimeTicks start_;
- base::TimeTicks limit_;
- base::TimeTicks last_;
- base::TimeDelta time_to_sleep_;
- bool success_;
- MethodID method_;
- base::PlatformFileError last_error_;
- RetrierProvider* provider_;
- };
-
- virtual Status RenameFile(const std::string& src, const std::string& dst) {
- Status result;
- base::FilePath src_file_path = CreateFilePath(src);
- if (!::file_util::PathExists(src_file_path))
- return result;
- base::FilePath destination = CreateFilePath(dst);
+Status ChromiumEnv::NewSequentialFile(const std::string& fname,
+ SequentialFile** result) {
+ FILE* f = fopen_internal(fname.c_str(), "rb");
+ if (f == NULL) {
+ *result = NULL;
+ int saved_errno = errno;
+ RecordOSError(kNewSequentialFile, saved_errno);
+ return MakeIOError(
+ fname, strerror(saved_errno), kNewSequentialFile, saved_errno);
+ } else {
+ *result = new ChromiumSequentialFile(fname, f, this);
+ return Status::OK();
+ }
+}
- Retrier retrier(kRenameFile, this);
- base::PlatformFileError error = base::PLATFORM_FILE_OK;
- do {
- if (::file_util::ReplaceFileAndGetError(
- src_file_path, destination, &error)) {
- sync_parent(dst);
- if (src_file_path.DirName() != destination.DirName()) {
- // As leveldb is implemented now this branch will never be taken, but
- // this is future-proof.
- sync_parent(src);
- }
- return result;
- }
- } while (retrier.ShouldKeepTrying(error));
-
- DCHECK(error != base::PLATFORM_FILE_OK);
- RecordOSError(kRenameFile, error);
- char buf[100];
- snprintf(buf, sizeof(buf), "Could not rename file: %s",
- PlatformFileErrorString(error));
- return MakeIOError(src, buf, kRenameFile, error);
- }
-
- 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;
- Retrier retrier(kLockFile, this);
- do {
- file = ::base::CreatePlatformFile(
- CreateFilePath(fname), flags, &created, &error_code);
- } while (error_code != ::base::PLATFORM_FILE_OK &&
- retrier.ShouldKeepTrying(error_code));
-
- if (error_code == ::base::PLATFORM_FILE_ERROR_NOT_FOUND) {
- ::base::FilePath parent = CreateFilePath(fname).DirName();
- ::base::FilePath last_parent;
- int num_missing_ancestors = 0;
- do {
- if (file_util::DirectoryExists(parent))
- break;
- ++num_missing_ancestors;
- last_parent = parent;
- parent = parent.DirName();
- } while (parent != last_parent);
- RecordLockFileAncestors(num_missing_ancestors);
- }
+void ChromiumEnv::RecordOpenFilesLimit(const std::string& type) {
+#if defined(OS_POSIX)
+ struct rlimit nofile;
+ if (getrlimit(RLIMIT_NOFILE, &nofile))
+ return;
+ GetMaxFDHistogram(type)->Add(nofile.rlim_cur);
+#endif
+}
- if (error_code != ::base::PLATFORM_FILE_OK) {
- result = MakeIOError(
- fname, PlatformFileErrorString(error_code), kLockFile, error_code);
- RecordOSError(kLockFile, error_code);
- } else {
- ChromiumFileLock* my_lock = new ChromiumFileLock;
- my_lock->file_ = file;
- *lock = my_lock;
- }
- return result;
+Status ChromiumEnv::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 = new ChromiumRandomAccessFile(fname, file, this);
+ RecordOpenFilesLimit("Success");
+ return Status::OK();
}
+ if (error_code == ::base::PLATFORM_FILE_ERROR_TOO_MANY_OPENED)
+ RecordOpenFilesLimit("TooManyOpened");
+ else
+ RecordOpenFilesLimit("OtherError");
+ *result = NULL;
+ RecordOSError(kNewRandomAccessFile, error_code);
+ return MakeIOError(fname,
+ PlatformFileErrorString(error_code),
+ kNewRandomAccessFile,
+ error_code);
+}
- virtual Status UnlockFile(FileLock* lock) {
- ChromiumFileLock* my_lock = reinterpret_cast<ChromiumFileLock*>(lock);
- Status result;
- if (!::base::ClosePlatformFile(my_lock->file_)) {
- result = MakeIOError("Could not close lock file.", "", kUnlockFile);
- RecordErrorAt(kUnlockFile);
+Status ChromiumEnv::NewWritableFile(const std::string& fname,
+ WritableFile** result) {
+ *result = NULL;
+ FILE* f = fopen_internal(fname.c_str(), "wb");
+ if (f == NULL) {
+ RecordErrorAt(kNewWritableFile);
+ return MakeIOError(fname, strerror(errno), kNewWritableFile, errno);
+ } else {
+ if (!sync_parent(fname)) {
+ fclose(f);
+ RecordErrorAt(kNewWritableFile);
+ return MakeIOError(fname, strerror(errno), kNewWritableFile, errno);
}
- delete my_lock;
- return result;
+ *result = new ChromiumWritableFile(fname, f, this);
+ return Status::OK();
}
+}
- virtual void Schedule(void (*function)(void*), void* arg);
+bool ChromiumEnv::FileExists(const std::string& fname) {
+ return ::file_util::PathExists(CreateFilePath(fname));
+}
- virtual void StartThread(void (*function)(void* arg), void* arg);
+Status ChromiumEnv::GetChildren(const std::string& dir,
+ std::vector<std::string>* result) {
+ result->clear();
+ ::file_util::FileEnumerator iter(
+ CreateFilePath(dir), false, ::file_util::FileEnumerator::FILES);
+ base::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 GetTestDirectory(std::string* path) {
- mu_.Acquire();
- if (test_directory_.empty()) {
- if (!::file_util::CreateNewTempDirectory(kLevelDBTestDirectoryPrefix,
- &test_directory_)) {
- mu_.Release();
- RecordErrorAt(kGetTestDirectory);
- return MakeIOError("Could not create temp directory.",
- "",
- kGetTestDirectory);
- }
- }
- *path = FilePathToString(test_directory_);
- mu_.Release();
- return Status::OK();
+Status ChromiumEnv::DeleteFile(const std::string& fname) {
+ Status result;
+ // TODO(jorlow): Should we assert this is a file?
+ if (!::file_util::Delete(CreateFilePath(fname), false)) {
+ result = MakeIOError(fname, "Could not delete file.", kDeleteFile);
+ RecordErrorAt(kDeleteFile);
}
+ return result;
+}
- virtual Status NewLogger(const std::string& fname, Logger** result) {
- FILE* f = fopen_internal(fname.c_str(), "w");
- if (f == NULL) {
- *result = NULL;
- int saved_errno = errno;
- RecordOSError(kNewLogger, saved_errno);
- return MakeIOError(fname, strerror(saved_errno), kNewLogger, saved_errno);
- } else {
- if (!sync_parent(fname)) {
- fclose(f);
- return MakeIOError(fname, strerror(errno), kNewLogger, errno);
- }
- *result = new ChromiumLogger(f);
- return Status::OK();
- }
+Status ChromiumEnv::CreateDir(const std::string& name) {
+ Status result;
+ if (!::file_util::CreateDirectory(CreateFilePath(name))) {
+ result = MakeIOError(name, "Could not create directory.", kCreateDir);
+ RecordErrorAt(kCreateDir);
}
+ return result;
+}
- virtual uint64_t NowMicros() {
- return ::base::TimeTicks::Now().ToInternalValue();
+Status ChromiumEnv::DeleteDir(const std::string& name) {
+ Status result;
+ // TODO(jorlow): Should we assert this is a directory?
+ if (!::file_util::Delete(CreateFilePath(name), false)) {
+ result = MakeIOError(name, "Could not delete directory.", kDeleteDir);
+ RecordErrorAt(kDeleteDir);
}
+ return result;
+}
- virtual void SleepForMicroseconds(int micros) {
- // Round up to the next millisecond.
- ::base::PlatformThread::Sleep(::base::TimeDelta::FromMicroseconds(micros));
- }
+Status ChromiumEnv::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 = MakeIOError(fname, "Could not determine file size.", kGetFileSize);
+ RecordErrorAt(kGetFileSize);
+ } else {
+ *size = static_cast<uint64_t>(signed_size);
+ }
+ return s;
+}
- void RecordErrorAt(MethodID method) const {
- GetMethodIOErrorHistogram()->Add(method);
- }
+Status ChromiumEnv::RenameFile(const std::string& src, const std::string& dst) {
+ Status result;
+ base::FilePath src_file_path = CreateFilePath(src);
+ if (!::file_util::PathExists(src_file_path))
+ return result;
+ base::FilePath destination = CreateFilePath(dst);
+
+ Retrier retrier(kRenameFile, this);
+ base::PlatformFileError error = base::PLATFORM_FILE_OK;
+ do {
+ if (::file_util::ReplaceFileAndGetError(
+ src_file_path, destination, &error)) {
+ sync_parent(dst);
+ if (src_file_path.DirName() != destination.DirName()) {
+ // As leveldb is implemented now this branch will never be taken, but
+ // this is future-proof.
+ sync_parent(src);
+ }
+ return result;
+ }
+ } while (retrier.ShouldKeepTrying(error));
- void RecordLockFileAncestors(int num_missing_ancestors) const {
- GetLockFileAncestorHistogram()->Add(num_missing_ancestors);
- }
+ DCHECK(error != base::PLATFORM_FILE_OK);
+ RecordOSError(kRenameFile, error);
+ char buf[100];
+ snprintf(buf,
+ sizeof(buf),
+ "Could not rename file: %s",
+ PlatformFileErrorString(error));
+ return MakeIOError(src, buf, kRenameFile, error);
+}
- void RecordOSError(MethodID method, base::PlatformFileError error) const {
- DCHECK(error < 0);
- RecordErrorAt(method);
- GetOSErrorHistogram(method, -base::PLATFORM_FILE_ERROR_MAX)->
- Add(-error);
- }
+Status ChromiumEnv::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;
+ Retrier retrier(kLockFile, this);
+ do {
+ file = ::base::CreatePlatformFile(
+ CreateFilePath(fname), flags, &created, &error_code);
+ } while (error_code != ::base::PLATFORM_FILE_OK &&
+ retrier.ShouldKeepTrying(error_code));
+
+ if (error_code == ::base::PLATFORM_FILE_ERROR_NOT_FOUND) {
+ ::base::FilePath parent = CreateFilePath(fname).DirName();
+ ::base::FilePath last_parent;
+ int num_missing_ancestors = 0;
+ do {
+ if (file_util::DirectoryExists(parent))
+ break;
+ ++num_missing_ancestors;
+ last_parent = parent;
+ parent = parent.DirName();
+ } while (parent != last_parent);
+ RecordLockFileAncestors(num_missing_ancestors);
+ }
+
+ if (error_code != ::base::PLATFORM_FILE_OK) {
+ result = MakeIOError(
+ fname, PlatformFileErrorString(error_code), kLockFile, error_code);
+ RecordOSError(kLockFile, error_code);
+ } else {
+ ChromiumFileLock* my_lock = new ChromiumFileLock;
+ my_lock->file_ = file;
+ *lock = my_lock;
+ }
+ return result;
+}
- void RecordOSError(MethodID method, int error) const {
- DCHECK(error > 0);
- RecordErrorAt(method);
- GetOSErrorHistogram(method, ERANGE + 1)->Add(error);
+Status ChromiumEnv::UnlockFile(FileLock* lock) {
+ ChromiumFileLock* my_lock = reinterpret_cast<ChromiumFileLock*>(lock);
+ Status result;
+ if (!::base::ClosePlatformFile(my_lock->file_)) {
+ result = MakeIOError("Could not close lock file.", "", kUnlockFile);
+ RecordErrorAt(kUnlockFile);
}
+ delete my_lock;
+ return result;
+}
- protected:
- std::string name_;
+Status ChromiumEnv::GetTestDirectory(std::string* path) {
+ mu_.Acquire();
+ if (test_directory_.empty()) {
+ if (!::file_util::CreateNewTempDirectory(kLevelDBTestDirectoryPrefix,
+ &test_directory_)) {
+ mu_.Release();
+ RecordErrorAt(kGetTestDirectory);
+ return MakeIOError(
+ "Could not create temp directory.", "", kGetTestDirectory);
+ }
+ }
+ *path = FilePathToString(test_directory_);
+ mu_.Release();
+ return Status::OK();
+}
- private:
- const int kMaxRetryTimeMillis;
- // BGThread() is the body of the background thread
- void BGThread();
- static void BGThreadWrapper(void* arg) {
- reinterpret_cast<ChromiumEnv*>(arg)->BGThread();
+Status ChromiumEnv::NewLogger(const std::string& fname, Logger** result) {
+ FILE* f = fopen_internal(fname.c_str(), "w");
+ if (f == NULL) {
+ *result = NULL;
+ int saved_errno = errno;
+ RecordOSError(kNewLogger, saved_errno);
+ return MakeIOError(fname, strerror(saved_errno), kNewLogger, saved_errno);
+ } else {
+ if (!sync_parent(fname)) {
+ fclose(f);
+ return MakeIOError(fname, strerror(errno), kNewLogger, errno);
+ }
+ *result = new ChromiumLogger(f);
+ return Status::OK();
}
+}
- base::HistogramBase* GetOSErrorHistogram(MethodID method, int limit) const;
- base::HistogramBase* GetMethodIOErrorHistogram() const;
- base::HistogramBase* GetMaxFDHistogram(const std::string& type) const;
- base::HistogramBase* GetLockFileAncestorHistogram() const;
+uint64_t ChromiumEnv::NowMicros() {
+ return ::base::TimeTicks::Now().ToInternalValue();
+}
- // RetrierProvider implementation.
- virtual int MaxRetryTimeMillis() const {
- return kMaxRetryTimeMillis;
- }
- virtual base::HistogramBase* GetRetryTimeHistogram(MethodID method) const;
- virtual base::HistogramBase* GetRecoveredFromErrorHistogram(
- MethodID method) const;
+void ChromiumEnv::SleepForMicroseconds(int micros) {
+ // Round up to the next millisecond.
+ ::base::PlatformThread::Sleep(::base::TimeDelta::FromMicroseconds(micros));
+}
- base::FilePath test_directory_;
+void ChromiumEnv::RecordErrorAt(MethodID method) const {
+ GetMethodIOErrorHistogram()->Add(method);
+}
- ::base::Lock mu_;
- ::base::ConditionVariable bgsignal_;
- bool started_bgthread_;
+void ChromiumEnv::RecordLockFileAncestors(int num_missing_ancestors) const {
+ GetLockFileAncestorHistogram()->Add(num_missing_ancestors);
+}
- // Entry per Schedule() call
- struct BGItem { void* arg; void (*function)(void*); };
- typedef std::deque<BGItem> BGQueue;
- BGQueue queue_;
-};
+void ChromiumEnv::RecordOSError(MethodID method,
+ base::PlatformFileError error) const {
+ DCHECK(error < 0);
+ RecordErrorAt(method);
+ GetOSErrorHistogram(method, -base::PLATFORM_FILE_ERROR_MAX)->Add(-error);
+}
-ChromiumEnv::ChromiumEnv()
- : name_("LevelDBEnv"),
- bgsignal_(&mu_),
- started_bgthread_(false),
- kMaxRetryTimeMillis(1000) {
+void ChromiumEnv::RecordOSError(MethodID method, int error) const {
+ DCHECK(error > 0);
+ RecordErrorAt(method);
+ GetOSErrorHistogram(method, ERANGE + 1)->Add(error);
}
base::HistogramBase* ChromiumEnv::GetOSErrorHistogram(MethodID method,
- int limit) const {
+ int limit) const {
std::string uma_name(name_);
// TODO(dgrogan): This is probably not the best way to concatenate strings.
uma_name.append(".IOError.").append(MethodIDToString(method));
@@ -906,82 +907,6 @@ void ChromiumEnv::StartThread(void (*function)(void* arg), void* arg) {
new Thread(function, arg); // Will self-delete.
}
-class IDBEnv : public ChromiumEnv {
- public:
- IDBEnv() : ChromiumEnv() {
- name_ = "LevelDBEnv.IDB";
- }
-};
-
-::base::LazyInstance<IDBEnv>::Leaky
- idb_env = LAZY_INSTANCE_INITIALIZER;
-
-::base::LazyInstance<ChromiumEnv>::Leaky
- default_env = LAZY_INSTANCE_INITIALIZER;
-
-} // unnamed namespace
-
-Status MakeIOError(Slice filename,
- const char* message,
- MethodID method,
- int saved_errno) {
- char buf[512];
- snprintf(buf,
- sizeof(buf),
- "%s (ChromeMethodErrno: %d::%s::%d)",
- message,
- method,
- MethodIDToString(method),
- saved_errno);
- return Status::IOError(filename, buf);
-}
-
-Status MakeIOError(Slice filename,
- const char* message,
- MethodID method,
- base::PlatformFileError error) {
- DCHECK(error < 0);
- char buf[512];
- snprintf(buf,
- sizeof(buf),
- "%s (ChromeMethodPFE: %d::%s::%d)",
- message,
- method,
- MethodIDToString(method),
- -error);
- return Status::IOError(filename, buf);
-}
-
-Status MakeIOError(Slice filename, const char* message, MethodID method) {
- char buf[512];
- snprintf(buf,
- sizeof(buf),
- "%s (ChromeMethodOnly: %d::%s)",
- message,
- method,
- MethodIDToString(method));
- return Status::IOError(filename, buf);
-}
-
-bool ParseMethodAndError(const char* string, int* method, int* error) {
- if (RE2::PartialMatch(string, "ChromeMethodOnly: (\\d+)", method))
- return true;
- if (RE2::PartialMatch(string,
- "ChromeMethodPFE: (\\d+)::.*::(\\d+)",
- method,
- error)) {
- *error = -*error;
- return true;
- }
- if (RE2::PartialMatch(string,
- "ChromeMethodErrno: (\\d+)::.*::(\\d+)",
- method,
- error)) {
- return true;
- }
- return false;
-}
-
} // namespace leveldb_env
namespace leveldb {