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

Side by Side Diff: net/base/file_stream_posix.cc

Issue 7583049: Record UMA statistics for file_stream operations. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed Posix compile error. Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698