OLD | NEW |
---|---|
(Empty) | |
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. | |
4 | |
5 #include "components/enhanced_bookmarks/persistent_image_store.h" | |
6 | |
7 #include "components/enhanced_bookmarks/image_store_util.h" | |
8 #include "sql/statement.h" | |
9 #include "sql/transaction.h" | |
10 #include "ui/gfx/geometry/size.h" | |
11 #include "url/gurl.h" | |
12 | |
13 namespace { | |
14 | |
15 bool InitTables(sql::Connection& db) { | |
16 const char kTableSql[] = | |
17 "CREATE TABLE IF NOT EXISTS images_by_url (" | |
18 " page_url LONGVARCHAR NOT NULL," | |
19 " image_url LONGVARCHAR NOT NULL," | |
Scott Hess - ex-Googler
2014/05/09 17:51:36
Anything matching .*CHAR.* is converted to TEXT in
| |
20 " image_data BLOB," | |
21 " width INTEGER," | |
22 " height INTEGER" | |
23 ")"; | |
24 if (!db.Execute(kTableSql)) | |
25 return false; | |
26 return true; | |
27 } | |
28 | |
29 bool InitIndices(sql::Connection& db) { | |
30 const char kIndexSql[] = | |
31 "CREATE INDEX IF NOT EXISTS images_by_url_idx ON images_by_url(page_url)"; | |
Scott Hess - ex-Googler
2014/05/09 17:51:36
I cannot tell from the code if you actually want t
| |
32 if (!db.Execute(kIndexSql)) | |
33 return false; | |
34 return true; | |
35 } | |
36 | |
37 sql::InitStatus OpenDatabaseImpl(sql::Connection& db, | |
38 const base::FilePath& db_path) { | |
39 DCHECK(!db.is_open()); | |
40 | |
41 db.set_histogram_tag("BookmarkImages"); | |
Scott Hess - ex-Googler
2014/05/09 17:51:36
Good! The main reason I stopped in here was to ma
Kibeom Kim (inactive)
2014/05/09 23:13:05
Done.
| |
42 // TODO(noyau): Set page and cache sizes? | |
43 // TODO(noyau): Set error callback? | |
44 | |
45 // Run the database in exclusive mode. Nobody else should be accessing the | |
46 // database while we're running, and this will give somewhat improved perf. | |
47 db.set_exclusive_locking(); | |
48 | |
49 if (!db.Open(db_path)) | |
50 return sql::INIT_FAILURE; | |
51 | |
52 // Scope initialization in a transaction so we can't be partially initialized. | |
53 sql::Transaction transaction(&db); | |
54 if (!transaction.Begin()) | |
55 return sql::INIT_FAILURE; | |
56 | |
57 // Create the tables. | |
58 if (!InitTables(db) || | |
59 !InitIndices(db)) { | |
60 return sql::INIT_FAILURE; | |
61 } | |
62 | |
63 // Initialization is complete. | |
64 if (!transaction.Commit()) | |
65 return sql::INIT_FAILURE; | |
66 | |
67 return sql::INIT_OK; | |
68 } | |
69 | |
70 } // namespace | |
71 | |
72 PersistentImageStore::PersistentImageStore(const base::FilePath& path) | |
73 : ImageStore(), | |
74 path_(path.Append( | |
75 base::FilePath::StringType("BookmarkImageAndUrlStore.db"))) { | |
76 } | |
77 | |
78 bool PersistentImageStore::HasKey(const GURL& page_url) { | |
79 DCHECK(thread_checker_.CalledOnValidThread()); | |
80 if (OpenDatabase() != sql::INIT_OK) | |
81 return false; | |
82 | |
83 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, | |
84 "SELECT COUNT(*) FROM images_by_url WHERE page_url = ?")); | |
85 statement.BindString(0, page_url.possibly_invalid_spec()); | |
86 | |
87 int count = statement.Step() ? statement.ColumnInt(0) : 0; | |
88 | |
89 return !!count; | |
Scott Hess - ex-Googler
2014/05/09 17:51:36
Another option would be query "SELECT 1 FROM image
| |
90 } | |
91 | |
92 void PersistentImageStore::Insert(const GURL& page_url, | |
93 const GURL& image_url, | |
94 const gfx::Image& image) { | |
95 DCHECK(thread_checker_.CalledOnValidThread()); | |
96 if (OpenDatabase() != sql::INIT_OK) | |
97 return; | |
98 | |
99 Erase(page_url); // Remove previous image for this url, if any. | |
100 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, | |
101 "INSERT INTO images_by_url " | |
102 " (page_url, image_url, image_data, width, height)" | |
103 " VALUES (?, ?, ?, ?, ?)")); | |
Scott Hess - ex-Googler
2014/05/09 17:51:36
If you really want these indented, put it in the C
Kibeom Kim (inactive)
2014/05/09 22:52:30
Done.
| |
104 | |
105 statement.BindString(0, page_url.possibly_invalid_spec()); | |
106 statement.BindString(1, image_url.possibly_invalid_spec()); | |
107 | |
108 scoped_refptr<base::RefCountedMemory> image_bytes = | |
109 enhanced_bookmarks::BytesForImage(image); | |
110 | |
111 // Insert an empty image in case encoding fails. | |
112 if (!image_bytes.get()) | |
113 image_bytes = enhanced_bookmarks::BytesForImage(gfx::Image()); | |
114 | |
115 CHECK(image_bytes.get()); | |
116 | |
117 statement.BindBlob(2, image_bytes->front(), image_bytes->size()); | |
118 | |
119 statement.BindInt(3, image.Size().width()); | |
120 statement.BindInt(4, image.Size().height()); | |
121 statement.Run(); | |
122 } | |
123 | |
124 void PersistentImageStore::Erase(const GURL& page_url) { | |
125 DCHECK(thread_checker_.CalledOnValidThread()); | |
126 if (OpenDatabase() != sql::INIT_OK) | |
127 return; | |
128 | |
129 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, | |
130 "DELETE FROM images_by_url WHERE page_url = ?")); | |
131 statement.BindString(0, page_url.possibly_invalid_spec()); | |
132 statement.Run(); | |
133 } | |
134 | |
135 std::pair<gfx::Image, GURL> PersistentImageStore::Get(const GURL& page_url) { | |
136 DCHECK(thread_checker_.CalledOnValidThread()); | |
137 if (OpenDatabase() != sql::INIT_OK) | |
138 return std::make_pair(gfx::Image(), GURL()); | |
139 | |
140 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, | |
141 "SELECT image_data, image_url FROM images_by_url WHERE page_url = ?")); | |
142 | |
143 statement.BindString(0, page_url.possibly_invalid_spec()); | |
144 | |
145 while (statement.Step()) { | |
146 if (statement.ColumnByteLength(0) > 0) { | |
147 scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes()); | |
148 statement.ColumnBlobAsVector(0, &data->data()); | |
149 | |
150 return std::make_pair(enhanced_bookmarks::ImageForBytes(data), | |
151 GURL(statement.ColumnString(1))); | |
152 } | |
153 } | |
154 | |
155 return std::make_pair(gfx::Image(), GURL()); | |
156 } | |
157 | |
158 gfx::Size PersistentImageStore::GetSize(const GURL& page_url) { | |
159 DCHECK(thread_checker_.CalledOnValidThread()); | |
160 if (OpenDatabase() != sql::INIT_OK) | |
161 return gfx::Size(); | |
162 | |
163 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, | |
164 "SELECT width, height FROM images_by_url WHERE page_url = ?")); | |
165 | |
166 statement.BindString(0, page_url.possibly_invalid_spec()); | |
167 | |
168 while (statement.Step()) { | |
169 if (statement.ColumnByteLength(0) > 0) { | |
170 int width = statement.ColumnInt(0); | |
171 int height = statement.ColumnInt(1); | |
172 return gfx::Size(width, height); | |
173 } | |
174 } | |
175 return gfx::Size(); | |
176 } | |
177 | |
178 void PersistentImageStore::GetAllPageUrls(std::set<GURL>* urls) { | |
179 DCHECK(thread_checker_.CalledOnValidThread()); | |
180 DCHECK(urls->empty()); | |
181 if (OpenDatabase() != sql::INIT_OK) | |
182 return; | |
183 | |
184 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE, | |
185 "SELECT page_url FROM images_by_url")); | |
186 while (statement.Step()) | |
187 urls->insert(GURL(statement.ColumnString(0))); | |
188 } | |
189 | |
190 void PersistentImageStore::ClearAll() { | |
191 DCHECK(thread_checker_.CalledOnValidThread()); | |
192 if (OpenDatabase() != sql::INIT_OK) | |
193 return; | |
194 | |
195 sql::Statement statement(db_.GetCachedStatement( | |
196 SQL_FROM_HERE, "DELETE FROM images_by_url")); | |
197 statement.Run(); | |
198 } | |
199 | |
200 PersistentImageStore::~PersistentImageStore() { | |
201 DCHECK(thread_checker_.CalledOnValidThread()); | |
202 } | |
203 | |
204 sql::InitStatus PersistentImageStore::OpenDatabase() { | |
205 DCHECK(thread_checker_.CalledOnValidThread()); | |
206 | |
207 if (db_.is_open()) | |
208 return sql::INIT_OK; | |
209 | |
210 const size_t kAttempts = 2; | |
211 | |
212 sql::InitStatus status = sql::INIT_FAILURE; | |
213 for (size_t i = 0; i < kAttempts; ++i) { | |
214 status = OpenDatabaseImpl(db_, path_); | |
215 if (status == sql::INIT_OK) | |
216 return status; | |
217 | |
218 // Can't open, raze(). | |
219 if (db_.is_open()) | |
220 db_.Raze(); | |
221 db_.Close(); | |
222 } | |
223 | |
224 DCHECK(false) << "Can't open image DB"; | |
225 return sql::INIT_FAILURE; | |
226 } | |
OLD | NEW |