 Chromium Code Reviews
 Chromium Code Reviews Issue 7583049:
  Record UMA statistics for file_stream operations.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 7583049:
  Record UMA statistics for file_stream operations.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| OLD | NEW | 
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium 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. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 // For 64-bit file access (off_t = off64_t, lseek64, etc). | 5 // For 64-bit file access (off_t = off64_t, lseek64, etc). | 
| 6 #define _FILE_OFFSET_BITS 64 | 6 #define _FILE_OFFSET_BITS 64 | 
| 7 | 7 | 
| 8 #include "net/base/file_stream.h" | 8 #include "net/base/file_stream.h" | 
| 9 | 9 | 
| 10 #include <sys/types.h> | 10 #include <sys/types.h> | 
| 11 #include <sys/stat.h> | 11 #include <sys/stat.h> | 
| 12 #include <fcntl.h> | 12 #include <fcntl.h> | 
| 13 #include <unistd.h> | 13 #include <unistd.h> | 
| 14 #include <errno.h> | 14 #include <errno.h> | 
| 15 | 15 | 
| 16 #include "base/basictypes.h" | 16 #include "base/basictypes.h" | 
| 17 #include "base/callback.h" | 17 #include "base/callback.h" | 
| 18 #include "base/eintr_wrapper.h" | 18 #include "base/eintr_wrapper.h" | 
| 19 #include "base/file_path.h" | 19 #include "base/file_path.h" | 
| 20 #include "base/logging.h" | 20 #include "base/logging.h" | 
| 21 #include "base/message_loop.h" | 21 #include "base/message_loop.h" | 
| 22 #include "base/metrics/histogram.h" | 22 #include "base/metrics/histogram.h" | 
| 23 #include "base/string_util.h" | 23 #include "base/string_util.h" | 
| 24 #include "base/task.h" | 24 #include "base/task.h" | 
| 25 #include "base/threading/thread_restrictions.h" | 25 #include "base/threading/thread_restrictions.h" | 
| 26 #include "base/threading/worker_pool.h" | 26 #include "base/threading/worker_pool.h" | 
| 27 #include "base/synchronization/waitable_event.h" | 27 #include "base/synchronization/waitable_event.h" | 
| 28 #include "net/base/file_stream_metrics.h" | |
| 28 #include "net/base/net_errors.h" | 29 #include "net/base/net_errors.h" | 
| 29 | 30 | 
| 30 #if defined(OS_ANDROID) | 31 #if defined(OS_ANDROID) | 
| 31 // Android's bionic libc only supports the LFS transitional API. | 32 // Android's bionic libc only supports the LFS transitional API. | 
| 32 #define off_t off64_t | 33 #define off_t off64_t | 
| 33 #define lseek lseek64 | 34 #define lseek lseek64 | 
| 34 #define stat stat64 | 35 #define stat stat64 | 
| 35 #define fstat fstat64 | 36 #define fstat fstat64 | 
| 36 #endif | 37 #endif | 
| 37 | 38 | 
| (...skipping 17 matching lines...) Expand all Loading... | |
| 55 case EACCES: | 56 case EACCES: | 
| 56 return ERR_ACCESS_DENIED; | 57 return ERR_ACCESS_DENIED; | 
| 57 default: | 58 default: | 
| 58 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; | 59 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; | 
| 59 return ERR_FAILED; | 60 return ERR_FAILED; | 
| 60 } | 61 } | 
| 61 } | 62 } | 
| 62 | 63 | 
| 63 // ReadFile() is a simple wrapper around read() that handles EINTR signals and | 64 // ReadFile() is a simple wrapper around read() that handles EINTR signals and | 
| 64 // calls MapErrorCode() to map errno to net error codes. | 65 // calls MapErrorCode() to map errno to net error codes. | 
| 65 int ReadFile(base::PlatformFile file, char* buf, int buf_len) { | 66 int ReadFile(base::PlatformFile file, char* buf, int buf_len, bool record_uma) { | 
| 66 base::ThreadRestrictions::AssertIOAllowed(); | 67 base::ThreadRestrictions::AssertIOAllowed(); | 
| 67 // read(..., 0) returns 0 to indicate end-of-file. | 68 // read(..., 0) returns 0 to indicate end-of-file. | 
| 68 | 69 | 
| 69 // Loop in the case of getting interrupted by a signal. | 70 // Loop in the case of getting interrupted by a signal. | 
| 70 ssize_t res = HANDLE_EINTR(read(file, buf, static_cast<size_t>(buf_len))); | 71 ssize_t res = HANDLE_EINTR(read(file, buf, static_cast<size_t>(buf_len))); | 
| 71 if (res == static_cast<ssize_t>(-1)) | 72 if (res == static_cast<ssize_t>(-1)) { | 
| 72 return MapErrorCode(errno); | 73 int error = errno; | 
| 
cbentzel
2011/08/18 13:31:28
Why don't you call RecordAndMapErrorCode(errno, FI
 
ahendrickson
2011/08/18 15:56:45
Now that RecordAndMapErrorCode is no longer a memb
 | |
| 74 RecordFileError(error, FILE_ERROR_SOURCE_READ, record_uma); | |
| 75 return MapErrorCode(error); | |
| 76 } | |
| 73 return static_cast<int>(res); | 77 return static_cast<int>(res); | 
| 74 } | 78 } | 
| 75 | 79 | 
| 76 void ReadFileTask(base::PlatformFile file, | 80 void ReadFileTask(base::PlatformFile file, | 
| 77 char* buf, | 81 char* buf, | 
| 78 int buf_len, | 82 int buf_len, | 
| 83 bool record_uma, | |
| 79 CompletionCallback* callback) { | 84 CompletionCallback* callback) { | 
| 80 callback->Run(ReadFile(file, buf, buf_len)); | 85 callback->Run(ReadFile(file, buf, buf_len, record_uma)); | 
| 81 } | 86 } | 
| 82 | 87 | 
| 83 // WriteFile() is a simple wrapper around write() that handles EINTR signals and | 88 // WriteFile() is a simple wrapper around write() that handles EINTR signals and | 
| 84 // calls MapErrorCode() to map errno to net error codes. It tries to write to | 89 // calls MapErrorCode() to map errno to net error codes. It tries to write to | 
| 85 // completion. | 90 // completion. | 
| 86 int WriteFile(base::PlatformFile file, const char* buf, int buf_len) { | 91 int WriteFile(base::PlatformFile file, const char* buf, int buf_len, | 
| 92 bool record_uma) { | |
| 87 base::ThreadRestrictions::AssertIOAllowed(); | 93 base::ThreadRestrictions::AssertIOAllowed(); | 
| 88 ssize_t res = HANDLE_EINTR(write(file, buf, buf_len)); | 94 ssize_t res = HANDLE_EINTR(write(file, buf, buf_len)); | 
| 89 if (res == -1) | 95 if (res == -1) { | 
| 90 return MapErrorCode(errno); | 96 int error = errno; | 
| 97 RecordFileError(error, FILE_ERROR_SOURCE_WRITE, record_uma); | |
| 98 return MapErrorCode(error); | |
| 99 } | |
| 91 return res; | 100 return res; | 
| 92 } | 101 } | 
| 93 | 102 | 
| 94 void WriteFileTask(base::PlatformFile file, | 103 void WriteFileTask(base::PlatformFile file, | 
| 95 const char* buf, | 104 const char* buf, | 
| 96 int buf_len, | 105 int buf_len, bool record_uma, | 
| 97 CompletionCallback* callback) { | 106 CompletionCallback* callback) { | 
| 98 callback->Run(WriteFile(file, buf, buf_len)); | 107 callback->Run(WriteFile(file, buf, buf_len, record_uma)); | 
| 99 } | 108 } | 
| 100 | 109 | 
| 101 // FlushFile() is a simple wrapper around fsync() that handles EINTR signals and | 110 // FlushFile() is a simple wrapper around fsync() that handles EINTR signals and | 
| 102 // calls MapErrorCode() to map errno to net error codes. It tries to flush to | 111 // calls MapErrorCode() to map errno to net error codes. It tries to flush to | 
| 103 // completion. | 112 // completion. | 
| 104 int FlushFile(base::PlatformFile file) { | 113 int FlushFile(base::PlatformFile file, bool record_uma) { | 
| 105 base::ThreadRestrictions::AssertIOAllowed(); | 114 base::ThreadRestrictions::AssertIOAllowed(); | 
| 106 ssize_t res = HANDLE_EINTR(fsync(file)); | 115 ssize_t res = HANDLE_EINTR(fsync(file)); | 
| 107 if (res == -1) | 116 if (res == -1) { | 
| 108 return MapErrorCode(errno); | 117 int error = errno; | 
| 118 RecordFileError(error, FILE_ERROR_SOURCE_FLUSH, record_uma); | |
| 119 return MapErrorCode(error); | |
| 120 } | |
| 109 return res; | 121 return res; | 
| 110 } | 122 } | 
| 111 | 123 | 
| 112 } // namespace | 124 } // namespace | 
| 113 | 125 | 
| 114 // CancelableCallbackTask takes ownership of the Callback. This task gets | 126 // CancelableCallbackTask takes ownership of the Callback. This task gets | 
| 115 // posted to the MessageLoopForIO instance. | 127 // posted to the MessageLoopForIO instance. | 
| 116 class CancelableCallbackTask : public CancelableTask { | 128 class CancelableCallbackTask : public CancelableTask { | 
| 117 public: | 129 public: | 
| 118 explicit CancelableCallbackTask(Callback0::Type* callback) | 130 explicit CancelableCallbackTask(Callback0::Type* callback) | 
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 150 CompletionCallback* callback() const { return callback_; } | 162 CompletionCallback* callback() const { return callback_; } | 
| 151 | 163 | 
| 152 // Called by the WorkerPool thread executing the IO after the IO completes. | 164 // Called by the WorkerPool thread executing the IO after the IO completes. | 
| 153 // This method queues RunAsynchronousCallback() on the MessageLoop and signals | 165 // This method queues RunAsynchronousCallback() on the MessageLoop and signals | 
| 154 // |background_io_completed_callback_|, in case the destructor is waiting. In | 166 // |background_io_completed_callback_|, in case the destructor is waiting. In | 
| 155 // that case, the destructor will call RunAsynchronousCallback() instead, and | 167 // that case, the destructor will call RunAsynchronousCallback() instead, and | 
| 156 // cancel |message_loop_task_|. | 168 // cancel |message_loop_task_|. | 
| 157 // |result| is the result of the Read/Write task. | 169 // |result| is the result of the Read/Write task. | 
| 158 void OnBackgroundIOCompleted(int result); | 170 void OnBackgroundIOCompleted(int result); | 
| 159 | 171 | 
| 172 void EnableErrorStatistics() { | |
| 173 record_uma_ = true; | |
| 174 } | |
| 175 | |
| 160 private: | 176 private: | 
| 161 // Always called on the IO thread, either directly by a task on the | 177 // Always called on the IO thread, either directly by a task on the | 
| 162 // MessageLoop or by ~AsyncContext(). | 178 // MessageLoop or by ~AsyncContext(). | 
| 163 void RunAsynchronousCallback(); | 179 void RunAsynchronousCallback(); | 
| 164 | 180 | 
| 165 // The MessageLoopForIO that this AsyncContext is running on. | 181 // The MessageLoopForIO that this AsyncContext is running on. | 
| 166 MessageLoopForIO* const message_loop_; | 182 MessageLoopForIO* const message_loop_; | 
| 167 CompletionCallback* callback_; // The user provided callback. | 183 CompletionCallback* callback_; // The user provided callback. | 
| 168 | 184 | 
| 169 // A callback wrapper around OnBackgroundIOCompleted(). Run by the WorkerPool | 185 // A callback wrapper around OnBackgroundIOCompleted(). Run by the WorkerPool | 
| 170 // thread doing the background IO on our behalf. | 186 // thread doing the background IO on our behalf. | 
| 171 CompletionCallbackImpl<AsyncContext> background_io_completed_callback_; | 187 CompletionCallbackImpl<AsyncContext> background_io_completed_callback_; | 
| 172 | 188 | 
| 173 // This is used to synchronize between the AsyncContext destructor (which runs | 189 // This is used to synchronize between the AsyncContext destructor (which runs | 
| 174 // on the IO thread and OnBackgroundIOCompleted() which runs on the WorkerPool | 190 // on the IO thread and OnBackgroundIOCompleted() which runs on the WorkerPool | 
| 175 // thread. | 191 // thread. | 
| 176 base::WaitableEvent background_io_completed_; | 192 base::WaitableEvent background_io_completed_; | 
| 177 | 193 | 
| 178 // These variables are only valid when background_io_completed is signaled. | 194 // These variables are only valid when background_io_completed is signaled. | 
| 179 int result_; | 195 int result_; | 
| 180 CancelableCallbackTask* message_loop_task_; | 196 CancelableCallbackTask* message_loop_task_; | 
| 181 | 197 | 
| 182 bool is_closing_; | 198 bool is_closing_; | 
| 199 bool record_uma_; | |
| 183 | 200 | 
| 184 DISALLOW_COPY_AND_ASSIGN(AsyncContext); | 201 DISALLOW_COPY_AND_ASSIGN(AsyncContext); | 
| 185 }; | 202 }; | 
| 186 | 203 | 
| 187 FileStream::AsyncContext::AsyncContext() | 204 FileStream::AsyncContext::AsyncContext() | 
| 188 : message_loop_(MessageLoopForIO::current()), | 205 : message_loop_(MessageLoopForIO::current()), | 
| 189 callback_(NULL), | 206 callback_(NULL), | 
| 190 background_io_completed_callback_( | 207 background_io_completed_callback_( | 
| 191 this, &AsyncContext::OnBackgroundIOCompleted), | 208 this, &AsyncContext::OnBackgroundIOCompleted), | 
| 192 background_io_completed_(true, false), | 209 background_io_completed_(true, false), | 
| 193 message_loop_task_(NULL), | 210 message_loop_task_(NULL), | 
| 194 is_closing_(false) {} | 211 is_closing_(false), | 
| 212 record_uma_(false) {} | |
| 195 | 213 | 
| 196 FileStream::AsyncContext::~AsyncContext() { | 214 FileStream::AsyncContext::~AsyncContext() { | 
| 197 is_closing_ = true; | 215 is_closing_ = true; | 
| 198 if (callback_) { | 216 if (callback_) { | 
| 199 // If |callback_| is non-NULL, that implies either the worker thread is | 217 // If |callback_| is non-NULL, that implies either the worker thread is | 
| 200 // still running the IO task, or the completion callback is queued up on the | 218 // still running the IO task, or the completion callback is queued up on the | 
| 201 // MessageLoopForIO, but AsyncContext() got deleted before then. | 219 // MessageLoopForIO, but AsyncContext() got deleted before then. | 
| 202 const bool need_to_wait = !background_io_completed_.IsSignaled(); | 220 const bool need_to_wait = !background_io_completed_.IsSignaled(); | 
| 203 base::TimeTicks start = base::TimeTicks::Now(); | 221 base::TimeTicks start = base::TimeTicks::Now(); | 
| 204 RunAsynchronousCallback(); | 222 RunAsynchronousCallback(); | 
| 205 if (need_to_wait) { | 223 if (need_to_wait) { | 
| 206 // We want to see if we block the message loop for too long. | 224 // We want to see if we block the message loop for too long. | 
| 207 UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose", | 225 UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose", | 
| 208 base::TimeTicks::Now() - start); | 226 base::TimeTicks::Now() - start); | 
| 209 } | 227 } | 
| 210 } | 228 } | 
| 211 } | 229 } | 
| 212 | 230 | 
| 213 void FileStream::AsyncContext::InitiateAsyncRead( | 231 void FileStream::AsyncContext::InitiateAsyncRead( | 
| 214 base::PlatformFile file, char* buf, int buf_len, | 232 base::PlatformFile file, char* buf, int buf_len, | 
| 215 CompletionCallback* callback) { | 233 CompletionCallback* callback) { | 
| 216 DCHECK(!callback_); | 234 DCHECK(!callback_); | 
| 217 callback_ = callback; | 235 callback_ = callback; | 
| 218 | 236 | 
| 219 base::WorkerPool::PostTask(FROM_HERE, | 237 base::WorkerPool::PostTask(FROM_HERE, | 
| 220 NewRunnableFunction( | 238 NewRunnableFunction( | 
| 221 &ReadFileTask, | 239 &ReadFileTask, | 
| 222 file, buf, buf_len, | 240 file, buf, buf_len, | 
| 241 record_uma_, | |
| 223 &background_io_completed_callback_), | 242 &background_io_completed_callback_), | 
| 224 true /* task_is_slow */); | 243 true /* task_is_slow */); | 
| 225 } | 244 } | 
| 226 | 245 | 
| 227 void FileStream::AsyncContext::InitiateAsyncWrite( | 246 void FileStream::AsyncContext::InitiateAsyncWrite( | 
| 228 base::PlatformFile file, const char* buf, int buf_len, | 247 base::PlatformFile file, const char* buf, int buf_len, | 
| 229 CompletionCallback* callback) { | 248 CompletionCallback* callback) { | 
| 230 DCHECK(!callback_); | 249 DCHECK(!callback_); | 
| 231 callback_ = callback; | 250 callback_ = callback; | 
| 232 | 251 | 
| 233 base::WorkerPool::PostTask(FROM_HERE, | 252 base::WorkerPool::PostTask(FROM_HERE, | 
| 234 NewRunnableFunction( | 253 NewRunnableFunction( | 
| 235 &WriteFileTask, | 254 &WriteFileTask, | 
| 236 file, buf, buf_len, | 255 file, buf, buf_len, | 
| 256 record_uma_, | |
| 237 &background_io_completed_callback_), | 257 &background_io_completed_callback_), | 
| 238 true /* task_is_slow */); | 258 true /* task_is_slow */); | 
| 239 } | 259 } | 
| 240 | 260 | 
| 241 void FileStream::AsyncContext::OnBackgroundIOCompleted(int result) { | 261 void FileStream::AsyncContext::OnBackgroundIOCompleted(int result) { | 
| 242 result_ = result; | 262 result_ = result; | 
| 243 message_loop_task_ = new CancelableCallbackTask( | 263 message_loop_task_ = new CancelableCallbackTask( | 
| 244 NewCallback(this, &AsyncContext::RunAsynchronousCallback)); | 264 NewCallback(this, &AsyncContext::RunAsynchronousCallback)); | 
| 245 message_loop_->PostTask(FROM_HERE, message_loop_task_); | 265 message_loop_->PostTask(FROM_HERE, message_loop_task_); | 
| 246 background_io_completed_.Signal(); | 266 background_io_completed_.Signal(); | 
| (...skipping 20 matching lines...) Expand all Loading... | |
| 267 std::swap(temp, callback_); | 287 std::swap(temp, callback_); | 
| 268 background_io_completed_.Reset(); | 288 background_io_completed_.Reset(); | 
| 269 temp->Run(result_); | 289 temp->Run(result_); | 
| 270 } | 290 } | 
| 271 | 291 | 
| 272 // FileStream ------------------------------------------------------------ | 292 // FileStream ------------------------------------------------------------ | 
| 273 | 293 | 
| 274 FileStream::FileStream() | 294 FileStream::FileStream() | 
| 275 : file_(base::kInvalidPlatformFileValue), | 295 : file_(base::kInvalidPlatformFileValue), | 
| 276 open_flags_(0), | 296 open_flags_(0), | 
| 277 auto_closed_(true) { | 297 auto_closed_(false), | 
| 298 record_uma_(false) { | |
| 278 DCHECK(!IsOpen()); | 299 DCHECK(!IsOpen()); | 
| 279 } | 300 } | 
| 280 | 301 | 
| 281 FileStream::FileStream(base::PlatformFile file, int flags) | 302 FileStream::FileStream(base::PlatformFile file, int flags) | 
| 282 : file_(file), | 303 : file_(file), | 
| 283 open_flags_(flags), | 304 open_flags_(flags), | 
| 284 auto_closed_(false) { | 305 auto_closed_(false), | 
| 306 record_uma_(false) { | |
| 285 // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to | 307 // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to | 
| 286 // make sure we will perform asynchronous File IO to it. | 308 // make sure we will perform asynchronous File IO to it. | 
| 287 if (flags & base::PLATFORM_FILE_ASYNC) { | 309 if (flags & base::PLATFORM_FILE_ASYNC) { | 
| 288 async_context_.reset(new AsyncContext()); | 310 async_context_.reset(new AsyncContext()); | 
| 289 } | 311 } | 
| 290 } | 312 } | 
| 291 | 313 | 
| 292 FileStream::~FileStream() { | 314 FileStream::~FileStream() { | 
| 293 if (auto_closed_) | 315 if (auto_closed_) | 
| 294 Close(); | 316 Close(); | 
| (...skipping 12 matching lines...) Expand all Loading... | |
| 307 } | 329 } | 
| 308 | 330 | 
| 309 int FileStream::Open(const FilePath& path, int open_flags) { | 331 int FileStream::Open(const FilePath& path, int open_flags) { | 
| 310 if (IsOpen()) { | 332 if (IsOpen()) { | 
| 311 DLOG(FATAL) << "File is already open!"; | 333 DLOG(FATAL) << "File is already open!"; | 
| 312 return ERR_UNEXPECTED; | 334 return ERR_UNEXPECTED; | 
| 313 } | 335 } | 
| 314 | 336 | 
| 315 open_flags_ = open_flags; | 337 open_flags_ = open_flags; | 
| 316 file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL); | 338 file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL); | 
| 317 if (file_ == base::kInvalidPlatformFileValue) { | 339 if (file_ == base::kInvalidPlatformFileValue) | 
| 318 return MapErrorCode(errno); | 340 return RecordAndMapError(errno, FILE_ERROR_SOURCE_OPEN); | 
| 319 } | |
| 320 | 341 | 
| 321 if (open_flags_ & base::PLATFORM_FILE_ASYNC) { | 342 if (open_flags_ & base::PLATFORM_FILE_ASYNC) | 
| 322 async_context_.reset(new AsyncContext()); | 343 async_context_.reset(new AsyncContext()); | 
| 323 } | |
| 324 | 344 | 
| 325 return OK; | 345 return OK; | 
| 326 } | 346 } | 
| 327 | 347 | 
| 328 bool FileStream::IsOpen() const { | 348 bool FileStream::IsOpen() const { | 
| 329 return file_ != base::kInvalidPlatformFileValue; | 349 return file_ != base::kInvalidPlatformFileValue; | 
| 330 } | 350 } | 
| 331 | 351 | 
| 332 int64 FileStream::Seek(Whence whence, int64 offset) { | 352 int64 FileStream::Seek(Whence whence, int64 offset) { | 
| 333 base::ThreadRestrictions::AssertIOAllowed(); | 353 base::ThreadRestrictions::AssertIOAllowed(); | 
| 334 | 354 | 
| 335 if (!IsOpen()) | 355 if (!IsOpen()) | 
| 336 return ERR_UNEXPECTED; | 356 return ERR_UNEXPECTED; | 
| 337 | 357 | 
| 338 // If we're in async, make sure we don't have a request in flight. | 358 // If we're in async, make sure we don't have a request in flight. | 
| 339 DCHECK(!async_context_.get() || !async_context_->callback()); | 359 DCHECK(!async_context_.get() || !async_context_->callback()); | 
| 340 | 360 | 
| 341 off_t res = lseek(file_, static_cast<off_t>(offset), | 361 off_t res = lseek(file_, static_cast<off_t>(offset), | 
| 342 static_cast<int>(whence)); | 362 static_cast<int>(whence)); | 
| 343 if (res == static_cast<off_t>(-1)) | 363 if (res == static_cast<off_t>(-1)) | 
| 344 return MapErrorCode(errno); | 364 return RecordAndMapError(errno, FILE_ERROR_SOURCE_SEEK); | 
| 345 | 365 | 
| 346 return res; | 366 return res; | 
| 347 } | 367 } | 
| 348 | 368 | 
| 349 int64 FileStream::Available() { | 369 int64 FileStream::Available() { | 
| 350 base::ThreadRestrictions::AssertIOAllowed(); | 370 base::ThreadRestrictions::AssertIOAllowed(); | 
| 351 | 371 | 
| 352 if (!IsOpen()) | 372 if (!IsOpen()) | 
| 353 return ERR_UNEXPECTED; | 373 return ERR_UNEXPECTED; | 
| 354 | 374 | 
| 355 int64 cur_pos = Seek(FROM_CURRENT, 0); | 375 int64 cur_pos = Seek(FROM_CURRENT, 0); | 
| 356 if (cur_pos < 0) | 376 if (cur_pos < 0) | 
| 357 return cur_pos; | 377 return cur_pos; | 
| 358 | 378 | 
| 359 struct stat info; | 379 struct stat info; | 
| 360 if (fstat(file_, &info) != 0) | 380 if (fstat(file_, &info) != 0) | 
| 361 return MapErrorCode(errno); | 381 return RecordAndMapError(errno, FILE_ERROR_SOURCE_GET_SIZE); | 
| 362 | 382 | 
| 363 int64 size = static_cast<int64>(info.st_size); | 383 int64 size = static_cast<int64>(info.st_size); | 
| 364 DCHECK_GT(size, cur_pos); | 384 DCHECK_GT(size, cur_pos); | 
| 365 | 385 | 
| 366 return size - cur_pos; | 386 return size - cur_pos; | 
| 367 } | 387 } | 
| 368 | 388 | 
| 369 int FileStream::Read( | 389 int FileStream::Read( | 
| 370 char* buf, int buf_len, CompletionCallback* callback) { | 390 char* buf, int buf_len, CompletionCallback* callback) { | 
| 371 if (!IsOpen()) | 391 if (!IsOpen()) | 
| 372 return ERR_UNEXPECTED; | 392 return ERR_UNEXPECTED; | 
| 373 | 393 | 
| 374 // read(..., 0) will return 0, which indicates end-of-file. | 394 // read(..., 0) will return 0, which indicates end-of-file. | 
| 375 DCHECK(buf_len > 0); | 395 DCHECK(buf_len > 0); | 
| 376 DCHECK(open_flags_ & base::PLATFORM_FILE_READ); | 396 DCHECK(open_flags_ & base::PLATFORM_FILE_READ); | 
| 377 | 397 | 
| 378 if (async_context_.get()) { | 398 if (async_context_.get()) { | 
| 379 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); | 399 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); | 
| 380 // If we're in async, make sure we don't have a request in flight. | 400 // If we're in async, make sure we don't have a request in flight. | 
| 381 DCHECK(!async_context_->callback()); | 401 DCHECK(!async_context_->callback()); | 
| 402 if (record_uma_) | |
| 403 async_context_->EnableErrorStatistics(); | |
| 382 async_context_->InitiateAsyncRead(file_, buf, buf_len, callback); | 404 async_context_->InitiateAsyncRead(file_, buf, buf_len, callback); | 
| 383 return ERR_IO_PENDING; | 405 return ERR_IO_PENDING; | 
| 384 } else { | 406 } else { | 
| 385 return ReadFile(file_, buf, buf_len); | 407 return ReadFile(file_, buf, buf_len, record_uma_); | 
| 386 } | 408 } | 
| 387 } | 409 } | 
| 388 | 410 | 
| 389 int FileStream::ReadUntilComplete(char *buf, int buf_len) { | 411 int FileStream::ReadUntilComplete(char *buf, int buf_len) { | 
| 390 int to_read = buf_len; | 412 int to_read = buf_len; | 
| 391 int bytes_total = 0; | 413 int bytes_total = 0; | 
| 392 | 414 | 
| 393 do { | 415 do { | 
| 394 int bytes_read = Read(buf, to_read, NULL); | 416 int bytes_read = Read(buf, to_read, NULL); | 
| 395 if (bytes_read <= 0) { | 417 if (bytes_read <= 0) { | 
| (...skipping 16 matching lines...) Expand all Loading... | |
| 412 // write(..., 0) will return 0, which indicates end-of-file. | 434 // write(..., 0) will return 0, which indicates end-of-file. | 
| 413 DCHECK_GT(buf_len, 0); | 435 DCHECK_GT(buf_len, 0); | 
| 414 | 436 | 
| 415 if (!IsOpen()) | 437 if (!IsOpen()) | 
| 416 return ERR_UNEXPECTED; | 438 return ERR_UNEXPECTED; | 
| 417 | 439 | 
| 418 if (async_context_.get()) { | 440 if (async_context_.get()) { | 
| 419 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); | 441 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); | 
| 420 // If we're in async, make sure we don't have a request in flight. | 442 // If we're in async, make sure we don't have a request in flight. | 
| 421 DCHECK(!async_context_->callback()); | 443 DCHECK(!async_context_->callback()); | 
| 444 if (record_uma_) | |
| 445 async_context_->EnableErrorStatistics(); | |
| 422 async_context_->InitiateAsyncWrite(file_, buf, buf_len, callback); | 446 async_context_->InitiateAsyncWrite(file_, buf, buf_len, callback); | 
| 423 return ERR_IO_PENDING; | 447 return ERR_IO_PENDING; | 
| 424 } else { | 448 } else { | 
| 425 return WriteFile(file_, buf, buf_len); | 449 return WriteFile(file_, buf, buf_len, record_uma_); | 
| 426 } | 450 } | 
| 427 } | 451 } | 
| 428 | 452 | 
| 429 int64 FileStream::Truncate(int64 bytes) { | 453 int64 FileStream::Truncate(int64 bytes) { | 
| 430 base::ThreadRestrictions::AssertIOAllowed(); | 454 base::ThreadRestrictions::AssertIOAllowed(); | 
| 431 | 455 | 
| 432 if (!IsOpen()) | 456 if (!IsOpen()) | 
| 433 return ERR_UNEXPECTED; | 457 return ERR_UNEXPECTED; | 
| 434 | 458 | 
| 435 // We better be open for reading. | 459 // We better be open for reading. | 
| 436 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); | 460 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); | 
| 437 | 461 | 
| 438 // Seek to the position to truncate from. | 462 // Seek to the position to truncate from. | 
| 439 int64 seek_position = Seek(FROM_BEGIN, bytes); | 463 int64 seek_position = Seek(FROM_BEGIN, bytes); | 
| 440 if (seek_position != bytes) | 464 if (seek_position != bytes) | 
| 441 return ERR_UNEXPECTED; | 465 return ERR_UNEXPECTED; | 
| 442 | 466 | 
| 443 // And truncate the file. | 467 // And truncate the file. | 
| 444 int result = ftruncate(file_, bytes); | 468 int result = HANDLE_EINTR(ftruncate(file_, bytes)); | 
| 445 return result == 0 ? seek_position : MapErrorCode(errno); | 469 if (result == 0) | 
| 470 return seek_position; | |
| 471 | |
| 472 return RecordAndMapError(errno, FILE_ERROR_SOURCE_SET_EOF); | |
| 446 } | 473 } | 
| 447 | 474 | 
| 448 int FileStream::Flush() { | 475 int FileStream::Flush() { | 
| 449 if (!IsOpen()) | 476 if (!IsOpen()) | 
| 450 return ERR_UNEXPECTED; | 477 return ERR_UNEXPECTED; | 
| 451 | 478 | 
| 452 return FlushFile(file_); | 479 return FlushFile(file_, record_uma_); | 
| 480 } | |
| 481 | |
| 482 void FileStream::EnableErrorStatistics() { | |
| 483 record_uma_ = true; | |
| 484 } | |
| 485 | |
| 486 int FileStream::RecordAndMapError(int error, FileErrorSource source) { | |
| 487 RecordFileError(error, source, record_uma_); | |
| 488 return MapErrorCode(error); | |
| 453 } | 489 } | 
| 454 | 490 | 
| 455 } // namespace net | 491 } // namespace net | 
| OLD | NEW |