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;
}
Exemple #3
0
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);                                        
        }
    }
}
Exemple #6
0
/*!
 * \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;
}