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 |