fix possible race condition in Normalizer cache
This commit is contained in:
parent
08b0685ad1
commit
b0a2cff43a
5 changed files with 117 additions and 66 deletions
|
@ -24,28 +24,28 @@
|
||||||
#include "util/log/Log.h"
|
#include "util/log/Log.h"
|
||||||
#include "xml/pfxml.h"
|
#include "xml/pfxml.h"
|
||||||
|
|
||||||
using util::geo::webMercMeterDist;
|
using ad::cppgtfs::gtfs::Stop;
|
||||||
using util::geo::Box;
|
using pfaedle::osm::BlockSearch;
|
||||||
using util::Nullable;
|
using pfaedle::osm::EdgeGrid;
|
||||||
using pfaedle::trgraph::Normalizer;
|
using pfaedle::osm::EqSearch;
|
||||||
|
using pfaedle::osm::NodeGrid;
|
||||||
|
using pfaedle::osm::OsmBuilder;
|
||||||
|
using pfaedle::osm::OsmNode;
|
||||||
|
using pfaedle::osm::OsmRel;
|
||||||
|
using pfaedle::osm::OsmWay;
|
||||||
|
using pfaedle::trgraph::Component;
|
||||||
|
using pfaedle::trgraph::Edge;
|
||||||
|
using pfaedle::trgraph::EdgePL;
|
||||||
using pfaedle::trgraph::Graph;
|
using pfaedle::trgraph::Graph;
|
||||||
using pfaedle::trgraph::Node;
|
using pfaedle::trgraph::Node;
|
||||||
using pfaedle::trgraph::NodePL;
|
using pfaedle::trgraph::NodePL;
|
||||||
using pfaedle::trgraph::Edge;
|
using pfaedle::trgraph::Normalizer;
|
||||||
using pfaedle::trgraph::EdgePL;
|
|
||||||
using pfaedle::trgraph::TransitEdgeLine;
|
|
||||||
using pfaedle::trgraph::StatInfo;
|
|
||||||
using pfaedle::trgraph::StatGroup;
|
using pfaedle::trgraph::StatGroup;
|
||||||
using pfaedle::trgraph::Component;
|
using pfaedle::trgraph::StatInfo;
|
||||||
using pfaedle::osm::OsmBuilder;
|
using pfaedle::trgraph::TransitEdgeLine;
|
||||||
using pfaedle::osm::OsmWay;
|
using util::Nullable;
|
||||||
using pfaedle::osm::OsmRel;
|
using util::geo::Box;
|
||||||
using pfaedle::osm::OsmNode;
|
using util::geo::webMercMeterDist;
|
||||||
using pfaedle::osm::EdgeGrid;
|
|
||||||
using pfaedle::osm::NodeGrid;
|
|
||||||
using pfaedle::osm::EqSearch;
|
|
||||||
using pfaedle::osm::BlockSearch;
|
|
||||||
using ad::cppgtfs::gtfs::Stop;
|
|
||||||
|
|
||||||
// _____________________________________________________________________________
|
// _____________________________________________________________________________
|
||||||
bool EqSearch::operator()(const Node* cand, const StatInfo* si) const {
|
bool EqSearch::operator()(const Node* cand, const StatInfo* si) const {
|
||||||
|
@ -425,8 +425,8 @@ void OsmBuilder::readWriteWays(pfxml::file* i, util::xml::XmlWriter* o,
|
||||||
NodePL OsmBuilder::plFromGtfs(const Stop* s, const OsmReadOpts& ops) {
|
NodePL OsmBuilder::plFromGtfs(const Stop* s, const OsmReadOpts& ops) {
|
||||||
NodePL ret(
|
NodePL ret(
|
||||||
util::geo::latLngToWebMerc<PFAEDLE_PRECISION>(s->getLat(), s->getLng()),
|
util::geo::latLngToWebMerc<PFAEDLE_PRECISION>(s->getLat(), s->getLng()),
|
||||||
StatInfo(ops.statNormzer(s->getName()),
|
StatInfo(ops.statNormzer.norm(s->getName()),
|
||||||
ops.trackNormzer(s->getPlatformCode()), false));
|
ops.trackNormzer.norm(s->getPlatformCode()), false));
|
||||||
|
|
||||||
#ifdef PFAEDLE_STATION_IDS
|
#ifdef PFAEDLE_STATION_IDS
|
||||||
// debug feature, store station id from GTFS
|
// debug feature, store station id from GTFS
|
||||||
|
@ -434,7 +434,8 @@ NodePL OsmBuilder::plFromGtfs(const Stop* s, const OsmReadOpts& ops) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (s->getParentStation()) {
|
if (s->getParentStation()) {
|
||||||
ret.getSI()->addAltName(ops.statNormzer(s->getParentStation()->getName()));
|
ret.getSI()->addAltName(
|
||||||
|
ops.statNormzer.norm(s->getParentStation()->getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -739,7 +740,8 @@ void OsmBuilder::readWriteNds(pfxml::file* i, util::xml::XmlWriter* o,
|
||||||
{"lat", std::to_string(nd.lat)},
|
{"lat", std::to_string(nd.lat)},
|
||||||
{"lon", std::to_string(nd.lng)}});
|
{"lon", std::to_string(nd.lng)}});
|
||||||
for (const auto& kv : nd.attrs) {
|
for (const auto& kv : nd.attrs) {
|
||||||
o->openTag("tag", {{"k", kv.first}, {"v", pfxml::file::decode(kv.second)}});
|
o->openTag("tag",
|
||||||
|
{{"k", kv.first}, {"v", pfxml::file::decode(kv.second)}});
|
||||||
o->closeTag();
|
o->closeTag();
|
||||||
}
|
}
|
||||||
o->closeTag();
|
o->closeTag();
|
||||||
|
@ -937,10 +939,11 @@ std::string OsmBuilder::getAttrByFirstMatch(const DeepAttrLst& rule, osmid id,
|
||||||
const AttrMap& attrs,
|
const AttrMap& attrs,
|
||||||
const RelMap& entRels,
|
const RelMap& entRels,
|
||||||
const RelLst& rels,
|
const RelLst& rels,
|
||||||
const Normalizer& norm) const {
|
const Normalizer& normzer) const {
|
||||||
std::string ret;
|
std::string ret;
|
||||||
for (const auto& s : rule) {
|
for (const auto& s : rule) {
|
||||||
ret = norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels)));
|
ret =
|
||||||
|
normzer.norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels)));
|
||||||
if (!ret.empty()) return ret;
|
if (!ret.empty()) return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -950,11 +953,12 @@ std::string OsmBuilder::getAttrByFirstMatch(const DeepAttrLst& rule, osmid id,
|
||||||
// _____________________________________________________________________________
|
// _____________________________________________________________________________
|
||||||
std::vector<std::string> OsmBuilder::getAttrMatchRanked(
|
std::vector<std::string> OsmBuilder::getAttrMatchRanked(
|
||||||
const DeepAttrLst& rule, osmid id, const AttrMap& attrs,
|
const DeepAttrLst& rule, osmid id, const AttrMap& attrs,
|
||||||
const RelMap& entRels, const RelLst& rels, const Normalizer& norm) const {
|
const RelMap& entRels, const RelLst& rels,
|
||||||
|
const Normalizer& normzer) const {
|
||||||
std::vector<std::string> ret;
|
std::vector<std::string> ret;
|
||||||
for (const auto& s : rule) {
|
for (const auto& s : rule) {
|
||||||
std::string tmp =
|
std::string tmp =
|
||||||
norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels)));
|
normzer.norm(pfxml::file::decode(getAttr(s, id, attrs, entRels, rels)));
|
||||||
if (!tmp.empty()) ret.push_back(tmp);
|
if (!tmp.empty()) ret.push_back(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1183,8 +1187,7 @@ Node* OsmBuilder::depthSearch(const Edge* e, const StatInfo* si, const POINT& p,
|
||||||
|
|
||||||
int fullTurn = 0;
|
int fullTurn = 0;
|
||||||
|
|
||||||
if (cur.fromEdge &&
|
if (cur.fromEdge && cur.node->getInDeg() + cur.node->getOutDeg() >
|
||||||
cur.node->getInDeg() + cur.node->getOutDeg() >
|
|
||||||
2) { // only intersection angles
|
2) { // only intersection angles
|
||||||
const POINT& toP = *cand->pl().getGeom();
|
const POINT& toP = *cand->pl().getGeom();
|
||||||
const POINT& fromP =
|
const POINT& fromP =
|
||||||
|
@ -1425,7 +1428,8 @@ std::vector<TransitEdgeLine*> OsmBuilder::getLines(
|
||||||
for (const auto& r : ops.relLinerules.sNameRule) {
|
for (const auto& r : ops.relLinerules.sNameRule) {
|
||||||
for (const auto& relAttr : rels.rels[relId]) {
|
for (const auto& relAttr : rels.rels[relId]) {
|
||||||
if (relAttr.first == r) {
|
if (relAttr.first == r) {
|
||||||
el.shortName = ops.lineNormzer(pfxml::file::decode(relAttr.second));
|
el.shortName =
|
||||||
|
ops.lineNormzer.norm(pfxml::file::decode(relAttr.second));
|
||||||
if (!el.shortName.empty()) found = true;
|
if (!el.shortName.empty()) found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1436,7 +1440,8 @@ std::vector<TransitEdgeLine*> OsmBuilder::getLines(
|
||||||
for (const auto& r : ops.relLinerules.fromNameRule) {
|
for (const auto& r : ops.relLinerules.fromNameRule) {
|
||||||
for (const auto& relAttr : rels.rels[relId]) {
|
for (const auto& relAttr : rels.rels[relId]) {
|
||||||
if (relAttr.first == r) {
|
if (relAttr.first == r) {
|
||||||
el.fromStr = ops.statNormzer(pfxml::file::decode(relAttr.second));
|
el.fromStr =
|
||||||
|
ops.statNormzer.norm(pfxml::file::decode(relAttr.second));
|
||||||
if (!el.fromStr.empty()) found = true;
|
if (!el.fromStr.empty()) found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1447,7 +1452,8 @@ std::vector<TransitEdgeLine*> OsmBuilder::getLines(
|
||||||
for (const auto& r : ops.relLinerules.toNameRule) {
|
for (const auto& r : ops.relLinerules.toNameRule) {
|
||||||
for (const auto& relAttr : rels.rels[relId]) {
|
for (const auto& relAttr : rels.rels[relId]) {
|
||||||
if (relAttr.first == r) {
|
if (relAttr.first == r) {
|
||||||
el.toStr = ops.statNormzer(pfxml::file::decode(relAttr.second));
|
el.toStr =
|
||||||
|
ops.statNormzer.norm(pfxml::file::decode(relAttr.second));
|
||||||
if (!el.toStr.empty()) found = true;
|
if (!el.toStr.empty()) found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1895,7 +1901,8 @@ void OsmBuilder::snapStats(const OsmReadOpts& opts, Graph* g,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notSnapped.size())
|
if (notSnapped.size())
|
||||||
LOG(VDEBUG) << notSnapped.size() << " stations could not be snapped in "
|
LOG(VDEBUG) << notSnapped.size()
|
||||||
|
<< " stations could not be snapped in "
|
||||||
"normal run, trying again in orphan "
|
"normal run, trying again in orphan "
|
||||||
"mode.";
|
"mode.";
|
||||||
|
|
||||||
|
|
|
@ -29,28 +29,28 @@
|
||||||
#include "util/graph/EDijkstra.h"
|
#include "util/graph/EDijkstra.h"
|
||||||
#include "util/log/Log.h"
|
#include "util/log/Log.h"
|
||||||
|
|
||||||
using util::geo::extendBox;
|
|
||||||
using util::geo::DBox;
|
using util::geo::DBox;
|
||||||
using util::geo::DPoint;
|
using util::geo::DPoint;
|
||||||
|
using util::geo::extendBox;
|
||||||
using util::geo::minbox;
|
using util::geo::minbox;
|
||||||
|
|
||||||
using util::geo::webMercMeterDist;
|
using ad::cppgtfs::gtfs::ShapePoint;
|
||||||
using util::geo::webMercToLatLng;
|
using ad::cppgtfs::gtfs::Stop;
|
||||||
using util::geo::latLngToWebMerc;
|
using pfaedle::gtfs::Feed;
|
||||||
using util::geo::output::GeoGraphJsonOutput;
|
using pfaedle::gtfs::StopTime;
|
||||||
using pfaedle::router::ShapeBuilder;
|
using pfaedle::gtfs::Trip;
|
||||||
|
using pfaedle::osm::BBoxIdx;
|
||||||
|
using pfaedle::router::Clusters;
|
||||||
|
using pfaedle::router::EdgeListHops;
|
||||||
using pfaedle::router::FeedStops;
|
using pfaedle::router::FeedStops;
|
||||||
using pfaedle::router::NodeCandGroup;
|
using pfaedle::router::NodeCandGroup;
|
||||||
using pfaedle::router::NodeCandRoute;
|
using pfaedle::router::NodeCandRoute;
|
||||||
using pfaedle::router::RoutingAttrs;
|
using pfaedle::router::RoutingAttrs;
|
||||||
using pfaedle::router::EdgeListHops;
|
using pfaedle::router::ShapeBuilder;
|
||||||
using pfaedle::router::Clusters;
|
using util::geo::latLngToWebMerc;
|
||||||
using pfaedle::osm::BBoxIdx;
|
using util::geo::webMercMeterDist;
|
||||||
using ad::cppgtfs::gtfs::Stop;
|
using util::geo::webMercToLatLng;
|
||||||
using pfaedle::gtfs::Trip;
|
using util::geo::output::GeoGraphJsonOutput;
|
||||||
using pfaedle::gtfs::Feed;
|
|
||||||
using pfaedle::gtfs::StopTime;
|
|
||||||
using ad::cppgtfs::gtfs::ShapePoint;
|
|
||||||
|
|
||||||
// _____________________________________________________________________________
|
// _____________________________________________________________________________
|
||||||
ShapeBuilder::ShapeBuilder(Feed* feed, ad::cppgtfs::gtfs::Feed* evalFeed,
|
ShapeBuilder::ShapeBuilder(Feed* feed, ad::cppgtfs::gtfs::Feed* evalFeed,
|
||||||
|
@ -404,16 +404,17 @@ const RoutingAttrs& ShapeBuilder::getRAttrs(const Trip* trip) {
|
||||||
|
|
||||||
const auto& lnormzer = _motCfg.osmBuildOpts.lineNormzer;
|
const auto& lnormzer = _motCfg.osmBuildOpts.lineNormzer;
|
||||||
|
|
||||||
ret.shortName = lnormzer(trip->getRoute()->getShortName());
|
ret.shortName = lnormzer.norm(trip->getRoute()->getShortName());
|
||||||
|
|
||||||
if (ret.shortName.empty()) ret.shortName = lnormzer(trip->getShortname());
|
|
||||||
|
|
||||||
if (ret.shortName.empty())
|
if (ret.shortName.empty())
|
||||||
ret.shortName = lnormzer(trip->getRoute()->getLongName());
|
ret.shortName = lnormzer.norm(trip->getShortname());
|
||||||
|
|
||||||
ret.fromString = _motCfg.osmBuildOpts.statNormzer(
|
if (ret.shortName.empty())
|
||||||
|
ret.shortName = lnormzer.norm(trip->getRoute()->getLongName());
|
||||||
|
|
||||||
|
ret.fromString = _motCfg.osmBuildOpts.statNormzer.norm(
|
||||||
trip->getStopTimes().begin()->getStop()->getName());
|
trip->getStopTimes().begin()->getStop()->getName());
|
||||||
ret.toString = _motCfg.osmBuildOpts.statNormzer(
|
ret.toString = _motCfg.osmBuildOpts.statNormzer.norm(
|
||||||
(--trip->getStopTimes().end())->getStop()->getName());
|
(--trip->getStopTimes().end())->getStop()->getName());
|
||||||
|
|
||||||
return _rAttrs
|
return _rAttrs
|
||||||
|
@ -532,12 +533,12 @@ Clusters ShapeBuilder::clusterTrips(Feed* f, MOTs mots) {
|
||||||
bool ShapeBuilder::routingEqual(const Stop* a, const Stop* b) {
|
bool ShapeBuilder::routingEqual(const Stop* a, const Stop* b) {
|
||||||
if (a == b) return true; // trivial
|
if (a == b) return true; // trivial
|
||||||
|
|
||||||
auto namea = _motCfg.osmBuildOpts.statNormzer(a->getName());
|
auto namea = _motCfg.osmBuildOpts.statNormzer.norm(a->getName());
|
||||||
auto nameb = _motCfg.osmBuildOpts.statNormzer(b->getName());
|
auto nameb = _motCfg.osmBuildOpts.statNormzer.norm(b->getName());
|
||||||
if (namea != nameb) return false;
|
if (namea != nameb) return false;
|
||||||
|
|
||||||
auto tracka = _motCfg.osmBuildOpts.trackNormzer(a->getPlatformCode());
|
auto tracka = _motCfg.osmBuildOpts.trackNormzer.norm(a->getPlatformCode());
|
||||||
auto trackb = _motCfg.osmBuildOpts.trackNormzer(b->getPlatformCode());
|
auto trackb = _motCfg.osmBuildOpts.trackNormzer.norm(b->getPlatformCode());
|
||||||
if (tracka != trackb) return false;
|
if (tracka != trackb) return false;
|
||||||
|
|
||||||
POINT ap =
|
POINT ap =
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <mutex>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
@ -15,12 +17,39 @@
|
||||||
using pfaedle::trgraph::Normalizer;
|
using pfaedle::trgraph::Normalizer;
|
||||||
|
|
||||||
// _____________________________________________________________________________
|
// _____________________________________________________________________________
|
||||||
Normalizer::Normalizer(const ReplRules& rules) : _rulesOrig(rules) {
|
Normalizer::Normalizer(const ReplRules& rules)
|
||||||
|
: _rulesOrig(rules) {
|
||||||
buildRules(rules);
|
buildRules(rules);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// _____________________________________________________________________________
|
||||||
|
Normalizer::Normalizer(const Normalizer& other)
|
||||||
|
: _rules(other._rules),
|
||||||
|
_rulesOrig(other._rulesOrig),
|
||||||
|
_cache(other._cache) {}
|
||||||
|
|
||||||
|
// _____________________________________________________________________________
|
||||||
|
Normalizer& Normalizer::operator=(Normalizer other) {
|
||||||
|
std::swap(this->_rules, other._rules);
|
||||||
|
std::swap(this->_rulesOrig, other._rulesOrig);
|
||||||
|
std::swap(this->_cache, other._cache);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
// _____________________________________________________________________________
|
// _____________________________________________________________________________
|
||||||
std::string Normalizer::operator()(std::string sn) const {
|
std::string Normalizer::operator()(std::string sn) const {
|
||||||
|
return normTS(sn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// _____________________________________________________________________________
|
||||||
|
std::string Normalizer::normTS(const std::string& sn) const {
|
||||||
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
|
return norm(sn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// _____________________________________________________________________________
|
||||||
|
std::string Normalizer::norm(const std::string& sn) const {
|
||||||
auto i = _cache.find(sn);
|
auto i = _cache.find(sn);
|
||||||
if (i != _cache.end()) return i->second;
|
if (i != _cache.end()) return i->second;
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
namespace pfaedle {
|
namespace pfaedle {
|
||||||
namespace trgraph {
|
namespace trgraph {
|
||||||
|
@ -28,7 +29,19 @@ class Normalizer {
|
||||||
Normalizer() {}
|
Normalizer() {}
|
||||||
explicit Normalizer(const ReplRules& rules);
|
explicit Normalizer(const ReplRules& rules);
|
||||||
|
|
||||||
// Normalize sn based on the rules of this normalizer
|
// copy constructor
|
||||||
|
Normalizer(const Normalizer& other);
|
||||||
|
|
||||||
|
// assignment op
|
||||||
|
Normalizer& operator=(Normalizer other);
|
||||||
|
|
||||||
|
// Normalize sn, not thread safe
|
||||||
|
std::string norm(const std::string& sn) const;
|
||||||
|
// Normalize sn, thread safe
|
||||||
|
std::string normTS(const std::string& sn) const;
|
||||||
|
|
||||||
|
// Normalize sn based on the rules of this normalizer, uses the thread safe
|
||||||
|
// version of norm() internally
|
||||||
std::string operator()(std::string sn) const;
|
std::string operator()(std::string sn) const;
|
||||||
bool operator==(const Normalizer& b) const;
|
bool operator==(const Normalizer& b) const;
|
||||||
|
|
||||||
|
@ -36,6 +49,7 @@ class Normalizer {
|
||||||
ReplRulesComp _rules;
|
ReplRulesComp _rules;
|
||||||
ReplRules _rulesOrig;
|
ReplRules _rulesOrig;
|
||||||
mutable std::unordered_map<std::string, std::string> _cache;
|
mutable std::unordered_map<std::string, std::string> _cache;
|
||||||
|
mutable std::mutex _mutex;
|
||||||
|
|
||||||
void buildRules(const ReplRules& rules);
|
void buildRules(const ReplRules& rules);
|
||||||
};
|
};
|
||||||
|
|
|
@ -68,7 +68,7 @@ double StatGroup::getPen(const Stop* s, trgraph::Node* n,
|
||||||
double distPen = util::geo::webMercMeterDist(p, *n->pl().getGeom());
|
double distPen = util::geo::webMercMeterDist(p, *n->pl().getGeom());
|
||||||
distPen *= distPenFac;
|
distPen *= distPenFac;
|
||||||
|
|
||||||
std::string platform = platformNorm(s->getPlatformCode());
|
std::string platform = platformNorm.norm(s->getPlatformCode());
|
||||||
|
|
||||||
if (!platform.empty() && !n->pl().getSI()->getTrack().empty() &&
|
if (!platform.empty() && !n->pl().getSI()->getTrack().empty() &&
|
||||||
n->pl().getSI()->getTrack() == platform) {
|
n->pl().getSI()->getTrack() == platform) {
|
||||||
|
|
Loading…
Reference in a new issue