OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 "chrome/browser/net/sqlite_persistent_cookie_store.h" | 5 #include "chrome/browser/net/sqlite_persistent_cookie_store.h" |
6 | 6 |
7 #include <list> | 7 #include <list> |
8 | 8 |
9 #include "app/sql/statement.h" | 9 #include "app/sql/statement.h" |
10 #include "app/sql/transaction.h" | 10 #include "app/sql/transaction.h" |
11 #include "base/basictypes.h" | 11 #include "base/basictypes.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/ref_counted.h" | 13 #include "base/ref_counted.h" |
14 #include "base/scoped_ptr.h" | 14 #include "base/scoped_ptr.h" |
15 #include "base/string_util.h" | 15 #include "base/string_util.h" |
16 #include "base/thread.h" | 16 #include "base/thread.h" |
| 17 #include "chrome/browser/chrome_thread.h" |
17 #include "chrome/browser/diagnostics/sqlite_diagnostics.h" | 18 #include "chrome/browser/diagnostics/sqlite_diagnostics.h" |
18 | 19 |
19 using base::Time; | 20 using base::Time; |
20 | 21 |
21 // This class is designed to be shared between any calling threads and the | 22 // This class is designed to be shared between any calling threads and the |
22 // database thread. It batches operations and commits them on a timer. | 23 // database thread. It batches operations and commits them on a timer. |
23 class SQLitePersistentCookieStore::Backend | 24 class SQLitePersistentCookieStore::Backend |
24 : public base::RefCountedThreadSafe<SQLitePersistentCookieStore::Backend> { | 25 : public base::RefCountedThreadSafe<SQLitePersistentCookieStore::Backend> { |
25 public: | 26 public: |
26 // The passed database pointer must be already-initialized. This object will | 27 // The passed database pointer must be already-initialized. This object will |
27 // take ownership. | 28 // take ownership. |
28 explicit Backend(sql::Connection* db, MessageLoop* loop) | 29 explicit Backend(sql::Connection* db) |
29 : db_(db), | 30 : db_(db), |
30 background_loop_(loop), | |
31 num_pending_(0) { | 31 num_pending_(0) { |
32 DCHECK(db_) << "Database must exist."; | 32 DCHECK(db_) << "Database must exist."; |
33 } | 33 } |
34 | 34 |
35 // You should call Close() before destructing this object. | 35 // You should call Close() before destructing this object. |
36 ~Backend() { | 36 ~Backend() { |
37 DCHECK(!db_) << "Close should have already been called."; | 37 DCHECK(!db_) << "Close should have already been called."; |
38 DCHECK(num_pending_ == 0 && pending_.empty()); | 38 DCHECK(num_pending_ == 0 && pending_.empty()); |
39 } | 39 } |
40 | 40 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
80 // Batch a cookie operation (add or delete) | 80 // Batch a cookie operation (add or delete) |
81 void BatchOperation(PendingOperation::OperationType op, | 81 void BatchOperation(PendingOperation::OperationType op, |
82 const std::string& key, | 82 const std::string& key, |
83 const net::CookieMonster::CanonicalCookie& cc); | 83 const net::CookieMonster::CanonicalCookie& cc); |
84 // Commit our pending operations to the database. | 84 // Commit our pending operations to the database. |
85 void Commit(); | 85 void Commit(); |
86 // Close() executed on the background thread. | 86 // Close() executed on the background thread. |
87 void InternalBackgroundClose(); | 87 void InternalBackgroundClose(); |
88 | 88 |
89 sql::Connection* db_; | 89 sql::Connection* db_; |
90 MessageLoop* background_loop_; | |
91 | 90 |
92 typedef std::list<PendingOperation*> PendingOperationsList; | 91 typedef std::list<PendingOperation*> PendingOperationsList; |
93 PendingOperationsList pending_; | 92 PendingOperationsList pending_; |
94 PendingOperationsList::size_type num_pending_; | 93 PendingOperationsList::size_type num_pending_; |
95 Lock pending_lock_; // Guard pending_ and num_pending_ | 94 Lock pending_lock_; // Guard pending_ and num_pending_ |
96 | 95 |
97 DISALLOW_COPY_AND_ASSIGN(Backend); | 96 DISALLOW_COPY_AND_ASSIGN(Backend); |
98 }; | 97 }; |
99 | 98 |
100 void SQLitePersistentCookieStore::Backend::AddCookie( | 99 void SQLitePersistentCookieStore::Backend::AddCookie( |
(...skipping 13 matching lines...) Expand all Loading... |
114 } | 113 } |
115 | 114 |
116 void SQLitePersistentCookieStore::Backend::BatchOperation( | 115 void SQLitePersistentCookieStore::Backend::BatchOperation( |
117 PendingOperation::OperationType op, | 116 PendingOperation::OperationType op, |
118 const std::string& key, | 117 const std::string& key, |
119 const net::CookieMonster::CanonicalCookie& cc) { | 118 const net::CookieMonster::CanonicalCookie& cc) { |
120 // Commit every 30 seconds. | 119 // Commit every 30 seconds. |
121 static const int kCommitIntervalMs = 30 * 1000; | 120 static const int kCommitIntervalMs = 30 * 1000; |
122 // Commit right away if we have more than 512 outstanding operations. | 121 // Commit right away if we have more than 512 outstanding operations. |
123 static const size_t kCommitAfterBatchSize = 512; | 122 static const size_t kCommitAfterBatchSize = 512; |
124 DCHECK(MessageLoop::current() != background_loop_); | 123 DCHECK(!ChromeThread::CurrentlyOn(ChromeThread::DB)); |
125 | 124 |
126 // We do a full copy of the cookie here, and hopefully just here. | 125 // We do a full copy of the cookie here, and hopefully just here. |
127 scoped_ptr<PendingOperation> po(new PendingOperation(op, key, cc)); | 126 scoped_ptr<PendingOperation> po(new PendingOperation(op, key, cc)); |
128 CHECK(po.get()); | 127 CHECK(po.get()); |
129 | 128 |
130 PendingOperationsList::size_type num_pending; | 129 PendingOperationsList::size_type num_pending; |
131 { | 130 { |
132 AutoLock locked(pending_lock_); | 131 AutoLock locked(pending_lock_); |
133 pending_.push_back(po.release()); | 132 pending_.push_back(po.release()); |
134 num_pending = ++num_pending_; | 133 num_pending = ++num_pending_; |
135 } | 134 } |
136 | 135 |
137 // TODO(abarth): What if the DB thread is being destroyed on the UI thread? | |
138 if (num_pending == 1) { | 136 if (num_pending == 1) { |
139 // We've gotten our first entry for this batch, fire off the timer. | 137 // We've gotten our first entry for this batch, fire off the timer. |
140 background_loop_->PostDelayedTask(FROM_HERE, | 138 ChromeThread::PostDelayedTask( |
| 139 ChromeThread::DB, FROM_HERE, |
141 NewRunnableMethod(this, &Backend::Commit), kCommitIntervalMs); | 140 NewRunnableMethod(this, &Backend::Commit), kCommitIntervalMs); |
142 } else if (num_pending == kCommitAfterBatchSize) { | 141 } else if (num_pending == kCommitAfterBatchSize) { |
143 // We've reached a big enough batch, fire off a commit now. | 142 // We've reached a big enough batch, fire off a commit now. |
144 background_loop_->PostTask(FROM_HERE, | 143 ChromeThread::PostTask( |
145 NewRunnableMethod(this, &Backend::Commit)); | 144 ChromeThread::DB, FROM_HERE, NewRunnableMethod(this, &Backend::Commit)); |
146 } | 145 } |
147 } | 146 } |
148 | 147 |
149 void SQLitePersistentCookieStore::Backend::Commit() { | 148 void SQLitePersistentCookieStore::Backend::Commit() { |
150 DCHECK(MessageLoop::current() == background_loop_); | 149 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); |
151 PendingOperationsList ops; | 150 PendingOperationsList ops; |
152 { | 151 { |
153 AutoLock locked(pending_lock_); | 152 AutoLock locked(pending_lock_); |
154 pending_.swap(ops); | 153 pending_.swap(ops); |
155 num_pending_ = 0; | 154 num_pending_ = 0; |
156 } | 155 } |
157 | 156 |
158 // Maybe an old timer fired or we are already Close()'ed. | 157 // Maybe an old timer fired or we are already Close()'ed. |
159 if (!db_ || ops.empty()) | 158 if (!db_ || ops.empty()) |
160 return; | 159 return; |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 break; | 228 break; |
230 } | 229 } |
231 } | 230 } |
232 transaction.Commit(); | 231 transaction.Commit(); |
233 } | 232 } |
234 | 233 |
235 // Fire off a close message to the background thread. We could still have a | 234 // Fire off a close message to the background thread. We could still have a |
236 // pending commit timer that will be holding a reference on us, but if/when | 235 // pending commit timer that will be holding a reference on us, but if/when |
237 // this fires we will already have been cleaned up and it will be ignored. | 236 // this fires we will already have been cleaned up and it will be ignored. |
238 void SQLitePersistentCookieStore::Backend::Close() { | 237 void SQLitePersistentCookieStore::Backend::Close() { |
239 DCHECK(MessageLoop::current() != background_loop_); | 238 DCHECK(!ChromeThread::CurrentlyOn(ChromeThread::DB)); |
240 // Must close the backend on the background thread. | 239 // Must close the backend on the background thread. |
241 // TODO(abarth): What if the DB thread is being destroyed on the UI thread? | 240 ChromeThread::PostTask( |
242 background_loop_->PostTask(FROM_HERE, | 241 ChromeThread::DB, FROM_HERE, |
243 NewRunnableMethod(this, &Backend::InternalBackgroundClose)); | 242 NewRunnableMethod(this, &Backend::InternalBackgroundClose)); |
244 } | 243 } |
245 | 244 |
246 void SQLitePersistentCookieStore::Backend::InternalBackgroundClose() { | 245 void SQLitePersistentCookieStore::Backend::InternalBackgroundClose() { |
247 DCHECK(MessageLoop::current() == background_loop_); | 246 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::DB)); |
248 // Commit any pending operations | 247 // Commit any pending operations |
249 Commit(); | 248 Commit(); |
250 | 249 |
251 delete db_; | 250 delete db_; |
252 db_ = NULL; | 251 db_ = NULL; |
253 } | 252 } |
254 | 253 |
255 SQLitePersistentCookieStore::SQLitePersistentCookieStore( | 254 SQLitePersistentCookieStore::SQLitePersistentCookieStore(const FilePath& path) |
256 const FilePath& path, | 255 : path_(path) { |
257 MessageLoop* background_loop) | |
258 : path_(path), | |
259 background_loop_(background_loop) { | |
260 DCHECK(background_loop) << "SQLitePersistentCookieStore needs a MessageLoop"; | |
261 } | 256 } |
262 | 257 |
263 SQLitePersistentCookieStore::~SQLitePersistentCookieStore() { | 258 SQLitePersistentCookieStore::~SQLitePersistentCookieStore() { |
264 if (backend_.get()) { | 259 if (backend_.get()) { |
265 backend_->Close(); | 260 backend_->Close(); |
266 // Release our reference, it will probably still have a reference if the | 261 // Release our reference, it will probably still have a reference if the |
267 // background thread has not run Close() yet. | 262 // background thread has not run Close() yet. |
268 backend_ = NULL; | 263 backend_ = NULL; |
269 } | 264 } |
270 } | 265 } |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
346 true, // has_expires | 341 true, // has_expires |
347 Time::FromInternalValue(smt.ColumnInt64(5)))); // expires_utc | 342 Time::FromInternalValue(smt.ColumnInt64(5)))); // expires_utc |
348 DLOG_IF(WARNING, | 343 DLOG_IF(WARNING, |
349 cc->CreationDate() > Time::Now()) << L"CreationDate too recent"; | 344 cc->CreationDate() > Time::Now()) << L"CreationDate too recent"; |
350 cookies->push_back( | 345 cookies->push_back( |
351 net::CookieMonster::KeyedCanonicalCookie(smt.ColumnString(1), | 346 net::CookieMonster::KeyedCanonicalCookie(smt.ColumnString(1), |
352 cc.release())); | 347 cc.release())); |
353 } | 348 } |
354 | 349 |
355 // Create the backend, this will take ownership of the db pointer. | 350 // Create the backend, this will take ownership of the db pointer. |
356 backend_ = new Backend(db.release(), background_loop_); | 351 backend_ = new Backend(db.release()); |
357 return true; | 352 return true; |
358 } | 353 } |
359 | 354 |
360 bool SQLitePersistentCookieStore::EnsureDatabaseVersion(sql::Connection* db) { | 355 bool SQLitePersistentCookieStore::EnsureDatabaseVersion(sql::Connection* db) { |
361 // Version check. | 356 // Version check. |
362 if (!meta_table_.Init(db, kCurrentVersionNumber, kCompatibleVersionNumber)) | 357 if (!meta_table_.Init(db, kCurrentVersionNumber, kCompatibleVersionNumber)) |
363 return false; | 358 return false; |
364 | 359 |
365 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) { | 360 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) { |
366 LOG(WARNING) << "Cookie database is too new."; | 361 LOG(WARNING) << "Cookie database is too new."; |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
440 const net::CookieMonster::CanonicalCookie& cc) { | 435 const net::CookieMonster::CanonicalCookie& cc) { |
441 if (backend_.get()) | 436 if (backend_.get()) |
442 backend_->UpdateCookieAccessTime(cc); | 437 backend_->UpdateCookieAccessTime(cc); |
443 } | 438 } |
444 | 439 |
445 void SQLitePersistentCookieStore::DeleteCookie( | 440 void SQLitePersistentCookieStore::DeleteCookie( |
446 const net::CookieMonster::CanonicalCookie& cc) { | 441 const net::CookieMonster::CanonicalCookie& cc) { |
447 if (backend_.get()) | 442 if (backend_.get()) |
448 backend_->DeleteCookie(cc); | 443 backend_->DeleteCookie(cc); |
449 } | 444 } |
OLD | NEW |