void Graph::addAncestor (set<int>& s,int n) { s.insert(n); set<int>::iterator s_iter; set<Node*>& ancestors = G[n]->getParents(); set<Node*>::iterator sn_iter; for (sn_iter = ancestors.begin(); sn_iter!=ancestors.end();sn_iter++) { int anc = (*sn_iter)->getId(); s_iter = s.find(anc); if (s_iter == s.end()) addAncestor(s,anc); } }
set<int> Graph::getAncestorsOfNode(int n) { set<int> ret; set<int>::iterator s_iter; set<Node*>& ancestors = G[n]->getParents(); set<Node*>::iterator sn_iter; for (sn_iter = ancestors.begin(); sn_iter!=ancestors.end();sn_iter++) { int anc = (*sn_iter)->getId(); s_iter = ret.find(anc); if (s_iter == ret.end()) addAncestor(ret,anc); } return ret; }
void JsonDbObject::populateHistory(QJsonArray *history, const JsonDbObject &doc, bool includeCurrent) const { QJsonArray versions = doc.value(JsonDbString::kMetaStr).toObject().value(QStringLiteral("history")).toArray(); for (int ii = 0; ii < versions.size(); ii++) { QJsonValue hash = versions.at(ii); if (hash.isString()) { addAncestor(history, ii + 1, hash.toString()); } else if (hash.isArray()) { QJsonArray hashArray = hash.toArray(); for (QJsonArray::const_iterator jj = hashArray.begin(); jj != hashArray.end(); jj++) { if ((*jj).isString()) addAncestor(history, ii + 1, (*jj).toString()); } } } if (includeCurrent) { int updateCount; QString hash = tokenizeVersion(doc.version(), &updateCount); addAncestor(history, updateCount, hash); } }
vector<Path> Graph::getAncestralPathsOfNode(int n,int max) { vector<Path> paths; set<int>::iterator s_iter; //set<Node*>& ancestors = G[n]->getParents(); //set<Node*>::iterator sn_iter; //for (sn_iter = ancestors.begin(); sn_iter!=ancestors.end();sn_iter++) { // int anc = (*sn_iter)->getId(); vector<int> path; set<int> nodesUsed; addAncestor(paths, nodesUsed, path, n, 0, max); //} // fix the maximum distance problem for (int i=0;i<paths.size();i++) { Path& p = paths[i]; p.addDummyNode(); } return paths; }
void Graph::addAncestor (vector<Path>& paths, set<int> s, vector<int> path, int n) { path.push_back(n); s.insert(n); set<int>::iterator s_iter; set<Node*>& ancestors = G[n]->getParents(); set<Node*>::iterator sn_iter; if (ancestors.size() == 0) { Path p (s,path); paths.push_back(p); } else { for (sn_iter = ancestors.begin(); sn_iter!=ancestors.end();sn_iter++) { int anc = (*sn_iter)->getId(); s_iter = s.find(anc); if (s_iter != s.end()) { Path p (s,path); paths.push_back(p); } else addAncestor(paths,s,path,anc); } } }
/*! * \brief JsonDbObject::updateVersionOptimistic implement an optimisticWrite * \param other the object containing the update to be written. Do NOT call computeVersion() * on the other object before passing it in! other._meta.history is assumed untrusted. * \param versionWritten contains the version string of the write upon return * \param trackHistory whether version history should be tracked or not. Defaults to true. * \return true if the passed object is a valid write. As this version can operate * on conflicts too, version() and versionWritten can differ. */ bool JsonDbObject::updateVersionOptimistic(const JsonDbObject &other, QString *versionWrittenOut, bool trackHistory) { QString versionWritten; // this is trusted and expected to contain a _meta object with book keeping info QJsonObject meta = value(JsonDbString::kMetaStr).toObject(); // an array of all versions this object has replaced QJsonArray history = meta.value(QStringLiteral("history")).toArray(); // all known conflicts QJsonArray conflicts = meta.value(JsonDbString::kConflictsStr).toArray(); // check for in-object override of history tracking if (trackHistory && value(JsonDbString::kLocalStr).toBool()) trackHistory = false; QString replacedVersion = other.version(); int replacedCount; QString replacedHash = tokenizeVersion(replacedVersion, &replacedCount); int updateCount = replacedCount; QString hash = replacedHash; // we don't trust other._meta.history, so other._version must be replacedVersion // if other.computeVersion() was called before updateVersionOptimistic(), other can at max be a replay // as we lost which version other is replacing. bool isReplay = !other.computeVersion(replacedCount, replacedHash, &updateCount, &hash); bool isValidWrite = false; // first we check if this version can eliminate a conflict for (QJsonArray::const_iterator ii = conflicts.begin(); ii < conflicts.end(); ii++) { JsonDbObject conflict((*ii).toObject()); if (conflict.version() == replacedVersion) { if (!isReplay) conflicts.removeAt(ii.i); if (!isValidWrite) { addAncestor(&history, updateCount, hash); versionWritten = versionAsString(updateCount, hash); } isValidWrite = true; } } // now we check if this version can progress the head if (version().isEmpty() || version() == replacedVersion) { if (!isReplay) *this = other; if (!isValidWrite) versionWritten = versionAsString(updateCount, hash); insert(JsonDbString::kVersionStr, versionWritten); isValidWrite = true; } // make sure we can resurrect a tombstone // Issue: Recreating a _uuid must have a updateCount higher than the tombstone // otherwise it is considered a conflict. if (!isValidWrite && isDeleted()) { if (!isReplay) { addAncestor(&history, replacedCount, replacedHash); } replacedHash = tokenizeVersion(version(), &replacedCount); updateCount = replacedCount + 1; versionWritten = versionAsString(updateCount, hash); *this = other; insert(JsonDbString::kVersionStr, versionWritten); isValidWrite = true; } // update the book keeping of what versions we have replaced in this version branch if (isValidWrite && !isReplay) { addAncestor(&history, replacedCount, replacedHash); meta = QJsonObject(); if (trackHistory && history.size()) meta.insert(QStringLiteral("history"), history); if (conflicts.size()) meta.insert(JsonDbString::kConflictsStr, history); if (!meta.isEmpty()) insert(JsonDbString::kMetaStr, meta); else insert(JsonDbString::kMetaStr, QJsonValue::Undefined); } // last chance for a valid write: other is a replay from history if (!isValidWrite && isAncestorOf(history, updateCount, hash)) { isValidWrite = true; versionWritten = versionAsString(updateCount, hash); } if (versionWrittenOut) *versionWrittenOut = versionWritten; return isValidWrite; }