refs #659, #657 Fixed mistake in synchronize() where a future would be broken prematurely if async load had not yet started after 1 second timeout.

This commit is contained in:
Mathew Sutcliffe
2016-06-05 19:19:19 +01:00
parent aefef81cd7
commit d53237cebc
2 changed files with 15 additions and 6 deletions

View File

@@ -42,11 +42,16 @@ namespace BlackMisc
LockGuard(const LockGuard &) = delete; LockGuard(const LockGuard &) = delete;
LockGuard &operator =(const LockGuard &) = delete; LockGuard &operator =(const LockGuard &) = delete;
LockGuard(LockGuard &&other) noexcept : m_movedFrom(true) { *this = std::move(other); } LockGuard(LockGuard &&other) noexcept : m_movedFrom(true) { *this = std::move(other); }
LockGuard &operator =(LockGuard &&other) noexcept { std::swap(m_movedFrom, other.m_movedFrom); std::swap(m_rev, other.m_rev); return *this; } LockGuard &operator =(LockGuard &&other) noexcept
{
auto tuple = std::tie(other.m_movedFrom, other.m_keepPromises, other.m_rev);
std::tie(m_movedFrom, m_keepPromises, m_rev).swap(tuple);
return *this;
}
~LockGuard() ~LockGuard()
{ {
if (! m_movedFrom) { m_rev->finishUpdate(); } if (! m_movedFrom) { m_rev->finishUpdate(m_keepPromises); }
} }
operator bool() const { return ! m_movedFrom; } operator bool() const { return ! m_movedFrom; }
@@ -54,9 +59,11 @@ namespace BlackMisc
private: private:
LockGuard() : m_movedFrom(true) {} LockGuard() : m_movedFrom(true) {}
LockGuard(CDataCacheRevision *rev) : m_movedFrom(! rev), m_rev(rev) {} LockGuard(CDataCacheRevision *rev) : m_movedFrom(! rev), m_rev(rev) {}
LockGuard &keepPromises() { m_keepPromises = true; return *this; }
friend class CDataCacheRevision; friend class CDataCacheRevision;
bool m_movedFrom = false; bool m_movedFrom = false;
bool m_keepPromises = false;
CDataCacheRevision *m_rev = nullptr; CDataCacheRevision *m_rev = nullptr;
}; };
@@ -423,7 +430,7 @@ namespace BlackMisc
revisionFile.write(QJsonDocument(json).toJson()); revisionFile.write(QJsonDocument(json).toJson());
} }
void CDataCacheRevision::finishUpdate() void CDataCacheRevision::finishUpdate(bool keepPromises)
{ {
QMutexLocker lock(&m_mutex); QMutexLocker lock(&m_mutex);
@@ -433,7 +440,7 @@ namespace BlackMisc
m_updateInProgress = false; m_updateInProgress = false;
m_pendingRead = false; m_pendingRead = false;
m_pendingWrite = false; m_pendingWrite = false;
breakPromises(); if (! keepPromises) { breakPromises(); }
m_lockFile.unlock(); m_lockFile.unlock();
} }
@@ -474,7 +481,8 @@ namespace BlackMisc
// Temporary guard object returned by beginUpdate is deleted at the end of the full expression, // Temporary guard object returned by beginUpdate is deleted at the end of the full expression,
// don't try to split the conditional into multiple statements. // don't try to split the conditional into multiple statements.
return (m_updateInProgress || m_pendingWrite || beginUpdate({{ key, timestamp }}, false)) // If a future is still waiting for the next update to begin, we don't want to break its associated promise.
return (m_updateInProgress || m_pendingWrite || beginUpdate({{ key, timestamp }}, false).keepPromises())
&& (m_timestamps.contains(key) || m_admittedQueue.contains(key)); && (m_timestamps.contains(key) || m_admittedQueue.contains(key));
} }

View File

@@ -106,7 +106,8 @@ namespace BlackMisc
void writeNewRevision(const QMap<QString, qint64> &timestamps); void writeNewRevision(const QMap<QString, qint64> &timestamps);
//! Release the revision file lock and mark everything up-to-date (called by LockGuard destructor). //! Release the revision file lock and mark everything up-to-date (called by LockGuard destructor).
void finishUpdate(); //! \param keepPromises Don't break pending promises.
void finishUpdate(bool keepPromises = false);
//! True if beginUpdate found some values with timestamps newer than in memory. //! True if beginUpdate found some values with timestamps newer than in memory.
bool isPendingRead() const; bool isPendingRead() const;