Check if drivers support GL_OES_texture_float even with GLES3 context.
[chromium-blink-merge.git] / net / http / disk_cache_based_quic_server_info.cc
blob4ed2bfa2b4380cebc6d85f08adcf360ec253c6ec
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/http/disk_cache_based_quic_server_info.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/logging.h"
10 #include "base/metrics/histogram.h"
11 #include "net/base/completion_callback.h"
12 #include "net/base/io_buffer.h"
13 #include "net/base/net_errors.h"
14 #include "net/http/http_cache.h"
15 #include "net/http/http_network_session.h"
16 #include "net/quic/quic_server_id.h"
18 namespace net {
20 // Some APIs inside disk_cache take a handle that the caller must keep alive
21 // until the API has finished its asynchronous execution.
23 // Unfortunately, DiskCacheBasedQuicServerInfo may be deleted before the
24 // operation completes causing a use-after-free.
26 // This data shim struct is meant to provide a location for the disk_cache
27 // APIs to write into even if the originating DiskCacheBasedQuicServerInfo
28 // object has been deleted. The lifetime for instances of this struct
29 // should be bound to the CompletionCallback that is passed to the disk_cache
30 // API. We do this by binding an instance of this struct to an unused
31 // parameter for OnIOComplete() using base::Owned().
33 // This is a hack. A better fix is to make it so that the disk_cache APIs
34 // take a Callback to a mutator for setting the output value rather than
35 // writing into a raw handle. Then the caller can just pass in a Callback
36 // bound to WeakPtr for itself. This callback would correctly "no-op" itself
37 // when the DiskCacheBasedQuicServerInfo object is deleted.
39 // TODO(ajwong): Change disk_cache's API to return results via Callback.
40 struct DiskCacheBasedQuicServerInfo::CacheOperationDataShim {
41 CacheOperationDataShim() : backend(NULL), entry(NULL) {}
43 disk_cache::Backend* backend;
44 disk_cache::Entry* entry;
47 DiskCacheBasedQuicServerInfo::DiskCacheBasedQuicServerInfo(
48 const QuicServerId& server_id,
49 HttpCache* http_cache)
50 : QuicServerInfo(server_id),
51 data_shim_(new CacheOperationDataShim()),
52 state_(GET_BACKEND),
53 ready_(false),
54 found_entry_(false),
55 server_id_(server_id),
56 http_cache_(http_cache),
57 backend_(NULL),
58 entry_(NULL),
59 weak_factory_(this) {
60 io_callback_ =
61 base::Bind(&DiskCacheBasedQuicServerInfo::OnIOComplete,
62 weak_factory_.GetWeakPtr(),
63 base::Owned(data_shim_)); // Ownership assigned.
66 void DiskCacheBasedQuicServerInfo::Start() {
67 DCHECK(CalledOnValidThread());
68 DCHECK_EQ(GET_BACKEND, state_);
69 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_START);
70 load_start_time_ = base::TimeTicks::Now();
71 DoLoop(OK);
74 int DiskCacheBasedQuicServerInfo::WaitForDataReady(
75 const CompletionCallback& callback) {
76 DCHECK(CalledOnValidThread());
77 DCHECK_NE(GET_BACKEND, state_);
79 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY);
80 if (ready_)
81 return OK;
83 if (!callback.is_null()) {
84 // Prevent a new callback for WaitForDataReady overwriting an existing
85 // pending callback (|user_callback_|).
86 // TODO(rtenneti): Rename user_callback_ as wait_for_ready_callback_.
87 if (!user_callback_.is_null()) {
88 RecordQuicServerInfoFailure(WAIT_FOR_DATA_READY_INVALID_ARGUMENT_FAILURE);
89 return ERR_INVALID_ARGUMENT;
91 user_callback_ = callback;
94 return ERR_IO_PENDING;
97 void DiskCacheBasedQuicServerInfo::CancelWaitForDataReadyCallback() {
98 DCHECK(CalledOnValidThread());
100 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL);
101 if (!user_callback_.is_null())
102 user_callback_.Reset();
105 bool DiskCacheBasedQuicServerInfo::IsDataReady() {
106 return ready_;
109 bool DiskCacheBasedQuicServerInfo::IsReadyToPersist() {
110 // The data can be persisted if it has been loaded from the disk cache
111 // and there are no pending writes.
112 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_READY_TO_PERSIST);
113 if (ready_ && new_data_.empty())
114 return true;
115 RecordQuicServerInfoFailure(READY_TO_PERSIST_FAILURE);
116 return false;
119 void DiskCacheBasedQuicServerInfo::Persist() {
120 DCHECK(CalledOnValidThread());
121 if (!IsReadyToPersist()) {
122 // Handle updates while a write is pending or if we haven't loaded from disk
123 // cache. Save the data to be written into a temporary buffer and then
124 // persist that data when we are ready to persist.
125 pending_write_data_ = Serialize();
126 return;
128 PersistInternal();
131 void DiskCacheBasedQuicServerInfo::PersistInternal() {
132 DCHECK(CalledOnValidThread());
133 DCHECK_NE(GET_BACKEND, state_);
135 DCHECK(new_data_.empty());
136 CHECK(ready_);
137 DCHECK(user_callback_.is_null());
138 if (pending_write_data_.empty()) {
139 new_data_ = Serialize();
140 } else {
141 new_data_ = pending_write_data_;
142 pending_write_data_.clear();
145 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_PERSIST);
146 if (!backend_) {
147 RecordQuicServerInfoFailure(PERSIST_NO_BACKEND_FAILURE);
148 return;
151 state_ = CREATE_OR_OPEN;
152 DoLoop(OK);
155 void DiskCacheBasedQuicServerInfo::OnExternalCacheHit() {
156 DCHECK(CalledOnValidThread());
157 DCHECK_NE(GET_BACKEND, state_);
159 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_EXTERNAL_CACHE_HIT);
160 if (!backend_) {
161 RecordQuicServerInfoFailure(PERSIST_NO_BACKEND_FAILURE);
162 return;
165 backend_->OnExternalCacheHit(key());
168 DiskCacheBasedQuicServerInfo::~DiskCacheBasedQuicServerInfo() {
169 DCHECK(user_callback_.is_null());
170 if (entry_)
171 entry_->Close();
174 std::string DiskCacheBasedQuicServerInfo::key() const {
175 return "quicserverinfo:" + server_id_.ToString();
178 void DiskCacheBasedQuicServerInfo::OnIOComplete(CacheOperationDataShim* unused,
179 int rv) {
180 DCHECK_NE(NONE, state_);
181 rv = DoLoop(rv);
182 if (rv == ERR_IO_PENDING)
183 return;
184 if (!user_callback_.is_null()) {
185 CompletionCallback callback = user_callback_;
186 user_callback_.Reset();
187 callback.Run(rv);
189 if (ready_ && !pending_write_data_.empty()) {
190 DCHECK_EQ(NONE, state_);
191 PersistInternal();
195 int DiskCacheBasedQuicServerInfo::DoLoop(int rv) {
196 do {
197 switch (state_) {
198 case GET_BACKEND:
199 rv = DoGetBackend();
200 break;
201 case GET_BACKEND_COMPLETE:
202 rv = DoGetBackendComplete(rv);
203 break;
204 case OPEN:
205 rv = DoOpen();
206 break;
207 case OPEN_COMPLETE:
208 rv = DoOpenComplete(rv);
209 break;
210 case READ:
211 rv = DoRead();
212 break;
213 case READ_COMPLETE:
214 rv = DoReadComplete(rv);
215 break;
216 case WAIT_FOR_DATA_READY_DONE:
217 rv = DoWaitForDataReadyDone();
218 break;
219 case CREATE_OR_OPEN:
220 rv = DoCreateOrOpen();
221 break;
222 case CREATE_OR_OPEN_COMPLETE:
223 rv = DoCreateOrOpenComplete(rv);
224 break;
225 case WRITE:
226 rv = DoWrite();
227 break;
228 case WRITE_COMPLETE:
229 rv = DoWriteComplete(rv);
230 break;
231 case SET_DONE:
232 rv = DoSetDone();
233 break;
234 default:
235 rv = OK;
236 NOTREACHED();
238 } while (rv != ERR_IO_PENDING && state_ != NONE);
240 return rv;
243 int DiskCacheBasedQuicServerInfo::DoGetBackendComplete(int rv) {
244 if (rv == OK) {
245 backend_ = data_shim_->backend;
246 state_ = OPEN;
247 } else {
248 RecordQuicServerInfoFailure(GET_BACKEND_FAILURE);
249 state_ = WAIT_FOR_DATA_READY_DONE;
251 return OK;
254 int DiskCacheBasedQuicServerInfo::DoOpenComplete(int rv) {
255 if (rv == OK) {
256 entry_ = data_shim_->entry;
257 state_ = READ;
258 found_entry_ = true;
259 } else {
260 RecordQuicServerInfoFailure(OPEN_FAILURE);
261 state_ = WAIT_FOR_DATA_READY_DONE;
264 return OK;
267 int DiskCacheBasedQuicServerInfo::DoReadComplete(int rv) {
268 if (rv > 0)
269 data_.assign(read_buffer_->data(), rv);
270 else if (rv < 0)
271 RecordQuicServerInfoFailure(READ_FAILURE);
273 state_ = WAIT_FOR_DATA_READY_DONE;
274 return OK;
277 int DiskCacheBasedQuicServerInfo::DoWriteComplete(int rv) {
278 if (rv < 0)
279 RecordQuicServerInfoFailure(WRITE_FAILURE);
280 state_ = SET_DONE;
281 return OK;
284 int DiskCacheBasedQuicServerInfo::DoCreateOrOpenComplete(int rv) {
285 if (rv != OK) {
286 RecordQuicServerInfoFailure(CREATE_OR_OPEN_FAILURE);
287 state_ = SET_DONE;
288 } else {
289 if (!entry_) {
290 entry_ = data_shim_->entry;
291 found_entry_ = true;
293 DCHECK(entry_);
294 state_ = WRITE;
296 return OK;
299 int DiskCacheBasedQuicServerInfo::DoGetBackend() {
300 state_ = GET_BACKEND_COMPLETE;
301 return http_cache_->GetBackend(&data_shim_->backend, io_callback_);
304 int DiskCacheBasedQuicServerInfo::DoOpen() {
305 state_ = OPEN_COMPLETE;
306 return backend_->OpenEntry(key(), &data_shim_->entry, io_callback_);
309 int DiskCacheBasedQuicServerInfo::DoRead() {
310 const int32 size = entry_->GetDataSize(0 /* index */);
311 if (!size) {
312 state_ = WAIT_FOR_DATA_READY_DONE;
313 return OK;
316 read_buffer_ = new IOBuffer(size);
317 state_ = READ_COMPLETE;
318 return entry_->ReadData(
319 0 /* index */, 0 /* offset */, read_buffer_.get(), size, io_callback_);
322 int DiskCacheBasedQuicServerInfo::DoWrite() {
323 write_buffer_ = new IOBuffer(new_data_.size());
324 memcpy(write_buffer_->data(), new_data_.data(), new_data_.size());
325 state_ = WRITE_COMPLETE;
327 return entry_->WriteData(0 /* index */,
328 0 /* offset */,
329 write_buffer_.get(),
330 new_data_.size(),
331 io_callback_,
332 true /* truncate */);
335 int DiskCacheBasedQuicServerInfo::DoCreateOrOpen() {
336 state_ = CREATE_OR_OPEN_COMPLETE;
337 if (entry_)
338 return OK;
340 if (found_entry_) {
341 return backend_->OpenEntry(key(), &data_shim_->entry, io_callback_);
344 return backend_->CreateEntry(key(), &data_shim_->entry, io_callback_);
347 int DiskCacheBasedQuicServerInfo::DoWaitForDataReadyDone() {
348 DCHECK(!ready_);
349 state_ = NONE;
350 ready_ = true;
351 // We close the entry because, if we shutdown before ::Persist is called,
352 // then we might leak a cache reference, which causes a DCHECK on shutdown.
353 if (entry_)
354 entry_->Close();
355 entry_ = NULL;
357 RecordQuicServerInfoStatus(QUIC_SERVER_INFO_PARSE);
358 if (!Parse(data_)) {
359 if (data_.empty())
360 RecordQuicServerInfoFailure(PARSE_NO_DATA_FAILURE);
361 else
362 RecordQuicServerInfoFailure(PARSE_FAILURE);
365 UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheLoadTime",
366 base::TimeTicks::Now() - load_start_time_);
367 return OK;
370 int DiskCacheBasedQuicServerInfo::DoSetDone() {
371 if (entry_)
372 entry_->Close();
373 entry_ = NULL;
374 new_data_.clear();
375 state_ = NONE;
376 return OK;
379 void DiskCacheBasedQuicServerInfo::RecordQuicServerInfoStatus(
380 QuicServerInfoAPICall call) {
381 if (!backend_) {
382 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.NoBackend", call,
383 QUIC_SERVER_INFO_NUM_OF_API_CALLS);
384 } else if (backend_->GetCacheType() == net::MEMORY_CACHE) {
385 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.MemoryCache", call,
386 QUIC_SERVER_INFO_NUM_OF_API_CALLS);
387 } else {
388 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.DiskCache", call,
389 QUIC_SERVER_INFO_NUM_OF_API_CALLS);
393 void DiskCacheBasedQuicServerInfo::RecordQuicServerInfoFailure(
394 FailureReason failure) {
395 if (!backend_) {
396 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.NoBackend",
397 failure, NUM_OF_FAILURES);
398 } else if (backend_->GetCacheType() == net::MEMORY_CACHE) {
399 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.MemoryCache",
400 failure, NUM_OF_FAILURES);
401 } else {
402 UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.DiskCache",
403 failure, NUM_OF_FAILURES);
407 } // namespace net