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

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: 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 #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 21 matching lines...) Expand all
45 default: 46 default:
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:
56 enum AsyncOperation {
57 ASYNC_OPERATION_NONE = 0,
58 ASYNC_OPERATION_READ,
59 ASYNC_OPERATION_WRITE,
60 ASYNC_OPERATION_SEEK,
61 };
62
55 AsyncContext(FileStream* owner) 63 AsyncContext(FileStream* owner)
56 : owner_(owner), context_(), callback_(NULL), is_closing_(false) { 64 : owner_(owner), context_(), callback_(NULL), is_closing_(false),
65 record_uma_(false), operation_(ASYNC_OPERATION_NONE) {
57 context_.handler = this; 66 context_.handler = this;
58 } 67 }
59 ~AsyncContext(); 68 ~AsyncContext();
60 69
61 void IOCompletionIsPending(CompletionCallback* callback); 70 void IOCompletionIsPending(CompletionCallback* callback);
62 71
63 OVERLAPPED* overlapped() { return &context_.overlapped; } 72 OVERLAPPED* overlapped() { return &context_.overlapped; }
64 CompletionCallback* callback() const { return callback_; } 73 CompletionCallback* callback() const { return callback_; }
65 74
75 void set_operation(AsyncOperation operation) { operation_ = operation; }
cbentzel 2011/08/18 13:31:28 Why isn't this just FILE_ERROR_SOURCE? That way yo
ahendrickson 2011/08/18 15:56:45 I believe there is 0 or 1 AsyncContext's per FileS
76
77 void EnableErrorStatistics() {
78 record_uma_ = true;
79 }
80
66 private: 81 private:
67 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context, 82 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
68 DWORD bytes_read, DWORD error); 83 DWORD bytes_read, DWORD error);
69 84
70 FileStream* owner_; 85 FileStream* owner_;
71 MessageLoopForIO::IOContext context_; 86 MessageLoopForIO::IOContext context_;
72 CompletionCallback* callback_; 87 CompletionCallback* callback_;
73 bool is_closing_; 88 bool is_closing_;
89 bool record_uma_;
90 AsyncOperation operation_;
74 }; 91 };
75 92
76 FileStream::AsyncContext::~AsyncContext() { 93 FileStream::AsyncContext::~AsyncContext() {
77 is_closing_ = true; 94 is_closing_ = true;
78 bool waited = false; 95 bool waited = false;
79 base::TimeTicks start = base::TimeTicks::Now(); 96 base::TimeTicks start = base::TimeTicks::Now();
80 while (callback_) { 97 while (callback_) {
81 waited = true; 98 waited = true;
82 MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this); 99 MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this);
83 } 100 }
84 if (waited) { 101 if (waited) {
85 // We want to see if we block the message loop for too long. 102 // We want to see if we block the message loop for too long.
86 UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose", 103 UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose",
87 base::TimeTicks::Now() - start); 104 base::TimeTicks::Now() - start);
88 } 105 }
89 } 106 }
90 107
91 void FileStream::AsyncContext::IOCompletionIsPending( 108 void FileStream::AsyncContext::IOCompletionIsPending(
92 CompletionCallback* callback) { 109 CompletionCallback* callback) {
93 DCHECK(!callback_); 110 DCHECK(!callback_);
94 callback_ = callback; 111 callback_ = callback;
95 } 112 }
96 113
97 void FileStream::AsyncContext::OnIOCompleted( 114 void FileStream::AsyncContext::OnIOCompleted(
98 MessageLoopForIO::IOContext* context, DWORD bytes_read, DWORD error) { 115 MessageLoopForIO::IOContext* context, DWORD bytes_read, DWORD error) {
99 DCHECK_EQ(&context_, context); 116 DCHECK_EQ(&context_, context);
100 DCHECK(callback_); 117 DCHECK(callback_);
101 118
119 static FileErrorSource source_map[] = {
120 FILE_ERROR_SOURCE_COUNT, // ASYNC_OPERATION_NONE
121 FILE_ERROR_SOURCE_READ, // ASYNC_OPERATION_READ
122 FILE_ERROR_SOURCE_WRITE, // ASYNC_OPERATION_WRITE
123 FILE_ERROR_SOURCE_SEEK, // ASYNC_OPERATION_SEEK
124 };
125
102 if (is_closing_) { 126 if (is_closing_) {
103 callback_ = NULL; 127 callback_ = NULL;
104 return; 128 return;
105 } 129 }
106 130
107 int result = static_cast<int>(bytes_read); 131 int result = static_cast<int>(bytes_read);
108 if (error && error != ERROR_HANDLE_EOF) 132 if (error && error != ERROR_HANDLE_EOF) {
133 RecordFileError(error, source_map[operation_], record_uma_);
109 result = MapErrorCode(error); 134 result = MapErrorCode(error);
135 }
110 136
111 if (bytes_read) 137 if (bytes_read)
112 IncrementOffset(&context->overlapped, bytes_read); 138 IncrementOffset(&context->overlapped, bytes_read);
113 139
114 CompletionCallback* temp = NULL; 140 CompletionCallback* temp = NULL;
115 std::swap(temp, callback_); 141 std::swap(temp, callback_);
116 temp->Run(result); 142 temp->Run(result);
117 } 143 }
118 144
119 // FileStream ------------------------------------------------------------ 145 // FileStream ------------------------------------------------------------
120 146
121 FileStream::FileStream() 147 FileStream::FileStream()
122 : file_(INVALID_HANDLE_VALUE), 148 : file_(INVALID_HANDLE_VALUE),
123 open_flags_(0), 149 open_flags_(0),
124 auto_closed_(true) { 150 auto_closed_(true),
151 record_uma_(false) {
125 } 152 }
126 153
127 FileStream::FileStream(base::PlatformFile file, int flags) 154 FileStream::FileStream(base::PlatformFile file, int flags)
128 : file_(file), 155 : file_(file),
129 open_flags_(flags), 156 open_flags_(flags),
130 auto_closed_(false) { 157 auto_closed_(false),
158 record_uma_(false) {
131 // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to 159 // 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. 160 // make sure we will perform asynchronous File IO to it.
133 if (flags & base::PLATFORM_FILE_ASYNC) { 161 if (flags & base::PLATFORM_FILE_ASYNC) {
134 async_context_.reset(new AsyncContext(this)); 162 async_context_.reset(new AsyncContext(this));
135 MessageLoopForIO::current()->RegisterIOHandler(file_, 163 MessageLoopForIO::current()->RegisterIOHandler(file_,
136 async_context_.get()); 164 async_context_.get());
137 } 165 }
138 } 166 }
139 167
140 FileStream::~FileStream() { 168 FileStream::~FileStream() {
(...skipping 16 matching lines...) Expand all
157 if (IsOpen()) { 185 if (IsOpen()) {
158 DLOG(FATAL) << "File is already open!"; 186 DLOG(FATAL) << "File is already open!";
159 return ERR_UNEXPECTED; 187 return ERR_UNEXPECTED;
160 } 188 }
161 189
162 open_flags_ = open_flags; 190 open_flags_ = open_flags;
163 file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL); 191 file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL);
164 if (file_ == INVALID_HANDLE_VALUE) { 192 if (file_ == INVALID_HANDLE_VALUE) {
165 DWORD error = GetLastError(); 193 DWORD error = GetLastError();
166 LOG(WARNING) << "Failed to open file: " << error; 194 LOG(WARNING) << "Failed to open file: " << error;
167 return MapErrorCode(error); 195 return RecordAndMapError(error, FILE_ERROR_SOURCE_OPEN);
168 } 196 }
169 197
170 if (open_flags_ & base::PLATFORM_FILE_ASYNC) { 198 if (open_flags_ & base::PLATFORM_FILE_ASYNC) {
171 async_context_.reset(new AsyncContext(this)); 199 async_context_.reset(new AsyncContext(this));
200 if (record_uma_)
201 async_context_->EnableErrorStatistics();
172 MessageLoopForIO::current()->RegisterIOHandler(file_, 202 MessageLoopForIO::current()->RegisterIOHandler(file_,
173 async_context_.get()); 203 async_context_.get());
174 } 204 }
175 205
176 return OK; 206 return OK;
177 } 207 }
178 208
179 bool FileStream::IsOpen() const { 209 bool FileStream::IsOpen() const {
180 return file_ != INVALID_HANDLE_VALUE; 210 return file_ != INVALID_HANDLE_VALUE;
181 } 211 }
182 212
183 int64 FileStream::Seek(Whence whence, int64 offset) { 213 int64 FileStream::Seek(Whence whence, int64 offset) {
184 if (!IsOpen()) 214 if (!IsOpen())
185 return ERR_UNEXPECTED; 215 return ERR_UNEXPECTED;
216
186 DCHECK(!async_context_.get() || !async_context_->callback()); 217 DCHECK(!async_context_.get() || !async_context_->callback());
187 218
188 LARGE_INTEGER distance, result; 219 LARGE_INTEGER distance, result;
189 distance.QuadPart = offset; 220 distance.QuadPart = offset;
190 DWORD move_method = static_cast<DWORD>(whence); 221 DWORD move_method = static_cast<DWORD>(whence);
191 if (!SetFilePointerEx(file_, distance, &result, move_method)) { 222 if (!SetFilePointerEx(file_, distance, &result, move_method)) {
192 DWORD error = GetLastError(); 223 DWORD error = GetLastError();
193 LOG(WARNING) << "SetFilePointerEx failed: " << error; 224 LOG(WARNING) << "SetFilePointerEx failed: " << error;
194 return MapErrorCode(error); 225 return RecordAndMapError(error, FILE_ERROR_SOURCE_SEEK);
195 } 226 }
196 if (async_context_.get()) 227 if (async_context_.get()) {
228 async_context_->set_operation(AsyncContext::ASYNC_OPERATION_SEEK);
197 SetOffset(async_context_->overlapped(), result); 229 SetOffset(async_context_->overlapped(), result);
230 }
198 return result.QuadPart; 231 return result.QuadPart;
199 } 232 }
200 233
201 int64 FileStream::Available() { 234 int64 FileStream::Available() {
202 base::ThreadRestrictions::AssertIOAllowed(); 235 base::ThreadRestrictions::AssertIOAllowed();
203 236
204 if (!IsOpen()) 237 if (!IsOpen())
205 return ERR_UNEXPECTED; 238 return ERR_UNEXPECTED;
206 239
207 int64 cur_pos = Seek(FROM_CURRENT, 0); 240 int64 cur_pos = Seek(FROM_CURRENT, 0);
208 if (cur_pos < 0) 241 if (cur_pos < 0)
209 return cur_pos; 242 return cur_pos;
210 243
211 LARGE_INTEGER file_size; 244 LARGE_INTEGER file_size;
212 if (!GetFileSizeEx(file_, &file_size)) { 245 if (!GetFileSizeEx(file_, &file_size)) {
213 DWORD error = GetLastError(); 246 DWORD error = GetLastError();
214 LOG(WARNING) << "GetFileSizeEx failed: " << error; 247 LOG(WARNING) << "GetFileSizeEx failed: " << error;
215 return MapErrorCode(error); 248 return RecordAndMapError(error, FILE_ERROR_SOURCE_GET_SIZE);
216 } 249 }
217 250
218 return file_size.QuadPart - cur_pos; 251 return file_size.QuadPart - cur_pos;
219 } 252 }
220 253
221 int FileStream::Read( 254 int FileStream::Read(
222 char* buf, int buf_len, CompletionCallback* callback) { 255 char* buf, int buf_len, CompletionCallback* callback) {
223 if (!IsOpen()) 256 if (!IsOpen())
224 return ERR_UNEXPECTED; 257 return ERR_UNEXPECTED;
258
225 DCHECK(open_flags_ & base::PLATFORM_FILE_READ); 259 DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
226 260
227 OVERLAPPED* overlapped = NULL; 261 OVERLAPPED* overlapped = NULL;
228 if (async_context_.get()) { 262 if (async_context_.get()) {
229 DCHECK(callback); 263 DCHECK(callback);
230 DCHECK(!async_context_->callback()); 264 DCHECK(!async_context_->callback());
231 overlapped = async_context_->overlapped(); 265 overlapped = async_context_->overlapped();
266 async_context_->set_operation(AsyncContext::ASYNC_OPERATION_READ);
232 } else { 267 } else {
233 DCHECK(!callback); 268 DCHECK(!callback);
234 base::ThreadRestrictions::AssertIOAllowed(); 269 base::ThreadRestrictions::AssertIOAllowed();
235 } 270 }
236 271
237 int rv; 272 int rv;
238 273
239 DWORD bytes_read; 274 DWORD bytes_read;
240 if (!ReadFile(file_, buf, buf_len, &bytes_read, overlapped)) { 275 if (!ReadFile(file_, buf, buf_len, &bytes_read, overlapped)) {
241 DWORD error = GetLastError(); 276 DWORD error = GetLastError();
242 if (async_context_.get() && error == ERROR_IO_PENDING) { 277 if (async_context_.get() && error == ERROR_IO_PENDING) {
243 async_context_->IOCompletionIsPending(callback); 278 async_context_->IOCompletionIsPending(callback);
244 rv = ERR_IO_PENDING; 279 rv = ERR_IO_PENDING;
245 } else if (error == ERROR_HANDLE_EOF) { 280 } else if (error == ERROR_HANDLE_EOF) {
246 rv = 0; // Report EOF by returning 0 bytes read. 281 rv = 0; // Report EOF by returning 0 bytes read.
247 } else { 282 } else {
248 LOG(WARNING) << "ReadFile failed: " << error; 283 LOG(WARNING) << "ReadFile failed: " << error;
249 rv = MapErrorCode(error); 284 rv = RecordAndMapError(error, FILE_ERROR_SOURCE_READ);
250 } 285 }
251 } else if (overlapped) { 286 } else if (overlapped) {
252 async_context_->IOCompletionIsPending(callback); 287 async_context_->IOCompletionIsPending(callback);
253 rv = ERR_IO_PENDING; 288 rv = ERR_IO_PENDING;
254 } else { 289 } else {
255 rv = static_cast<int>(bytes_read); 290 rv = static_cast<int>(bytes_read);
256 } 291 }
257 return rv; 292 return rv;
258 } 293 }
259 294
(...skipping 15 matching lines...) Expand all
275 to_read -= bytes_read; 310 to_read -= bytes_read;
276 } while (bytes_total < buf_len); 311 } while (bytes_total < buf_len);
277 312
278 return bytes_total; 313 return bytes_total;
279 } 314 }
280 315
281 int FileStream::Write( 316 int FileStream::Write(
282 const char* buf, int buf_len, CompletionCallback* callback) { 317 const char* buf, int buf_len, CompletionCallback* callback) {
283 if (!IsOpen()) 318 if (!IsOpen())
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();
328 async_context_->set_operation(AsyncContext::ASYNC_OPERATION_WRITE);
292 } else { 329 } else {
293 DCHECK(!callback); 330 DCHECK(!callback);
294 base::ThreadRestrictions::AssertIOAllowed(); 331 base::ThreadRestrictions::AssertIOAllowed();
295 } 332 }
296 333
297 int rv; 334 int rv;
298 DWORD bytes_written; 335 DWORD bytes_written;
299 if (!WriteFile(file_, buf, buf_len, &bytes_written, overlapped)) { 336 if (!WriteFile(file_, buf, buf_len, &bytes_written, overlapped)) {
300 DWORD error = GetLastError(); 337 DWORD error = GetLastError();
301 if (async_context_.get() && error == ERROR_IO_PENDING) { 338 if (async_context_.get() && error == ERROR_IO_PENDING) {
302 async_context_->IOCompletionIsPending(callback); 339 async_context_->IOCompletionIsPending(callback);
303 rv = ERR_IO_PENDING; 340 rv = ERR_IO_PENDING;
304 } else { 341 } else {
305 LOG(WARNING) << "WriteFile failed: " << error; 342 LOG(WARNING) << "WriteFile failed: " << error;
306 rv = MapErrorCode(error); 343 rv = RecordAndMapError(error, FILE_ERROR_SOURCE_WRITE);
307 } 344 }
308 } else if (overlapped) { 345 } else if (overlapped) {
309 async_context_->IOCompletionIsPending(callback); 346 async_context_->IOCompletionIsPending(callback);
310 rv = ERR_IO_PENDING; 347 rv = ERR_IO_PENDING;
311 } else { 348 } else {
312 rv = static_cast<int>(bytes_written); 349 rv = static_cast<int>(bytes_written);
313 } 350 }
314 return rv; 351 return rv;
315 } 352 }
316 353
317 int FileStream::Flush() { 354 int FileStream::Flush() {
318 base::ThreadRestrictions::AssertIOAllowed(); 355 base::ThreadRestrictions::AssertIOAllowed();
319 356
320 if (!IsOpen()) 357 if (!IsOpen())
321 return ERR_UNEXPECTED; 358 return ERR_UNEXPECTED;
322 359
323 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); 360 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
324 if (FlushFileBuffers(file_)) { 361 if (FlushFileBuffers(file_)) {
325 return OK; 362 return OK;
326 } 363 }
327 364
328 int rv; 365 return RecordAndMapError(GetLastError(), FILE_ERROR_SOURCE_FLUSH);
329 DWORD error = GetLastError();
330 rv = MapErrorCode(error);
331 return rv;
332 } 366 }
333 367
334 int64 FileStream::Truncate(int64 bytes) { 368 int64 FileStream::Truncate(int64 bytes) {
335 base::ThreadRestrictions::AssertIOAllowed(); 369 base::ThreadRestrictions::AssertIOAllowed();
336 370
337 if (!IsOpen()) 371 if (!IsOpen())
338 return ERR_UNEXPECTED; 372 return ERR_UNEXPECTED;
339 373
340 // We better be open for reading. 374 // We better be open for reading.
341 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); 375 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
342 376
343 // Seek to the position to truncate from. 377 // Seek to the position to truncate from.
344 int64 seek_position = Seek(FROM_BEGIN, bytes); 378 int64 seek_position = Seek(FROM_BEGIN, bytes);
345 if (seek_position != bytes) 379 if (seek_position != bytes)
346 return ERR_UNEXPECTED; 380 return ERR_UNEXPECTED;
347 381
348 // And truncate the file. 382 // And truncate the file.
349 BOOL result = SetEndOfFile(file_); 383 BOOL result = SetEndOfFile(file_);
350 if (!result) { 384 if (!result) {
351 DWORD error = GetLastError(); 385 DWORD error = GetLastError();
352 LOG(WARNING) << "SetEndOfFile failed: " << error; 386 LOG(WARNING) << "SetEndOfFile failed: " << error;
353 return MapErrorCode(error); 387 return RecordAndMapError(error, FILE_ERROR_SOURCE_SET_EOF);
354 } 388 }
355 389
356 // Success. 390 // Success.
357 return seek_position; 391 return seek_position;
358 } 392 }
359 393
394 void FileStream::EnableErrorStatistics() {
395 record_uma_ = true;
396
397 if (async_context_.get())
398 async_context_->EnableErrorStatistics();
399 }
400
401 int FileStream::RecordAndMapError(int error, FileErrorSource source) {
402 RecordFileError(error, source, record_uma_);
403 return MapErrorCode(error);
404 }
405
360 } // namespace net 406 } // 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