SyncSourceRevisions: added updateAll[Sub]Items
There may be backends (like CalDAV) where updating existing information about items is more efficient than reading them from scratch. This commit adds updateAll[Sub]Items in SyncSourceRevisions/TrackingSyncSource resp. the SubSyncSource API for that purpose. If it is called when some information exits (without it, the attempt would be useless) and when change tracking may resuse existing information. So an explicit slow sync still reads all items and wipes out all old information, just in case that it is somehow broken. Should not matter in most cases, though, because wrong luids and mismatching revisions will be detected and corrected. The only situation where incorrect information would matter is correct luid+revision with wrong meta information attached in MapSyncSource (subids, UID, ...).
This commit is contained in:
parent
c1116941e5
commit
7e542c596d
5 changed files with 127 additions and 21 deletions
|
@ -236,24 +236,9 @@ MapSyncSource::MapSyncSource(const SyncSourceParams ¶ms,
|
|||
}
|
||||
}
|
||||
|
||||
void MapSyncSource::listAllItems(SyncSourceRevisions::RevisionMap_t &revisions)
|
||||
void MapSyncSource::RevMap2SubRevMap(const SyncSourceRevisions::RevisionMap_t &revisions,
|
||||
SubSyncSource::SubRevisionMap_t &subrevisions)
|
||||
{
|
||||
SubSyncSource::SubRevisionMap_t subrevisions;
|
||||
m_sub->listAllSubItems(subrevisions);
|
||||
BOOST_FOREACH(const SubSyncSource::SubRevisionMap_t::value_type &subentry,
|
||||
subrevisions) {
|
||||
const std::string &mainid = subentry.first;
|
||||
const SubSyncSource::SubRevisionEntry &entry = subentry.second;
|
||||
BOOST_FOREACH(const std::string &subid, entry.m_subids) {
|
||||
std::string luid = createLUID(mainid, subid);
|
||||
revisions[luid] = entry.m_revision;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MapSyncSource::setAllItems(const SyncSourceRevisions::RevisionMap_t &revisions)
|
||||
{
|
||||
SubSyncSource::SubRevisionMap_t subrevisions;
|
||||
BOOST_FOREACH(const SyncSourceRevisions::RevisionMap_t::value_type &entry,
|
||||
revisions) {
|
||||
const std::string &luid = entry.first;
|
||||
|
@ -267,9 +252,44 @@ void MapSyncSource::setAllItems(const SyncSourceRevisions::RevisionMap_t &revisi
|
|||
}
|
||||
subentry.m_subids.insert(ids.second);
|
||||
}
|
||||
m_sub->setAllSubItems(subrevisions);
|
||||
}
|
||||
|
||||
void MapSyncSource::SubRevMap2RevMap(const SubSyncSource::SubRevisionMap_t &subrevisions,
|
||||
SyncSourceRevisions::RevisionMap_t &revisions)
|
||||
{
|
||||
BOOST_FOREACH(const SubSyncSource::SubRevisionMap_t::value_type &subentry,
|
||||
subrevisions) {
|
||||
const std::string &mainid = subentry.first;
|
||||
const SubSyncSource::SubRevisionEntry &entry = subentry.second;
|
||||
BOOST_FOREACH(const std::string &subid, entry.m_subids) {
|
||||
std::string luid = createLUID(mainid, subid);
|
||||
revisions[luid] = entry.m_revision;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MapSyncSource::listAllItems(SyncSourceRevisions::RevisionMap_t &revisions)
|
||||
{
|
||||
SubSyncSource::SubRevisionMap_t subrevisions;
|
||||
m_sub->listAllSubItems(subrevisions);
|
||||
SubRevMap2RevMap(subrevisions, revisions);
|
||||
}
|
||||
|
||||
void MapSyncSource::updateAllItems(SyncSourceRevisions::RevisionMap_t &revisions)
|
||||
{
|
||||
SubSyncSource::SubRevisionMap_t subrevisions;
|
||||
RevMap2SubRevMap(revisions, subrevisions);
|
||||
m_sub->updateAllSubItems(subrevisions);
|
||||
revisions.clear();
|
||||
SubRevMap2RevMap(subrevisions, revisions);
|
||||
}
|
||||
|
||||
void MapSyncSource::setAllItems(const SyncSourceRevisions::RevisionMap_t &revisions)
|
||||
{
|
||||
SubSyncSource::SubRevisionMap_t subrevisions;
|
||||
RevMap2SubRevMap(revisions, subrevisions);
|
||||
m_sub->setAllSubItems(subrevisions);
|
||||
}
|
||||
|
||||
SyncSourceRaw::InsertItemResult MapSyncSource::insertItem(const std::string &luid, const std::string &item, bool raw)
|
||||
{
|
||||
|
|
|
@ -128,14 +128,27 @@ class SubSyncSource : virtual public SyncSourceBase
|
|||
virtual std::string subDatabaseRevision() { return ""; }
|
||||
|
||||
/**
|
||||
* Either listAllSubItems() or setAllSubItems() will be called after begin().
|
||||
* Either listAllSubItems(), setAllSubItems(), or updateAllSubitems()
|
||||
* will be called after begin().
|
||||
*
|
||||
* In the first case, the sub source is expected to provide a full list
|
||||
* of its items. In the second case, the caller was able to determine
|
||||
* that its cached copy of that list is still correct and provides it
|
||||
* the the source.
|
||||
* the the source. In the third case, some revision information is know,
|
||||
* but it may be obsolete (revision string and/or subids changed or removed)
|
||||
* or incomplete (new items missing). The callee then must update the
|
||||
* information, possibly by falling back to listAllSubItems().
|
||||
*/
|
||||
virtual void listAllSubItems(SubRevisionMap_t &revisions) = 0;
|
||||
|
||||
/**
|
||||
* Called instead of listAllSubItems().
|
||||
*/
|
||||
virtual void updateAllSubItems(SubRevisionMap_t &revisions) {
|
||||
revisions.clear();
|
||||
listAllSubItems(revisions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called instead of listAllSubItems().
|
||||
*/
|
||||
|
@ -229,6 +242,7 @@ class MapSyncSource : public TrackingSyncSource,
|
|||
virtual std::string endSync(bool success) { m_sub->endSubSync(success); return TrackingSyncSource::endSync(success); }
|
||||
virtual bool isEmpty() { return dynamic_cast<SyncSource &>(*m_sub).getOperations().m_isEmpty(); }
|
||||
virtual void listAllItems(SyncSourceRevisions::RevisionMap_t &revisions);
|
||||
virtual void updateAllItems(SyncSourceRevisions::RevisionMap_t &revisions);
|
||||
virtual void setAllItems(const SyncSourceRevisions::RevisionMap_t &revisions);
|
||||
virtual std::string databaseRevision() { return m_sub->subDatabaseRevision(); }
|
||||
virtual InsertItemResult insertItem(const std::string &luid, const std::string &item, bool raw);
|
||||
|
@ -253,6 +267,11 @@ class MapSyncSource : public TrackingSyncSource,
|
|||
* first.
|
||||
*/
|
||||
void checkFlush(const std::string &luid);
|
||||
|
||||
void SubRevMap2RevMap(const SubSyncSource::SubRevisionMap_t &subrevisions,
|
||||
SyncSourceRevisions::RevisionMap_t &revisions);
|
||||
void RevMap2SubRevMap(const SyncSourceRevisions::RevisionMap_t &revisions,
|
||||
SubSyncSource::SubRevisionMap_t &subrevisions);
|
||||
};
|
||||
|
||||
SE_END_CXX
|
||||
|
|
|
@ -936,6 +936,33 @@ void SyncSourceRevisions::detectChanges(ConfigNode &trackingNode, ChangeMode mod
|
|||
return;
|
||||
}
|
||||
|
||||
if (!m_revisionsSet &&
|
||||
mode == CHANGES_FULL) {
|
||||
ConfigProps props;
|
||||
trackingNode.readProperties(props);
|
||||
if (!props.empty()) {
|
||||
// We were not asked to throw away all old information and
|
||||
// there is some that may be worth salvaging, so let's give
|
||||
// our derived class a chance to update it instead of having
|
||||
// to reread everything.
|
||||
//
|
||||
// The exact number of items at which the update method is
|
||||
// more efficient depends on the derived class; here we assume
|
||||
// that even a single item makes it worthwhile. The derived
|
||||
// class can always ignore the information if it has different
|
||||
// tradeoffs.
|
||||
//
|
||||
// TODO (?): an API which only provides the information
|
||||
// on demand...
|
||||
m_revisions.clear();
|
||||
m_revisions.insert(props.begin(), props.end());
|
||||
updateAllItems(m_revisions);
|
||||
// continue with m_revisions initialized below
|
||||
m_revisionsSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
// traditional, slow fallback follows...
|
||||
initRevisions();
|
||||
|
||||
// Delay setProperty calls until after checking all uids.
|
||||
|
|
|
@ -1695,7 +1695,7 @@ class SyncSourceRevisions : virtual public SyncSourceChanges, virtual public Syn
|
|||
/**
|
||||
* Called by SyncSourceRevisions::detectChanges() to tell
|
||||
* the derived class about the cached information if (and only
|
||||
* if) listAllItems() was not called. The derived class
|
||||
* if) listAllItems() and updateAllItems() were not called. The derived class
|
||||
* might not need this information, so the default implementation
|
||||
* simply ignores.
|
||||
*
|
||||
|
@ -1704,6 +1704,20 @@ class SyncSourceRevisions : virtual public SyncSourceChanges, virtual public Syn
|
|||
*/
|
||||
virtual void setAllItems(const RevisionMap_t &revisions) {}
|
||||
|
||||
/**
|
||||
* updates the revision map to reflect the current state
|
||||
*
|
||||
* May be called instead of listAllItems() if the caller has
|
||||
* a valid list to start from. If the implementor
|
||||
* cannot update the list, it must start from scratch by
|
||||
* reseting the list and calling listAllItems(). The default
|
||||
* implementation of this method does that.
|
||||
*/
|
||||
virtual void updateAllItems(SyncSourceRevisions::RevisionMap_t &revisions) {
|
||||
revisions.clear();
|
||||
listAllItems(revisions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells detectChanges() how to do its job.
|
||||
*/
|
||||
|
|
|
@ -150,6 +150,32 @@ class TrackingSyncSource : public TestingSyncSource,
|
|||
*/
|
||||
virtual void listAllItems(SyncSourceRevisions::RevisionMap_t &revisions) = 0;
|
||||
|
||||
/**
|
||||
* Called at the start of the sync session to tell
|
||||
* the derived class about the cached information if (and only
|
||||
* if) listAllItems() and updateAllItems() were not called. The derived class
|
||||
* might not need this information, so the default implementation
|
||||
* simply ignores.
|
||||
*
|
||||
* A more complex API could have been defined to only prepare the
|
||||
* information when needed, but that seemed unnecessarily complex.
|
||||
*/
|
||||
virtual void setAllItems(const RevisionMap_t &revisions) {}
|
||||
|
||||
/**
|
||||
* updates the revision map to reflect the current state
|
||||
*
|
||||
* May be called instead of listAllItems() if the caller has
|
||||
* a valid list to start from. If the implementor
|
||||
* cannot update the list, it must start from scratch by
|
||||
* reseting the list and calling listAllItems(). The default
|
||||
* implementation of this method does that.
|
||||
*/
|
||||
virtual void updateAllItems(SyncSourceRevisions::RevisionMap_t &revisions) {
|
||||
revisions.clear();
|
||||
listAllItems(revisions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or modify an item.
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue