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

Side by Side Diff: net/base/file_stream_win.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 #include "net/base/file_stream.h" 5 #include "net/base/file_stream.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 8
9 #include "base/file_path.h" 9 #include "base/file_path.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/message_loop.h" 11 #include "base/message_loop.h"
12 #include "base/metrics/histogram.h" 12 #include "base/metrics/histogram.h"
13 #include "base/threading/thread_restrictions.h" 13 #include "base/threading/thread_restrictions.h"
14 #include "net/base/file_stream_metrics.h"
14 #include "net/base/net_errors.h" 15 #include "net/base/net_errors.h"
15 16
16 namespace net { 17 namespace net {
17 18
18 // Ensure that we can just use our Whence values directly. 19 // Ensure that we can just use our Whence values directly.
19 COMPILE_ASSERT(FROM_BEGIN == FILE_BEGIN, bad_whence_begin); 20 COMPILE_ASSERT(FROM_BEGIN == FILE_BEGIN, bad_whence_begin);
20 COMPILE_ASSERT(FROM_CURRENT == FILE_CURRENT, bad_whence_current); 21 COMPILE_ASSERT(FROM_CURRENT == FILE_CURRENT, bad_whence_current);
21 COMPILE_ASSERT(FROM_END == FILE_END, bad_whence_end); 22 COMPILE_ASSERT(FROM_END == FILE_END, bad_whence_end);
22 23
23 static void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) { 24 static void SetOffset(OVERLAPPED* overlapped, const LARGE_INTEGER& offset) {
(...skipping 22 matching lines...) Expand all
46 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; 47 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
47 return ERR_FAILED; 48 return ERR_FAILED;
48 } 49 }
49 } 50 }
50 51
51 // FileStream::AsyncContext ---------------------------------------------- 52 // FileStream::AsyncContext ----------------------------------------------
52 53
53 class FileStream::AsyncContext : public MessageLoopForIO::IOHandler { 54 class FileStream::AsyncContext : public MessageLoopForIO::IOHandler {
54 public: 55 public:
55 AsyncContext(FileStream* owner) 56 AsyncContext(FileStream* owner)
56 : owner_(owner), context_(), callback_(NULL), is_closing_(false) { 57 : owner_(owner), context_(), callback_(NULL), is_closing_(false),
58 record_uma_(false) {
57 context_.handler = this; 59 context_.handler = this;
58 } 60 }
59 ~AsyncContext(); 61 ~AsyncContext();
60 62
61 void IOCompletionIsPending(CompletionCallback* callback); 63 void IOCompletionIsPending(CompletionCallback* callback);
62 64
63 OVERLAPPED* overlapped() { return &context_.overlapped; } 65 OVERLAPPED* overlapped() { return &context_.overlapped; }
64 CompletionCallback* callback() const { return callback_; } 66 CompletionCallback* callback() const { return callback_; }
65 67
68 void EnableRecording() {
69 record_uma_ = true;
70 }
71
66 private: 72 private:
67 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context, 73 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
68 DWORD bytes_read, DWORD error); 74 DWORD bytes_read, DWORD error);
69 75
70 FileStream* owner_; 76 FileStream* owner_;
71 MessageLoopForIO::IOContext context_; 77 MessageLoopForIO::IOContext context_;
72 CompletionCallback* callback_; 78 CompletionCallback* callback_;
73 bool is_closing_; 79 bool is_closing_;
80 bool record_uma_;
74 }; 81 };
75 82
76 FileStream::AsyncContext::~AsyncContext() { 83 FileStream::AsyncContext::~AsyncContext() {
77 is_closing_ = true; 84 is_closing_ = true;
78 bool waited = false; 85 bool waited = false;
79 base::TimeTicks start = base::TimeTicks::Now(); 86 base::TimeTicks start = base::TimeTicks::Now();
80 while (callback_) { 87 while (callback_) {
81 waited = true; 88 waited = true;
82 MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this); 89 MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this);
83 } 90 }
(...skipping 14 matching lines...) Expand all
98 MessageLoopForIO::IOContext* context, DWORD bytes_read, DWORD error) { 105 MessageLoopForIO::IOContext* context, DWORD bytes_read, DWORD error) {
99 DCHECK_EQ(&context_, context); 106 DCHECK_EQ(&context_, context);
100 DCHECK(callback_); 107 DCHECK(callback_);
101 108
102 if (is_closing_) { 109 if (is_closing_) {
103 callback_ = NULL; 110 callback_ = NULL;
104 return; 111 return;
105 } 112 }
106 113
107 int result = static_cast<int>(bytes_read); 114 int result = static_cast<int>(bytes_read);
108 if (error && error != ERROR_HANDLE_EOF) 115 if (error && error != ERROR_HANDLE_EOF) {
116 if (record_uma_)
117 RecordFileError(error, FILE_ERROR_SOURCE_READ);
cbentzel 2011/08/16 13:36:02 This could be done for both reads and writes. You
ahendrickson 2011/08/17 20:12:04 Done.
109 result = MapErrorCode(error); 118 result = MapErrorCode(error);
119 }
110 120
111 if (bytes_read) 121 if (bytes_read)
112 IncrementOffset(&context->overlapped, bytes_read); 122 IncrementOffset(&context->overlapped, bytes_read);
113 123
114 CompletionCallback* temp = NULL; 124 CompletionCallback* temp = NULL;
115 std::swap(temp, callback_); 125 std::swap(temp, callback_);
116 temp->Run(result); 126 temp->Run(result);
117 } 127 }
118 128
119 // FileStream ------------------------------------------------------------ 129 // FileStream ------------------------------------------------------------
120 130
121 FileStream::FileStream() 131 FileStream::FileStream()
122 : file_(INVALID_HANDLE_VALUE), 132 : file_(INVALID_HANDLE_VALUE),
123 open_flags_(0), 133 open_flags_(0),
124 auto_closed_(true) { 134 auto_closed_(true),
135 record_uma_(false) {
125 } 136 }
126 137
127 FileStream::FileStream(base::PlatformFile file, int flags) 138 FileStream::FileStream(base::PlatformFile file, int flags)
128 : file_(file), 139 : file_(file),
129 open_flags_(flags), 140 open_flags_(flags),
130 auto_closed_(false) { 141 auto_closed_(false),
142 record_uma_(false) {
131 // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to 143 // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to
132 // make sure we will perform asynchronous File IO to it. 144 // make sure we will perform asynchronous File IO to it.
133 if (flags & base::PLATFORM_FILE_ASYNC) { 145 if (flags & base::PLATFORM_FILE_ASYNC) {
134 async_context_.reset(new AsyncContext(this)); 146 async_context_.reset(new AsyncContext(this));
135 MessageLoopForIO::current()->RegisterIOHandler(file_, 147 MessageLoopForIO::current()->RegisterIOHandler(file_,
136 async_context_.get()); 148 async_context_.get());
137 } 149 }
138 } 150 }
139 151
140 FileStream::~FileStream() { 152 FileStream::~FileStream() {
(...skipping 16 matching lines...) Expand all
157 if (IsOpen()) { 169 if (IsOpen()) {
158 DLOG(FATAL) << "File is already open!"; 170 DLOG(FATAL) << "File is already open!";
159 return ERR_UNEXPECTED; 171 return ERR_UNEXPECTED;
160 } 172 }
161 173
162 open_flags_ = open_flags; 174 open_flags_ = open_flags;
163 file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL); 175 file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL);
164 if (file_ == INVALID_HANDLE_VALUE) { 176 if (file_ == INVALID_HANDLE_VALUE) {
165 DWORD error = GetLastError(); 177 DWORD error = GetLastError();
166 LOG(WARNING) << "Failed to open file: " << error; 178 LOG(WARNING) << "Failed to open file: " << error;
179 if (record_uma_)
180 RecordFileError(error, FILE_ERROR_SOURCE_OPEN);
167 return MapErrorCode(error); 181 return MapErrorCode(error);
168 } 182 }
169 183
170 if (open_flags_ & base::PLATFORM_FILE_ASYNC) { 184 if (open_flags_ & base::PLATFORM_FILE_ASYNC) {
171 async_context_.reset(new AsyncContext(this)); 185 async_context_.reset(new AsyncContext(this));
186 if (record_uma_)
187 async_context_->EnableRecording();
172 MessageLoopForIO::current()->RegisterIOHandler(file_, 188 MessageLoopForIO::current()->RegisterIOHandler(file_,
173 async_context_.get()); 189 async_context_.get());
174 } 190 }
175 191
176 return OK; 192 return OK;
177 } 193 }
178 194
179 bool FileStream::IsOpen() const { 195 bool FileStream::IsOpen() const {
180 return file_ != INVALID_HANDLE_VALUE; 196 return file_ != INVALID_HANDLE_VALUE;
181 } 197 }
182 198
183 int64 FileStream::Seek(Whence whence, int64 offset) { 199 int64 FileStream::Seek(Whence whence, int64 offset) {
184 if (!IsOpen()) 200 if (!IsOpen()) {
201 if (record_uma_)
cbentzel 2011/08/16 13:36:02 Again - in this file I would remove the recording
ahendrickson 2011/08/17 20:12:04 Done.
202 RecordFileError(ERROR_INVALID_HANDLE, FILE_ERROR_SOURCE_IS_NOT_OPEN);
185 return ERR_UNEXPECTED; 203 return ERR_UNEXPECTED;
204 }
205
186 DCHECK(!async_context_.get() || !async_context_->callback()); 206 DCHECK(!async_context_.get() || !async_context_->callback());
187 207
188 LARGE_INTEGER distance, result; 208 LARGE_INTEGER distance, result;
189 distance.QuadPart = offset; 209 distance.QuadPart = offset;
190 DWORD move_method = static_cast<DWORD>(whence); 210 DWORD move_method = static_cast<DWORD>(whence);
191 if (!SetFilePointerEx(file_, distance, &result, move_method)) { 211 if (!SetFilePointerEx(file_, distance, &result, move_method)) {
192 DWORD error = GetLastError(); 212 DWORD error = GetLastError();
193 LOG(WARNING) << "SetFilePointerEx failed: " << error; 213 LOG(WARNING) << "SetFilePointerEx failed: " << error;
214 if (record_uma_)
215 RecordFileError(error, FILE_ERROR_SOURCE_SEEK);
194 return MapErrorCode(error); 216 return MapErrorCode(error);
195 } 217 }
196 if (async_context_.get()) 218 if (async_context_.get())
197 SetOffset(async_context_->overlapped(), result); 219 SetOffset(async_context_->overlapped(), result);
198 return result.QuadPart; 220 return result.QuadPart;
199 } 221 }
200 222
201 int64 FileStream::Available() { 223 int64 FileStream::Available() {
202 base::ThreadRestrictions::AssertIOAllowed(); 224 base::ThreadRestrictions::AssertIOAllowed();
203 225
204 if (!IsOpen()) 226 if (!IsOpen()) {
227 if (record_uma_)
228 RecordFileError(ERROR_INVALID_HANDLE, FILE_ERROR_SOURCE_IS_NOT_OPEN);
205 return ERR_UNEXPECTED; 229 return ERR_UNEXPECTED;
230 }
206 231
207 int64 cur_pos = Seek(FROM_CURRENT, 0); 232 int64 cur_pos = Seek(FROM_CURRENT, 0);
208 if (cur_pos < 0) 233 if (cur_pos < 0)
209 return cur_pos; 234 return cur_pos;
210 235
211 LARGE_INTEGER file_size; 236 LARGE_INTEGER file_size;
212 if (!GetFileSizeEx(file_, &file_size)) { 237 if (!GetFileSizeEx(file_, &file_size)) {
213 DWORD error = GetLastError(); 238 DWORD error = GetLastError();
214 LOG(WARNING) << "GetFileSizeEx failed: " << error; 239 LOG(WARNING) << "GetFileSizeEx failed: " << error;
240 if (record_uma_)
241 RecordFileError(error, FILE_ERROR_SOURCE_GET_SIZE);
215 return MapErrorCode(error); 242 return MapErrorCode(error);
216 } 243 }
217 244
218 return file_size.QuadPart - cur_pos; 245 return file_size.QuadPart - cur_pos;
219 } 246 }
220 247
221 int FileStream::Read( 248 int FileStream::Read(
222 char* buf, int buf_len, CompletionCallback* callback) { 249 char* buf, int buf_len, CompletionCallback* callback) {
223 if (!IsOpen()) 250 if (!IsOpen()) {
251 if (record_uma_)
252 RecordFileError(ERROR_INVALID_HANDLE, FILE_ERROR_SOURCE_IS_NOT_OPEN);
224 return ERR_UNEXPECTED; 253 return ERR_UNEXPECTED;
254 }
255
225 DCHECK(open_flags_ & base::PLATFORM_FILE_READ); 256 DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
226 257
227 OVERLAPPED* overlapped = NULL; 258 OVERLAPPED* overlapped = NULL;
228 if (async_context_.get()) { 259 if (async_context_.get()) {
229 DCHECK(callback); 260 DCHECK(callback);
230 DCHECK(!async_context_->callback()); 261 DCHECK(!async_context_->callback());
231 overlapped = async_context_->overlapped(); 262 overlapped = async_context_->overlapped();
232 } else { 263 } else {
233 DCHECK(!callback); 264 DCHECK(!callback);
234 base::ThreadRestrictions::AssertIOAllowed(); 265 base::ThreadRestrictions::AssertIOAllowed();
235 } 266 }
236 267
237 int rv; 268 int rv;
238 269
239 DWORD bytes_read; 270 DWORD bytes_read;
240 if (!ReadFile(file_, buf, buf_len, &bytes_read, overlapped)) { 271 if (!ReadFile(file_, buf, buf_len, &bytes_read, overlapped)) {
241 DWORD error = GetLastError(); 272 DWORD error = GetLastError();
242 if (async_context_.get() && error == ERROR_IO_PENDING) { 273 if (async_context_.get() && error == ERROR_IO_PENDING) {
243 async_context_->IOCompletionIsPending(callback); 274 async_context_->IOCompletionIsPending(callback);
244 rv = ERR_IO_PENDING; 275 rv = ERR_IO_PENDING;
245 } else if (error == ERROR_HANDLE_EOF) { 276 } else if (error == ERROR_HANDLE_EOF) {
246 rv = 0; // Report EOF by returning 0 bytes read. 277 rv = 0; // Report EOF by returning 0 bytes read.
247 } else { 278 } else {
248 LOG(WARNING) << "ReadFile failed: " << error; 279 LOG(WARNING) << "ReadFile failed: " << error;
280 if (record_uma_)
281 RecordFileError(error, FILE_ERROR_SOURCE_READ);
249 rv = MapErrorCode(error); 282 rv = MapErrorCode(error);
250 } 283 }
251 } else if (overlapped) { 284 } else if (overlapped) {
252 async_context_->IOCompletionIsPending(callback); 285 async_context_->IOCompletionIsPending(callback);
253 rv = ERR_IO_PENDING; 286 rv = ERR_IO_PENDING;
254 } else { 287 } else {
255 rv = static_cast<int>(bytes_read); 288 rv = static_cast<int>(bytes_read);
256 } 289 }
257 return rv; 290 return rv;
258 } 291 }
(...skipping 14 matching lines...) Expand all
273 bytes_total += bytes_read; 306 bytes_total += bytes_read;
274 buf += bytes_read; 307 buf += bytes_read;
275 to_read -= bytes_read; 308 to_read -= bytes_read;
276 } while (bytes_total < buf_len); 309 } while (bytes_total < buf_len);
277 310
278 return bytes_total; 311 return bytes_total;
279 } 312 }
280 313
281 int FileStream::Write( 314 int FileStream::Write(
282 const char* buf, int buf_len, CompletionCallback* callback) { 315 const char* buf, int buf_len, CompletionCallback* callback) {
283 if (!IsOpen()) 316 if (!IsOpen()) {
317 if (record_uma_)
318 RecordFileError(ERROR_INVALID_HANDLE, FILE_ERROR_SOURCE_IS_NOT_OPEN);
284 return ERR_UNEXPECTED; 319 return ERR_UNEXPECTED;
320 }
285 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); 321 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
286 322
287 OVERLAPPED* overlapped = NULL; 323 OVERLAPPED* overlapped = NULL;
288 if (async_context_.get()) { 324 if (async_context_.get()) {
289 DCHECK(callback); 325 DCHECK(callback);
290 DCHECK(!async_context_->callback()); 326 DCHECK(!async_context_->callback());
291 overlapped = async_context_->overlapped(); 327 overlapped = async_context_->overlapped();
292 } else { 328 } else {
293 DCHECK(!callback); 329 DCHECK(!callback);
294 base::ThreadRestrictions::AssertIOAllowed(); 330 base::ThreadRestrictions::AssertIOAllowed();
295 } 331 }
296 332
297 int rv; 333 int rv;
298 DWORD bytes_written; 334 DWORD bytes_written;
299 if (!WriteFile(file_, buf, buf_len, &bytes_written, overlapped)) { 335 if (!WriteFile(file_, buf, buf_len, &bytes_written, overlapped)) {
300 DWORD error = GetLastError(); 336 DWORD error = GetLastError();
301 if (async_context_.get() && error == ERROR_IO_PENDING) { 337 if (async_context_.get() && error == ERROR_IO_PENDING) {
cbentzel 2011/08/16 13:36:02 So, in the Windows case I _don't_ think it will he
ahendrickson 2011/08/17 20:12:04 It's not as useful, but still works.
302 async_context_->IOCompletionIsPending(callback); 338 async_context_->IOCompletionIsPending(callback);
303 rv = ERR_IO_PENDING; 339 rv = ERR_IO_PENDING;
304 } else { 340 } else {
305 LOG(WARNING) << "WriteFile failed: " << error; 341 LOG(WARNING) << "WriteFile failed: " << error;
342 if (record_uma_)
343 RecordFileError(error, FILE_ERROR_SOURCE_WRITE);
306 rv = MapErrorCode(error); 344 rv = MapErrorCode(error);
307 } 345 }
308 } else if (overlapped) { 346 } else if (overlapped) {
309 async_context_->IOCompletionIsPending(callback); 347 async_context_->IOCompletionIsPending(callback);
310 rv = ERR_IO_PENDING; 348 rv = ERR_IO_PENDING;
311 } else { 349 } else {
312 rv = static_cast<int>(bytes_written); 350 rv = static_cast<int>(bytes_written);
313 } 351 }
314 return rv; 352 return rv;
315 } 353 }
316 354
317 int FileStream::Flush() { 355 int FileStream::Flush() {
318 base::ThreadRestrictions::AssertIOAllowed(); 356 base::ThreadRestrictions::AssertIOAllowed();
319 357
320 if (!IsOpen()) 358 if (!IsOpen()) {
359 if (record_uma_)
360 RecordFileError(ERROR_INVALID_HANDLE, FILE_ERROR_SOURCE_IS_NOT_OPEN);
321 return ERR_UNEXPECTED; 361 return ERR_UNEXPECTED;
362 }
322 363
323 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); 364 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
324 if (FlushFileBuffers(file_)) { 365 if (FlushFileBuffers(file_)) {
325 return OK; 366 return OK;
326 } 367 }
327 368
328 int rv; 369 int rv;
329 DWORD error = GetLastError(); 370 DWORD error = GetLastError();
371 if (record_uma_)
372 RecordFileError(error, FILE_ERROR_SOURCE_FLUSH);
330 rv = MapErrorCode(error); 373 rv = MapErrorCode(error);
331 return rv; 374 return rv;
332 } 375 }
333 376
334 int64 FileStream::Truncate(int64 bytes) { 377 int64 FileStream::Truncate(int64 bytes) {
335 base::ThreadRestrictions::AssertIOAllowed(); 378 base::ThreadRestrictions::AssertIOAllowed();
336 379
337 if (!IsOpen()) 380 if (!IsOpen()) {
381 if (record_uma_)
382 RecordFileError(ERROR_INVALID_HANDLE, FILE_ERROR_SOURCE_IS_NOT_OPEN);
338 return ERR_UNEXPECTED; 383 return ERR_UNEXPECTED;
384 }
339 385
340 // We better be open for reading. 386 // We better be open for reading.
341 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); 387 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
342 388
343 // Seek to the position to truncate from. 389 // Seek to the position to truncate from.
344 int64 seek_position = Seek(FROM_BEGIN, bytes); 390 int64 seek_position = Seek(FROM_BEGIN, bytes);
345 if (seek_position != bytes) 391 if (seek_position != bytes)
346 return ERR_UNEXPECTED; 392 return ERR_UNEXPECTED;
347 393
348 // And truncate the file. 394 // And truncate the file.
349 BOOL result = SetEndOfFile(file_); 395 BOOL result = SetEndOfFile(file_);
350 if (!result) { 396 if (!result) {
351 DWORD error = GetLastError(); 397 DWORD error = GetLastError();
352 LOG(WARNING) << "SetEndOfFile failed: " << error; 398 LOG(WARNING) << "SetEndOfFile failed: " << error;
399 if (record_uma_)
400 RecordFileError(error, FILE_ERROR_SOURCE_SET_EOF);
353 return MapErrorCode(error); 401 return MapErrorCode(error);
354 } 402 }
355 403
356 // Success. 404 // Success.
357 return seek_position; 405 return seek_position;
358 } 406 }
359 407
408 void FileStream::EnableRecording() {
409 record_uma_ = true;
410
411 if (async_context_.get())
412 async_context_->EnableRecording();
413 }
414
360 } // namespace net 415 } // namespace net
OLDNEW
« net/base/file_stream_posix.cc ('K') | « net/base/file_stream_posix.cc ('k') | net/net.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698