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

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: Removed extra logging. Created 9 years, 3 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
« no previous file with comments | « net/base/file_stream_posix.cc ('k') | net/base/net_errors_posix.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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) {
24 overlapped->Offset = offset.LowPart; 25 overlapped->Offset = offset.LowPart;
25 overlapped->OffsetHigh = offset.HighPart; 26 overlapped->OffsetHigh = offset.HighPart;
26 } 27 }
27 28
28 static void IncrementOffset(OVERLAPPED* overlapped, DWORD count) { 29 static void IncrementOffset(OVERLAPPED* overlapped, DWORD count) {
29 LARGE_INTEGER offset; 30 LARGE_INTEGER offset;
30 offset.LowPart = overlapped->Offset; 31 offset.LowPart = overlapped->Offset;
31 offset.HighPart = overlapped->OffsetHigh; 32 offset.HighPart = overlapped->OffsetHigh;
32 offset.QuadPart += static_cast<LONGLONG>(count); 33 offset.QuadPart += static_cast<LONGLONG>(count);
33 SetOffset(overlapped, offset); 34 SetOffset(overlapped, offset);
34 } 35 }
35 36
37 namespace {
38
39 int RecordAndMapError(int error, FileErrorSource source, bool record_uma) {
40 RecordFileError(error, source, record_uma);
41 return MapSystemError(error);
42 }
43
44 } // namespace
45
36 // FileStream::AsyncContext ---------------------------------------------- 46 // FileStream::AsyncContext ----------------------------------------------
37 47
38 class FileStream::AsyncContext : public MessageLoopForIO::IOHandler { 48 class FileStream::AsyncContext : public MessageLoopForIO::IOHandler {
39 public: 49 public:
40 AsyncContext(FileStream* owner) 50 AsyncContext(FileStream* owner)
41 : owner_(owner), context_(), callback_(NULL), is_closing_(false) { 51 : owner_(owner), context_(), callback_(NULL), is_closing_(false),
52 record_uma_(false), error_source_(FILE_ERROR_SOURCE_COUNT) {
42 context_.handler = this; 53 context_.handler = this;
43 } 54 }
44 ~AsyncContext(); 55 ~AsyncContext();
45 56
46 void IOCompletionIsPending(CompletionCallback* callback); 57 void IOCompletionIsPending(CompletionCallback* callback);
47 58
48 OVERLAPPED* overlapped() { return &context_.overlapped; } 59 OVERLAPPED* overlapped() { return &context_.overlapped; }
49 CompletionCallback* callback() const { return callback_; } 60 CompletionCallback* callback() const { return callback_; }
50 61
62 void set_error_source(FileErrorSource source) { error_source_ = source; }
63
64 void EnableErrorStatistics() {
65 record_uma_ = true;
66 }
67
51 private: 68 private:
52 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context, 69 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
53 DWORD bytes_read, DWORD error); 70 DWORD bytes_read, DWORD error);
54 71
55 FileStream* owner_; 72 FileStream* owner_;
56 MessageLoopForIO::IOContext context_; 73 MessageLoopForIO::IOContext context_;
57 CompletionCallback* callback_; 74 CompletionCallback* callback_;
58 bool is_closing_; 75 bool is_closing_;
76 bool record_uma_;
77 FileErrorSource error_source_;
59 }; 78 };
60 79
61 FileStream::AsyncContext::~AsyncContext() { 80 FileStream::AsyncContext::~AsyncContext() {
62 is_closing_ = true; 81 is_closing_ = true;
63 bool waited = false; 82 bool waited = false;
64 base::TimeTicks start = base::TimeTicks::Now(); 83 base::TimeTicks start = base::TimeTicks::Now();
65 while (callback_) { 84 while (callback_) {
66 waited = true; 85 waited = true;
67 MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this); 86 MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this);
68 } 87 }
(...skipping 15 matching lines...) Expand all
84 DCHECK_EQ(&context_, context); 103 DCHECK_EQ(&context_, context);
85 DCHECK(callback_); 104 DCHECK(callback_);
86 105
87 if (is_closing_) { 106 if (is_closing_) {
88 callback_ = NULL; 107 callback_ = NULL;
89 return; 108 return;
90 } 109 }
91 110
92 int result = static_cast<int>(bytes_read); 111 int result = static_cast<int>(bytes_read);
93 if (error && error != ERROR_HANDLE_EOF) 112 if (error && error != ERROR_HANDLE_EOF)
94 result = MapSystemError(error); 113 result = RecordAndMapError(error, error_source_, record_uma_);
95 114
96 if (bytes_read) 115 if (bytes_read)
97 IncrementOffset(&context->overlapped, bytes_read); 116 IncrementOffset(&context->overlapped, bytes_read);
98 117
99 CompletionCallback* temp = NULL; 118 CompletionCallback* temp = NULL;
100 std::swap(temp, callback_); 119 std::swap(temp, callback_);
101 temp->Run(result); 120 temp->Run(result);
102 } 121 }
103 122
104 // FileStream ------------------------------------------------------------ 123 // FileStream ------------------------------------------------------------
105 124
106 FileStream::FileStream() 125 FileStream::FileStream()
107 : file_(INVALID_HANDLE_VALUE), 126 : file_(INVALID_HANDLE_VALUE),
108 open_flags_(0), 127 open_flags_(0),
109 auto_closed_(true) { 128 auto_closed_(true),
129 record_uma_(false) {
110 } 130 }
111 131
112 FileStream::FileStream(base::PlatformFile file, int flags) 132 FileStream::FileStream(base::PlatformFile file, int flags)
113 : file_(file), 133 : file_(file),
114 open_flags_(flags), 134 open_flags_(flags),
115 auto_closed_(false) { 135 auto_closed_(false),
136 record_uma_(false) {
116 // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to 137 // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to
117 // make sure we will perform asynchronous File IO to it. 138 // make sure we will perform asynchronous File IO to it.
118 if (flags & base::PLATFORM_FILE_ASYNC) { 139 if (flags & base::PLATFORM_FILE_ASYNC) {
119 async_context_.reset(new AsyncContext(this)); 140 async_context_.reset(new AsyncContext(this));
120 MessageLoopForIO::current()->RegisterIOHandler(file_, 141 MessageLoopForIO::current()->RegisterIOHandler(file_,
121 async_context_.get()); 142 async_context_.get());
122 } 143 }
123 } 144 }
124 145
125 FileStream::~FileStream() { 146 FileStream::~FileStream() {
(...skipping 16 matching lines...) Expand all
142 if (IsOpen()) { 163 if (IsOpen()) {
143 DLOG(FATAL) << "File is already open!"; 164 DLOG(FATAL) << "File is already open!";
144 return ERR_UNEXPECTED; 165 return ERR_UNEXPECTED;
145 } 166 }
146 167
147 open_flags_ = open_flags; 168 open_flags_ = open_flags;
148 file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL); 169 file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL);
149 if (file_ == INVALID_HANDLE_VALUE) { 170 if (file_ == INVALID_HANDLE_VALUE) {
150 DWORD error = GetLastError(); 171 DWORD error = GetLastError();
151 LOG(WARNING) << "Failed to open file: " << error; 172 LOG(WARNING) << "Failed to open file: " << error;
152 return MapSystemError(error); 173 return RecordAndMapError(error, FILE_ERROR_SOURCE_OPEN, record_uma_);
153 } 174 }
154 175
155 if (open_flags_ & base::PLATFORM_FILE_ASYNC) { 176 if (open_flags_ & base::PLATFORM_FILE_ASYNC) {
156 async_context_.reset(new AsyncContext(this)); 177 async_context_.reset(new AsyncContext(this));
178 if (record_uma_)
179 async_context_->EnableErrorStatistics();
157 MessageLoopForIO::current()->RegisterIOHandler(file_, 180 MessageLoopForIO::current()->RegisterIOHandler(file_,
158 async_context_.get()); 181 async_context_.get());
159 } 182 }
160 183
161 return OK; 184 return OK;
162 } 185 }
163 186
164 bool FileStream::IsOpen() const { 187 bool FileStream::IsOpen() const {
165 return file_ != INVALID_HANDLE_VALUE; 188 return file_ != INVALID_HANDLE_VALUE;
166 } 189 }
167 190
168 int64 FileStream::Seek(Whence whence, int64 offset) { 191 int64 FileStream::Seek(Whence whence, int64 offset) {
169 if (!IsOpen()) 192 if (!IsOpen())
170 return ERR_UNEXPECTED; 193 return ERR_UNEXPECTED;
194
171 DCHECK(!async_context_.get() || !async_context_->callback()); 195 DCHECK(!async_context_.get() || !async_context_->callback());
172 196
173 LARGE_INTEGER distance, result; 197 LARGE_INTEGER distance, result;
174 distance.QuadPart = offset; 198 distance.QuadPart = offset;
175 DWORD move_method = static_cast<DWORD>(whence); 199 DWORD move_method = static_cast<DWORD>(whence);
176 if (!SetFilePointerEx(file_, distance, &result, move_method)) { 200 if (!SetFilePointerEx(file_, distance, &result, move_method)) {
177 DWORD error = GetLastError(); 201 DWORD error = GetLastError();
178 LOG(WARNING) << "SetFilePointerEx failed: " << error; 202 LOG(WARNING) << "SetFilePointerEx failed: " << error;
179 return MapSystemError(error); 203 return RecordAndMapError(error, FILE_ERROR_SOURCE_SEEK, record_uma_);
180 } 204 }
181 if (async_context_.get()) 205 if (async_context_.get()) {
206 async_context_->set_error_source(FILE_ERROR_SOURCE_SEEK);
182 SetOffset(async_context_->overlapped(), result); 207 SetOffset(async_context_->overlapped(), result);
208 }
183 return result.QuadPart; 209 return result.QuadPart;
184 } 210 }
185 211
186 int64 FileStream::Available() { 212 int64 FileStream::Available() {
187 base::ThreadRestrictions::AssertIOAllowed(); 213 base::ThreadRestrictions::AssertIOAllowed();
188 214
189 if (!IsOpen()) 215 if (!IsOpen())
190 return ERR_UNEXPECTED; 216 return ERR_UNEXPECTED;
191 217
192 int64 cur_pos = Seek(FROM_CURRENT, 0); 218 int64 cur_pos = Seek(FROM_CURRENT, 0);
193 if (cur_pos < 0) 219 if (cur_pos < 0)
194 return cur_pos; 220 return cur_pos;
195 221
196 LARGE_INTEGER file_size; 222 LARGE_INTEGER file_size;
197 if (!GetFileSizeEx(file_, &file_size)) { 223 if (!GetFileSizeEx(file_, &file_size)) {
198 DWORD error = GetLastError(); 224 DWORD error = GetLastError();
199 LOG(WARNING) << "GetFileSizeEx failed: " << error; 225 LOG(WARNING) << "GetFileSizeEx failed: " << error;
200 return MapSystemError(error); 226 return RecordAndMapError(error, FILE_ERROR_SOURCE_GET_SIZE, record_uma_);
201 } 227 }
202 228
203 return file_size.QuadPart - cur_pos; 229 return file_size.QuadPart - cur_pos;
204 } 230 }
205 231
206 int FileStream::Read( 232 int FileStream::Read(
207 char* buf, int buf_len, CompletionCallback* callback) { 233 char* buf, int buf_len, CompletionCallback* callback) {
208 if (!IsOpen()) 234 if (!IsOpen())
209 return ERR_UNEXPECTED; 235 return ERR_UNEXPECTED;
236
210 DCHECK(open_flags_ & base::PLATFORM_FILE_READ); 237 DCHECK(open_flags_ & base::PLATFORM_FILE_READ);
211 238
212 OVERLAPPED* overlapped = NULL; 239 OVERLAPPED* overlapped = NULL;
213 if (async_context_.get()) { 240 if (async_context_.get()) {
214 DCHECK(callback); 241 DCHECK(callback);
215 DCHECK(!async_context_->callback()); 242 DCHECK(!async_context_->callback());
216 overlapped = async_context_->overlapped(); 243 overlapped = async_context_->overlapped();
244 async_context_->set_error_source(FILE_ERROR_SOURCE_READ);
217 } else { 245 } else {
218 DCHECK(!callback); 246 DCHECK(!callback);
219 base::ThreadRestrictions::AssertIOAllowed(); 247 base::ThreadRestrictions::AssertIOAllowed();
220 } 248 }
221 249
222 int rv; 250 int rv;
223 251
224 DWORD bytes_read; 252 DWORD bytes_read;
225 if (!ReadFile(file_, buf, buf_len, &bytes_read, overlapped)) { 253 if (!ReadFile(file_, buf, buf_len, &bytes_read, overlapped)) {
226 DWORD error = GetLastError(); 254 DWORD error = GetLastError();
227 if (async_context_.get() && error == ERROR_IO_PENDING) { 255 if (async_context_.get() && error == ERROR_IO_PENDING) {
228 async_context_->IOCompletionIsPending(callback); 256 async_context_->IOCompletionIsPending(callback);
229 rv = ERR_IO_PENDING; 257 rv = ERR_IO_PENDING;
230 } else if (error == ERROR_HANDLE_EOF) { 258 } else if (error == ERROR_HANDLE_EOF) {
231 rv = 0; // Report EOF by returning 0 bytes read. 259 rv = 0; // Report EOF by returning 0 bytes read.
232 } else { 260 } else {
233 LOG(WARNING) << "ReadFile failed: " << error; 261 LOG(WARNING) << "ReadFile failed: " << error;
234 rv = MapSystemError(error); 262 rv = RecordAndMapError(error, FILE_ERROR_SOURCE_READ, record_uma_);
235 } 263 }
236 } else if (overlapped) { 264 } else if (overlapped) {
237 async_context_->IOCompletionIsPending(callback); 265 async_context_->IOCompletionIsPending(callback);
238 rv = ERR_IO_PENDING; 266 rv = ERR_IO_PENDING;
239 } else { 267 } else {
240 rv = static_cast<int>(bytes_read); 268 rv = static_cast<int>(bytes_read);
241 } 269 }
242 return rv; 270 return rv;
243 } 271 }
244 272
(...skipping 15 matching lines...) Expand all
260 to_read -= bytes_read; 288 to_read -= bytes_read;
261 } while (bytes_total < buf_len); 289 } while (bytes_total < buf_len);
262 290
263 return bytes_total; 291 return bytes_total;
264 } 292 }
265 293
266 int FileStream::Write( 294 int FileStream::Write(
267 const char* buf, int buf_len, CompletionCallback* callback) { 295 const char* buf, int buf_len, CompletionCallback* callback) {
268 if (!IsOpen()) 296 if (!IsOpen())
269 return ERR_UNEXPECTED; 297 return ERR_UNEXPECTED;
298
270 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); 299 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
271 300
272 OVERLAPPED* overlapped = NULL; 301 OVERLAPPED* overlapped = NULL;
273 if (async_context_.get()) { 302 if (async_context_.get()) {
274 DCHECK(callback); 303 DCHECK(callback);
275 DCHECK(!async_context_->callback()); 304 DCHECK(!async_context_->callback());
276 overlapped = async_context_->overlapped(); 305 overlapped = async_context_->overlapped();
306 async_context_->set_error_source(FILE_ERROR_SOURCE_WRITE);
277 } else { 307 } else {
278 DCHECK(!callback); 308 DCHECK(!callback);
279 base::ThreadRestrictions::AssertIOAllowed(); 309 base::ThreadRestrictions::AssertIOAllowed();
280 } 310 }
281 311
282 int rv; 312 int rv;
283 DWORD bytes_written; 313 DWORD bytes_written;
284 if (!WriteFile(file_, buf, buf_len, &bytes_written, overlapped)) { 314 if (!WriteFile(file_, buf, buf_len, &bytes_written, overlapped)) {
285 DWORD error = GetLastError(); 315 DWORD error = GetLastError();
286 if (async_context_.get() && error == ERROR_IO_PENDING) { 316 if (async_context_.get() && error == ERROR_IO_PENDING) {
287 async_context_->IOCompletionIsPending(callback); 317 async_context_->IOCompletionIsPending(callback);
288 rv = ERR_IO_PENDING; 318 rv = ERR_IO_PENDING;
289 } else { 319 } else {
290 LOG(WARNING) << "WriteFile failed: " << error; 320 LOG(WARNING) << "WriteFile failed: " << error;
291 rv = MapSystemError(error); 321 rv = RecordAndMapError(error, FILE_ERROR_SOURCE_WRITE, record_uma_);
292 } 322 }
293 } else if (overlapped) { 323 } else if (overlapped) {
294 async_context_->IOCompletionIsPending(callback); 324 async_context_->IOCompletionIsPending(callback);
295 rv = ERR_IO_PENDING; 325 rv = ERR_IO_PENDING;
296 } else { 326 } else {
297 rv = static_cast<int>(bytes_written); 327 rv = static_cast<int>(bytes_written);
298 } 328 }
299 return rv; 329 return rv;
300 } 330 }
301 331
302 int FileStream::Flush() { 332 int FileStream::Flush() {
303 base::ThreadRestrictions::AssertIOAllowed(); 333 base::ThreadRestrictions::AssertIOAllowed();
304 334
305 if (!IsOpen()) 335 if (!IsOpen())
306 return ERR_UNEXPECTED; 336 return ERR_UNEXPECTED;
307 337
308 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); 338 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
309 if (FlushFileBuffers(file_)) { 339 if (FlushFileBuffers(file_)) {
310 return OK; 340 return OK;
311 } 341 }
312 342
313 int rv; 343 return RecordAndMapError(GetLastError(),
314 DWORD error = GetLastError(); 344 FILE_ERROR_SOURCE_FLUSH,
315 rv = MapSystemError(error); 345 record_uma_);
316 return rv;
317 } 346 }
318 347
319 int64 FileStream::Truncate(int64 bytes) { 348 int64 FileStream::Truncate(int64 bytes) {
320 base::ThreadRestrictions::AssertIOAllowed(); 349 base::ThreadRestrictions::AssertIOAllowed();
321 350
322 if (!IsOpen()) 351 if (!IsOpen())
323 return ERR_UNEXPECTED; 352 return ERR_UNEXPECTED;
324 353
325 // We better be open for reading. 354 // We better be open for reading.
326 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE); 355 DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);
327 356
328 // Seek to the position to truncate from. 357 // Seek to the position to truncate from.
329 int64 seek_position = Seek(FROM_BEGIN, bytes); 358 int64 seek_position = Seek(FROM_BEGIN, bytes);
330 if (seek_position != bytes) 359 if (seek_position != bytes)
331 return ERR_UNEXPECTED; 360 return ERR_UNEXPECTED;
332 361
333 // And truncate the file. 362 // And truncate the file.
334 BOOL result = SetEndOfFile(file_); 363 BOOL result = SetEndOfFile(file_);
335 if (!result) { 364 if (!result) {
336 DWORD error = GetLastError(); 365 DWORD error = GetLastError();
337 LOG(WARNING) << "SetEndOfFile failed: " << error; 366 LOG(WARNING) << "SetEndOfFile failed: " << error;
338 return MapSystemError(error); 367 return RecordAndMapError(error, FILE_ERROR_SOURCE_SET_EOF, record_uma_);
339 } 368 }
340 369
341 // Success. 370 // Success.
342 return seek_position; 371 return seek_position;
343 } 372 }
344 373
374 void FileStream::EnableErrorStatistics() {
375 record_uma_ = true;
376
377 if (async_context_.get())
378 async_context_->EnableErrorStatistics();
379 }
380
345 } // namespace net 381 } // namespace net
OLDNEW
« no previous file with comments | « net/base/file_stream_posix.cc ('k') | net/base/net_errors_posix.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698