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