• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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.
4 
5 #include "content/browser/indexed_db/indexed_db_context_impl.h"
6 
7 #include <algorithm>
8 #include <utility>
9 
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/files/file_enumerator.h"
13 #include "base/files/file_util.h"
14 #include "base/logging.h"
15 #include "base/metrics/histogram.h"
16 #include "base/sequenced_task_runner.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/threading/thread_restrictions.h"
20 #include "base/time/time.h"
21 #include "base/values.h"
22 #include "content/browser/browser_main_loop.h"
23 #include "content/browser/indexed_db/indexed_db_connection.h"
24 #include "content/browser/indexed_db/indexed_db_database.h"
25 #include "content/browser/indexed_db/indexed_db_dispatcher_host.h"
26 #include "content/browser/indexed_db/indexed_db_factory_impl.h"
27 #include "content/browser/indexed_db/indexed_db_quota_client.h"
28 #include "content/browser/indexed_db/indexed_db_tracing.h"
29 #include "content/browser/indexed_db/indexed_db_transaction.h"
30 #include "content/public/browser/browser_thread.h"
31 #include "content/public/browser/indexed_db_info.h"
32 #include "content/public/common/content_switches.h"
33 #include "storage/browser/database/database_util.h"
34 #include "storage/browser/quota/quota_manager_proxy.h"
35 #include "storage/browser/quota/special_storage_policy.h"
36 #include "storage/common/database/database_identifier.h"
37 #include "ui/base/text/bytes_formatting.h"
38 
39 using base::DictionaryValue;
40 using base::ListValue;
41 using storage::DatabaseUtil;
42 
43 namespace content {
44 const base::FilePath::CharType IndexedDBContextImpl::kIndexedDBDirectory[] =
45     FILE_PATH_LITERAL("IndexedDB");
46 
47 static const base::FilePath::CharType kIndexedDBExtension[] =
48     FILE_PATH_LITERAL(".indexeddb");
49 
50 static const base::FilePath::CharType kLevelDBExtension[] =
51     FILE_PATH_LITERAL(".leveldb");
52 
53 namespace {
54 
55 // This may be called after the IndexedDBContext is destroyed.
GetAllOriginsAndPaths(const base::FilePath & indexeddb_path,std::vector<GURL> * origins,std::vector<base::FilePath> * file_paths)56 void GetAllOriginsAndPaths(const base::FilePath& indexeddb_path,
57                            std::vector<GURL>* origins,
58                            std::vector<base::FilePath>* file_paths) {
59   // TODO(jsbell): DCHECK that this is running on an IndexedDB thread,
60   // if a global handle to it is ever available.
61   if (indexeddb_path.empty())
62     return;
63   base::FileEnumerator file_enumerator(
64       indexeddb_path, false, base::FileEnumerator::DIRECTORIES);
65   for (base::FilePath file_path = file_enumerator.Next(); !file_path.empty();
66        file_path = file_enumerator.Next()) {
67     if (file_path.Extension() == kLevelDBExtension &&
68         file_path.RemoveExtension().Extension() == kIndexedDBExtension) {
69       std::string origin_id = file_path.BaseName().RemoveExtension()
70           .RemoveExtension().MaybeAsASCII();
71       origins->push_back(storage::GetOriginFromIdentifier(origin_id));
72       if (file_paths)
73         file_paths->push_back(file_path);
74     }
75   }
76 }
77 
78 // This will be called after the IndexedDBContext is destroyed.
ClearSessionOnlyOrigins(const base::FilePath & indexeddb_path,scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy)79 void ClearSessionOnlyOrigins(
80     const base::FilePath& indexeddb_path,
81     scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy) {
82   // TODO(jsbell): DCHECK that this is running on an IndexedDB thread,
83   // if a global handle to it is ever available.
84   std::vector<GURL> origins;
85   std::vector<base::FilePath> file_paths;
86   GetAllOriginsAndPaths(indexeddb_path, &origins, &file_paths);
87   DCHECK_EQ(origins.size(), file_paths.size());
88   std::vector<base::FilePath>::const_iterator file_path_iter =
89       file_paths.begin();
90   for (std::vector<GURL>::const_iterator iter = origins.begin();
91        iter != origins.end();
92        ++iter, ++file_path_iter) {
93     if (!special_storage_policy->IsStorageSessionOnly(*iter))
94       continue;
95     if (special_storage_policy->IsStorageProtected(*iter))
96       continue;
97     base::DeleteFile(*file_path_iter, true);
98   }
99 }
100 
101 }  // namespace
102 
IndexedDBContextImpl(const base::FilePath & data_path,storage::SpecialStoragePolicy * special_storage_policy,storage::QuotaManagerProxy * quota_manager_proxy,base::SequencedTaskRunner * task_runner)103 IndexedDBContextImpl::IndexedDBContextImpl(
104     const base::FilePath& data_path,
105     storage::SpecialStoragePolicy* special_storage_policy,
106     storage::QuotaManagerProxy* quota_manager_proxy,
107     base::SequencedTaskRunner* task_runner)
108     : force_keep_session_state_(false),
109       special_storage_policy_(special_storage_policy),
110       quota_manager_proxy_(quota_manager_proxy),
111       task_runner_(task_runner) {
112   IDB_TRACE("init");
113   if (!data_path.empty())
114     data_path_ = data_path.Append(kIndexedDBDirectory);
115   if (quota_manager_proxy) {
116     quota_manager_proxy->RegisterClient(new IndexedDBQuotaClient(this));
117   }
118 }
119 
GetIDBFactory()120 IndexedDBFactory* IndexedDBContextImpl::GetIDBFactory() {
121   DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
122   if (!factory_.get()) {
123     // Prime our cache of origins with existing databases so we can
124     // detect when dbs are newly created.
125     GetOriginSet();
126     factory_ = new IndexedDBFactoryImpl(this);
127   }
128   return factory_.get();
129 }
130 
GetAllOrigins()131 std::vector<GURL> IndexedDBContextImpl::GetAllOrigins() {
132   DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
133   std::vector<GURL> origins;
134   std::set<GURL>* origins_set = GetOriginSet();
135   for (std::set<GURL>::const_iterator iter = origins_set->begin();
136        iter != origins_set->end();
137        ++iter) {
138     origins.push_back(*iter);
139   }
140   return origins;
141 }
142 
GetAllOriginsInfo()143 std::vector<IndexedDBInfo> IndexedDBContextImpl::GetAllOriginsInfo() {
144   DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
145   std::vector<GURL> origins = GetAllOrigins();
146   std::vector<IndexedDBInfo> result;
147   for (std::vector<GURL>::const_iterator iter = origins.begin();
148        iter != origins.end();
149        ++iter) {
150     const GURL& origin_url = *iter;
151 
152     base::FilePath idb_directory = GetFilePath(origin_url);
153     size_t connection_count = GetConnectionCount(origin_url);
154     result.push_back(IndexedDBInfo(origin_url,
155                                    GetOriginDiskUsage(origin_url),
156                                    GetOriginLastModified(origin_url),
157                                    idb_directory,
158                                    connection_count));
159   }
160   return result;
161 }
162 
HostNameComparator(const GURL & i,const GURL & j)163 static bool HostNameComparator(const GURL& i, const GURL& j) {
164   return i.host() < j.host();
165 }
166 
GetAllOriginsDetails()167 base::ListValue* IndexedDBContextImpl::GetAllOriginsDetails() {
168   DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
169   std::vector<GURL> origins = GetAllOrigins();
170 
171   std::sort(origins.begin(), origins.end(), HostNameComparator);
172 
173   scoped_ptr<base::ListValue> list(new base::ListValue());
174   for (std::vector<GURL>::const_iterator iter = origins.begin();
175        iter != origins.end();
176        ++iter) {
177     const GURL& origin_url = *iter;
178 
179     scoped_ptr<base::DictionaryValue> info(new base::DictionaryValue());
180     info->SetString("url", origin_url.spec());
181     info->SetString("size", ui::FormatBytes(GetOriginDiskUsage(origin_url)));
182     info->SetDouble("last_modified",
183                     GetOriginLastModified(origin_url).ToJsTime());
184     if (!is_incognito())
185       info->SetString("path", GetFilePath(origin_url).value());
186     info->SetDouble("connection_count", GetConnectionCount(origin_url));
187 
188     // This ends up being O(n^2) since we iterate over all open databases
189     // to extract just those in the origin, and we're iterating over all
190     // origins in the outer loop.
191 
192     if (factory_.get()) {
193       std::pair<IndexedDBFactory::OriginDBMapIterator,
194                 IndexedDBFactory::OriginDBMapIterator> range =
195           factory_->GetOpenDatabasesForOrigin(origin_url);
196       // TODO(jsbell): Sort by name?
197       scoped_ptr<base::ListValue> database_list(new base::ListValue());
198 
199       for (IndexedDBFactory::OriginDBMapIterator it = range.first;
200            it != range.second;
201            ++it) {
202         const IndexedDBDatabase* db = it->second;
203         scoped_ptr<base::DictionaryValue> db_info(new base::DictionaryValue());
204 
205         db_info->SetString("name", db->name());
206         db_info->SetDouble("pending_opens", db->PendingOpenCount());
207         db_info->SetDouble("pending_upgrades", db->PendingUpgradeCount());
208         db_info->SetDouble("running_upgrades", db->RunningUpgradeCount());
209         db_info->SetDouble("pending_deletes", db->PendingDeleteCount());
210         db_info->SetDouble("connection_count",
211                            db->ConnectionCount() - db->PendingUpgradeCount() -
212                                db->RunningUpgradeCount());
213 
214         scoped_ptr<base::ListValue> transaction_list(new base::ListValue());
215         std::vector<const IndexedDBTransaction*> transactions =
216             db->transaction_coordinator().GetTransactions();
217         for (std::vector<const IndexedDBTransaction*>::iterator trans_it =
218                  transactions.begin();
219              trans_it != transactions.end();
220              ++trans_it) {
221           const IndexedDBTransaction* transaction = *trans_it;
222           scoped_ptr<base::DictionaryValue> transaction_info(
223               new base::DictionaryValue());
224 
225           const char* kModes[] = { "readonly", "readwrite", "versionchange" };
226           transaction_info->SetString("mode", kModes[transaction->mode()]);
227           switch (transaction->state()) {
228             case IndexedDBTransaction::CREATED:
229               transaction_info->SetString("status", "blocked");
230               break;
231             case IndexedDBTransaction::STARTED:
232               if (transaction->diagnostics().tasks_scheduled > 0)
233                 transaction_info->SetString("status", "running");
234               else
235                 transaction_info->SetString("status", "started");
236               break;
237             case IndexedDBTransaction::COMMITTING:
238               transaction_info->SetString("status", "committing");
239               break;
240             case IndexedDBTransaction::FINISHED:
241               transaction_info->SetString("status", "finished");
242               break;
243           }
244 
245           transaction_info->SetDouble(
246               "pid",
247               IndexedDBDispatcherHost::TransactionIdToProcessId(
248                   transaction->id()));
249           transaction_info->SetDouble(
250               "tid",
251               IndexedDBDispatcherHost::TransactionIdToRendererTransactionId(
252                   transaction->id()));
253           transaction_info->SetDouble(
254               "age",
255               (base::Time::Now() - transaction->diagnostics().creation_time)
256                   .InMillisecondsF());
257           transaction_info->SetDouble(
258               "runtime",
259               (base::Time::Now() - transaction->diagnostics().start_time)
260                   .InMillisecondsF());
261           transaction_info->SetDouble(
262               "tasks_scheduled", transaction->diagnostics().tasks_scheduled);
263           transaction_info->SetDouble(
264               "tasks_completed", transaction->diagnostics().tasks_completed);
265 
266           scoped_ptr<base::ListValue> scope(new base::ListValue());
267           for (std::set<int64>::const_iterator scope_it =
268                    transaction->scope().begin();
269                scope_it != transaction->scope().end();
270                ++scope_it) {
271             IndexedDBDatabaseMetadata::ObjectStoreMap::const_iterator it =
272                 db->metadata().object_stores.find(*scope_it);
273             if (it != db->metadata().object_stores.end())
274               scope->AppendString(it->second.name);
275           }
276 
277           transaction_info->Set("scope", scope.release());
278           transaction_list->Append(transaction_info.release());
279         }
280         db_info->Set("transactions", transaction_list.release());
281 
282         database_list->Append(db_info.release());
283       }
284       info->Set("databases", database_list.release());
285     }
286 
287     list->Append(info.release());
288   }
289   return list.release();
290 }
291 
GetOriginDiskUsage(const GURL & origin_url)292 int64 IndexedDBContextImpl::GetOriginDiskUsage(const GURL& origin_url) {
293   DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
294   if (data_path_.empty() || !IsInOriginSet(origin_url))
295     return 0;
296   EnsureDiskUsageCacheInitialized(origin_url);
297   return origin_size_map_[origin_url];
298 }
299 
GetOriginLastModified(const GURL & origin_url)300 base::Time IndexedDBContextImpl::GetOriginLastModified(const GURL& origin_url) {
301   DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
302   if (data_path_.empty() || !IsInOriginSet(origin_url))
303     return base::Time();
304   base::FilePath idb_directory = GetFilePath(origin_url);
305   base::File::Info file_info;
306   if (!base::GetFileInfo(idb_directory, &file_info))
307     return base::Time();
308   return file_info.last_modified;
309 }
310 
DeleteForOrigin(const GURL & origin_url)311 void IndexedDBContextImpl::DeleteForOrigin(const GURL& origin_url) {
312   DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
313   ForceClose(origin_url, FORCE_CLOSE_DELETE_ORIGIN);
314   if (data_path_.empty() || !IsInOriginSet(origin_url))
315     return;
316 
317   base::FilePath idb_directory = GetFilePath(origin_url);
318   EnsureDiskUsageCacheInitialized(origin_url);
319   leveldb::Status s = LevelDBDatabase::Destroy(idb_directory);
320   if (!s.ok()) {
321     LOG(WARNING) << "Failed to delete LevelDB database: "
322                  << idb_directory.AsUTF8Unsafe();
323   } else {
324     // LevelDB does not delete empty directories; work around this.
325     // TODO(jsbell): Remove when upstream bug is fixed.
326     // https://code.google.com/p/leveldb/issues/detail?id=209
327     const bool kNonRecursive = false;
328     base::DeleteFile(idb_directory, kNonRecursive);
329   }
330 
331   QueryDiskAndUpdateQuotaUsage(origin_url);
332   if (s.ok()) {
333     RemoveFromOriginSet(origin_url);
334     origin_size_map_.erase(origin_url);
335     space_available_map_.erase(origin_url);
336   }
337 }
338 
ForceClose(const GURL origin_url,ForceCloseReason reason)339 void IndexedDBContextImpl::ForceClose(const GURL origin_url,
340                                       ForceCloseReason reason) {
341   DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
342   UMA_HISTOGRAM_ENUMERATION("WebCore.IndexedDB.Context.ForceCloseReason",
343                             reason,
344                             FORCE_CLOSE_REASON_MAX);
345 
346   if (data_path_.empty() || !IsInOriginSet(origin_url))
347     return;
348 
349   if (factory_.get())
350     factory_->ForceClose(origin_url);
351   DCHECK_EQ(0UL, GetConnectionCount(origin_url));
352 }
353 
GetConnectionCount(const GURL & origin_url)354 size_t IndexedDBContextImpl::GetConnectionCount(const GURL& origin_url) {
355   DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
356   if (data_path_.empty() || !IsInOriginSet(origin_url))
357     return 0;
358 
359   if (!factory_.get())
360     return 0;
361 
362   return factory_->GetConnectionCount(origin_url);
363 }
364 
GetFilePath(const GURL & origin_url) const365 base::FilePath IndexedDBContextImpl::GetFilePath(const GURL& origin_url) const {
366   std::string origin_id = storage::GetIdentifierFromOrigin(origin_url);
367   return GetIndexedDBFilePath(origin_id);
368 }
369 
GetFilePathForTesting(const std::string & origin_id) const370 base::FilePath IndexedDBContextImpl::GetFilePathForTesting(
371     const std::string& origin_id) const {
372   return GetIndexedDBFilePath(origin_id);
373 }
374 
SetTaskRunnerForTesting(base::SequencedTaskRunner * task_runner)375 void IndexedDBContextImpl::SetTaskRunnerForTesting(
376     base::SequencedTaskRunner* task_runner) {
377   DCHECK(!task_runner_.get());
378   task_runner_ = task_runner;
379 }
380 
ConnectionOpened(const GURL & origin_url,IndexedDBConnection * connection)381 void IndexedDBContextImpl::ConnectionOpened(const GURL& origin_url,
382                                             IndexedDBConnection* connection) {
383   DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
384   if (quota_manager_proxy()) {
385     quota_manager_proxy()->NotifyStorageAccessed(
386         storage::QuotaClient::kIndexedDatabase,
387         origin_url,
388         storage::kStorageTypeTemporary);
389   }
390   if (AddToOriginSet(origin_url)) {
391     // A newly created db, notify the quota system.
392     QueryDiskAndUpdateQuotaUsage(origin_url);
393   } else {
394     EnsureDiskUsageCacheInitialized(origin_url);
395   }
396   QueryAvailableQuota(origin_url);
397 }
398 
ConnectionClosed(const GURL & origin_url,IndexedDBConnection * connection)399 void IndexedDBContextImpl::ConnectionClosed(const GURL& origin_url,
400                                             IndexedDBConnection* connection) {
401   DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
402   if (quota_manager_proxy()) {
403     quota_manager_proxy()->NotifyStorageAccessed(
404         storage::QuotaClient::kIndexedDatabase,
405         origin_url,
406         storage::kStorageTypeTemporary);
407   }
408   if (factory_.get() && factory_->GetConnectionCount(origin_url) == 0)
409     QueryDiskAndUpdateQuotaUsage(origin_url);
410 }
411 
TransactionComplete(const GURL & origin_url)412 void IndexedDBContextImpl::TransactionComplete(const GURL& origin_url) {
413   DCHECK(!factory_.get() || factory_->GetConnectionCount(origin_url) > 0);
414   QueryDiskAndUpdateQuotaUsage(origin_url);
415   QueryAvailableQuota(origin_url);
416 }
417 
DatabaseDeleted(const GURL & origin_url)418 void IndexedDBContextImpl::DatabaseDeleted(const GURL& origin_url) {
419   AddToOriginSet(origin_url);
420   QueryDiskAndUpdateQuotaUsage(origin_url);
421   QueryAvailableQuota(origin_url);
422 }
423 
WouldBeOverQuota(const GURL & origin_url,int64 additional_bytes)424 bool IndexedDBContextImpl::WouldBeOverQuota(const GURL& origin_url,
425                                             int64 additional_bytes) {
426   if (space_available_map_.find(origin_url) == space_available_map_.end()) {
427     // We haven't heard back from the QuotaManager yet, just let it through.
428     return false;
429   }
430   bool over_quota = additional_bytes > space_available_map_[origin_url];
431   return over_quota;
432 }
433 
IsOverQuota(const GURL & origin_url)434 bool IndexedDBContextImpl::IsOverQuota(const GURL& origin_url) {
435   const int kOneAdditionalByte = 1;
436   return WouldBeOverQuota(origin_url, kOneAdditionalByte);
437 }
438 
quota_manager_proxy()439 storage::QuotaManagerProxy* IndexedDBContextImpl::quota_manager_proxy() {
440   return quota_manager_proxy_.get();
441 }
442 
~IndexedDBContextImpl()443 IndexedDBContextImpl::~IndexedDBContextImpl() {
444   if (factory_.get()) {
445     TaskRunner()->PostTask(
446         FROM_HERE, base::Bind(&IndexedDBFactory::ContextDestroyed, factory_));
447     factory_ = NULL;
448   }
449 
450   if (data_path_.empty())
451     return;
452 
453   if (force_keep_session_state_)
454     return;
455 
456   bool has_session_only_databases =
457       special_storage_policy_.get() &&
458       special_storage_policy_->HasSessionOnlyOrigins();
459 
460   // Clearing only session-only databases, and there are none.
461   if (!has_session_only_databases)
462     return;
463 
464   TaskRunner()->PostTask(
465       FROM_HERE,
466       base::Bind(
467           &ClearSessionOnlyOrigins, data_path_, special_storage_policy_));
468 }
469 
GetIndexedDBFilePath(const std::string & origin_id) const470 base::FilePath IndexedDBContextImpl::GetIndexedDBFilePath(
471     const std::string& origin_id) const {
472   DCHECK(!data_path_.empty());
473   return data_path_.AppendASCII(origin_id).AddExtension(kIndexedDBExtension)
474       .AddExtension(kLevelDBExtension);
475 }
476 
ReadUsageFromDisk(const GURL & origin_url) const477 int64 IndexedDBContextImpl::ReadUsageFromDisk(const GURL& origin_url) const {
478   if (data_path_.empty())
479     return 0;
480   base::FilePath file_path = GetFilePath(origin_url);
481   return base::ComputeDirectorySize(file_path);
482 }
483 
EnsureDiskUsageCacheInitialized(const GURL & origin_url)484 void IndexedDBContextImpl::EnsureDiskUsageCacheInitialized(
485     const GURL& origin_url) {
486   if (origin_size_map_.find(origin_url) == origin_size_map_.end())
487     origin_size_map_[origin_url] = ReadUsageFromDisk(origin_url);
488 }
489 
QueryDiskAndUpdateQuotaUsage(const GURL & origin_url)490 void IndexedDBContextImpl::QueryDiskAndUpdateQuotaUsage(
491     const GURL& origin_url) {
492   int64 former_disk_usage = origin_size_map_[origin_url];
493   int64 current_disk_usage = ReadUsageFromDisk(origin_url);
494   int64 difference = current_disk_usage - former_disk_usage;
495   if (difference) {
496     origin_size_map_[origin_url] = current_disk_usage;
497     // quota_manager_proxy() is NULL in unit tests.
498     if (quota_manager_proxy()) {
499       quota_manager_proxy()->NotifyStorageModified(
500           storage::QuotaClient::kIndexedDatabase,
501           origin_url,
502           storage::kStorageTypeTemporary,
503           difference);
504     }
505   }
506 }
507 
GotUsageAndQuota(const GURL & origin_url,storage::QuotaStatusCode status,int64 usage,int64 quota)508 void IndexedDBContextImpl::GotUsageAndQuota(const GURL& origin_url,
509                                             storage::QuotaStatusCode status,
510                                             int64 usage,
511                                             int64 quota) {
512   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
513   DCHECK(status == storage::kQuotaStatusOk ||
514          status == storage::kQuotaErrorAbort)
515       << "status was " << status;
516   if (status == storage::kQuotaErrorAbort) {
517     // We seem to no longer care to wait around for the answer.
518     return;
519   }
520   TaskRunner()->PostTask(FROM_HERE,
521                          base::Bind(&IndexedDBContextImpl::GotUpdatedQuota,
522                                     this,
523                                     origin_url,
524                                     usage,
525                                     quota));
526 }
527 
GotUpdatedQuota(const GURL & origin_url,int64 usage,int64 quota)528 void IndexedDBContextImpl::GotUpdatedQuota(const GURL& origin_url,
529                                            int64 usage,
530                                            int64 quota) {
531   DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
532   space_available_map_[origin_url] = quota - usage;
533 }
534 
QueryAvailableQuota(const GURL & origin_url)535 void IndexedDBContextImpl::QueryAvailableQuota(const GURL& origin_url) {
536   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
537     DCHECK(TaskRunner()->RunsTasksOnCurrentThread());
538     if (quota_manager_proxy()) {
539       BrowserThread::PostTask(
540           BrowserThread::IO,
541           FROM_HERE,
542           base::Bind(
543               &IndexedDBContextImpl::QueryAvailableQuota, this, origin_url));
544     }
545     return;
546   }
547   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
548   if (!quota_manager_proxy() || !quota_manager_proxy()->quota_manager())
549     return;
550   quota_manager_proxy()->quota_manager()->GetUsageAndQuota(
551       origin_url,
552       storage::kStorageTypeTemporary,
553       base::Bind(&IndexedDBContextImpl::GotUsageAndQuota, this, origin_url));
554 }
555 
GetOriginSet()556 std::set<GURL>* IndexedDBContextImpl::GetOriginSet() {
557   if (!origin_set_) {
558     origin_set_.reset(new std::set<GURL>);
559     std::vector<GURL> origins;
560     GetAllOriginsAndPaths(data_path_, &origins, NULL);
561     for (std::vector<GURL>::const_iterator iter = origins.begin();
562          iter != origins.end();
563          ++iter) {
564       origin_set_->insert(*iter);
565     }
566   }
567   return origin_set_.get();
568 }
569 
ResetCaches()570 void IndexedDBContextImpl::ResetCaches() {
571   origin_set_.reset();
572   origin_size_map_.clear();
573   space_available_map_.clear();
574 }
575 
TaskRunner() const576 base::SequencedTaskRunner* IndexedDBContextImpl::TaskRunner() const {
577   return task_runner_.get();
578 }
579 
580 }  // namespace content
581