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

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: Simplified the UMA error statistics gathering. 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;
74 if (record_uma)
75 RecordFileError(error, FILE_ERROR_SOURCE_READ);
76 return MapErrorCode(error);
77 }
73 return static_cast<int>(res); 78 return static_cast<int>(res);
74 } 79 }
75 80
76 void ReadFileTask(base::PlatformFile file, 81 void ReadFileTask(base::PlatformFile file,
77 char* buf, 82 char* buf,
78 int buf_len, 83 int buf_len,
84 bool record_uma,
79 CompletionCallback* callback) { 85 CompletionCallback* callback) {
80 callback->Run(ReadFile(file, buf, buf_len)); 86 callback->Run(ReadFile(file, buf, buf_len, record_uma));
81 } 87 }
82 88
83 // WriteFile() is a simple wrapper around write() that handles EINTR signals and 89 // 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 90 // calls MapErrorCode() to map errno to net error codes. It tries to write to
85 // completion. 91 // completion.
86 int WriteFile(base::PlatformFile file, const char* buf, int buf_len) { 92 int WriteFile(base::PlatformFile file, const char* buf, int buf_len,
93 bool record_uma) {
87 base::ThreadRestrictions::AssertIOAllowed(); 94 base::ThreadRestrictions::AssertIOAllowed();
88 ssize_t res = HANDLE_EINTR(write(file, buf, buf_len)); 95 ssize_t res = HANDLE_EINTR(write(file, buf, buf_len));
89 if (res == -1) 96 if (res == -1) {
90 return MapErrorCode(errno); 97 int error = errno;
98 if (record_uma)
99 RecordFileError(error, FILE_ERROR_SOURCE_WRITE);
100 return MapErrorCode(error);
101 }
91 return res; 102 return res;
92 } 103 }
93 104
94 void WriteFileTask(base::PlatformFile file, 105 void WriteFileTask(base::PlatformFile file,
95 const char* buf, 106 const char* buf,
96 int buf_len, 107 int buf_len, bool record_uma,
97 CompletionCallback* callback) { 108 CompletionCallback* callback) {
98 callback->Run(WriteFile(file, buf, buf_len)); 109 callback->Run(WriteFile(file, buf, buf_len, record_uma));
99 } 110 }
100 111
101 // FlushFile() is a simple wrapper around fsync() that handles EINTR signals and 112 // 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 113 // calls MapErrorCode() to map errno to net error codes. It tries to flush to
103 // completion. 114 // completion.
104 int FlushFile(base::PlatformFile file) { 115 int FlushFile(base::PlatformFile file, bool record_uma) {
105 base::ThreadRestrictions::AssertIOAllowed(); 116 base::ThreadRestrictions::AssertIOAllowed();
106 ssize_t res = HANDLE_EINTR(fsync(file)); 117 ssize_t res = HANDLE_EINTR(fsync(file));
107 if (res == -1) 118 if (res == -1) {
108 return MapErrorCode(errno); 119 int error = errno;
120 if (record_uma)
121 RecordFileError(error, FILE_ERROR_SOURCE_FLUSH);
122 return MapErrorCode(error);
123 }
109 return res; 124 return res;
110 } 125 }
111 126
112 } // namespace 127 } // namespace
113 128
114 // CancelableCallbackTask takes ownership of the Callback. This task gets 129 // CancelableCallbackTask takes ownership of the Callback. This task gets
115 // posted to the MessageLoopForIO instance. 130 // posted to the MessageLoopForIO instance.
116 class CancelableCallbackTask : public CancelableTask { 131 class CancelableCallbackTask : public CancelableTask {
117 public: 132 public:
118 explicit CancelableCallbackTask(Callback0::Type* callback) 133 explicit CancelableCallbackTask(Callback0::Type* callback)
(...skipping 15 matching lines...) Expand all
134 149
135 // FileStream::AsyncContext ---------------------------------------------- 150 // FileStream::AsyncContext ----------------------------------------------
136 151
137 class FileStream::AsyncContext { 152 class FileStream::AsyncContext {
138 public: 153 public:
139 AsyncContext(); 154 AsyncContext();
140 ~AsyncContext(); 155 ~AsyncContext();
141 156
142 // These methods post synchronous read() and write() calls to a WorkerThread. 157 // These methods post synchronous read() and write() calls to a WorkerThread.
143 void InitiateAsyncRead( 158 void InitiateAsyncRead(
144 base::PlatformFile file, char* buf, int buf_len, 159 base::PlatformFile file, char* buf, int buf_len, bool record_uma,
145 CompletionCallback* callback); 160 CompletionCallback* callback);
146 void InitiateAsyncWrite( 161 void InitiateAsyncWrite(
147 base::PlatformFile file, const char* buf, int buf_len, 162 base::PlatformFile file, const char* buf, int buf_len, bool record_uma,
148 CompletionCallback* callback); 163 CompletionCallback* callback);
149 164
150 CompletionCallback* callback() const { return callback_; } 165 CompletionCallback* callback() const { return callback_; }
151 166
152 // Called by the WorkerPool thread executing the IO after the IO completes. 167 // Called by the WorkerPool thread executing the IO after the IO completes.
153 // This method queues RunAsynchronousCallback() on the MessageLoop and signals 168 // This method queues RunAsynchronousCallback() on the MessageLoop and signals
154 // |background_io_completed_callback_|, in case the destructor is waiting. In 169 // |background_io_completed_callback_|, in case the destructor is waiting. In
155 // that case, the destructor will call RunAsynchronousCallback() instead, and 170 // that case, the destructor will call RunAsynchronousCallback() instead, and
156 // cancel |message_loop_task_|. 171 // cancel |message_loop_task_|.
157 // |result| is the result of the Read/Write task. 172 // |result| is the result of the Read/Write task.
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 RunAsynchronousCallback(); 219 RunAsynchronousCallback();
205 if (need_to_wait) { 220 if (need_to_wait) {
206 // We want to see if we block the message loop for too long. 221 // We want to see if we block the message loop for too long.
207 UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose", 222 UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose",
208 base::TimeTicks::Now() - start); 223 base::TimeTicks::Now() - start);
209 } 224 }
210 } 225 }
211 } 226 }
212 227
213 void FileStream::AsyncContext::InitiateAsyncRead( 228 void FileStream::AsyncContext::InitiateAsyncRead(
214 base::PlatformFile file, char* buf, int buf_len, 229 base::PlatformFile file, char* buf, int buf_len, bool record_uma,
215 CompletionCallback* callback) { 230 CompletionCallback* callback) {
216 DCHECK(!callback_); 231 DCHECK(!callback_);
217 callback_ = callback; 232 callback_ = callback;
218 233
219 base::WorkerPool::PostTask(FROM_HERE, 234 base::WorkerPool::PostTask(FROM_HERE,
220 NewRunnableFunction( 235 NewRunnableFunction(
221 &ReadFileTask, 236 &ReadFileTask,
222 file, buf, buf_len, 237 file, buf, buf_len, record_uma,
223 &background_io_completed_callback_), 238 &background_io_completed_callback_),
224 true /* task_is_slow */); 239 true /* task_is_slow */);
225 } 240 }
226 241
227 void FileStream::AsyncContext::InitiateAsyncWrite( 242 void FileStream::AsyncContext::InitiateAsyncWrite(
228 base::PlatformFile file, const char* buf, int buf_len, 243 base::PlatformFile file, const char* buf, int buf_len, bool record_uma,
229 CompletionCallback* callback) { 244 CompletionCallback* callback) {
230 DCHECK(!callback_); 245 DCHECK(!callback_);
231 callback_ = callback; 246 callback_ = callback;
232 247
233 base::WorkerPool::PostTask(FROM_HERE, 248 base::WorkerPool::PostTask(FROM_HERE,
234 NewRunnableFunction( 249 NewRunnableFunction(
235 &WriteFileTask, 250 &WriteFileTask,
236 file, buf, buf_len, 251 file, buf, buf_len, record_uma,
237 &background_io_completed_callback_), 252 &background_io_completed_callback_),
238 true /* task_is_slow */); 253 true /* task_is_slow */);
239 } 254 }
240 255
241 void FileStream::AsyncContext::OnBackgroundIOCompleted(int result) { 256 void FileStream::AsyncContext::OnBackgroundIOCompleted(int result) {
242 result_ = result; 257 result_ = result;
243 message_loop_task_ = new CancelableCallbackTask( 258 message_loop_task_ = new CancelableCallbackTask(
244 NewCallback(this, &AsyncContext::RunAsynchronousCallback)); 259 NewCallback(this, &AsyncContext::RunAsynchronousCallback));
245 message_loop_->PostTask(FROM_HERE, message_loop_task_); 260 message_loop_->PostTask(FROM_HERE, message_loop_task_);
246 background_io_completed_.Signal(); 261 background_io_completed_.Signal();
(...skipping 20 matching lines...) Expand all
267 std::swap(temp, callback_); 282 std::swap(temp, callback_);
268 background_io_completed_.Reset(); 283 background_io_completed_.Reset();
269 temp->Run(result_); 284 temp->Run(result_);
270 } 285 }
271 286
272 // FileStream ------------------------------------------------------------ 287 // FileStream ------------------------------------------------------------
273 288
274 FileStream::FileStream() 289 FileStream::FileStream()
275 : file_(base::kInvalidPlatformFileValue), 290 : file_(base::kInvalidPlatformFileValue),
276 open_flags_(0), 291 open_flags_(0),
277 auto_closed_(true) { 292 auto_closed_(false),
293 record_uma_(false) {
278 DCHECK(!IsOpen()); 294 DCHECK(!IsOpen());
279 } 295 }
280 296
281 FileStream::FileStream(base::PlatformFile file, int flags) 297 FileStream::FileStream(base::PlatformFile file, int flags)
282 : file_(file), 298 : file_(file),
283 open_flags_(flags), 299 open_flags_(flags),
284 auto_closed_(false) { 300 auto_closed_(false),
301 record_uma_(false) {
285 // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to 302 // 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. 303 // make sure we will perform asynchronous File IO to it.
287 if (flags & base::PLATFORM_FILE_ASYNC) { 304 if (flags & base::PLATFORM_FILE_ASYNC) {
288 async_context_.reset(new AsyncContext()); 305 async_context_.reset(new AsyncContext());
289 } 306 }
290 } 307 }
291 308
292 FileStream::~FileStream() { 309 FileStream::~FileStream() {
293 if (auto_closed_) 310 if (auto_closed_)
294 Close(); 311 Close();
(...skipping 13 matching lines...) Expand all
308 325
309 int FileStream::Open(const FilePath& path, int open_flags) { 326 int FileStream::Open(const FilePath& path, int open_flags) {
310 if (IsOpen()) { 327 if (IsOpen()) {
311 DLOG(FATAL) << "File is already open!"; 328 DLOG(FATAL) << "File is already open!";
312 return ERR_UNEXPECTED; 329 return ERR_UNEXPECTED;
313 } 330 }
314 331
315 open_flags_ = open_flags; 332 open_flags_ = open_flags;
316 file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL); 333 file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL);
317 if (file_ == base::kInvalidPlatformFileValue) { 334 if (file_ == base::kInvalidPlatformFileValue) {
318 return MapErrorCode(errno); 335 int error = errno;
336 if (record_uma_)
337 RecordFileError(error, FILE_ERROR_SOURCE_OPEN);
338 return MapErrorCode(error);
319 } 339 }
320 340
321 if (open_flags_ & base::PLATFORM_FILE_ASYNC) { 341 if (open_flags_ & base::PLATFORM_FILE_ASYNC) {
322 async_context_.reset(new AsyncContext()); 342 async_context_.reset(new AsyncContext());
323 } 343 }
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()) {
356 if (record_uma_)
357 RecordFileError(EINVAL, FILE_ERROR_SOURCE_IS_NOT_OPEN);
336 return ERR_UNEXPECTED; 358 return ERR_UNEXPECTED;
359 }
337 360
338 // If we're in async, make sure we don't have a request in flight. 361 // If we're in async, make sure we don't have a request in flight.
339 DCHECK(!async_context_.get() || !async_context_->callback()); 362 DCHECK(!async_context_.get() || !async_context_->callback());
340 363
341 off_t res = lseek(file_, static_cast<off_t>(offset), 364 off_t res = lseek(file_, static_cast<off_t>(offset),
342 static_cast<int>(whence)); 365 static_cast<int>(whence));
343 if (res == static_cast<off_t>(-1)) 366 if (res == static_cast<off_t>(-1)) {
344 return MapErrorCode(errno); 367 int error = errno;
cbentzel 2011/08/16 13:36:02 Perhaps a helper function like MapAndRecordErrorC
ahendrickson 2011/08/17 20:12:04 Done.
368 if (record_uma_)
369 RecordFileError(error, FILE_ERROR_SOURCE_SEEK);
370 return MapErrorCode(error);
371 }
345 372
346 return res; 373 return res;
347 } 374 }
348 375
349 int64 FileStream::Available() { 376 int64 FileStream::Available() {
350 base::ThreadRestrictions::AssertIOAllowed(); 377 base::ThreadRestrictions::AssertIOAllowed();
351 378
352 if (!IsOpen()) 379 if (!IsOpen()) {
380 if (record_uma_)
cbentzel 2011/08/16 13:36:02 I don't think it's worth recording these errors re
ahendrickson 2011/08/17 20:12:04 Done.
381 RecordFileError(EINVAL, FILE_ERROR_SOURCE_IS_NOT_OPEN);
353 return ERR_UNEXPECTED; 382 return ERR_UNEXPECTED;
383 }
354 384
355 int64 cur_pos = Seek(FROM_CURRENT, 0); 385 int64 cur_pos = Seek(FROM_CURRENT, 0);
356 if (cur_pos < 0) 386 if (cur_pos < 0)
357 return cur_pos; 387 return cur_pos;
358 388
359 struct stat info; 389 struct stat info;
360 if (fstat(file_, &info) != 0) 390 if (fstat(file_, &info) != 0) {
361 return MapErrorCode(errno); 391 int error = errno;
362 392 if (record_uma_)
393 RecordFileError(error, FILE_ERROR_SOURCE_GET_SIZE);
394 return MapErrorCode(error);
395 }
363 int64 size = static_cast<int64>(info.st_size); 396 int64 size = static_cast<int64>(info.st_size);
364 DCHECK_GT(size, cur_pos); 397 DCHECK_GT(size, cur_pos);
365 398
366 return size - cur_pos; 399 return size - cur_pos;
367 } 400 }
368 401
369 int FileStream::Read( 402 int FileStream::Read(
370 char* buf, int buf_len, CompletionCallback* callback) { 403 char* buf, int buf_len, CompletionCallback* callback) {
371 if (!IsOpen()) 404 if (!IsOpen()) {
405 if (record_uma_)
406 RecordFileError(EINVAL, FILE_ERROR_SOURCE_IS_NOT_OPEN);
372 return ERR_UNEXPECTED; 407 return ERR_UNEXPECTED;
408 }
373 409
374 // read(..., 0) will return 0, which indicates end-of-file. 410 // read(..., 0) will return 0, which indicates end-of-file.
375 DCHECK(buf_len > 0); 411 DCHECK(buf_len > 0);
376 DCHECK(open_flags_ & base::PLATFORM_FILE_READ); 412 DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
377 413
378 if (async_context_.get()) { 414 if (async_context_.get()) {
379 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); 415 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
380 // If we're in async, make sure we don't have a request in flight. 416 // If we're in async, make sure we don't have a request in flight.
381 DCHECK(!async_context_->callback()); 417 DCHECK(!async_context_->callback());
382 async_context_->InitiateAsyncRead(file_, buf, buf_len, callback); 418 async_context_->InitiateAsyncRead(file_, buf, buf_len, record_uma_,
419 callback);
383 return ERR_IO_PENDING; 420 return ERR_IO_PENDING;
384 } else { 421 } else {
385 return ReadFile(file_, buf, buf_len); 422 return ReadFile(file_, buf, buf_len, record_uma_);
386 } 423 }
387 } 424 }
388 425
389 int FileStream::ReadUntilComplete(char *buf, int buf_len) { 426 int FileStream::ReadUntilComplete(char *buf, int buf_len) {
390 int to_read = buf_len; 427 int to_read = buf_len;
391 int bytes_total = 0; 428 int bytes_total = 0;
392 429
393 do { 430 do {
394 int bytes_read = Read(buf, to_read, NULL); 431 int bytes_read = Read(buf, to_read, NULL);
395 if (bytes_read <= 0) { 432 if (bytes_read <= 0) {
396 if (bytes_total == 0) 433 if (bytes_total == 0)
397 return bytes_read; 434 return bytes_read;
398 435
399 return bytes_total; 436 return bytes_total;
400 } 437 }
401 438
402 bytes_total += bytes_read; 439 bytes_total += bytes_read;
403 buf += bytes_read; 440 buf += bytes_read;
404 to_read -= bytes_read; 441 to_read -= bytes_read;
405 } while (bytes_total < buf_len); 442 } while (bytes_total < buf_len);
406 443
407 return bytes_total; 444 return bytes_total;
408 } 445 }
409 446
410 int FileStream::Write( 447 int FileStream::Write(
411 const char* buf, int buf_len, CompletionCallback* callback) { 448 const char* buf, int buf_len, CompletionCallback* callback) {
412 // write(..., 0) will return 0, which indicates end-of-file. 449 // write(..., 0) will return 0, which indicates end-of-file.
413 DCHECK_GT(buf_len, 0); 450 DCHECK_GT(buf_len, 0);
414 451
415 if (!IsOpen()) 452 if (!IsOpen()) {
453 if (record_uma_)
454 RecordFileError(EINVAL, FILE_ERROR_SOURCE_IS_NOT_OPEN);
416 return ERR_UNEXPECTED; 455 return ERR_UNEXPECTED;
456 }
417 457
418 if (async_context_.get()) { 458 if (async_context_.get()) {
419 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC); 459 DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
420 // If we're in async, make sure we don't have a request in flight. 460 // If we're in async, make sure we don't have a request in flight.
421 DCHECK(!async_context_->callback()); 461 DCHECK(!async_context_->callback());
422 async_context_->InitiateAsyncWrite(file_, buf, buf_len, callback); 462 async_context_->InitiateAsyncWrite(file_, buf, buf_len, record_uma_,
463 callback);
423 return ERR_IO_PENDING; 464 return ERR_IO_PENDING;
424 } else { 465 } else {
425 return WriteFile(file_, buf, buf_len); 466 return WriteFile(file_, buf, buf_len, record_uma_);
426 } 467 }
427 } 468 }
428 469
429 int64 FileStream::Truncate(int64 bytes) { 470 int64 FileStream::Truncate(int64 bytes) {
430 base::ThreadRestrictions::AssertIOAllowed(); 471 base::ThreadRestrictions::AssertIOAllowed();
431 472
432 if (!IsOpen()) 473 if (!IsOpen()) {
474 if (record_uma_)
475 RecordFileError(EINVAL, FILE_ERROR_SOURCE_IS_NOT_OPEN);
433 return ERR_UNEXPECTED; 476 return ERR_UNEXPECTED;
477 }
434 478
435 // We better be open for reading. 479 // We better be open for reading.
436 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); 480 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
437 481
438 // Seek to the position to truncate from. 482 // Seek to the position to truncate from.
439 int64 seek_position = Seek(FROM_BEGIN, bytes); 483 int64 seek_position = Seek(FROM_BEGIN, bytes);
440 if (seek_position != bytes) 484 if (seek_position != bytes)
441 return ERR_UNEXPECTED; 485 return ERR_UNEXPECTED;
442 486
443 // And truncate the file. 487 // And truncate the file.
444 int result = ftruncate(file_, bytes); 488 int result = ftruncate(file_, bytes);
cbentzel 2011/08/16 13:36:02 This existed before - but we may want to make this
ahendrickson 2011/08/17 20:12:04 What does HANDLE_EINTR do?
cbentzel 2011/08/18 13:31:27 HANDLE_EINTR re-executes the function if the errno
ahendrickson 2011/08/18 15:56:45 OK, removed.
445 return result == 0 ? seek_position : MapErrorCode(errno); 489 if (result == 0)
490 return seek_position;
491
492 int error = errno;
493 if (record_uma_)
494 RecordFileError(error, FILE_ERROR_SOURCE_SET_EOF);
495 return MapErrorCode(error);
446 } 496 }
447 497
448 int FileStream::Flush() { 498 int FileStream::Flush() {
449 if (!IsOpen()) 499 if (!IsOpen()) {
500 if (record_uma_)
501 RecordFileError(EINVAL, FILE_ERROR_SOURCE_IS_NOT_OPEN);
450 return ERR_UNEXPECTED; 502 return ERR_UNEXPECTED;
503 }
451 504
452 return FlushFile(file_); 505 return FlushFile(file_, record_uma_);
506 }
507
508 void FileStream::EnableRecording() {
509 record_uma_ = true;
cbentzel 2011/08/16 13:36:02 Do you need to do the if (async_context_) asyn
ahendrickson 2011/08/17 20:12:04 Doing something similar now: Setting it at the ti
cbentzel 2011/08/18 13:31:27 Yup. After the fact I realized how different the t
453 } 510 }
454 511
455 } // namespace net 512 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698