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

Side by Side Diff: third_party/leveldatabase/env_chromium.cc

Issue 710373002: LevelDB: Using base::File for all file I/O (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Deleted ErrnoWin32 test Created 6 years, 1 month 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2011 The LevelDB Authors. All rights reserved. 1 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. See the AUTHORS file for names of contributors. 3 // found in the LICENSE file. See the AUTHORS file for names of contributors.
4 4
5 #include "third_party/leveldatabase/env_chromium.h" 5 #include "third_party/leveldatabase/env_chromium.h"
6 6
7 #if defined(OS_WIN)
8 #include <io.h>
9 #endif
10
11 #include "base/debug/trace_event.h" 7 #include "base/debug/trace_event.h"
8 #include "base/files/file_enumerator.h"
12 #include "base/files/file_util.h" 9 #include "base/files/file_util.h"
13 #include "base/lazy_instance.h" 10 #include "base/lazy_instance.h"
11 #include "base/memory/shared_memory.h"
14 #include "base/metrics/histogram.h" 12 #include "base/metrics/histogram.h"
13 #include "base/process/process_metrics.h"
15 #include "base/stl_util.h" 14 #include "base/stl_util.h"
16 #include "base/strings/utf_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h"
17 #include "third_party/leveldatabase/env_chromium_stdio.h" 16 #include "third_party/leveldatabase/chromium_logger.h"
18 #include "third_party/re2/re2/re2.h" 17 #include "third_party/re2/re2/re2.h"
19 18
20 #if defined(OS_WIN)
21 #include "base/command_line.h"
22 #include "base/win/win_util.h"
23 #include "third_party/leveldatabase/env_chromium_win.h"
24 #endif
25
26 using leveldb::FileLock; 19 using leveldb::FileLock;
27 using leveldb::Slice; 20 using leveldb::Slice;
28 using leveldb::Status; 21 using leveldb::Status;
29 22
30 namespace leveldb_env { 23 namespace leveldb_env {
31 24
32 namespace { 25 namespace {
33 26
34 const base::FilePath::CharType backup_table_extension[] = 27 const base::FilePath::CharType backup_table_extension[] =
35 FILE_PATH_LITERAL(".bak"); 28 FILE_PATH_LITERAL(".bak");
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 base::TimeTicks start_; 74 base::TimeTicks start_;
82 base::TimeTicks limit_; 75 base::TimeTicks limit_;
83 base::TimeTicks last_; 76 base::TimeTicks last_;
84 base::TimeDelta time_to_sleep_; 77 base::TimeDelta time_to_sleep_;
85 bool success_; 78 bool success_;
86 MethodID method_; 79 MethodID method_;
87 base::File::Error last_error_; 80 base::File::Error last_error_;
88 RetrierProvider* provider_; 81 RetrierProvider* provider_;
89 }; 82 };
90 83
91 class IDBEnvStdio : public ChromiumEnvStdio { 84 class ChromiumSequentialFile : public leveldb::SequentialFile {
92 public: 85 public:
93 IDBEnvStdio() : ChromiumEnvStdio() { 86 ChromiumSequentialFile(const std::string& fname,
87 base::File* f,
88 const UMALogger* uma_logger)
89 : filename_(fname), file_(f), uma_logger_(uma_logger) {}
90 virtual ~ChromiumSequentialFile() {}
91
92 virtual Status Read(size_t n, Slice* result, char* scratch) {
jsbell 2014/11/12 01:04:04 Drop `virtual`, add `override` here and below?
cmumford 2014/11/12 20:59:33 Done.
93 int bytes_read = file_->ReadAtCurrentPos(scratch, n);
94 if (bytes_read == -1) {
95 int saved_errno = errno;
jsbell 2014/11/12 01:04:05 Uh... isn't errno a POSIX thing? The Win32 APIs do
cmumford 2014/11/12 20:59:33 There were a bunch of other errno uses - I cleaned
96 uma_logger_->RecordErrorAt(kSequentialFileRead);
97 return MakeIOError(filename_, strerror(saved_errno), kSequentialFileRead,
98 saved_errno);
99 } else {
jsbell 2014/11/12 01:04:04 This appears to be missing the logic from the old
cmumford 2014/11/12 20:59:33 I don't think so - or maybe I'm misunderstanding h
jsbell 2014/11/14 00:12:33 I was looking at the file_posix.cc impl; if it man
cmumford 2014/11/14 22:43:56 I believe that calling ReadAtCurrentPosNoBestEffor
100 *result = Slice(scratch, bytes_read);
101 return Status::OK();
102 }
103 }
104
105 virtual Status Skip(uint64_t n) {
106 if (file_->Seek(base::File::FROM_CURRENT, n) == -1) {
107 int saved_errno = errno;
108 uma_logger_->RecordErrorAt(kSequentialFileSkip);
109 return MakeIOError(filename_, strerror(saved_errno), kSequentialFileSkip,
110 saved_errno);
111 } else {
112 return Status::OK();
113 }
114 }
115
116 private:
117 std::string filename_;
118 scoped_ptr<base::File> file_;
119 const UMALogger* uma_logger_;
120 };
121
122 class ChromiumRandomAccessFile : public leveldb::RandomAccessFile {
123 public:
124 ChromiumRandomAccessFile(const std::string& fname,
125 ::base::File file,
126 const UMALogger* uma_logger)
127 : filename_(fname), file_(file.Pass()), uma_logger_(uma_logger) {}
128 virtual ~ChromiumRandomAccessFile() {}
129
130 virtual Status Read(uint64_t offset,
131 size_t n,
132 Slice* result,
133 char* scratch) const {
134 Status s;
135 int r = file_.Read(offset, scratch, n);
136 *result = Slice(scratch, (r < 0) ? 0 : r);
137 if (r < 0) {
138 // An error: return a non-ok status
139 s = MakeIOError(filename_, "Could not perform read",
140 kRandomAccessFileRead);
141 uma_logger_->RecordErrorAt(kRandomAccessFileRead);
142 }
143 return s;
144 }
145
146 private:
147 std::string filename_;
148 mutable ::base::File file_;
149 const UMALogger* uma_logger_;
150 };
151
152 class ChromiumWritableFile : public leveldb::WritableFile {
153 public:
154 ChromiumWritableFile(const std::string& fname,
155 base::File* f,
156 const UMALogger* uma_logger,
157 WriteTracker* tracker,
158 bool make_backup);
159 virtual ~ChromiumWritableFile() {}
160 virtual leveldb::Status Append(const leveldb::Slice& data);
161 virtual leveldb::Status Close();
162 virtual leveldb::Status Flush();
163 virtual leveldb::Status Sync();
164
165 private:
166 enum Type { kManifest, kTable, kOther };
167 leveldb::Status SyncParent();
168
169 std::string filename_;
170 scoped_ptr<base::File> file_;
171 const UMALogger* uma_logger_;
172 WriteTracker* tracker_;
173 Type file_type_;
174 std::string parent_dir_;
175 bool make_backup_;
176 };
177
178 ChromiumWritableFile::ChromiumWritableFile(const std::string& fname,
179 base::File* f,
180 const UMALogger* uma_logger,
181 WriteTracker* tracker,
182 bool make_backup)
183 : filename_(fname),
184 file_(f),
185 uma_logger_(uma_logger),
186 tracker_(tracker),
187 file_type_(kOther),
188 make_backup_(make_backup) {
189 base::FilePath path = base::FilePath::FromUTF8Unsafe(fname);
190 if (FilePathToString(path.BaseName()).find("MANIFEST") == 0)
191 file_type_ = kManifest;
192 else if (ChromiumEnv::HasTableExtension(path))
193 file_type_ = kTable;
194 if (file_type_ != kManifest)
195 tracker_->DidCreateNewFile(filename_);
196 parent_dir_ = FilePathToString(ChromiumEnv::CreateFilePath(fname).DirName());
197 }
198
199 Status ChromiumWritableFile::SyncParent() {
200 TRACE_EVENT0("leveldb", "SyncParent");
201 #if defined(OS_POSIX)
202 base::FilePath path = base::FilePath::FromUTF8Unsafe(parent_dir_);
203 base::File f(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
204 if (!f.IsValid()) {
205 return MakeIOError(parent_dir_, "Unable to open directory", kSyncParent,
206 f.error_details());
207 } else if (!f.Flush()) {
jsbell 2014/11/12 01:04:04 Since the previous if() clause returns, drop the e
cmumford 2014/11/12 20:59:32 Done.
208 int saved_errno = errno;
209 return MakeIOError(parent_dir_, strerror(saved_errno), kSyncParent,
210 saved_errno);
211 }
212 #endif
213 return Status::OK();
214 }
215
216 Status ChromiumWritableFile::Append(const Slice& data) {
217 if (file_type_ == kManifest && tracker_->DoesDirNeedSync(filename_)) {
218 Status s = SyncParent();
219 if (!s.ok())
220 return s;
221 tracker_->DidSyncDir(filename_);
222 }
223
224 int bytes_written = file_->WriteAtCurrentPos(data.data(), data.size());
225 if (bytes_written != data.size()) {
226 int saved_errno = errno;
227 uma_logger_->RecordOSError(kWritableFileAppend, saved_errno);
228 return MakeIOError(filename_, strerror(saved_errno), kWritableFileAppend,
229 saved_errno);
230 } else {
jsbell 2014/11/12 01:04:05 Drop the else, this can be unconditional since the
cmumford 2014/11/12 20:59:32 Done.
231 return Status::OK();
232 }
233 }
234
235 Status ChromiumWritableFile::Close() {
236 file_->Close();
237 return Status::OK();
238 }
239
240 Status ChromiumWritableFile::Flush() {
241 // base::File doesn't do buffered I/O (i.e. POSIX FILE streams) so nothing to
jsbell 2014/11/12 01:04:04 Agreed, this matches previous posix/win32 env beha
cmumford 2014/11/12 20:59:33 My read is that LDB's Env is designed so that you
242 // flush.
243 return Status::OK();
244 }
245
246 Status ChromiumWritableFile::Sync() {
247 TRACE_EVENT0("leveldb", "WritableFile::Sync");
248
249 if (!file_->Flush()) {
jsbell 2014/11/12 01:04:04 It looks like the old POSIX used fdatasync(), whic
cmumford 2014/11/12 20:59:33 The old POSIX used libc's fdatasync - not the one
250 int saved_errno = errno;
251 uma_logger_->RecordErrorAt(kWritableFileSync);
252 return MakeIOError(filename_, strerror(saved_errno), kWritableFileSync,
253 saved_errno);
254 }
255
256 if (make_backup_ && file_type_ == kTable) {
jsbell 2014/11/12 01:04:04 Can drop the {} here
cmumford 2014/11/12 20:59:33 Done.
257 uma_logger_->RecordBackupResult(ChromiumEnv::MakeBackup(filename_));
258 }
259
260 return Status::OK();
261 }
262
263 class IDBEnv : public ChromiumEnv {
264 public:
265 IDBEnv() : ChromiumEnv() {
94 name_ = "LevelDBEnv.IDB"; 266 name_ = "LevelDBEnv.IDB";
95 make_backup_ = true; 267 make_backup_ = true;
96 } 268 }
97 }; 269 };
98 270
99 #if defined(OS_WIN) 271 ::base::LazyInstance<IDBEnv>::Leaky idb_env = LAZY_INSTANCE_INITIALIZER;
100 class IDBEnvWin : public ChromiumEnvWin {
101 public:
102 IDBEnvWin() : ChromiumEnvWin() {
103 name_ = "LevelDBEnv.IDB";
104 make_backup_ = true;
105 }
106 };
107 #endif
108 272
109 #if defined(OS_WIN) 273 ::base::LazyInstance<ChromiumEnv>::Leaky default_env =
110 ::base::LazyInstance<IDBEnvWin>::Leaky idb_env =
111 LAZY_INSTANCE_INITIALIZER;
112 #else
113 ::base::LazyInstance<IDBEnvStdio>::Leaky idb_env =
114 LAZY_INSTANCE_INITIALIZER;
115 #endif
116
117 ::base::LazyInstance<ChromiumEnvStdio>::Leaky default_env =
118 LAZY_INSTANCE_INITIALIZER; 274 LAZY_INSTANCE_INITIALIZER;
119 275
120 } // unnamed namespace 276 } // unnamed namespace
121 277
122 const char* MethodIDToString(MethodID method) { 278 const char* MethodIDToString(MethodID method) {
123 switch (method) { 279 switch (method) {
124 case kSequentialFileRead: 280 case kSequentialFileRead:
125 return "SequentialFileRead"; 281 return "SequentialFileRead";
126 case kSequentialFileSkip: 282 case kSequentialFileSkip:
127 return "SequentialFileSkip"; 283 return "SequentialFileSkip";
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after
459 it != backups_only.end(); 615 it != backups_only.end();
460 ++it) { 616 ++it) {
461 base::FilePath restored_table_name = 617 base::FilePath restored_table_name =
462 RestoreFromBackup(dir_filepath.Append(*it)); 618 RestoreFromBackup(dir_filepath.Append(*it));
463 result->push_back(FilePathToString(restored_table_name.BaseName())); 619 result->push_back(FilePathToString(restored_table_name.BaseName()));
464 } 620 }
465 } 621 }
466 622
467 Status ChromiumEnv::GetChildren(const std::string& dir_string, 623 Status ChromiumEnv::GetChildren(const std::string& dir_string,
468 std::vector<std::string>* result) { 624 std::vector<std::string>* result) {
469 std::vector<base::FilePath> entries;
470 base::File::Error error =
471 GetDirectoryEntries(CreateFilePath(dir_string), &entries);
jsbell 2014/11/12 01:04:04 This was added to avoid early-exit on error. Does
cmumford 2014/11/12 20:59:33 It looks like FileEnumerator mostly ignores errors
472 if (error != base::File::FILE_OK) {
473 RecordOSError(kGetChildren, error);
474 return MakeIOError(
475 dir_string, "Could not open/read directory", kGetChildren, error);
476 }
477 result->clear(); 625 result->clear();
478 for (std::vector<base::FilePath>::iterator it = entries.begin(); 626 base::FileEnumerator enumerator(CreateFilePath(dir_string),
479 it != entries.end(); 627 false, // not recursive
480 ++it) { 628 base::FileEnumerator::FILES);
481 result->push_back(FilePathToString(*it)); 629 for (base::FilePath current = enumerator.Next(); !current.empty();
630 current = enumerator.Next()) {
631 result->push_back(FilePathToString(current.BaseName()));
482 } 632 }
483 633
484 if (make_backup_) 634 if (make_backup_)
485 RestoreIfNecessary(dir_string, result); 635 RestoreIfNecessary(dir_string, result);
486 return Status::OK(); 636 return Status::OK();
487 } 637 }
488 638
489 Status ChromiumEnv::DeleteFile(const std::string& fname) { 639 Status ChromiumEnv::DeleteFile(const std::string& fname) {
490 Status result; 640 Status result;
491 base::FilePath fname_filepath = CreateFilePath(fname); 641 base::FilePath fname_filepath = CreateFilePath(fname);
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
648 RecordErrorAt(kGetTestDirectory); 798 RecordErrorAt(kGetTestDirectory);
649 return MakeIOError( 799 return MakeIOError(
650 "Could not create temp directory.", "", kGetTestDirectory); 800 "Could not create temp directory.", "", kGetTestDirectory);
651 } 801 }
652 } 802 }
653 *path = FilePathToString(test_directory_); 803 *path = FilePathToString(test_directory_);
654 mu_.Release(); 804 mu_.Release();
655 return Status::OK(); 805 return Status::OK();
656 } 806 }
657 807
808 Status ChromiumEnv::NewLogger(const std::string& fname,
809 leveldb::Logger** result) {
810 base::FilePath path = CreateFilePath(fname);
811 scoped_ptr<base::File> f(new base::File(
812 path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE));
813 if (!f->IsValid()) {
814 *result = NULL;
815 RecordOSError(kNewLogger, f->error_details());
816 return MakeIOError(fname, "Unable to create log file", kNewLogger,
817 f->error_details());
818 } else {
819 *result = new leveldb::ChromiumLogger(f.release());
820 return Status::OK();
821 }
822 }
823
824 Status ChromiumEnv::NewSequentialFile(const std::string& fname,
825 leveldb::SequentialFile** result) {
826 base::FilePath path = CreateFilePath(fname);
827 scoped_ptr<base::File> f(
828 new base::File(path, base::File::FLAG_OPEN | base::File::FLAG_READ));
829 if (!f->IsValid()) {
830 *result = NULL;
831 int saved_errno = errno;
832 RecordOSError(kNewSequentialFile, f->error_details());
833 return MakeIOError(fname, "Unable to create sequential file",
834 kNewSequentialFile, f->error_details());
835 } else {
836 *result = new ChromiumSequentialFile(fname, f.release(), this);
837 return Status::OK();
838 }
839 }
840
841 void ChromiumEnv::RecordOpenFilesLimit(const std::string& type) {
842 GetMaxFDHistogram(type)->Add(base::SharedMemory::GetHandleLimit());
jsbell 2014/11/12 01:04:04 Although I think this does the right thing (eventu
cmumford 2014/11/12 20:59:32 Done. GetMaxFds was not exported - I fixed that an
843 }
844
845 Status ChromiumEnv::NewRandomAccessFile(const std::string& fname,
846 leveldb::RandomAccessFile** result) {
847 int flags = ::base::File::FLAG_READ | ::base::File::FLAG_OPEN;
848 ::base::File file(ChromiumEnv::CreateFilePath(fname), flags);
849 if (file.IsValid()) {
850 *result = new ChromiumRandomAccessFile(fname, file.Pass(), this);
851 RecordOpenFilesLimit("Success");
852 return Status::OK();
853 }
854 ::base::File::Error error_code = file.error_details();
855 if (error_code == ::base::File::FILE_ERROR_TOO_MANY_OPENED)
856 RecordOpenFilesLimit("TooManyOpened");
857 else
858 RecordOpenFilesLimit("OtherError");
859 *result = NULL;
860 RecordOSError(kNewRandomAccessFile, error_code);
861 return MakeIOError(fname, FileErrorString(error_code), kNewRandomAccessFile,
862 error_code);
863 }
864
865 Status ChromiumEnv::NewWritableFile(const std::string& fname,
866 leveldb::WritableFile** result) {
867 *result = NULL;
868 base::FilePath path = CreateFilePath(fname);
869 scoped_ptr<base::File> f(new base::File(
870 path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE));
871 if (!f->IsValid()) {
872 RecordErrorAt(kNewWritableFile);
873 return MakeIOError(fname, "Unable to create writable file",
874 kNewWritableFile, f->error_details());
875 } else {
876 *result =
877 new ChromiumWritableFile(fname, f.release(), this, this, make_backup_);
878 return Status::OK();
879 }
880 }
881
658 uint64_t ChromiumEnv::NowMicros() { 882 uint64_t ChromiumEnv::NowMicros() {
659 return ::base::TimeTicks::Now().ToInternalValue(); 883 return ::base::TimeTicks::Now().ToInternalValue();
660 } 884 }
661 885
662 void ChromiumEnv::SleepForMicroseconds(int micros) { 886 void ChromiumEnv::SleepForMicroseconds(int micros) {
663 // Round up to the next millisecond. 887 // Round up to the next millisecond.
664 ::base::PlatformThread::Sleep(::base::TimeDelta::FromMicroseconds(micros)); 888 ::base::PlatformThread::Sleep(::base::TimeDelta::FromMicroseconds(micros));
665 } 889 }
666 890
667 void ChromiumEnv::RecordErrorAt(MethodID method) const { 891 void ChromiumEnv::RecordErrorAt(MethodID method) const {
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
848 1072
849 Env* IDBEnv() { 1073 Env* IDBEnv() {
850 return leveldb_env::idb_env.Pointer(); 1074 return leveldb_env::idb_env.Pointer();
851 } 1075 }
852 1076
853 Env* Env::Default() { 1077 Env* Env::Default() {
854 return leveldb_env::default_env.Pointer(); 1078 return leveldb_env::default_env.Pointer();
855 } 1079 }
856 1080
857 } // namespace leveldb 1081 } // namespace leveldb
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698