OLD | NEW |
| (Empty) |
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 "chrome/browser/media_gallery/media_gallery_database.h" | |
6 | |
7 #include <algorithm> | |
8 #include <string> | |
9 | |
10 #include "base/file_path.h" | |
11 #include "base/logging.h" | |
12 #include "sql/statement.h" | |
13 #include "sql/transaction.h" | |
14 | |
15 #if defined(OS_WIN) | |
16 #include "base/string_util.h" | |
17 #include "base/sys_string_conversions.h" | |
18 #endif // OS_WIN | |
19 | |
20 #define MEDIA_GALLERY_COLLECTION_ROW_FIELDS \ | |
21 " collections.id, collections.path, collections.last_modified_time, " \ | |
22 "collections.entry_count, collections.all_parsed " | |
23 | |
24 namespace chrome { | |
25 | |
26 namespace { | |
27 | |
28 const int kCurrentVersionNumber = 1; | |
29 const int kCompatibleVersionNumber = 1; | |
30 const base::FilePath::CharType kMediaGalleryDatabaseName[] = | |
31 FILE_PATH_LITERAL(".media_gallery.db"); | |
32 | |
33 } // namespace | |
34 | |
35 MediaGalleryDatabase::MediaGalleryDatabase() { } | |
36 | |
37 MediaGalleryDatabase::~MediaGalleryDatabase() { } | |
38 | |
39 sql::InitStatus MediaGalleryDatabase::Init(const base::FilePath& database_dir) { | |
40 db_.set_error_histogram_name("Sqlite.MediaGallery.Error"); | |
41 | |
42 // Set the database page size to something a little larger to give us | |
43 // better performance (we're typically seek rather than bandwidth limited). | |
44 // This only has an effect before any tables have been created, otherwise | |
45 // this is a NOP. Must be a power of 2 and a max of 8192. | |
46 db_.set_page_size(4096); | |
47 | |
48 // Increase the cache size. The page size, plus a little extra, times this | |
49 // value, tells us how much memory the cache will use maximum. | |
50 // 6000 * 4KB = 24MB | |
51 db_.set_cache_size(6000); | |
52 | |
53 if (!db_.Open(database_dir.Append(base::FilePath(kMediaGalleryDatabaseName)))) | |
54 return sql::INIT_FAILURE; | |
55 | |
56 return InitInternal(&db_); | |
57 } | |
58 | |
59 sql::InitStatus MediaGalleryDatabase::InitInternal(sql::Connection* db) { | |
60 // Wrap the rest of init in a tranaction. This will prevent the database from | |
61 // getting corrupted if we crash in the middle of initialization or migration. | |
62 sql::Transaction committer(db); | |
63 if (!committer.Begin()) | |
64 return sql::INIT_FAILURE; | |
65 | |
66 // Prime the cache. | |
67 db->Preload(); | |
68 | |
69 // Create the tables and indices. | |
70 if (!meta_table_.Init(db, GetCurrentVersion(), kCompatibleVersionNumber)) | |
71 return sql::INIT_FAILURE; | |
72 | |
73 if (!CreateCollectionsTable(db)) | |
74 return sql::INIT_FAILURE; | |
75 | |
76 // Version check. | |
77 sql::InitStatus version_status = EnsureCurrentVersion(); | |
78 if (version_status != sql::INIT_OK) | |
79 return version_status; | |
80 | |
81 return committer.Commit() ? sql::INIT_OK : sql::INIT_FAILURE; | |
82 } | |
83 | |
84 sql::Connection& MediaGalleryDatabase::GetDB() { | |
85 return db_; | |
86 } | |
87 | |
88 sql::InitStatus MediaGalleryDatabase::EnsureCurrentVersion() { | |
89 // We can't read databases newer than we were designed for. | |
90 if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) { | |
91 VLOG(1) << "Media Gallery database is too new."; | |
92 return sql::INIT_TOO_NEW; | |
93 } | |
94 int cur_version = meta_table_.GetVersionNumber(); | |
95 if (cur_version == 0) { | |
96 DVLOG(1) << "Initializing the Media Gallery database."; | |
97 | |
98 ++cur_version; | |
99 meta_table_.SetVersionNumber(cur_version); | |
100 meta_table_.SetCompatibleVersionNumber( | |
101 std::min(cur_version, kCompatibleVersionNumber)); | |
102 } | |
103 return sql::INIT_OK; | |
104 } | |
105 | |
106 // static | |
107 int MediaGalleryDatabase::GetCurrentVersion() { | |
108 return kCurrentVersionNumber; | |
109 } | |
110 | |
111 CollectionId MediaGalleryDatabase::CreateCollectionRow( | |
112 CollectionRow* row) { | |
113 const char* sql = "INSERT INTO collections" | |
114 "(path, last_modified_time, entry_count, all_parsed) " | |
115 "VALUES(?, ?, ?, ?)"; | |
116 | |
117 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, sql)); | |
118 #if defined(OS_WIN) | |
119 // We standardize on UTF8 encoding for paths. | |
120 std::string path(base::SysWideToUTF8(row->path.value())); | |
121 #elif defined(OS_POSIX) | |
122 std::string path(row->path.value()); | |
123 #endif | |
124 | |
125 #if defined(FILE_PATH_USES_WIN_SEPARATORS) | |
126 // We standardize on POSIX-style paths, since any platform can understand | |
127 // them. | |
128 ReplaceChars(path, "\\", "/", &path); | |
129 #endif // FILE_PATH_USES_WIN_SEPARATORS | |
130 | |
131 statement.BindString(0, path.c_str()); | |
132 statement.BindInt64(1, row->last_modified_time.ToInternalValue()); | |
133 statement.BindInt(2, row->entry_count); | |
134 statement.BindInt(3, row->all_parsed ? 1 : 0); | |
135 | |
136 if (!statement.Run()) { | |
137 VLOG(0) << "Failed to add collection " << row->path.value() | |
138 << " to table media_gallery.collections"; | |
139 return 0; | |
140 } | |
141 return row->id = GetDB().GetLastInsertRowId(); | |
142 } | |
143 | |
144 bool MediaGalleryDatabase::GetCollectionRow(CollectionId id, | |
145 CollectionRow* row) { | |
146 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | |
147 "SELECT" MEDIA_GALLERY_COLLECTION_ROW_FIELDS | |
148 "FROM collections WHERE id=?")); | |
149 statement.BindInt64(0, id); | |
150 | |
151 if (statement.Step()) { | |
152 FillCollectionRow(statement, row); | |
153 return true; | |
154 } | |
155 return false; | |
156 } | |
157 | |
158 // Convenience method to fill a row from a statement. Must be in sync with the | |
159 // columns in MEDIA_GALLERY_COLLECTION_ROW_FIELDS | |
160 void MediaGalleryDatabase::FillCollectionRow(const sql::Statement& statement, | |
161 CollectionRow* row) { | |
162 row->id = statement.ColumnInt64(0); | |
163 #if defined(OS_WIN) | |
164 row->path = base::FilePath(base::SysUTF8ToWide(statement.ColumnString(1))); | |
165 #elif defined(OS_POSIX) | |
166 row->path = base::FilePath(statement.ColumnString(1)); | |
167 #endif // OS_WIN | |
168 row->last_modified_time = base::Time::FromInternalValue( | |
169 statement.ColumnInt64(2)); | |
170 row->entry_count = statement.ColumnInt(3); | |
171 row->all_parsed = statement.ColumnInt(4) != 0; | |
172 } | |
173 | |
174 // static | |
175 bool MediaGalleryDatabase::DoesCollectionsTableExist(sql::Connection *db) { | |
176 return db->DoesTableExist("collections"); | |
177 } | |
178 | |
179 // static | |
180 bool MediaGalleryDatabase::CreateCollectionsTable(sql::Connection* db) { | |
181 if (DoesCollectionsTableExist(db)) | |
182 return true; | |
183 | |
184 // TODO(tpayne): Add unique constraint on path once we standardize on path | |
185 // format. | |
186 return db->Execute("CREATE TABLE collections" | |
187 "(id INTEGER PRIMARY KEY," | |
188 " path LONGVARCHAR NOT NULL," | |
189 " last_modified_time INTEGER NOT NULL," | |
190 " entry_count INTEGER DEFAULT 0 NOT NULL," | |
191 " all_parsed INTEGER DEFAULT 0 NOT NULL)"); | |
192 } | |
193 | |
194 } // namespace chrome | |
OLD | NEW |