From 29e987f3fc13dc1e2a90f07556bf033b81a13e36 Mon Sep 17 00:00:00 2001 From: fonsinchen Date: Tue, 22 Oct 2013 16:13:28 +0000 Subject: [PATCH] (svn r25898) -Codechange: Add second timestamp for 'restricted links' to all edges. --- src/linkgraph/linkgraph.cpp | 58 ++++++++++++++++++++++++++--------- src/linkgraph/linkgraph.h | 45 ++++++++++++++++++++++----- src/saveload/linkgraph_sl.cpp | 13 ++++---- src/station_cmd.cpp | 11 +++++-- src/vehicle.cpp | 8 ++++- 5 files changed, 104 insertions(+), 31 deletions(-) diff --git a/src/linkgraph/linkgraph.cpp b/src/linkgraph/linkgraph.cpp index 87a95ad182..6bd29c92d8 100644 --- a/src/linkgraph/linkgraph.cpp +++ b/src/linkgraph/linkgraph.cpp @@ -39,7 +39,8 @@ inline void LinkGraph::BaseEdge::Init(uint distance) this->distance = distance; this->capacity = 0; this->usage = 0; - this->last_update = INVALID_DATE; + this->last_unrestricted_update = INVALID_DATE; + this->last_restricted_update = INVALID_DATE; this->next_edge = INVALID_NODE; } @@ -56,7 +57,8 @@ void LinkGraph::ShiftDates(int interval) if (source.last_update != INVALID_DATE) source.last_update += interval; for (NodeID node2 = 0; node2 < this->Size(); ++node2) { BaseEdge &edge = this->edges[node1][node2]; - if (edge.last_update != INVALID_DATE) edge.last_update += interval; + if (edge.last_unrestricted_update != INVALID_DATE) edge.last_unrestricted_update += interval; + if (edge.last_restricted_update != INVALID_DATE) edge.last_restricted_update += interval; } } } @@ -178,9 +180,11 @@ NodeID LinkGraph::AddNode(const Station *st) } /** - * Fill an edge with values from a link. + * Fill an edge with values from a link. If usage < capacity set the usage, + * otherwise set the restricted or unrestricted update timestamp. * @param to Destination node of the link. * @param capacity Capacity of the link. + * @param usage Usage to be added or REFRESH_UNRESTRICTED or REFRESH_RESTRICTED. */ void LinkGraph::Node::AddEdge(NodeID to, uint capacity, uint usage) { @@ -188,17 +192,32 @@ void LinkGraph::Node::AddEdge(NodeID to, uint capacity, uint usage) BaseEdge &edge = this->edges[to]; BaseEdge &first = this->edges[this->index]; edge.capacity = capacity; - edge.usage = usage == UINT_MAX ? 0 : usage; edge.next_edge = first.next_edge; first.next_edge = to; - edge.last_update = _date; + switch (usage) { + case REFRESH_UNRESTRICTED: + edge.last_unrestricted_update = _date; + break; + case REFRESH_RESTRICTED: + edge.last_restricted_update = _date; + break; + default: + edge.usage = usage; + break; + } } +/** + * Creates an edge if none exists yet or updates an existing edge. + * @param to Target node. + * @param capacity Capacity of the link. + * @param usage Usage to be added or REFRESH_UNRESTRICTED or REFRESH_RESTRICTED. + */ void LinkGraph::Node::UpdateEdge(NodeID to, uint capacity, uint usage) { assert(capacity > 0); - assert(usage <= capacity || usage == UINT_MAX); - if (this->edges[to].last_update == INVALID_DATE) { + assert(usage <= capacity || usage == REFRESH_RESTRICTED || usage == REFRESH_UNRESTRICTED); + if (this->edges[to].capacity == 0) { this->AddEdge(to, capacity, usage); } else { (*this)[to].Update(capacity, usage); @@ -214,7 +233,8 @@ void LinkGraph::Node::RemoveEdge(NodeID to) if (this->index == to) return; BaseEdge &edge = this->edges[to]; edge.capacity = 0; - edge.last_update = INVALID_DATE; + edge.last_unrestricted_update = INVALID_DATE; + edge.last_restricted_update = INVALID_DATE; edge.usage = 0; NodeID prev = this->index; @@ -233,24 +253,34 @@ void LinkGraph::Node::RemoveEdge(NodeID to) } /** - * Create a new edge or update an existing one. If usage is UINT_MAX refresh - * the edge to have at least the given capacity, otherwise add the capacity. + * Create a new edge or update an existing one. If usage is REFRESH_UNRESTRICTED + * or REFRESH_RESTRICTED refresh the edge to have at least the given capacity + * and also update the respective update timestamp, otherwise add the capacity. * @param from Start node of the edge. * @param to End node of the edge. * @param capacity Capacity to be added/updated. - * @param usage Usage to be added or UINT_MAX. + * @param usage Usage to be added or REFRESH_UNRESTRICTED or REFRESH_RESTRICTED. */ void LinkGraph::Edge::Update(uint capacity, uint usage) { assert(this->edge.capacity > 0); - if (usage == UINT_MAX) { + if (usage > capacity) { this->edge.capacity = max(this->edge.capacity, capacity); + switch (usage) { + case REFRESH_UNRESTRICTED: + this->edge.last_unrestricted_update = _date; + break; + case REFRESH_RESTRICTED: + this->edge.last_restricted_update = _date; + break; + default: + NOT_REACHED(); + break; + } } else { - assert(capacity >= usage); this->edge.capacity += capacity; this->edge.usage += usage; } - this->edge.last_update = _date; } /** diff --git a/src/linkgraph/linkgraph.h b/src/linkgraph/linkgraph.h index 07a6bed95b..cad557e19a 100644 --- a/src/linkgraph/linkgraph.h +++ b/src/linkgraph/linkgraph.h @@ -40,6 +40,22 @@ extern LinkGraphPool _link_graph_pool; class LinkGraph : public LinkGraphPool::PoolItem<&_link_graph_pool> { public: + /** + * Special modes for updating links. 'Restricted' means that vehicles with + * 'no loading' orders are serving the link. If a link is only served by + * such vehicles it's 'fully restricted'. This means the link can be used + * by cargo arriving in such vehicles, but not by cargo generated or + * transferring at the source station of the link. In order to find out + * about this condition we keep two update timestamps in each link, one for + * the restricted and one for the unrestricted part of it. If either one + * times out while the other is still valid the link becomes fully + * restricted or fully unrestricted, respectively. + */ + enum UpdateMode { + REFRESH_RESTRICTED = UINT_MAX - 1, ///< Refresh restricted link. + REFRESH_UNRESTRICTED = UINT_MAX ///< Refresh unrestricted link. + }; + /** * Node of the link graph. contains all relevant information from the associated * station. It's copied so that the link graph job can work on its own data set @@ -60,11 +76,12 @@ public: * the column as next_edge. */ struct BaseEdge { - uint distance; ///< Length of the link. - uint capacity; ///< Capacity of the link. - uint usage; ///< Usage of the link. - Date last_update; ///< When the link was last updated. - NodeID next_edge; ///< Destination of next valid edge starting at the same source node. + uint distance; ///< Length of the link. + uint capacity; ///< Capacity of the link. + uint usage; ///< Usage of the link. + Date last_unrestricted_update; ///< When the unrestricted part of the link was last updated. + Date last_restricted_update; ///< When the restricted part of the link was last updated. + NodeID next_edge; ///< Destination of next valid edge starting at the same source node. void Init(uint distance = 0); }; @@ -104,10 +121,22 @@ public: uint Distance() const { return this->edge.distance; } /** - * Get edge's last update. + * Get the date of the last update to the edge's unrestricted capacity. * @return Last update. */ - Date LastUpdate() const { return this->edge.last_update; } + Date LastUnrestrictedUpdate() const { return this->edge.last_unrestricted_update; } + + /** + * Get the date of the last update to the edge's restricted capacity. + * @return Last update. + */ + Date LastRestrictedUpdate() const { return this->edge.last_restricted_update; } + + /** + * Get the date of the last update to any part of the edge's capacity. + * @return Last update. + */ + Date LastUpdate() const { return max(this->edge.last_unrestricted_update, this->edge.last_restricted_update); } }; /** @@ -285,6 +314,8 @@ public: */ Edge(BaseEdge &edge) : EdgeWrapper(edge) {} void Update(uint capacity, uint usage); + void Restrict() { this->edge.last_unrestricted_update = INVALID_DATE; } + void Release() { this->edge.last_restricted_update = INVALID_DATE; } }; /** diff --git a/src/saveload/linkgraph_sl.cpp b/src/saveload/linkgraph_sl.cpp index f7d2893cee..f0dcb1dd45 100644 --- a/src/saveload/linkgraph_sl.cpp +++ b/src/saveload/linkgraph_sl.cpp @@ -118,12 +118,13 @@ static const SaveLoad _node_desc[] = { * SaveLoad desc for a link graph edge. */ static const SaveLoad _edge_desc[] = { - SLE_VAR(Edge, distance, SLE_UINT32), - SLE_VAR(Edge, capacity, SLE_UINT32), - SLE_VAR(Edge, usage, SLE_UINT32), - SLE_VAR(Edge, last_update, SLE_INT32), - SLE_VAR(Edge, next_edge, SLE_UINT16), - SLE_END() + SLE_VAR(Edge, distance, SLE_UINT32), + SLE_VAR(Edge, capacity, SLE_UINT32), + SLE_VAR(Edge, usage, SLE_UINT32), + SLE_VAR(Edge, last_unrestricted_update, SLE_INT32), + SLE_CONDVAR(Edge, last_restricted_update, SLE_INT32, 187, SL_MAX_VERSION), + SLE_VAR(Edge, next_edge, SLE_UINT16), + SLE_END() }; /** diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index acc0366362..f8bf61968f 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -3417,13 +3417,18 @@ void DeleteStaleLinks(Station *from) Edge edge = it->second; Station *to = Station::Get((*lg)[it->first].Station()); assert(to->goods[c].node == it->first); - ++it; // Do that before removing the node. Anything else may crash. + ++it; // Do that before removing the edge. Anything else may crash. assert(_date >= edge.LastUpdate()); - if ((uint)(_date - edge.LastUpdate()) > LinkGraph::MIN_TIMEOUT_DISTANCE + - (DistanceManhattan(from->xy, to->xy) >> 2)) { + uint timeout = LinkGraph::MIN_TIMEOUT_DISTANCE + (DistanceManhattan(from->xy, to->xy) >> 2); + if ((uint)(_date - edge.LastUpdate()) > timeout) { node.RemoveEdge(to->goods[c].node); ge.flows.DeleteFlows(to->index); RerouteCargo(from, c, to->index, from->index); + } else if (edge.LastUnrestrictedUpdate() != INVALID_DATE && (uint)(_date - edge.LastUnrestrictedUpdate()) > timeout) { + edge.Restrict(); + RerouteCargo(from, c, to->index, from->index); + } else if (edge.LastRestrictedUpdate() != INVALID_DATE && (uint)(_date - edge.LastRestrictedUpdate()) > timeout) { + edge.Release(); } } assert(_date >= lg->LastCompression()); diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 3d9da8447a..0abe6689d4 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -50,6 +50,7 @@ #include "tunnel_map.h" #include "depot_map.h" #include "gamelog.h" +#include "linkgraph/linkgraph.h" #include "table/strings.h" @@ -2267,7 +2268,12 @@ uint Vehicle::RefreshNextHopsStats(CapacitiesMap &capacities, if (st != NULL && next_station != INVALID_STATION && next_station != st->index) { for (CapacitiesMap::const_iterator i = capacities.begin(); i != capacities.end(); ++i) { /* Refresh the link and give it a minimum capacity. */ - if (i->second > 0) IncreaseStats(st, i->first, next_station, i->second, UINT_MAX); + if (i->second > 0) { + /* A link is at least partly restricted if a + * vehicle can't load at its source. */ + IncreaseStats(st, i->first, next_station, i->second, + (cur->GetLoadType() & OLFB_NO_LOAD) == 0 ? LinkGraph::REFRESH_UNRESTRICTED : LinkGraph::REFRESH_RESTRICTED); + } } } }