| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/sync/syncable/directory_backing_store.h" | 5 #include "chrome/browser/sync/syncable/directory_backing_store.h" |
| 6 | 6 |
| 7 #include "build/build_config.h" | 7 #include "build/build_config.h" |
| 8 | 8 |
| 9 #include <limits> | 9 #include <limits> |
| 10 | 10 |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 184 } | 184 } |
| 185 if (NULL != save_dbhandle_) { | 185 if (NULL != save_dbhandle_) { |
| 186 sqlite3_close(save_dbhandle_); | 186 sqlite3_close(save_dbhandle_); |
| 187 save_dbhandle_ = NULL; | 187 save_dbhandle_ = NULL; |
| 188 } | 188 } |
| 189 } | 189 } |
| 190 | 190 |
| 191 bool DirectoryBackingStore::OpenAndConfigureHandleHelper( | 191 bool DirectoryBackingStore::OpenAndConfigureHandleHelper( |
| 192 sqlite3** handle) const { | 192 sqlite3** handle) const { |
| 193 if (SQLITE_OK == sqlite_utils::OpenSqliteDb(backing_filepath_, handle)) { | 193 if (SQLITE_OK == sqlite_utils::OpenSqliteDb(backing_filepath_, handle)) { |
| 194 sqlite3_busy_timeout(*handle, std::numeric_limits<int>::max()); | 194 sqlite_utils::scoped_sqlite_db_ptr scoped_handle(*handle); |
| 195 sqlite3_busy_timeout(scoped_handle.get(), std::numeric_limits<int>::max()); |
| 195 { | 196 { |
| 196 string integrity_error; | 197 string integrity_error; |
| 197 bool is_ok = CheckIntegrity(*handle, &integrity_error); | 198 bool is_ok = CheckIntegrity(scoped_handle.get(), &integrity_error); |
| 198 if (!is_ok) { | 199 if (!is_ok) { |
| 199 LOG(ERROR) << "Integrity check failed: " << integrity_error; | 200 LOG(ERROR) << "Integrity check failed: " << integrity_error; |
| 200 sqlite3_close(*handle); | |
| 201 *handle = NULL; | |
| 202 return false; | 201 return false; |
| 203 } | 202 } |
| 204 } | 203 } |
| 205 { | 204 { |
| 206 sqlite_utils::SQLStatement statement; | 205 sqlite_utils::SQLStatement statement; |
| 207 statement.prepare(*handle, "PRAGMA fullfsync = 1"); | 206 statement.prepare(scoped_handle.get(), "PRAGMA fullfsync = 1"); |
| 208 if (SQLITE_DONE != statement.step()) { | 207 if (SQLITE_DONE != statement.step()) { |
| 209 LOG(ERROR) << sqlite3_errmsg(*handle); | 208 LOG(ERROR) << sqlite3_errmsg(scoped_handle.get()); |
| 210 sqlite3_close(*handle); | |
| 211 *handle = NULL; | |
| 212 return false; | 209 return false; |
| 213 } | 210 } |
| 214 } | 211 } |
| 215 { | 212 { |
| 216 sqlite_utils::SQLStatement statement; | 213 sqlite_utils::SQLStatement statement; |
| 217 statement.prepare(*handle, "PRAGMA synchronous = 2"); | 214 statement.prepare(scoped_handle.get(), "PRAGMA synchronous = 2"); |
| 218 if (SQLITE_DONE != statement.step()) { | 215 if (SQLITE_DONE != statement.step()) { |
| 219 LOG(ERROR) << sqlite3_errmsg(*handle); | 216 LOG(ERROR) << sqlite3_errmsg(scoped_handle.get()); |
| 220 sqlite3_close(*handle); | |
| 221 *handle = NULL; | |
| 222 return false; | 217 return false; |
| 223 } | 218 } |
| 224 } | 219 } |
| 225 sqlite3_busy_timeout(*handle, kDirectoryBackingStoreBusyTimeoutMs); | 220 sqlite3_busy_timeout(scoped_handle.release(), |
| 221 kDirectoryBackingStoreBusyTimeoutMs); |
| 226 #if defined(OS_WIN) | 222 #if defined(OS_WIN) |
| 227 // Do not index this file. Scanning can occur every time we close the file, | 223 // Do not index this file. Scanning can occur every time we close the file, |
| 228 // which causes long delays in SQLite's file locking. | 224 // which causes long delays in SQLite's file locking. |
| 229 const DWORD attrs = GetFileAttributes(backing_filepath_.value().c_str()); | 225 const DWORD attrs = GetFileAttributes(backing_filepath_.value().c_str()); |
| 230 const BOOL attrs_set = | 226 const BOOL attrs_set = |
| 231 SetFileAttributes(backing_filepath_.value().c_str(), | 227 SetFileAttributes(backing_filepath_.value().c_str(), |
| 232 attrs | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED); | 228 attrs | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED); |
| 233 #endif | 229 #endif |
| 234 | 230 |
| 235 return true; | 231 return true; |
| 236 } else { | |
| 237 // The sqlite3 API docs indicate a handle is usually returned even | |
| 238 // in the case of error. We clean it up here. | |
| 239 if (*handle != NULL) { | |
| 240 sqlite3_close(*handle); | |
| 241 *handle = NULL; | |
| 242 } | |
| 243 return false; | |
| 244 } | 232 } |
| 233 return false; |
| 245 } | 234 } |
| 246 | 235 |
| 247 bool DirectoryBackingStore::CheckIntegrity(sqlite3* handle, string* error) | 236 bool DirectoryBackingStore::CheckIntegrity(sqlite3* handle, string* error) |
| 248 const { | 237 const { |
| 249 sqlite_utils::SQLStatement statement; | 238 sqlite_utils::SQLStatement statement; |
| 250 if (SQLITE_OK != | 239 statement.prepare(handle, "PRAGMA integrity_check(1)"); |
| 251 statement.prepare(handle, "PRAGMA integrity_check(1)")) { | |
| 252 *error = sqlite3_errmsg(handle); | |
| 253 return false; | |
| 254 } | |
| 255 if (SQLITE_ROW != statement.step()) { | 240 if (SQLITE_ROW != statement.step()) { |
| 256 *error = sqlite3_errmsg(handle); | 241 *error = sqlite3_errmsg(handle); |
| 257 return false; | 242 return false; |
| 258 } | 243 } |
| 259 string integrity_result = statement.column_text(0); | 244 string integrity_result = statement.column_text(0); |
| 260 if (integrity_result != "ok") { | 245 if (integrity_result != "ok") { |
| 261 *error = integrity_result; | 246 *error = integrity_result; |
| 262 return false; | 247 return false; |
| 263 } | 248 } |
| 264 return true; | 249 return true; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 STLDeleteElements(entry_bucket); | 282 STLDeleteElements(entry_bucket); |
| 298 | 283 |
| 299 // Close database handle. | 284 // Close database handle. |
| 300 EndLoad(); | 285 EndLoad(); |
| 301 | 286 |
| 302 return result; | 287 return result; |
| 303 } | 288 } |
| 304 | 289 |
| 305 bool DirectoryBackingStore::BeginLoad() { | 290 bool DirectoryBackingStore::BeginLoad() { |
| 306 DCHECK(load_dbhandle_ == NULL); | 291 DCHECK(load_dbhandle_ == NULL); |
| 307 return OpenAndConfigureHandleHelper(&load_dbhandle_); | 292 bool ret = OpenAndConfigureHandleHelper(&load_dbhandle_); |
| 293 if (ret) |
| 294 return true; |
| 295 // Something's gone wrong. Nuke the database and try again. |
| 296 using ::operator<<; // For string16. |
| 297 LOG(ERROR) << "Sync database " << backing_filepath_.value() |
| 298 << " corrupt. Deleting and recreating."; |
| 299 file_util::Delete(backing_filepath_, false); |
| 300 bool failed_again = !OpenAndConfigureHandleHelper(&load_dbhandle_); |
| 301 |
| 302 // Using failed_again here lets us distinguish from cases where corruption |
| 303 // occurred even when re-opening a fresh directory (they'll go in a separate |
| 304 // double weight histogram bucket). Failing twice in a row means we disable |
| 305 // sync, so it's useful to see this number separately. |
| 306 int bucket = failed_again ? 2 : 1; |
| 307 #if defined(OS_WIN) |
| 308 UMA_HISTOGRAM_COUNTS_100("Sync.DirectoryOpenFailedWin", bucket); |
| 309 #elif defined(OS_MACOSX) |
| 310 UMA_HISTOGRAM_COUNTS_100("Sync.DirectoryOpenFailedMac", bucket); |
| 311 #else |
| 312 UMA_HISTOGRAM_COUNTS_100("Sync.DirectoryOpenFailedNotWinMac", bucket); |
| 313 |
| 314 #if defined(OS_CHROMEOS) |
| 315 UMA_HISTOGRAM_COUNTS_100("Sync.DirectoryOpenFailedCros", bucket); |
| 316 #elif defined(OS_LINUX) |
| 317 UMA_HISTOGRAM_COUNTS_100("Sync.DirectoryOpenFailedLinux", bucket); |
| 318 #else |
| 319 UMA_HISTOGRAM_COUNTS_100("Sync.DirectoryOpenFailedOther", bucket); |
| 320 #endif // OS_LINUX && !OS_CHROMEOS |
| 321 #endif // OS_WIN |
| 322 return !failed_again; |
| 308 } | 323 } |
| 309 | 324 |
| 310 void DirectoryBackingStore::EndLoad() { | 325 void DirectoryBackingStore::EndLoad() { |
| 311 sqlite3_close(load_dbhandle_); | 326 sqlite3_close(load_dbhandle_); |
| 312 load_dbhandle_ = NULL; // No longer used. | 327 load_dbhandle_ = NULL; // No longer used. |
| 313 } | 328 } |
| 314 | 329 |
| 315 void DirectoryBackingStore::EndSave() { | 330 void DirectoryBackingStore::EndSave() { |
| 316 sqlite3_close(save_dbhandle_); | 331 sqlite3_close(save_dbhandle_); |
| 317 save_dbhandle_ = NULL; | 332 save_dbhandle_ = NULL; |
| (...skipping 937 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1255 "id TEXT primary key, " | 1270 "id TEXT primary key, " |
| 1256 "name TEXT, " | 1271 "name TEXT, " |
| 1257 "store_birthday TEXT, " | 1272 "store_birthday TEXT, " |
| 1258 "db_create_version TEXT, " | 1273 "db_create_version TEXT, " |
| 1259 "db_create_time INT, " | 1274 "db_create_time INT, " |
| 1260 "next_id INT default -2, " | 1275 "next_id INT default -2, " |
| 1261 "cache_guid TEXT )"); | 1276 "cache_guid TEXT )"); |
| 1262 return ExecQuery(load_dbhandle_, query.c_str()); | 1277 return ExecQuery(load_dbhandle_, query.c_str()); |
| 1263 } | 1278 } |
| 1264 } // namespace syncable | 1279 } // namespace syncable |
| OLD | NEW |