15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sync/glue/typed_url_model_associator.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/location.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/history/history_backend.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/sync/profile_sync_service.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/api/sync_error.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/read_node.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/read_transaction.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/write_node.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/write_transaction.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/typed_url_specifics.pb.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread; 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace browser_sync { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The server backend can't handle arbitrarily large node sizes, so to keep 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the size under control we limit the visit array. 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMaxTypedUrlVisits = 100; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// There's no limit on how many visits the history DB could have for a given 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// typed URL, so we limit how many we fetch from the DB to avoid crashes due to 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// running out of memory (http://crbug.com/89793). This value is different 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// from kMaxTypedUrlVisits, as some of the visits fetched from the DB may be 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// RELOAD visits, which will be stripped. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMaxVisitsToFetch = 1000; 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kTypedUrlTag[] = "google_chrome_typed_urls"; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool CheckVisitOrdering(const history::VisitVector& visits) { 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 previous_visit_time = 0; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (history::VisitVector::const_iterator visit = visits.begin(); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visit != visits.end(); ++visit) { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (visit != visits.begin()) { 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We allow duplicate visits here - they shouldn't really be allowed, but 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // they still seem to show up sometimes and we haven't figured out the 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // source, so we just log an error instead of failing an assertion. 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (http://crbug.com/91473). 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (previous_visit_time == visit->visit_time.ToInternalValue()) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Duplicate visit time encountered"; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (previous_visit_time > visit->visit_time.ToInternalValue()) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) previous_visit_time = visit->visit_time.ToInternalValue(); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TypedUrlModelAssociator::TypedUrlModelAssociator( 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProfileSyncService* sync_service, 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::HistoryBackend* history_backend, 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DataTypeErrorHandler* error_handler) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : sync_service_(sync_service), 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history_backend_(history_backend), 6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) expected_loop_(base::MessageLoop::current()), 68a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) abort_requested_(false), 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error_handler_(error_handler), 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_db_accesses_(0), 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_db_errors_(0) { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(sync_service_); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // history_backend_ may be null for unit tests (since it's not mockable). 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TypedUrlModelAssociator::~TypedUrlModelAssociator() {} 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TypedUrlModelAssociator::FixupURLAndGetVisits( 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::URLRow* url, 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::VisitVector* visits) { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_db_accesses_; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(history_backend_); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!history_backend_->GetMostRecentVisitsForURL( 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url->id(), kMaxVisitsToFetch, visits)) { 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_db_errors_; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sometimes (due to a bug elsewhere in the history or sync code, or due to 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a crash between adding a URL to the history database and updating the 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // visit DB) the visit vector for a URL can be empty. If this happens, just 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // create a new visit whose timestamp is the same as the last_visit time. 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is a workaround for http://crbug.com/84258. 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (visits->empty()) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Found empty visits for URL: " << url->url(); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::VisitRow visit( 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url->id(), url->last_visit(), 0, content::PAGE_TRANSITION_TYPED, 0); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visits->push_back(visit); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GetMostRecentVisitsForURL() returns the data in the opposite order that 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we need it, so reverse it. 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::reverse(visits->begin(), visits->end()); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sometimes, the last_visit field in the URL doesn't match the timestamp of 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the last visit in our visit array (they come from different tables, so 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // crashes/bugs can cause them to mismatch), so just set it here. 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url->set_last_visit(visits->back().visit_time); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CheckVisitOrdering(*visits)); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TypedUrlModelAssociator::ShouldIgnoreUrl(const GURL& url) { 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore empty URLs. Not sure how this can happen (maybe import from other 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // busted browsers, or misuse of the history API, or just plain bugs) but we 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // can't deal with them. 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (url.spec().empty()) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore local file URLs. 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (url.SchemeIsFile()) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore localhost URLs. 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (net::IsLocalhost(url.host())) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TypedUrlModelAssociator::ShouldIgnoreVisits( 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const history::VisitVector& visits) { 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We ignore URLs that were imported, but have never been visited by 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // chromium. 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int kLastImportedSource = history::SOURCE_EXTENSION; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::VisitSourceMap map; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!history_backend_->GetVisitsSource(visits, &map)) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; // If we can't read the visit, assume it's not imported. 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Walk the list of visits and look for a non-imported item. 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (history::VisitVector::const_iterator it = visits.begin(); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != visits.end(); ++it) { 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (map.count(it->visit_id) == 0 || 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) map[it->visit_id] <= kLastImportedSource) { 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We only saw imported visits, so tell the caller to ignore them. 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)syncer::SyncError TypedUrlModelAssociator::AssociateModels( 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::SyncMergeResult* local_merge_result, 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) syncer::SyncMergeResult* syncer_merge_result) { 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ClearErrorStats(); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::SyncError error = DoAssociateModels(); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_PERCENTAGE("Sync.TypedUrlModelAssociationErrors", 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetErrorPercentage()); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ClearErrorStats(); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return error; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TypedUrlModelAssociator::ClearErrorStats() { 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_db_accesses_ = 0; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_db_errors_ = 0; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TypedUrlModelAssociator::GetErrorPercentage() const { 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return num_db_accesses_ ? (100 * num_db_errors_ / num_db_accesses_) : 0; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)syncer::SyncError TypedUrlModelAssociator::DoAssociateModels() { 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Associating TypedUrl Models"; 17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) DCHECK(expected_loop_ == base::MessageLoop::current()); 177a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::URLRows typed_urls; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_db_accesses_; 180a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) bool query_succeeded = 181a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) history_backend_ && history_backend_->GetAllTypedURLs(&typed_urls); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::URLRows new_urls; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypedUrlVisitVector new_visits; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypedUrlUpdateVector updated_urls; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 187a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) base::AutoLock au(abort_lock_); 188a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (abort_requested_) { 189a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return syncer::SyncError(FROM_HERE, 190a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) syncer::SyncError::DATATYPE_ERROR, 191a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) "Association was aborted.", 192a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) model_type()); 193a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 194a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 195a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Must lock and check first to make sure |error_handler_| is valid. 196a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!query_succeeded) { 197a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ++num_db_errors_; 198a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return error_handler_->CreateAndUploadError( 199a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) FROM_HERE, 200a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) "Could not get the typed_url entries.", 201a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) model_type()); 202a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 203a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 204a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Get all the visits. 205a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) std::map<history::URLID, history::VisitVector> visit_vectors; 206a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) for (history::URLRows::iterator ix = typed_urls.begin(); 207a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ix != typed_urls.end();) { 208a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) DCHECK_EQ(0U, visit_vectors.count(ix->id())); 209a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!FixupURLAndGetVisits(&(*ix), &(visit_vectors[ix->id()])) || 210a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ShouldIgnoreUrl(ix->url()) || 211a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ShouldIgnoreVisits(visit_vectors[ix->id()])) { 212a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Ignore this URL if we couldn't load the visits or if there's some 213a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // other problem with it (it was empty, or imported and never visited). 214a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ix = typed_urls.erase(ix); 215a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } else { 216a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ++ix; 217a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 218a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 219a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::WriteTransaction trans(FROM_HERE, sync_service_->GetUserShare()); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::ReadNode typed_url_root(&trans); 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (typed_url_root.InitByTagLookup(kTypedUrlTag) != 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::BaseNode::INIT_OK) { 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return error_handler_->CreateAndUploadError( 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Server did not create the top-level typed_url node. We " 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "might be running against an out-of-date server.", 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model_type()); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::set<std::string> current_urls; 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (history::URLRows::iterator ix = typed_urls.begin(); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ix != typed_urls.end(); ++ix) { 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string tag = ix->url().spec(); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Empty URLs should be filtered out by ShouldIgnoreUrl() previously. 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!tag.empty()); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::VisitVector& visits = visit_vectors[ix->id()]; 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::ReadNode node(&trans); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node.InitByClientTagLookup(syncer::TYPED_URLS, tag) == 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::BaseNode::INIT_OK) { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Same URL exists in sync data and in history data - compare the 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // entries to see if there's any difference. 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::TypedUrlSpecifics typed_url( 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FilterExpiredVisits(node.GetTypedUrlSpecifics())); 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(tag, typed_url.url()); 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Initialize fields in |new_url| to the same values as the fields in 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the existing URLRow in the history DB. This is needed because we 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // overwrite the existing value below in WriteToHistoryBackend(), but 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // some of the values in that structure are not synced (like 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // typed_count). 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::URLRow new_url(*ix); 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<history::VisitInfo> added_visits; 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MergeResult difference = 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MergeUrls(typed_url, *ix, &visits, &new_url, &added_visits); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (difference & DIFF_UPDATE_NODE) { 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::WriteNode write_node(&trans); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (write_node.InitByClientTagLookup(syncer::TYPED_URLS, tag) != 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::BaseNode::INIT_OK) { 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return error_handler_->CreateAndUploadError( 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to edit typed_url sync node.", 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model_type()); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We don't want to resurrect old visits that have been aged out by 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // other clients, so remove all visits that are older than the 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // earliest existing visit in the sync node. 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (typed_url.visits_size() > 0) { 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time earliest_visit = 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time::FromInternalValue(typed_url.visits(0)); 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (history::VisitVector::iterator it = visits.begin(); 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != visits.end() && it->visit_time < earliest_visit; ) { 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it = visits.erase(it); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Should never be possible to delete all the items, since the 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // visit vector contains all the items in typed_url.visits. 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(visits.size() > 0); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(new_url.last_visit().ToInternalValue(), 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visits.back().visit_time.ToInternalValue()); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteToSyncNode(new_url, visits, &write_node); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (difference & DIFF_LOCAL_ROW_CHANGED) { 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) updated_urls.push_back( 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::pair<history::URLID, history::URLRow>(ix->id(), new_url)); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (difference & DIFF_LOCAL_VISITS_ADDED) { 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_visits.push_back( 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::pair<GURL, std::vector<history::VisitInfo> >(ix->url(), 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) added_visits)); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sync has never seen this URL before. 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::WriteNode node(&trans); 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::WriteNode::InitUniqueByCreationResult result = 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) node.InitUniqueByCreation(syncer::TYPED_URLS, 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typed_url_root, tag); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result != syncer::WriteNode::INIT_SUCCESS) { 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return error_handler_->CreateAndUploadError( 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to create typed_url sync node: " + tag, 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model_type()); 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) node.SetTitle(UTF8ToWide(tag)); 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteToSyncNode(*ix, visits, &node); 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_urls.insert(tag); 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now walk the sync nodes and detect any URLs that exist there, but not in 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the history DB, so we can add them to our local history DB. 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<int64> obsolete_nodes; 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 sync_child_id = typed_url_root.GetFirstChildId(); 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (sync_child_id != syncer::kInvalidId) { 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::ReadNode sync_child_node(&trans); 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sync_child_node.InitByIdLookup(sync_child_id) != 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::BaseNode::INIT_OK) { 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return error_handler_->CreateAndUploadError( 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to fetch child node.", 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model_type()); 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::TypedUrlSpecifics& typed_url( 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_child_node.GetTypedUrlSpecifics()); 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_child_id = sync_child_node.GetSuccessorId(); 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ignore old sync nodes that don't have any transition data stored with 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // them, or transition data that does not match the visit data (will be 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // deleted below). 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (typed_url.visit_transitions_size() == 0 || 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typed_url.visit_transitions_size() != typed_url.visits_size()) { 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Generate a debug assertion to help track down http://crbug.com/91473, 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // even though we gracefully handle this case by throwing away this 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // node. 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(typed_url.visits_size(), typed_url.visit_transitions_size()); 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Deleting obsolete sync node with no visit " 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "transition info."; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) obsolete_nodes.push_back(sync_child_node.GetId()); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (typed_url.url().empty()) { 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Ignoring empty URL in sync DB"; 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Now, get rid of the expired visits, and if there are no un-expired 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // visits left, just ignore this node. 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::TypedUrlSpecifics filtered_url = FilterExpiredVisits(typed_url); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (filtered_url.visits_size() == 0) { 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Ignoring expired URL in sync DB: " << filtered_url.url(); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (current_urls.find(filtered_url.url()) == current_urls.end()) { 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Update the local DB from the sync DB. Since we are doing our 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // initial model association, we don't want to remove any of the 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // existing visits (pass NULL as |visits_to_remove|). 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateFromSyncDB(filtered_url, 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &new_visits, 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &updated_urls, 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &new_urls); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we encountered any obsolete nodes, remove them so they don't hang 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // around and confuse people looking at the sync node browser. 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!obsolete_nodes.empty()) { 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::vector<int64>::const_iterator it = obsolete_nodes.begin(); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != obsolete_nodes.end(); 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++it) { 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::WriteNode sync_node(&trans); 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sync_node.InitByIdLookup(*it) != syncer::BaseNode::INIT_OK) { 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return error_handler_->CreateAndUploadError( 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to fetch obsolete node.", 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) model_type()); 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sync_node.Tombstone(); 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since we're on the history thread, we don't have to worry about updating 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the history database after closing the write transaction, since 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // this is the only thread that writes to the database. We also don't have 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to worry about the sync model getting out of sync, because changes are 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // propagated to the ChangeProcessor on this thread. 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteToHistoryBackend(&new_urls, &updated_urls, &new_visits, NULL); 396a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return syncer::SyncError(); 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TypedUrlModelAssociator::UpdateFromSyncDB( 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::TypedUrlSpecifics& typed_url, 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypedUrlVisitVector* visits_to_add, 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::VisitVector* visits_to_remove, 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypedUrlUpdateVector* updated_urls, 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::URLRows* new_urls) { 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::URLRow new_url(GURL(typed_url.url())); 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::VisitVector existing_visits; 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool existing_url = history_backend_->GetURL(new_url.url(), &new_url); 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (existing_url) { 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This URL already exists locally - fetch the visits so we can 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // merge them below. 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!FixupURLAndGetVisits(&new_url, &existing_visits)) { 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Couldn't load the visits for this URL due to some kind of DB error. 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Don't bother writing this URL to the history DB (if we ignore the 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // error and continue, we might end up duplicating existing visits). 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Could not load visits for url: " << new_url.url(); 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visits_to_add->push_back(std::pair<GURL, std::vector<history::VisitInfo> >( 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_url.url(), std::vector<history::VisitInfo>())); 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Update the URL with information from the typed URL. 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateURLRowFromTypedUrlSpecifics(typed_url, &new_url); 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Figure out which visits we need to add. 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DiffVisits(existing_visits, typed_url, &visits_to_add->back().second, 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visits_to_remove); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (existing_url) { 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) updated_urls->push_back( 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::pair<history::URLID, history::URLRow>(new_url.id(), new_url)); 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_urls->push_back(new_url); 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sync_pb::TypedUrlSpecifics TypedUrlModelAssociator::FilterExpiredVisits( 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::TypedUrlSpecifics& source) { 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make a copy of the source, then regenerate the visits. 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::TypedUrlSpecifics specifics(source); 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) specifics.clear_visits(); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) specifics.clear_visit_transitions(); 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < source.visits_size(); ++i) { 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time time = base::Time::FromInternalValue(source.visits(i)); 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!history_backend_->IsExpiredVisitTime(time)) { 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) specifics.add_visits(source.visits(i)); 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) specifics.add_visit_transitions(source.visit_transitions(i)); 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(specifics.visits_size() == specifics.visit_transitions_size()); 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return specifics; 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TypedUrlModelAssociator::DeleteAllNodes( 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::WriteTransaction* trans) { 45690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) DCHECK(expected_loop_ == base::MessageLoop::current()); 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Just walk through all our child nodes and delete them. 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::ReadNode typed_url_root(trans); 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (typed_url_root.InitByTagLookup(kTypedUrlTag) != 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::BaseNode::INIT_OK) { 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Could not lookup root node"; 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int64 sync_child_id = typed_url_root.GetFirstChildId(); 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (sync_child_id != syncer::kInvalidId) { 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::WriteNode sync_child_node(trans); 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sync_child_node.InitByIdLookup(sync_child_id) != 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::BaseNode::INIT_OK) { 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Typed url node lookup failed."; 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_child_id = sync_child_node.GetSuccessorId(); 4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sync_child_node.Tombstone(); 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)syncer::SyncError TypedUrlModelAssociator::DisassociateModels() { 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return syncer::SyncError(); 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TypedUrlModelAssociator::AbortAssociation() { 484a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) base::AutoLock lock(abort_lock_); 485a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) abort_requested_ = true; 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TypedUrlModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) { 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(has_nodes); 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *has_nodes = false; 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare()); 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::ReadNode sync_node(&trans); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (sync_node.InitByTagLookup(kTypedUrlTag) != syncer::BaseNode::INIT_OK) { 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Server did not create the top-level typed_url node. We " 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "might be running against an out-of-date server."; 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The sync model has user created nodes if the typed_url folder has any 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // children. 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *has_nodes = sync_node.HasChildren(); 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TypedUrlModelAssociator::WriteToHistoryBackend( 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const history::URLRows* new_urls, 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const TypedUrlUpdateVector* updated_urls, 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const TypedUrlVisitVector* new_visits, 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const history::VisitVector* deleted_visits) { 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (new_urls) { 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history_backend_->AddPagesWithDetails(*new_urls, history::SOURCE_SYNCED); 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (updated_urls) { 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (TypedUrlUpdateVector::const_iterator url = updated_urls->begin(); 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url != updated_urls->end(); ++url) { 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is an existing entry in the URL database. We don't verify the 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // visit_count or typed_count values here, because either one (or both) 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // could be zero in the case of bookmarks, or in the case of a URL 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // transitioning from non-typed to typed as a result of this sync. 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_db_accesses_; 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!history_backend_->UpdateURL(url->first, url->second)) { 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In the field we sometimes run into errors on specific URLs. It's OK 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to just continue on (we can try writing again on the next model 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // association). 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_db_errors_; 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Could not update page: " << url->second.url().spec(); 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (new_visits) { 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (TypedUrlVisitVector::const_iterator visits = new_visits->begin(); 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visits != new_visits->end(); ++visits) { 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If there are no visits to add, just skip this. 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (visits->second.empty()) 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_db_accesses_; 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!history_backend_->AddVisits(visits->first, visits->second, 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::SOURCE_SYNCED)) { 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_db_errors_; 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Could not add visits."; 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (deleted_visits) { 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_db_accesses_; 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!history_backend_->RemoveVisits(*deleted_visits)) { 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_db_errors_; 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Could not remove visits."; 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is bad news, since it means we may end up resurrecting history 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // entries on the next reload. It's unavoidable so we'll just keep on 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // syncing. 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TypedUrlModelAssociator::MergeResult TypedUrlModelAssociator::MergeUrls( 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::TypedUrlSpecifics& node, 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const history::URLRow& url, 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::VisitVector* visits, 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::URLRow* new_url, 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<history::VisitInfo>* new_visits) { 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(new_url); 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!node.url().compare(url.url().spec())); 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!node.url().compare(new_url->url().spec())); 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(visits->size()); 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(node.visits_size(), node.visit_transitions_size()); 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we have an old-format node (before we added the visits and 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // visit_transitions arrays to the protobuf) or else the node only contained 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // expired visits, so just overwrite it with our local history data. 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node.visits_size() == 0) 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return DIFF_UPDATE_NODE; 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Convert these values only once. 576a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 node_title(UTF8ToUTF16(node.title())); 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time node_last_visit = base::Time::FromInternalValue( 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) node.visits(node.visits_size() - 1)); 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is a bitfield representing what we'll need to update with the output 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // value. 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MergeResult different = DIFF_NONE; 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if the non-incremented values changed. 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((node_title.compare(url.title()) != 0) || 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (node.hidden() != url.hidden())) { 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use the values from the most recent visit. 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node_last_visit >= url.last_visit()) { 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_url->set_title(node_title); 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_url->set_hidden(node.hidden()); 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) different |= DIFF_LOCAL_ROW_CHANGED; 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_url->set_title(url.title()); 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_url->set_hidden(url.hidden()); 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) different |= DIFF_UPDATE_NODE; 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No difference. 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_url->set_title(url.title()); 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_url->set_hidden(url.hidden()); 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t node_num_visits = node.visits_size(); 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t history_num_visits = visits->size(); 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t node_visit_index = 0; 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t history_visit_index = 0; 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time earliest_history_time = (*visits)[0].visit_time; 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Walk through the two sets of visits and figure out if any new visits were 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // added on either side. 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (node_visit_index < node_num_visits || 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history_visit_index < history_num_visits) { 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Time objects are initialized to "earliest possible time". 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time node_time, history_time; 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node_visit_index < node_num_visits) 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) node_time = base::Time::FromInternalValue(node.visits(node_visit_index)); 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (history_visit_index < history_num_visits) 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history_time = (*visits)[history_visit_index].visit_time; 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node_visit_index >= node_num_visits || 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (history_visit_index < history_num_visits && 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) node_time > history_time)) { 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We found a visit in the history DB that doesn't exist in the sync DB, 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so mark the node as modified so the caller will update the sync node. 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) different |= DIFF_UPDATE_NODE; 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++history_visit_index; 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (history_visit_index >= history_num_visits || 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) node_time < history_time) { 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Found a visit in the sync node that doesn't exist in the history DB, so 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // add it to our list of new visits and set the appropriate flag so the 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // caller will update the history DB. 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the node visit is older than any existing visit in the history DB, 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // don't re-add it - this keeps us from resurrecting visits that were 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // aged out locally. 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (node_time > earliest_history_time) { 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) different |= DIFF_LOCAL_VISITS_ADDED; 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_visits->push_back(history::VisitInfo( 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) node_time, 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::PageTransitionFromInt( 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) node.visit_transitions(node_visit_index)))); 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This visit is added to visits below. 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++node_visit_index; 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Same (already synced) entry found in both DBs - no need to do anything. 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++node_visit_index; 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++history_visit_index; 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CheckVisitOrdering(*visits)); 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (different & DIFF_LOCAL_VISITS_ADDED) { 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Insert new visits into the apropriate place in the visits vector. 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::VisitVector::iterator visit_ix = visits->begin(); 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::vector<history::VisitInfo>::iterator new_visit = 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_visits->begin(); 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_visit != new_visits->end(); ++new_visit) { 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (visit_ix != visits->end() && 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_visit->first > visit_ix->visit_time) { 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++visit_ix; 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visit_ix = visits->insert(visit_ix, 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::VisitRow(url.id(), new_visit->first, 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, new_visit->second, 0)); 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++visit_ix; 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CheckVisitOrdering(*visits)); 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_url->set_last_visit(visits->back().visit_time); 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return different; 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TypedUrlModelAssociator::WriteToSyncNode( 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const history::URLRow& url, 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const history::VisitVector& visits, 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::WriteNode* node) { 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::TypedUrlSpecifics typed_url; 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteToTypedUrlSpecifics(url, visits, &typed_url); 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) node->SetTypedUrlSpecifics(typed_url); 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TypedUrlModelAssociator::WriteToTypedUrlSpecifics( 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const history::URLRow& url, 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const history::VisitVector& visits, 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_pb::TypedUrlSpecifics* typed_url) { 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!url.last_visit().is_null()); 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!visits.empty()); 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(url.last_visit().ToInternalValue(), 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visits.back().visit_time.ToInternalValue()); 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typed_url->set_url(url.url().spec()); 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typed_url->set_title(UTF16ToUTF8(url.title())); 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typed_url->set_hidden(url.hidden()); 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CheckVisitOrdering(visits)); 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool only_typed = false; 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int skip_count = 0; 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (visits.size() > static_cast<size_t>(kMaxTypedUrlVisits)) { 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int typed_count = 0; 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int total = 0; 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Walk the passed-in visit vector and count the # of typed visits. 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (history::VisitVector::const_iterator visit = visits.begin(); 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visit != visits.end(); ++visit) { 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::PageTransition transition = content::PageTransitionFromInt( 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visit->transition & content::PAGE_TRANSITION_CORE_MASK); 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We ignore reload visits. 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (transition == content::PAGE_TRANSITION_RELOAD) 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++total; 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (transition == content::PAGE_TRANSITION_TYPED) 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++typed_count; 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should have at least one typed visit. This can sometimes happen if 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the history DB has an inaccurate count for some reason (there's been 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // bugs in the history code in the past which has left users in the wild 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // with incorrect counts - http://crbug.com/84258). 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(typed_count > 0); 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (typed_count > kMaxTypedUrlVisits) { 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) only_typed = true; 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) skip_count = typed_count - kMaxTypedUrlVisits; 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (total > kMaxTypedUrlVisits) { 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) skip_count = total - kMaxTypedUrlVisits; 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (history::VisitVector::const_iterator visit = visits.begin(); 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visit != visits.end(); ++visit) { 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::PageTransition transition = content::PageTransitionFromInt( 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visit->transition & content::PAGE_TRANSITION_CORE_MASK); 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Skip reload visits. 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (transition == content::PAGE_TRANSITION_RELOAD) 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we only have room for typed visits, then only add typed visits. 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (only_typed && transition != content::PAGE_TRANSITION_TYPED) 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (skip_count > 0) { 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have too many entries to fit, so we need to skip the oldest ones. 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only skip typed URLs if there are too many typed URLs to fit. 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (only_typed || transition != content::PAGE_TRANSITION_TYPED) { 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --skip_count; 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typed_url->add_visits(visit->visit_time.ToInternalValue()); 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typed_url->add_visit_transitions(visit->transition); 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(skip_count, 0); 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (typed_url->visits_size() == 0) { 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we get here, it's because we don't actually have any TYPED visits 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // even though the visit's typed_count > 0 (corrupted typed_count). So 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // let's go ahead and add a RELOAD visit at the most recent visit since 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // it's not legal to have an empty visit array (yet another workaround 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for http://crbug.com/84258). 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typed_url->add_visits(url.last_visit().ToInternalValue()); 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typed_url->add_visit_transitions(content::PAGE_TRANSITION_RELOAD); 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_GT(typed_url->visits_size(), 0); 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_LE(typed_url->visits_size(), kMaxTypedUrlVisits); 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(typed_url->visits_size(), typed_url->visit_transitions_size()); 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TypedUrlModelAssociator::DiffVisits( 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const history::VisitVector& old_visits, 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::TypedUrlSpecifics& new_url, 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<history::VisitInfo>* new_visits, 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) history::VisitVector* removed_visits) { 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(new_visits); 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t old_visit_count = old_visits.size(); 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t new_visit_count = new_url.visits_size(); 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t old_index = 0; 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t new_index = 0; 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (old_index < old_visit_count && new_index < new_visit_count) { 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time new_visit_time = 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time::FromInternalValue(new_url.visits(new_index)); 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (old_visits[old_index].visit_time < new_visit_time) { 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (new_index > 0 && removed_visits) { 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If there are visits missing from the start of the node, that 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // means that they were probably clipped off due to our code that 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // limits the size of the sync nodes - don't delete them from our 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // local history. 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) removed_visits->push_back(old_visits[old_index]); 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++old_index; 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (old_visits[old_index].visit_time > new_visit_time) { 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_visits->push_back(history::VisitInfo( 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_visit_time, 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::PageTransitionFromInt( 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_url.visit_transitions(new_index)))); 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++new_index; 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++old_index; 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++new_index; 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (removed_visits) { 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for ( ; old_index < old_visit_count; ++old_index) { 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) removed_visits->push_back(old_visits[old_index]); 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for ( ; new_index < new_visit_count; ++new_index) { 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_visits->push_back(history::VisitInfo( 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time::FromInternalValue(new_url.visits(new_index)), 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::PageTransitionFromInt(new_url.visit_transitions(new_index)))); 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TypedUrlModelAssociator::UpdateURLRowFromTypedUrlSpecifics( 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const sync_pb::TypedUrlSpecifics& typed_url, history::URLRow* new_url) { 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GT(typed_url.visits_size(), 0); 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(typed_url.visit_transitions_size(), typed_url.visits_size()); 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_url->set_title(UTF8ToUTF16(typed_url.title())); 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_url->set_hidden(typed_url.hidden()); 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Only provide the initial value for the last_visit field - after that, let 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the history code update the last_visit field on its own. 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (new_url->last_visit().is_null()) { 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_url->set_last_visit(base::Time::FromInternalValue( 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typed_url.visits(typed_url.visits_size() - 1))); 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TypedUrlModelAssociator::CryptoReadyIfNecessary() { 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We only access the cryptographer while holding a transaction. 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) syncer::ReadTransaction trans(FROM_HERE, sync_service_->GetUserShare()); 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const syncer::ModelTypeSet encrypted_types = trans.GetEncryptedTypes(); 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !encrypted_types.Has(syncer::TYPED_URLS) || 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_service_->IsCryptographerReady(&trans); 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace browser_sync 843