Chromium Code Reviews| 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 <deque> | 5 #include <deque> |
| 6 #include <errno.h> | 6 #include <errno.h> |
| 7 #include <stdio.h> | 7 #include <stdio.h> |
| 8 #include "base/at_exit.h" | 8 #include "base/at_exit.h" |
| 9 #include "base/file_path.h" | 9 #include "base/file_path.h" |
| 10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 117 kDeleteDir, | 117 kDeleteDir, |
| 118 kGetFileSize, | 118 kGetFileSize, |
| 119 kRenamefile, | 119 kRenamefile, |
| 120 kLockFile, | 120 kLockFile, |
| 121 kUnlockFile, | 121 kUnlockFile, |
| 122 kGetTestDirectory, | 122 kGetTestDirectory, |
| 123 kNewLogger, | 123 kNewLogger, |
| 124 kNumEntries | 124 kNumEntries |
| 125 }; | 125 }; |
| 126 | 126 |
| 127 void LogToUMA(UmaEntry entry) { | 127 class UMALogger { |
| 128 UMA_HISTOGRAM_ENUMERATION("LevelDBEnv.IOError", entry, kNumEntries); | 128 public: |
| 129 } | 129 UMALogger(std::string uma_title) : uma_title_(uma_title) { |
|
jsbell
2013/01/05 00:14:54
Nit: put the closing brace on the same line.
dgrogan
2013/01/07 18:49:13
Done.
| |
| 130 | 130 |
| 131 void LogRandomAccessFileError(base::PlatformFileError error_code) { | 131 } |
| 132 DCHECK(error_code < 0); | 132 void RecordErrorAt(UmaEntry entry) const { |
| 133 UMA_HISTOGRAM_ENUMERATION("LevelDBEnv.IOError.RandomAccessFile", | 133 std::string uma_name(uma_title_); |
| 134 -error_code, | 134 uma_name.append(".IOError"); |
| 135 -base::PLATFORM_FILE_ERROR_MAX); | 135 UMA_HISTOGRAM_ENUMERATION(uma_name, entry, kNumEntries); |
| 136 } | 136 } |
| 137 | |
| 138 void LogRandomAccessFileError(base::PlatformFileError error_code) const { | |
| 139 DCHECK(error_code < 0); | |
| 140 std::string uma_name(uma_title_); | |
| 141 uma_name.append(".IOError.RandomAccessFile"); | |
| 142 UMA_HISTOGRAM_ENUMERATION(uma_name, | |
| 143 -error_code, | |
| 144 -base::PLATFORM_FILE_ERROR_MAX); | |
| 145 } | |
| 146 private: | |
| 147 std::string uma_title_; | |
| 148 }; | |
| 137 | 149 |
| 138 } // namespace | 150 } // namespace |
| 139 | 151 |
| 140 namespace leveldb { | 152 namespace leveldb { |
| 141 | 153 |
| 142 namespace { | 154 namespace { |
| 143 | 155 |
| 144 class Thread; | 156 class Thread; |
| 145 | 157 |
| 146 static const ::FilePath::CharType kLevelDBTestDirectoryPrefix[] | 158 static const ::FilePath::CharType kLevelDBTestDirectoryPrefix[] |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 184 NOTREACHED(); | 196 NOTREACHED(); |
| 185 } | 197 } |
| 186 NOTIMPLEMENTED(); | 198 NOTIMPLEMENTED(); |
| 187 return "Unknown error."; | 199 return "Unknown error."; |
| 188 } | 200 } |
| 189 | 201 |
| 190 class ChromiumSequentialFile: public SequentialFile { | 202 class ChromiumSequentialFile: public SequentialFile { |
| 191 private: | 203 private: |
| 192 std::string filename_; | 204 std::string filename_; |
| 193 FILE* file_; | 205 FILE* file_; |
| 206 const UMALogger* uma_logger_; | |
|
jsbell
2013/01/05 00:14:54
How certain are we that these never outlive the En
dgrogan
2013/01/05 01:05:28
Env is never deleted (its destructor is NOTREACHED
| |
| 194 | 207 |
| 195 public: | 208 public: |
| 196 ChromiumSequentialFile(const std::string& fname, FILE* f) | 209 ChromiumSequentialFile(const std::string& fname, FILE* f, const UMALogger* uma _logger) |
|
jsbell
2013/01/05 00:14:54
Nit: Line length.
dgrogan
2013/01/05 01:05:28
Oops. Normally the presubmit catches this. Maybe i
| |
| 197 : filename_(fname), file_(f) { } | 210 : filename_(fname), file_(f), uma_logger_(uma_logger) { } |
| 198 virtual ~ChromiumSequentialFile() { fclose(file_); } | 211 virtual ~ChromiumSequentialFile() { fclose(file_); } |
| 199 | 212 |
| 200 virtual Status Read(size_t n, Slice* result, char* scratch) { | 213 virtual Status Read(size_t n, Slice* result, char* scratch) { |
| 201 Status s; | 214 Status s; |
| 202 size_t r = fread_unlocked(scratch, 1, n, file_); | 215 size_t r = fread_unlocked(scratch, 1, n, file_); |
| 203 *result = Slice(scratch, r); | 216 *result = Slice(scratch, r); |
| 204 if (r < n) { | 217 if (r < n) { |
| 205 if (feof(file_)) { | 218 if (feof(file_)) { |
| 206 // We leave status as ok if we hit the end of the file | 219 // We leave status as ok if we hit the end of the file |
| 207 } else { | 220 } else { |
| 208 // A partial read with an error: return a non-ok status | 221 // A partial read with an error: return a non-ok status |
| 209 s = Status::IOError(filename_, strerror(errno)); | 222 s = Status::IOError(filename_, strerror(errno)); |
| 210 LogToUMA(kSequentialFileRead); | 223 uma_logger_->RecordErrorAt(kSequentialFileRead); |
| 211 } | 224 } |
| 212 } | 225 } |
| 213 return s; | 226 return s; |
| 214 } | 227 } |
| 215 | 228 |
| 216 virtual Status Skip(uint64_t n) { | 229 virtual Status Skip(uint64_t n) { |
| 217 if (fseek(file_, n, SEEK_CUR)) { | 230 if (fseek(file_, n, SEEK_CUR)) { |
| 218 LogToUMA(kSequentialFileSkip); | 231 uma_logger_->RecordErrorAt(kSequentialFileSkip); |
| 219 return Status::IOError(filename_, strerror(errno)); | 232 return Status::IOError(filename_, strerror(errno)); |
| 220 } | 233 } |
| 221 return Status::OK(); | 234 return Status::OK(); |
| 222 } | 235 } |
| 223 }; | 236 }; |
| 224 | 237 |
| 225 class ChromiumRandomAccessFile: public RandomAccessFile { | 238 class ChromiumRandomAccessFile: public RandomAccessFile { |
| 226 private: | 239 private: |
| 227 std::string filename_; | 240 std::string filename_; |
| 228 ::base::PlatformFile file_; | 241 ::base::PlatformFile file_; |
| 242 const UMALogger* uma_logger_; | |
| 229 | 243 |
| 230 public: | 244 public: |
| 231 ChromiumRandomAccessFile(const std::string& fname, ::base::PlatformFile file) | 245 ChromiumRandomAccessFile(const std::string& fname, ::base::PlatformFile file, const UMALogger* uma_logger) |
|
jsbell
2013/01/05 00:14:54
Nit: line length.
dgrogan
2013/01/07 18:49:13
Done.
| |
| 232 : filename_(fname), file_(file) { } | 246 : filename_(fname), file_(file), uma_logger_(uma_logger) { } |
| 233 virtual ~ChromiumRandomAccessFile() { ::base::ClosePlatformFile(file_); } | 247 virtual ~ChromiumRandomAccessFile() { ::base::ClosePlatformFile(file_); } |
| 234 | 248 |
| 235 virtual Status Read(uint64_t offset, size_t n, Slice* result, | 249 virtual Status Read(uint64_t offset, size_t n, Slice* result, |
| 236 char* scratch) const { | 250 char* scratch) const { |
| 237 Status s; | 251 Status s; |
| 238 int r = ::base::ReadPlatformFile(file_, offset, scratch, n); | 252 int r = ::base::ReadPlatformFile(file_, offset, scratch, n); |
| 239 *result = Slice(scratch, (r < 0) ? 0 : r); | 253 *result = Slice(scratch, (r < 0) ? 0 : r); |
| 240 if (r < 0) { | 254 if (r < 0) { |
| 241 // An error: return a non-ok status | 255 // An error: return a non-ok status |
| 242 s = Status::IOError(filename_, "Could not perform read"); | 256 s = Status::IOError(filename_, "Could not perform read"); |
| 243 LogToUMA(kRandomAccessFileRead); | 257 uma_logger_->RecordErrorAt(kRandomAccessFileRead); |
| 244 } | 258 } |
| 245 return s; | 259 return s; |
| 246 } | 260 } |
| 247 }; | 261 }; |
| 248 | 262 |
| 249 class ChromiumWritableFile : public WritableFile { | 263 class ChromiumWritableFile : public WritableFile { |
| 250 private: | 264 private: |
| 251 std::string filename_; | 265 std::string filename_; |
| 252 FILE* file_; | 266 FILE* file_; |
| 267 const UMALogger* uma_logger_; | |
| 253 | 268 |
| 254 public: | 269 public: |
| 255 ChromiumWritableFile(const std::string& fname, FILE* f) | 270 ChromiumWritableFile(const std::string& fname, FILE* f, const UMALogger* uma_l ogger) |
|
jsbell
2013/01/05 00:14:54
Nit: line length.
dgrogan
2013/01/07 18:49:13
Done.
| |
| 256 : filename_(fname), file_(f) { } | 271 : filename_(fname), file_(f), uma_logger_(uma_logger) { } |
| 257 | 272 |
| 258 ~ChromiumWritableFile() { | 273 ~ChromiumWritableFile() { |
| 259 if (file_ != NULL) { | 274 if (file_ != NULL) { |
| 260 // Ignoring any potential errors | 275 // Ignoring any potential errors |
| 261 fclose(file_); | 276 fclose(file_); |
| 262 } | 277 } |
| 263 } | 278 } |
| 264 | 279 |
| 265 virtual Status Append(const Slice& data) { | 280 virtual Status Append(const Slice& data) { |
| 266 size_t r = fwrite_unlocked(data.data(), 1, data.size(), file_); | 281 size_t r = fwrite_unlocked(data.data(), 1, data.size(), file_); |
| 267 Status result; | 282 Status result; |
| 268 if (r != data.size()) { | 283 if (r != data.size()) { |
| 269 result = Status::IOError(filename_, strerror(errno)); | 284 result = Status::IOError(filename_, strerror(errno)); |
| 270 LogToUMA(kWritableFileAppend); | 285 uma_logger_->RecordErrorAt(kWritableFileAppend); |
| 271 } | 286 } |
| 272 return result; | 287 return result; |
| 273 } | 288 } |
| 274 | 289 |
| 275 virtual Status Close() { | 290 virtual Status Close() { |
| 276 Status result; | 291 Status result; |
| 277 if (fclose(file_) != 0) { | 292 if (fclose(file_) != 0) { |
| 278 result = Status::IOError(filename_, strerror(errno)); | 293 result = Status::IOError(filename_, strerror(errno)); |
| 279 LogToUMA(kWritableFileClose); | 294 uma_logger_->RecordErrorAt(kWritableFileClose); |
| 280 } | 295 } |
| 281 file_ = NULL; | 296 file_ = NULL; |
| 282 return result; | 297 return result; |
| 283 } | 298 } |
| 284 | 299 |
| 285 virtual Status Flush() { | 300 virtual Status Flush() { |
| 286 Status result; | 301 Status result; |
| 287 if (fflush_unlocked(file_) != 0) { | 302 if (fflush_unlocked(file_) != 0) { |
| 288 result = Status::IOError(filename_, strerror(errno)); | 303 result = Status::IOError(filename_, strerror(errno)); |
| 289 LogToUMA(kWritableFileFlush); | 304 uma_logger_->RecordErrorAt(kWritableFileFlush); |
| 290 } | 305 } |
| 291 return result; | 306 return result; |
| 292 } | 307 } |
| 293 | 308 |
| 294 virtual Status Sync() { | 309 virtual Status Sync() { |
| 295 Status result; | 310 Status result; |
| 296 int error = 0; | 311 int error = 0; |
| 297 | 312 |
| 298 if (fflush_unlocked(file_)) | 313 if (fflush_unlocked(file_)) |
| 299 error = errno; | 314 error = errno; |
| 300 // Sync even if fflush gave an error; perhaps the data actually got out, | 315 // Sync even if fflush gave an error; perhaps the data actually got out, |
| 301 // even though something went wrong. | 316 // even though something went wrong. |
| 302 if (fdatasync(fileno(file_)) && !error) | 317 if (fdatasync(fileno(file_)) && !error) |
| 303 error = errno; | 318 error = errno; |
| 304 // Report the first error we found. | 319 // Report the first error we found. |
| 305 if (error) { | 320 if (error) { |
| 306 result = Status::IOError(filename_, strerror(error)); | 321 result = Status::IOError(filename_, strerror(error)); |
| 307 LogToUMA(kWritableFileSync); | 322 uma_logger_->RecordErrorAt(kWritableFileSync); |
| 308 } | 323 } |
| 309 return result; | 324 return result; |
| 310 } | 325 } |
| 311 }; | 326 }; |
| 312 | 327 |
| 313 class ChromiumFileLock : public FileLock { | 328 class ChromiumFileLock : public FileLock { |
| 314 public: | 329 public: |
| 315 ::base::PlatformFile file_; | 330 ::base::PlatformFile file_; |
| 316 }; | 331 }; |
| 317 | 332 |
| 318 class ChromiumEnv : public Env { | 333 class ChromiumEnv : public Env { |
| 319 public: | 334 public: |
| 320 ChromiumEnv(); | 335 ChromiumEnv(); |
| 321 virtual ~ChromiumEnv() { | 336 virtual ~ChromiumEnv() { |
| 322 NOTREACHED(); | 337 NOTREACHED(); |
| 323 } | 338 } |
| 324 | 339 |
| 325 virtual Status NewSequentialFile(const std::string& fname, | 340 virtual Status NewSequentialFile(const std::string& fname, |
| 326 SequentialFile** result) { | 341 SequentialFile** result) { |
| 327 FILE* f = fopen_internal(fname.c_str(), "rb"); | 342 FILE* f = fopen_internal(fname.c_str(), "rb"); |
| 328 if (f == NULL) { | 343 if (f == NULL) { |
| 329 *result = NULL; | 344 *result = NULL; |
| 330 LogToUMA(kNewSequentialFile); | 345 uma_logger_->RecordErrorAt(kNewSequentialFile); |
| 331 return Status::IOError(fname, strerror(errno)); | 346 return Status::IOError(fname, strerror(errno)); |
| 332 } else { | 347 } else { |
| 333 *result = new ChromiumSequentialFile(fname, f); | 348 *result = new ChromiumSequentialFile(fname, f, uma_logger_.get()); |
| 334 return Status::OK(); | 349 return Status::OK(); |
| 335 } | 350 } |
| 336 } | 351 } |
| 337 | 352 |
| 338 virtual Status NewRandomAccessFile(const std::string& fname, | 353 virtual Status NewRandomAccessFile(const std::string& fname, |
| 339 RandomAccessFile** result) { | 354 RandomAccessFile** result) { |
| 340 int flags = ::base::PLATFORM_FILE_READ | ::base::PLATFORM_FILE_OPEN; | 355 int flags = ::base::PLATFORM_FILE_READ | ::base::PLATFORM_FILE_OPEN; |
| 341 bool created; | 356 bool created; |
| 342 ::base::PlatformFileError error_code; | 357 ::base::PlatformFileError error_code; |
| 343 ::base::PlatformFile file = ::base::CreatePlatformFile( | 358 ::base::PlatformFile file = ::base::CreatePlatformFile( |
| 344 CreateFilePath(fname), flags, &created, &error_code); | 359 CreateFilePath(fname), flags, &created, &error_code); |
| 345 if (error_code != ::base::PLATFORM_FILE_OK) { | 360 if (error_code != ::base::PLATFORM_FILE_OK) { |
| 346 *result = NULL; | 361 *result = NULL; |
| 347 LogToUMA(kNewRandomAccessFile); | 362 uma_logger_->RecordErrorAt(kNewRandomAccessFile); |
| 348 LogRandomAccessFileError(error_code); | 363 uma_logger_->LogRandomAccessFileError(error_code); |
| 349 return Status::IOError(fname, PlatformFileErrorString(error_code)); | 364 return Status::IOError(fname, PlatformFileErrorString(error_code)); |
| 350 } | 365 } |
| 351 *result = new ChromiumRandomAccessFile(fname, file); | 366 *result = new ChromiumRandomAccessFile(fname, file, uma_logger_.get()); |
| 352 return Status::OK(); | 367 return Status::OK(); |
| 353 } | 368 } |
| 354 | 369 |
| 355 virtual Status NewWritableFile(const std::string& fname, | 370 virtual Status NewWritableFile(const std::string& fname, |
| 356 WritableFile** result) { | 371 WritableFile** result) { |
| 357 *result = NULL; | 372 *result = NULL; |
| 358 FILE* f = fopen_internal(fname.c_str(), "wb"); | 373 FILE* f = fopen_internal(fname.c_str(), "wb"); |
| 359 if (f == NULL) { | 374 if (f == NULL) { |
| 360 LogToUMA(kNewWritableFile); | 375 uma_logger_->RecordErrorAt(kNewWritableFile); |
| 361 return Status::IOError(fname, strerror(errno)); | 376 return Status::IOError(fname, strerror(errno)); |
| 362 } else { | 377 } else { |
| 363 if (!sync_parent(fname)) { | 378 if (!sync_parent(fname)) { |
| 364 fclose(f); | 379 fclose(f); |
| 365 return Status::IOError(fname, strerror(errno)); | 380 return Status::IOError(fname, strerror(errno)); |
| 366 } | 381 } |
| 367 *result = new ChromiumWritableFile(fname, f); | 382 *result = new ChromiumWritableFile(fname, f, uma_logger_.get()); |
| 368 return Status::OK(); | 383 return Status::OK(); |
| 369 } | 384 } |
| 370 } | 385 } |
| 371 | 386 |
| 372 virtual bool FileExists(const std::string& fname) { | 387 virtual bool FileExists(const std::string& fname) { |
| 373 return ::file_util::PathExists(CreateFilePath(fname)); | 388 return ::file_util::PathExists(CreateFilePath(fname)); |
| 374 } | 389 } |
| 375 | 390 |
| 376 virtual Status GetChildren(const std::string& dir, | 391 virtual Status GetChildren(const std::string& dir, |
| 377 std::vector<std::string>* result) { | 392 std::vector<std::string>* result) { |
| 378 result->clear(); | 393 result->clear(); |
| 379 ::file_util::FileEnumerator iter( | 394 ::file_util::FileEnumerator iter( |
| 380 CreateFilePath(dir), false, ::file_util::FileEnumerator::FILES); | 395 CreateFilePath(dir), false, ::file_util::FileEnumerator::FILES); |
| 381 ::FilePath current = iter.Next(); | 396 ::FilePath current = iter.Next(); |
| 382 while (!current.empty()) { | 397 while (!current.empty()) { |
| 383 result->push_back(FilePathToString(current.BaseName())); | 398 result->push_back(FilePathToString(current.BaseName())); |
| 384 current = iter.Next(); | 399 current = iter.Next(); |
| 385 } | 400 } |
| 386 // TODO(jorlow): Unfortunately, the FileEnumerator swallows errors, so | 401 // TODO(jorlow): Unfortunately, the FileEnumerator swallows errors, so |
| 387 // we'll always return OK. Maybe manually check for error | 402 // we'll always return OK. Maybe manually check for error |
| 388 // conditions like the file not existing? | 403 // conditions like the file not existing? |
| 389 return Status::OK(); | 404 return Status::OK(); |
| 390 } | 405 } |
| 391 | 406 |
| 392 virtual Status DeleteFile(const std::string& fname) { | 407 virtual Status DeleteFile(const std::string& fname) { |
| 393 Status result; | 408 Status result; |
| 394 // TODO(jorlow): Should we assert this is a file? | 409 // TODO(jorlow): Should we assert this is a file? |
| 395 if (!::file_util::Delete(CreateFilePath(fname), false)) { | 410 if (!::file_util::Delete(CreateFilePath(fname), false)) { |
| 396 result = Status::IOError(fname, "Could not delete file."); | 411 result = Status::IOError(fname, "Could not delete file."); |
| 397 LogToUMA(kDeleteFile); | 412 uma_logger_->RecordErrorAt(kDeleteFile); |
| 398 } | 413 } |
| 399 return result; | 414 return result; |
| 400 }; | 415 }; |
| 401 | 416 |
| 402 virtual Status CreateDir(const std::string& name) { | 417 virtual Status CreateDir(const std::string& name) { |
| 403 Status result; | 418 Status result; |
| 404 if (!::file_util::CreateDirectory(CreateFilePath(name))) { | 419 if (!::file_util::CreateDirectory(CreateFilePath(name))) { |
| 405 result = Status::IOError(name, "Could not create directory."); | 420 result = Status::IOError(name, "Could not create directory."); |
| 406 LogToUMA(kCreateDir); | 421 uma_logger_->RecordErrorAt(kCreateDir); |
| 407 } | 422 } |
| 408 return result; | 423 return result; |
| 409 }; | 424 }; |
| 410 | 425 |
| 411 virtual Status DeleteDir(const std::string& name) { | 426 virtual Status DeleteDir(const std::string& name) { |
| 412 Status result; | 427 Status result; |
| 413 // TODO(jorlow): Should we assert this is a directory? | 428 // TODO(jorlow): Should we assert this is a directory? |
| 414 if (!::file_util::Delete(CreateFilePath(name), false)) { | 429 if (!::file_util::Delete(CreateFilePath(name), false)) { |
| 415 result = Status::IOError(name, "Could not delete directory."); | 430 result = Status::IOError(name, "Could not delete directory."); |
| 416 LogToUMA(kDeleteDir); | 431 uma_logger_->RecordErrorAt(kDeleteDir); |
| 417 } | 432 } |
| 418 return result; | 433 return result; |
| 419 }; | 434 }; |
| 420 | 435 |
| 421 virtual Status GetFileSize(const std::string& fname, uint64_t* size) { | 436 virtual Status GetFileSize(const std::string& fname, uint64_t* size) { |
| 422 Status s; | 437 Status s; |
| 423 int64_t signed_size; | 438 int64_t signed_size; |
| 424 if (!::file_util::GetFileSize(CreateFilePath(fname), &signed_size)) { | 439 if (!::file_util::GetFileSize(CreateFilePath(fname), &signed_size)) { |
| 425 *size = 0; | 440 *size = 0; |
| 426 s = Status::IOError(fname, "Could not determine file size."); | 441 s = Status::IOError(fname, "Could not determine file size."); |
| 427 LogToUMA(kGetFileSize); | 442 uma_logger_->RecordErrorAt(kGetFileSize); |
| 428 } else { | 443 } else { |
| 429 *size = static_cast<uint64_t>(signed_size); | 444 *size = static_cast<uint64_t>(signed_size); |
| 430 } | 445 } |
| 431 return s; | 446 return s; |
| 432 } | 447 } |
| 433 | 448 |
| 434 virtual Status RenameFile(const std::string& src, const std::string& dst) { | 449 virtual Status RenameFile(const std::string& src, const std::string& dst) { |
| 435 Status result; | 450 Status result; |
| 436 if (!::file_util::ReplaceFile(CreateFilePath(src), CreateFilePath(dst))) { | 451 if (!::file_util::ReplaceFile(CreateFilePath(src), CreateFilePath(dst))) { |
| 437 result = Status::IOError(src, "Could not rename file."); | 452 result = Status::IOError(src, "Could not rename file."); |
| 438 LogToUMA(kRenamefile); | 453 uma_logger_->RecordErrorAt(kRenamefile); |
| 439 } else { | 454 } else { |
| 440 sync_parent(dst); | 455 sync_parent(dst); |
| 441 if (src != dst) | 456 if (src != dst) |
| 442 sync_parent(src); | 457 sync_parent(src); |
| 443 } | 458 } |
| 444 return result; | 459 return result; |
| 445 } | 460 } |
| 446 | 461 |
| 447 virtual Status LockFile(const std::string& fname, FileLock** lock) { | 462 virtual Status LockFile(const std::string& fname, FileLock** lock) { |
| 448 *lock = NULL; | 463 *lock = NULL; |
| 449 Status result; | 464 Status result; |
| 450 int flags = ::base::PLATFORM_FILE_OPEN_ALWAYS | | 465 int flags = ::base::PLATFORM_FILE_OPEN_ALWAYS | |
| 451 ::base::PLATFORM_FILE_READ | | 466 ::base::PLATFORM_FILE_READ | |
| 452 ::base::PLATFORM_FILE_WRITE | | 467 ::base::PLATFORM_FILE_WRITE | |
| 453 ::base::PLATFORM_FILE_EXCLUSIVE_READ | | 468 ::base::PLATFORM_FILE_EXCLUSIVE_READ | |
| 454 ::base::PLATFORM_FILE_EXCLUSIVE_WRITE; | 469 ::base::PLATFORM_FILE_EXCLUSIVE_WRITE; |
| 455 bool created; | 470 bool created; |
| 456 ::base::PlatformFileError error_code; | 471 ::base::PlatformFileError error_code; |
| 457 ::base::PlatformFile file = ::base::CreatePlatformFile( | 472 ::base::PlatformFile file = ::base::CreatePlatformFile( |
| 458 CreateFilePath(fname), flags, &created, &error_code); | 473 CreateFilePath(fname), flags, &created, &error_code); |
| 459 if (error_code != ::base::PLATFORM_FILE_OK) { | 474 if (error_code != ::base::PLATFORM_FILE_OK) { |
| 460 result = Status::IOError(fname, PlatformFileErrorString(error_code)); | 475 result = Status::IOError(fname, PlatformFileErrorString(error_code)); |
| 461 LogToUMA(kLockFile); | 476 uma_logger_->RecordErrorAt(kLockFile); |
| 462 } else { | 477 } else { |
| 463 ChromiumFileLock* my_lock = new ChromiumFileLock; | 478 ChromiumFileLock* my_lock = new ChromiumFileLock; |
| 464 my_lock->file_ = file; | 479 my_lock->file_ = file; |
| 465 *lock = my_lock; | 480 *lock = my_lock; |
| 466 } | 481 } |
| 467 return result; | 482 return result; |
| 468 } | 483 } |
| 469 | 484 |
| 470 virtual Status UnlockFile(FileLock* lock) { | 485 virtual Status UnlockFile(FileLock* lock) { |
| 471 ChromiumFileLock* my_lock = reinterpret_cast<ChromiumFileLock*>(lock); | 486 ChromiumFileLock* my_lock = reinterpret_cast<ChromiumFileLock*>(lock); |
| 472 Status result; | 487 Status result; |
| 473 if (!::base::ClosePlatformFile(my_lock->file_)) { | 488 if (!::base::ClosePlatformFile(my_lock->file_)) { |
| 474 result = Status::IOError("Could not close lock file."); | 489 result = Status::IOError("Could not close lock file."); |
| 475 LogToUMA(kUnlockFile); | 490 uma_logger_->RecordErrorAt(kUnlockFile); |
| 476 } | 491 } |
| 477 delete my_lock; | 492 delete my_lock; |
| 478 return result; | 493 return result; |
| 479 } | 494 } |
| 480 | 495 |
| 481 virtual void Schedule(void (*function)(void*), void* arg); | 496 virtual void Schedule(void (*function)(void*), void* arg); |
| 482 | 497 |
| 483 virtual void StartThread(void (*function)(void* arg), void* arg); | 498 virtual void StartThread(void (*function)(void* arg), void* arg); |
| 484 | 499 |
| 485 virtual std::string UserIdentifier() { | 500 virtual std::string UserIdentifier() { |
| 486 #if defined(OS_WIN) | 501 #if defined(OS_WIN) |
| 487 std::wstring user_sid; | 502 std::wstring user_sid; |
| 488 bool ret = ::base::win::GetUserSidString(&user_sid); | 503 bool ret = ::base::win::GetUserSidString(&user_sid); |
| 489 DCHECK(ret); | 504 DCHECK(ret); |
| 490 return UTF16ToUTF8(user_sid); | 505 return UTF16ToUTF8(user_sid); |
| 491 #else | 506 #else |
| 492 char buf[100]; | 507 char buf[100]; |
| 493 snprintf(buf, sizeof(buf), "%d", int(geteuid())); | 508 snprintf(buf, sizeof(buf), "%d", int(geteuid())); |
| 494 return buf; | 509 return buf; |
| 495 #endif | 510 #endif |
| 496 } | 511 } |
| 497 | 512 |
| 498 virtual Status GetTestDirectory(std::string* path) { | 513 virtual Status GetTestDirectory(std::string* path) { |
| 499 mu_.Acquire(); | 514 mu_.Acquire(); |
| 500 if (test_directory_.empty()) { | 515 if (test_directory_.empty()) { |
| 501 if (!::file_util::CreateNewTempDirectory(kLevelDBTestDirectoryPrefix, | 516 if (!::file_util::CreateNewTempDirectory(kLevelDBTestDirectoryPrefix, |
| 502 &test_directory_)) { | 517 &test_directory_)) { |
| 503 mu_.Release(); | 518 mu_.Release(); |
| 504 LogToUMA(kGetTestDirectory); | 519 uma_logger_->RecordErrorAt(kGetTestDirectory); |
| 505 return Status::IOError("Could not create temp directory."); | 520 return Status::IOError("Could not create temp directory."); |
| 506 } | 521 } |
| 507 } | 522 } |
| 508 *path = FilePathToString(test_directory_); | 523 *path = FilePathToString(test_directory_); |
| 509 mu_.Release(); | 524 mu_.Release(); |
| 510 return Status::OK(); | 525 return Status::OK(); |
| 511 } | 526 } |
| 512 | 527 |
| 513 virtual Status NewLogger(const std::string& fname, Logger** result) { | 528 virtual Status NewLogger(const std::string& fname, Logger** result) { |
| 514 FILE* f = fopen_internal(fname.c_str(), "w"); | 529 FILE* f = fopen_internal(fname.c_str(), "w"); |
| 515 if (f == NULL) { | 530 if (f == NULL) { |
| 516 *result = NULL; | 531 *result = NULL; |
| 517 LogToUMA(kNewLogger); | 532 uma_logger_->RecordErrorAt(kNewLogger); |
| 518 return Status::IOError(fname, strerror(errno)); | 533 return Status::IOError(fname, strerror(errno)); |
| 519 } else { | 534 } else { |
| 520 if (!sync_parent(fname)) { | 535 if (!sync_parent(fname)) { |
| 521 fclose(f); | 536 fclose(f); |
| 522 return Status::IOError(fname, strerror(errno)); | 537 return Status::IOError(fname, strerror(errno)); |
| 523 } | 538 } |
| 524 *result = new ChromiumLogger(f); | 539 *result = new ChromiumLogger(f); |
| 525 return Status::OK(); | 540 return Status::OK(); |
| 526 } | 541 } |
| 527 } | 542 } |
| 528 | 543 |
| 529 virtual uint64_t NowMicros() { | 544 virtual uint64_t NowMicros() { |
| 530 return ::base::TimeTicks::Now().ToInternalValue(); | 545 return ::base::TimeTicks::Now().ToInternalValue(); |
| 531 } | 546 } |
| 532 | 547 |
| 533 virtual void SleepForMicroseconds(int micros) { | 548 virtual void SleepForMicroseconds(int micros) { |
| 534 // Round up to the next millisecond. | 549 // Round up to the next millisecond. |
| 535 ::base::PlatformThread::Sleep(::base::TimeDelta::FromMicroseconds(micros)); | 550 ::base::PlatformThread::Sleep(::base::TimeDelta::FromMicroseconds(micros)); |
| 536 } | 551 } |
| 537 | 552 |
| 553 protected: | |
| 554 scoped_ptr<UMALogger> uma_logger_; | |
| 555 | |
| 538 private: | 556 private: |
| 539 // BGThread() is the body of the background thread | 557 // BGThread() is the body of the background thread |
| 540 void BGThread(); | 558 void BGThread(); |
| 541 static void BGThreadWrapper(void* arg) { | 559 static void BGThreadWrapper(void* arg) { |
| 542 reinterpret_cast<ChromiumEnv*>(arg)->BGThread(); | 560 reinterpret_cast<ChromiumEnv*>(arg)->BGThread(); |
| 543 } | 561 } |
| 544 | 562 |
| 545 FilePath test_directory_; | 563 FilePath test_directory_; |
| 546 | 564 |
| 547 size_t page_size_; | 565 size_t page_size_; |
| 548 ::base::Lock mu_; | 566 ::base::Lock mu_; |
| 549 ::base::ConditionVariable bgsignal_; | 567 ::base::ConditionVariable bgsignal_; |
| 550 bool started_bgthread_; | 568 bool started_bgthread_; |
| 551 | 569 |
| 552 // Entry per Schedule() call | 570 // Entry per Schedule() call |
| 553 struct BGItem { void* arg; void (*function)(void*); }; | 571 struct BGItem { void* arg; void (*function)(void*); }; |
| 554 typedef std::deque<BGItem> BGQueue; | 572 typedef std::deque<BGItem> BGQueue; |
| 555 BGQueue queue_; | 573 BGQueue queue_; |
| 556 }; | 574 }; |
| 557 | 575 |
| 558 ChromiumEnv::ChromiumEnv() | 576 ChromiumEnv::ChromiumEnv() |
| 559 : page_size_(::base::SysInfo::VMAllocationGranularity()), | 577 : page_size_(::base::SysInfo::VMAllocationGranularity()), |
| 560 bgsignal_(&mu_), | 578 bgsignal_(&mu_), |
| 561 started_bgthread_(false) { | 579 started_bgthread_(false), |
| 580 uma_logger_(new UMALogger("LevelDBEnv")) { | |
| 562 } | 581 } |
| 563 | 582 |
| 564 class Thread : public ::base::PlatformThread::Delegate { | 583 class Thread : public ::base::PlatformThread::Delegate { |
| 565 public: | 584 public: |
| 566 Thread(void (*function)(void* arg), void* arg) | 585 Thread(void (*function)(void* arg), void* arg) |
| 567 : function_(function), arg_(arg) { | 586 : function_(function), arg_(arg) { |
| 568 ::base::PlatformThreadHandle handle; | 587 ::base::PlatformThreadHandle handle; |
| 569 bool success = ::base::PlatformThread::Create(0, this, &handle); | 588 bool success = ::base::PlatformThread::Create(0, this, &handle); |
| 570 DCHECK(success); | 589 DCHECK(success); |
| 571 } | 590 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 617 | 636 |
| 618 mu_.Release(); | 637 mu_.Release(); |
| 619 (*function)(arg); | 638 (*function)(arg); |
| 620 } | 639 } |
| 621 } | 640 } |
| 622 | 641 |
| 623 void ChromiumEnv::StartThread(void (*function)(void* arg), void* arg) { | 642 void ChromiumEnv::StartThread(void (*function)(void* arg), void* arg) { |
| 624 new Thread(function, arg); // Will self-delete. | 643 new Thread(function, arg); // Will self-delete. |
| 625 } | 644 } |
| 626 | 645 |
| 646 class IDBEnv : public ChromiumEnv { | |
| 647 public: | |
| 648 IDBEnv() : ChromiumEnv() { | |
| 649 uma_logger_.reset(new UMALogger("LevelDBEnv.IDB")); | |
|
jsbell
2013/01/05 00:14:54
Maybe make it a constructor parameter in ChromiumE
jsbell
2013/01/05 00:19:05
Actually, why not have ChromiumEnv take a const ch
dgrogan
2013/01/05 01:05:28
I set out to do something like what you're describ
| |
| 650 } | |
| 651 }; | |
| 652 | |
| 653 ::base::LazyInstance<IDBEnv>::Leaky | |
| 654 idb_env = LAZY_INSTANCE_INITIALIZER; | |
| 655 | |
| 627 ::base::LazyInstance<ChromiumEnv>::Leaky | 656 ::base::LazyInstance<ChromiumEnv>::Leaky |
| 628 default_env = LAZY_INSTANCE_INITIALIZER; | 657 default_env = LAZY_INSTANCE_INITIALIZER; |
| 629 | 658 |
| 630 } | 659 } |
| 631 | 660 |
| 661 Env* IDBEnv() { | |
|
jsbell
2013/01/05 00:14:54
FYI, this may cause some valgrind leak suppression
| |
| 662 return idb_env.Pointer(); | |
| 663 } | |
| 664 | |
| 632 Env* Env::Default() { | 665 Env* Env::Default() { |
| 633 return default_env.Pointer(); | 666 return default_env.Pointer(); |
| 634 } | 667 } |
| 635 | 668 |
| 636 } | 669 } |
| OLD | NEW |