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

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

Powered by Google App Engine
This is Rietveld 408576698