-
Notifications
You must be signed in to change notification settings - Fork 74
v0.2.54..v0.2.55 changeset OsmApiChangeset.cpp
Garret Voltz edited this page Aug 14, 2020
·
1 revision
diff --git a/hoot-core/src/main/cpp/hoot/core/io/OsmApiChangeset.cpp b/hoot-core/src/main/cpp/hoot/core/io/OsmApiChangeset.cpp
index 2c9087d..808906f 100644
--- a/hoot-core/src/main/cpp/hoot/core/io/OsmApiChangeset.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/io/OsmApiChangeset.cpp
@@ -587,7 +587,7 @@ void XmlChangeset::moveOrRemoveNode(ChangesetInfoPtr& source, ChangesetInfoPtr&
}
}
-bool XmlChangeset::moveNode(ChangesetInfoPtr& source, ChangesetInfoPtr& destination, ChangesetType type, ChangesetNode* node)
+bool XmlChangeset::moveNode(ChangesetInfoPtr& source, ChangesetInfoPtr& destination, ChangesetType type, ChangesetNode* node, bool /*failing*/)
{
// Add the node to the destination and remove from the source
destination->add(ElementType::Node, type, node->id());
@@ -717,7 +717,7 @@ void XmlChangeset::moveOrRemoveWay(ChangesetInfoPtr& source, ChangesetInfoPtr& d
}
}
-bool XmlChangeset::moveWay(ChangesetInfoPtr& source, ChangesetInfoPtr& destination, ChangesetType type, ChangesetWay* way)
+bool XmlChangeset::moveWay(ChangesetInfoPtr& source, ChangesetInfoPtr& destination, ChangesetType type, ChangesetWay* way, bool failing)
{
// Don't worry about the contents of a delete operation
if (type != ChangesetType::TypeDelete)
@@ -729,7 +729,28 @@ bool XmlChangeset::moveWay(ChangesetInfoPtr& source, ChangesetInfoPtr& destinati
for (int current_type = ChangesetType::TypeCreate; current_type != ChangesetType::TypeMax; ++current_type)
{
if (source->contains(ElementType::Node, (ChangesetType)current_type, id))
- moveNode(source, destination, (ChangesetType)current_type, dynamic_cast<ChangesetNode*>(_allNodes[id].get()));
+ {
+ bool allowMove = true;
+ // Don't move this node if it isn't free and clear when failing (and also an add)
+ if (failing && _nodes[TypeCreate].find(id) != _nodes[TypeCreate].end())
+ {
+ std::set<long> wayIds = _nodeIdsToWays[id];
+ // Nodes that intersect multiple ways need further checking
+ if (wayIds.size() > 1)
+ {
+ // Iterate all of the parent ways looking for a valid (non-error) way
+ for (std::set<long>::iterator it = wayIds.begin(); it != wayIds.end(); ++it)
+ {
+ // Ignore this way (hasn't been errored out yet) and look for a valid way
+ if (*it != way->id() && way->getStatus() != ChangesetElement::ElementStatus::Failed)
+ allowMove = false;
+ }
+ }
+ }
+ // Only move the node if it is allowed
+ if (allowMove)
+ moveNode(source, destination, (ChangesetType)current_type, dynamic_cast<ChangesetNode*>(_allNodes[id].get()));
+ }
}
}
}
@@ -812,7 +833,7 @@ bool XmlChangeset::addRelation(ChangesetInfoPtr& changeset, ChangesetType type,
{
ChangesetRelation* relation_member = dynamic_cast<ChangesetRelation*>(_allRelations[member.getRef()].get());
// Don't re-add self referencing relations
- if (relation->id() != relation_member->id())
+ if (relation_member && relation->id() != relation_member->id())
addRelation(changeset, type, relation_member);
}
}
@@ -898,7 +919,7 @@ void XmlChangeset::moveOrRemoveRelation(ChangesetInfoPtr& source, ChangesetInfoP
}
}
-bool XmlChangeset::moveRelation(ChangesetInfoPtr& source, ChangesetInfoPtr& destination, ChangesetType type, ChangesetRelation* relation)
+bool XmlChangeset::moveRelation(ChangesetInfoPtr& source, ChangesetInfoPtr& destination, ChangesetType type, ChangesetRelation* relation, bool failing)
{
// Don't worry about the contents of a delete operation
if (type != ChangesetType::TypeDelete)
@@ -915,7 +936,7 @@ bool XmlChangeset::moveRelation(ChangesetInfoPtr& source, ChangesetInfoPtr& dest
for (int current_type = ChangesetType::TypeCreate; current_type != ChangesetType::TypeMax; ++current_type)
{
if (source->contains(ElementType::Node, (ChangesetType)current_type, id))
- moveNode(source, destination, (ChangesetType)current_type, dynamic_cast<ChangesetNode*>(_allNodes[id].get()));
+ moveNode(source, destination, (ChangesetType)current_type, dynamic_cast<ChangesetNode*>(_allNodes[id].get()), failing);
}
}
else if (member.isWay())
@@ -923,7 +944,7 @@ bool XmlChangeset::moveRelation(ChangesetInfoPtr& source, ChangesetInfoPtr& dest
for (int current_type = ChangesetType::TypeCreate; current_type != ChangesetType::TypeMax; ++current_type)
{
if (source->contains(ElementType::Way, (ChangesetType)current_type, id))
- moveWay(source, destination, (ChangesetType)current_type, dynamic_cast<ChangesetWay*>(_allWays[id].get()));
+ moveWay(source, destination, (ChangesetType)current_type, dynamic_cast<ChangesetWay*>(_allWays[id].get()), failing);
}
}
else if (member.isRelation())
@@ -934,7 +955,7 @@ bool XmlChangeset::moveRelation(ChangesetInfoPtr& source, ChangesetInfoPtr& dest
for (int current_type = ChangesetType::TypeCreate; current_type != ChangesetType::TypeMax; ++current_type)
{
if (source->contains(ElementType::Relation, (ChangesetType)current_type, id))
- moveRelation(source, destination, (ChangesetType)current_type, dynamic_cast<ChangesetRelation*>(_allRelations[id].get()));
+ moveRelation(source, destination, (ChangesetType)current_type, dynamic_cast<ChangesetRelation*>(_allRelations[id].get()), failing);
}
}
}
@@ -1296,24 +1317,26 @@ bool XmlChangeset::matchesRelationFailure(const QString& hint, long& element_id,
return false;
}
-bool XmlChangeset::matchesMultiRelationFailure(const QString& hint,
- long& element_id,
- std::vector<long>& member_ids,
- ElementType::Type& member_type)
+bool XmlChangeset::matchesMultiElementFailure(const QString& hint,
+ long& element_id,
+ ElementType::Type& element_type,
+ std::vector<long>& member_ids,
+ ElementType::Type& member_type)
{
// Relation with id -2 requires the relations with id in 1707148,1707249, which either do not exist, or are not visible.
- QRegularExpression reg("Relation (-?[0-9]+) requires the (nodes|ways|relations) with id in ((-?[0-9]+,)+) (.*)", //-?[0-9]+,).*", //+ which either do not exist, or are not visible.",
+ QRegularExpression reg("(Relation|Way) (-?[0-9]+) requires the (nodes|ways|relations) with id in ((-?[0-9]+,)+) (.*)", //-?[0-9]+,).*", //+ which either do not exist, or are not visible.",
QRegularExpression::CaseInsensitiveOption);
QRegularExpressionMatch match = reg.match(hint);
if (match.hasMatch())
{
- QString error = match.captured(1);
+ element_type = ElementType::fromString(match.captured(1));
+ QString error = match.captured(2);
if (error != "")
element_id = error.toLong();
// Get the node/way/relation type (remove the 's') and id that failed
- member_type = ElementType::fromString(match.captured(2).left(match.captured(2).length() - 1));
+ member_type = ElementType::fromString(match.captured(3).left(match.captured(3).length() - 1));
bool success = false;
- QStringList ids = match.captured(3).split(",", QString::SkipEmptyParts);
+ QStringList ids = match.captured(4).split(",", QString::SkipEmptyParts);
for (int i = 0; i < ids.size(); ++i)
{
long id = ids[i].toLong(&success);
@@ -1325,9 +1348,10 @@ bool XmlChangeset::matchesMultiRelationFailure(const QString& hint,
return false;
}
-bool XmlChangeset::matchesChangesetPreconditionFailure(const QString& hint,
- long& member_id, ElementType::Type& member_type,
- long& element_id, ElementType::Type& element_type)
+bool XmlChangeset::matchesChangesetDeletePreconditionFailure(
+ const QString& hint,
+ long& member_id, ElementType::Type& member_type,
+ long& element_id, ElementType::Type& element_type)
{
// Precondition failed: Node 55 is still used by ways 123
QRegularExpression reg(
@@ -1420,7 +1444,8 @@ ChangesetInfoPtr XmlChangeset::splitChangeset(ChangesetInfoPtr changeset, const
std::vector<long> member_ids;
ElementType::Type member_type = ElementType::Unknown;
ElementType::Type element_type = ElementType::Unknown;
- // See if the hint is something like: Placeholder node not found for reference -145213 in way -5687
+ // See if the hint is something like:
+ // Placeholder node not found for reference -145213 in way -5687
if (matchesPlaceholderFailure(splitHint, member_id, member_type, element_id, element_type))
{
// Use the type and id to split the changeset
@@ -1432,8 +1457,16 @@ ChangesetInfoPtr XmlChangeset::splitChangeset(ChangesetInfoPtr changeset, const
{
ChangesetWay* way = dynamic_cast<ChangesetWay*>(_allWays[element_id].get());
// Add the way to the split and remove from the changeset
- split->add(element_type, (ChangesetType)current_type, way->id());
- changeset->remove(element_type, (ChangesetType)current_type, way->id());
+ if (current_type == ChangesetType::TypeCreate)
+ {
+ moveWay(changeset, split, (ChangesetType)current_type, way, true);
+ split->setError();
+ }
+ else
+ {
+ split->add(element_type, (ChangesetType)current_type, way->id());
+ changeset->remove(element_type, (ChangesetType)current_type, way->id());
+ }
return split;
}
else if (element_type == ElementType::Relation)
@@ -1447,7 +1480,8 @@ ChangesetInfoPtr XmlChangeset::splitChangeset(ChangesetInfoPtr changeset, const
}
}
}
- // See if the hint is something like: Relation with id cannot be saved due to Relation with id 1707699
+ // See if the hint is something like:
+ // Relation with id cannot be saved due to Relation with id 1707699
else if (matchesRelationFailure(splitHint, element_id, member_id, member_type))
{
if (element_id != 0)
@@ -1486,24 +1520,46 @@ ChangesetInfoPtr XmlChangeset::splitChangeset(ChangesetInfoPtr changeset, const
}
}
}
- // See if the hint is something like: Relation with id -2 requires the relations with id in 1707148,1707249, which either do not exist, or are not visible.
- else if (matchesMultiRelationFailure(splitHint, element_id, member_ids, member_type))
+ // See if the hint is something like:
+ // Relation with id -2 requires the relations with id in 1707148,1707249, which either do not exist, or are not visible.
+ else if (matchesMultiElementFailure(splitHint, element_id, element_type, member_ids, member_type))
{
// If there is a relation id, move just that relation to the split
for (int current_type = ChangesetType::TypeCreate; current_type != ChangesetType::TypeMax; ++current_type)
{
- if (changeset->contains(ElementType::Relation, (ChangesetType)current_type, element_id))
+ if (changeset->contains(element_type, (ChangesetType)current_type, element_id))
{
- ChangesetRelation* relation = dynamic_cast<ChangesetRelation*>(_allRelations[element_id].get());
- // Add the relation to the split and remove from the changeset
- split->add(ElementType::Relation, (ChangesetType)current_type, relation->id());
- changeset->remove(ElementType::Relation, (ChangesetType)current_type, relation->id());
- return split;
+ if (element_type == ElementType::Way)
+ {
+ ChangesetWay* way = dynamic_cast<ChangesetWay*>(_allWays[element_id].get());
+ // Add the way to the split and remove from the changeset
+ if (current_type == ChangesetType::TypeCreate)
+ {
+ moveWay(changeset, split, (ChangesetType)current_type, way, true);
+ split->setError();
+ }
+ else
+ {
+ split->add(element_type, (ChangesetType)current_type, way->id());
+ changeset->remove(element_type, (ChangesetType)current_type, way->id());
+ }
+ return split;
+ }
+ else if (element_type == ElementType::Relation)
+ {
+ ChangesetRelation* relation = dynamic_cast<ChangesetRelation*>(_allRelations[element_id].get());
+ // Add the relation to the split and remove from the changeset
+ split->add(ElementType::Relation, (ChangesetType)current_type, relation->id());
+ changeset->remove(ElementType::Relation, (ChangesetType)current_type, relation->id());
+ split->setError();
+ return split;
+ }
}
}
}
- // See if the hint is something like: Changeset precondition failed: Precondition failed: Node 5 is still used by ways 67
- else if (matchesChangesetPreconditionFailure(splitHint, member_id, member_type, element_id, element_type))
+ // See if the hint is something like:
+ // Changeset precondition failed: Precondition failed: Node 5 is still used by ways 67
+ else if (matchesChangesetDeletePreconditionFailure(splitHint, member_id, member_type, element_id, element_type))
{
// In this case the node 5 cannot be deleted because way 67 is still using it. Way 67 must be modified or deleted first
// here we figure out how to make that happen
@@ -1842,37 +1898,121 @@ void XmlChangeset::replaceRelationId(long old_id, long new_id)
_idMap.updateId(ElementType::Relation, old_id, new_id);
}
+void XmlChangeset::failChangeset(const ChangesetInfoPtr& changeset)
+{
+ if (!changeset)
+ return;
+ if (!changeset->getError())
+ return;
+ for (int current_type = ChangesetType::TypeCreate; current_type != ChangesetType::TypeMax; ++current_type)
+ {
+ // Iterate all of the nodes and fail them
+ for (ChangesetInfo::iterator it = changeset->begin(ElementType::Node, (ChangesetType)current_type);
+ it != changeset->end(ElementType::Node, (ChangesetType)current_type); ++it)
+ {
+ failNode(*it);
+ }
+ // Iterate all of the ways and fail them
+ for (ChangesetInfo::iterator it = changeset->begin(ElementType::Way, (ChangesetType)current_type);
+ it != changeset->end(ElementType::Way, (ChangesetType)current_type); ++it)
+ {
+ failWay(*it);
+ }
+ // Iterate all of the relations and fail them
+ for (ChangesetInfo::iterator it = changeset->begin(ElementType::Relation, (ChangesetType)current_type);
+ it != changeset->end(ElementType::Relation, (ChangesetType)current_type); ++it)
+ {
+ failRelation(*it);
+ }
+ }
+ // Write out any failed elements
+ writeErrorFile();
+}
+
void XmlChangeset::failNode(long id, bool beforeSend)
{
- // Set the node's status to failed
- _allNodes[id]->setStatus(ChangesetElement::ElementStatus::Failed);
+ // Validate the ID
+ if (_allNodes.find(id) == _allNodes.end() || !_allNodes[id])
+ return;
+ // Don't set it twice
+ if (_allNodes[id]->getStatus() == ChangesetElement::ElementStatus::Failed)
+ return;
// Update the failed count once
++_failedCount;
// Update sent count as if we already sent it and it failed
- if (beforeSend)
+ if (beforeSend || _allNodes[id]->getStatus() == ChangesetElement::ElementStatus::Available)
++_sentCount;
+ // Set the node's status to failed
+ _allNodes[id]->setStatus(ChangesetElement::ElementStatus::Failed);
+ // When a node fails to be created, any parent ways must fail also
+ // Along with any parent relations
+ if (_nodes[TypeCreate].find(id) != _nodes[TypeCreate].end())
+ {
+ // Fail parent ways
+ if (_nodeIdsToWays.find(id) != _nodeIdsToWays.end())
+ {
+ const std::set<long>& parents = _nodeIdsToWays[id];
+ for (std::set<long>::const_iterator it = parents.begin(); it != parents.end(); ++it)
+ failWay(*it, beforeSend);
+ }
+ // Fail parent relations
+ if (_nodeIdsToRelations.find(id) != _nodeIdsToRelations.end())
+ {
+ const std::set<long>& parents = _nodeIdsToRelations[id];
+ for (std::set<long>::const_iterator it = parents.begin(); it != parents.end(); ++it)
+ failRelation(*it, beforeSend);
+ }
+ }
}
void XmlChangeset::failWay(long id, bool beforeSend)
{
- // Set the way's status to failed
- _allWays[id]->setStatus(ChangesetElement::ElementStatus::Failed);
+ // Validate the ID
+ if (_allWays.find(id) == _allWays.end() || !_allWays[id])
+ return;
+ // Don't set it twice
+ if (_allWays[id]->getStatus() == ChangesetElement::ElementStatus::Failed)
+ return;
// Update the failed count once
++_failedCount;
// Update sent count as if we already sent it and it failed
- if (beforeSend)
+ if (beforeSend || _allWays[id]->getStatus() == ChangesetElement::ElementStatus::Available)
++_sentCount;
+ // Set the way's status to failed
+ _allWays[id]->setStatus(ChangesetElement::ElementStatus::Failed);
+ // When a way fails to be created, any parent relations must fail also
+ if (_ways[TypeCreate].find(id) != _ways[TypeCreate].end() &&
+ _wayIdsToRelations.find(id) != _wayIdsToRelations.end())
+ {
+ const std::set<long>& parents = _wayIdsToRelations[id];
+ for (std::set<long>::const_iterator it = parents.begin(); it != parents.end(); ++it)
+ failRelation(*it, beforeSend);
+ }
}
void XmlChangeset::failRelation(long id, bool beforeSend)
{
- // Set the relation's status to failed
- _allRelations[id]->setStatus(ChangesetElement::ElementStatus::Failed);
+ // Validate the ID
+ if (_allRelations.find(id) == _allRelations.end() || !_allRelations[id])
+ return;
+ // Don't set it twice
+ if (_allRelations[id]->getStatus() == ChangesetElement::ElementStatus::Failed)
+ return;
// Update the failed count once
++_failedCount;
// Update sent count as if we already sent it and it failed
- if (beforeSend)
+ if (beforeSend || _allRelations[id]->getStatus() == ChangesetElement::ElementStatus::Available)
++_sentCount;
+ // Set the relation's status to failed
+ _allRelations[id]->setStatus(ChangesetElement::ElementStatus::Failed);
+ // When a relation fails to be created, any parent relations must fail also
+ if (_relations[TypeCreate].find(id) != _relations[TypeCreate].end() &&
+ _relationIdsToRelations.find(id) != _relationIdsToRelations.end())
+ {
+ const std::set<long>& parents = _relationIdsToRelations[id];
+ for (std::set<long>::const_iterator it = parents.begin(); it != parents.end(); ++it)
+ failRelation(*it, beforeSend);
+ }
LOG_TRACE("Failed relation (" << id << ")");
}
@@ -1968,16 +2108,19 @@ bool XmlChangeset::calculateRemainingChangeset(ChangesetInfoPtr &changeset)
// Output the remaining changeset to a file to inform the user where the issues lie
if (!empty_changeset && !_errorPathname.isEmpty())
{
- // Replace error with remaining in the error pathname
- QString pathname = _errorPathname;
- pathname.replace("error", "remaining");
// Write the file with changeset ID of zero
- FileUtils::writeFully(pathname, this->getChangesetString(changeset, 0));
+ FileUtils::writeFully(getRemainingFilename(), this->getChangesetString(changeset, 0));
}
// Return true if there is anything in the changeset
return !empty_changeset;
}
+void XmlChangeset::updateRemainingChangeset()
+{
+ // Remove the "remaining" file once it comes back successfully
+ QFile::remove(getRemainingFilename());
+}
+
bool XmlChangeset::isMatch(const XmlChangeset& changeset)
{
bool isEqual = true;
@@ -2109,10 +2252,44 @@ bool XmlChangeset::isMatch(const XmlChangeset& changeset)
return isEqual;
}
+void XmlChangeset::failRemainingChangeset()
+{
+ // Fail all remaining nodes
+ failRemainingElements(_allNodes);
+ // Fail all remaining ways
+ failRemainingElements(_allWays);
+ // Fail all remaining relations
+ failRemainingElements(_allRelations);
+}
+
+void XmlChangeset::failRemainingElements(const ChangesetElementMap& elements)
+{
+ // Iterate all elements
+ for (ChangesetElementMap::const_iterator it = elements.begin(); it != elements.end(); ++it)
+ {
+ ChangesetElementPtr element = it->second;
+ // Anything that isn't finalized is now failed
+ if (element->getStatus() != ChangesetElement::Finalized)
+ {
+ element->setStatus(ChangesetElement::Failed);
+ ++_failedCount;
+ }
+ }
+}
+
+QString XmlChangeset::getRemainingFilename()
+{
+ // Replace error with remaining in the error pathname
+ QString pathname = _errorPathname;
+ pathname.replace("error", "remaining");
+ return pathname;
+}
+
ChangesetInfo::ChangesetInfo()
: _attemptedResolveChangesetIssues(false),
_numRetries(0),
- _last(false)
+ _last(false),
+ _isError(false)
{
}