OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |