WebDAV: use CTag for quick change detection
The CTag mechanism allows to quickly check whether data has changed. With WebDAV and the recent infrastructure changes in SyncSourceRevisions/TrackingSyncSource, that is straight-forward. With CalDAV it is a bit more complicated because the m_cache needs to be populated for some of the operations to succeed. This is accomplished via the setAll[Sub]Items() calls.
This commit is contained in:
parent
415e33bada
commit
6a4b2a124d
|
@ -130,6 +130,28 @@ int CalDAVSource::appendItem(SubRevisionMap_t &revisions,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void CalDAVSource::setAllSubItems(const SubRevisionMap_t &revisions)
|
||||
{
|
||||
if (!m_cache.m_initialized) {
|
||||
// populate our cache (without data) from the information cached
|
||||
// for us
|
||||
BOOST_FOREACH(const SubSyncSource::SubRevisionMap_t::value_type &subentry,
|
||||
revisions) {
|
||||
const std::string &luid = subentry.first;
|
||||
const std::string &rev = subentry.second.first;
|
||||
boost::shared_ptr<Event> &event = m_cache[luid];
|
||||
event.reset(new Event);
|
||||
event->m_DAVluid = luid;
|
||||
event->m_etag = rev;
|
||||
// We don't know the real UID (may be different from resource name == DAVluid),
|
||||
// sequence and last-modified. This information will have to be filled
|
||||
// in by loadItem() when some operation on this event needs it.
|
||||
event->m_subids = subentry.second.second;
|
||||
}
|
||||
m_cache.m_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
SubSyncSource::SubItemResult CalDAVSource::insertSubItem(const std::string &luid, const std::string &callerSubID,
|
||||
const std::string &item)
|
||||
{
|
||||
|
@ -179,7 +201,10 @@ SubSyncSource::SubItemResult CalDAVSource::insertSubItem(const std::string &luid
|
|||
}
|
||||
std::string subid = *newEvent->m_subids.begin();
|
||||
|
||||
// determine whether we already know the merged item even though our caller didn't
|
||||
// Determine whether we already know the merged item even though
|
||||
// our caller didn't. That additional safe guard will fail if
|
||||
// setAllSubItems() was used to fill the cache, because then the m_UID
|
||||
// values in the cache will not be set yet. That should be okay.
|
||||
std::string davLUID = luid;
|
||||
std::string knownSubID = callerSubID;
|
||||
if (davLUID.empty()) {
|
||||
|
@ -706,11 +731,17 @@ CalDAVSource::Event &CalDAVSource::loadItem(Event &event)
|
|||
Event::unescapeRecurrenceID(item);
|
||||
event.m_calendar.set(icalcomponent_new_from_string((char *)item.c_str()), // hack for old libical
|
||||
"parsing iCalendar 2.0");
|
||||
// sequence number might have been increased by last save,
|
||||
// so check it again
|
||||
|
||||
// Sequence number/last-modified might have been increased by last save.
|
||||
// Or the cache was populated by setAllSubItems(), which doesn't give
|
||||
// us the information. In that case, UID might also still be unknown.
|
||||
// Either way, check it again.
|
||||
for (icalcomponent *comp = icalcomponent_get_first_component(event.m_calendar, ICAL_VEVENT_COMPONENT);
|
||||
comp;
|
||||
comp = icalcomponent_get_next_component(event.m_calendar, ICAL_VEVENT_COMPONENT)) {
|
||||
if (event.m_UID.empty()) {
|
||||
event.m_UID = Event::getUID(comp);
|
||||
}
|
||||
long sequence = Event::getSequence(comp);
|
||||
if (sequence > event.m_sequence) {
|
||||
event.m_sequence = sequence;
|
||||
|
|
|
@ -34,7 +34,9 @@ class CalDAVSource : public WebDAVSource,
|
|||
/* implementation of SubSyncSource interface */
|
||||
virtual void begin() { contactServer(); }
|
||||
virtual void endSubSync(bool success) { if (success) { storeServerInfos(); } }
|
||||
virtual std::string subDatabaseRevision() { return databaseRevision(); }
|
||||
virtual void listAllSubItems(SubRevisionMap_t &revisions);
|
||||
virtual void setAllSubItems(const SubRevisionMap_t &revisions);
|
||||
virtual SubItemResult insertSubItem(const std::string &uid, const std::string &subid,
|
||||
const std::string &item);
|
||||
virtual void readSubItem(const std::string &uid, const std::string &subid, std::string &item);
|
||||
|
|
|
@ -881,6 +881,29 @@ void WebDAVSource::storeServerInfos()
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://trac.calendarserver.org/browser/CalendarServer/trunk/doc/Extensions/caldav-ctag.txt
|
||||
*/
|
||||
static const ne_propname getctag[] = {
|
||||
{ "http://calendarserver.org/ns/", "getctag" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
std::string WebDAVSource::databaseRevision()
|
||||
{
|
||||
Timespec deadline = createDeadline();
|
||||
Neon::Session::PropfindPropCallback_t callback =
|
||||
boost::bind(&WebDAVSource::openPropCallback,
|
||||
this, _1, _2, _3, _4);
|
||||
m_davProps[m_calendar.m_path]["http://calendarserver.org/ns/:getctag"] = "";
|
||||
m_session->propfindProp(m_calendar.m_path, 0, getctag, callback, deadline);
|
||||
// Fatal communication problems will be reported via exceptions.
|
||||
// Once we get here, invalid or incomplete results can be
|
||||
// treated as "don't have revision string".
|
||||
string ctag = m_davProps[m_calendar.m_path]["http://calendarserver.org/ns/:getctag"];
|
||||
return ctag;
|
||||
}
|
||||
|
||||
|
||||
static const ne_propname getetag[] = {
|
||||
{ "DAV:", "getetag" },
|
||||
|
|
|
@ -79,6 +79,7 @@ class WebDAVSource : public TrackingSyncSource, private boost::noncopyable
|
|||
}
|
||||
|
||||
/* implementation of TrackingSyncSource interface */
|
||||
virtual std::string databaseRevision();
|
||||
virtual void listAllItems(RevisionMap_t &revisions);
|
||||
virtual InsertItemResult insertItem(const string &luid, const std::string &item, bool raw);
|
||||
void readItem(const std::string &luid, std::string &item, bool raw);
|
||||
|
|
Loading…
Reference in a new issue