Repository: graphhopper/graphhopper
Pull request #2042 (2020-05-17 10:21:47)

Remove min_one_way_network parameter, clean up subnetwork removal
So far we were doing the subnetwork removal 'twice': First we were searching for strongly connected components (but excluding single-node networks) and then we were doing a BFS (breadth-first search) that finds connected components on an undirected graph and also included single node networks. The reason we did not include single-node networks in the first step was performance, but this has been fixed in: e6783acb1760c5ffff07c569244fefc97946f5e1 and is now no longer a problem. The BFS search is not the right thing to do on a directed graph and for example can depend on the order in which we traverse the nodes (see #761). 

So here I have removed the BFS search and the single-node components are now found with Tarjan's algorithm already. This way we also no longer need two different parameters to control the subnetwork search and I have removed `min_one_way_subnetwork_size`.

The subnetwork removal step is now faster and the (by far) most expensive part of it is not finding the subnetworks and setting the appropriate access flags, but the call to `graph.optimize()` afterwards.

With this we also might no longer need #1723 (I had to adjust some tests already)?

michaz: +1

Patch:
diff --git a/benchmark/benchmark.sh b/benchmark/benchmark.sh
index e6f149ff2..b1ef18d27 100755
--- a/benchmark/benchmark.sh
+++ b/benchmark/benchmark.sh
@@ -56,7 +56,6 @@ measurement.lm=false \
 "graph.flag_encoders=car|turn_costs=true" \
 graph.location=${TMP_DIR}measurement-small-gh \
 prepare.min_network_size=10000 \
-prepare.min_one_way_network_size=10000 \
 spatial_rules.borders_directory=${BORDERS_DIRECTORY} \
 measurement.json=true \
 measurement.count=5000 \
@@ -82,7 +81,6 @@ measurement.lm.edge_based=true \
 "graph.flag_encoders=car|turn_costs=true" \
 graph.location=${TMP_DIR}measurement-big-gh \
 prepare.min_network_size=10000 \
-prepare.min_one_way_network_size=10000 \
 spatial_rules.borders_directory=${BORDERS_DIRECTORY} \
 measurement.json=true \
 measurement.count=5000 \
@@ -111,7 +109,6 @@ measurement.lm.edge_based=false \
 "graph.flag_encoders=car|turn_costs=true" \
 graph.location=${TMP_DIR}measurement-big-little-custom-gh \
 prepare.min_network_size=10000 \
-prepare.min_one_way_network_size=10000 \
 spatial_rules.borders_directory=${BORDERS_DIRECTORY} \
 measurement.json=true \
 measurement.count=5000 \
@@ -140,7 +137,6 @@ measurement.lm.edge_based=false \
 "graph.flag_encoders=car|turn_costs=true" \
 graph.location=${TMP_DIR}measurement-big-very-custom-gh \
 prepare.min_network_size=10000 \
-prepare.min_one_way_network_size=10000 \
 spatial_rules.borders_directory=${BORDERS_DIRECTORY} \
 measurement.json=true \
 measurement.count=5000 \
diff --git a/config-example.yml b/config-example.yml
index 1885f88a6..26ab5fb8f 100644
--- a/config-example.yml
+++ b/config-example.yml
@@ -107,11 +107,11 @@ graphhopper:
   # the default worked for you.
   # prepare.lm.threads: 1
 
-
-  # avoid being stuck in a (oneway) subnetwork, see https://discuss.graphhopper.com/t/93
+  # In many cases the road network consists of independent components without any routes going in between. In
+  # the most simple case you can imagine an island without a bridge or ferry connection. The following parameter
+  # allows setting a minimum size (number of nodes) for such detached components. This can be used to reduce the number
+  # of cases where a connection between locations might not be found.
   prepare.min_network_size: 200
-  prepare.min_one_way_network_size: 200
-
 
 
   ##### Routing #####
diff --git a/core/files/changelog.txt b/core/files/changelog.txt
index 476b1b046..9449c1350 100644
--- a/core/files/changelog.txt
+++ b/core/files/changelog.txt
@@ -1,4 +1,5 @@
 1.0
+    removed min_one_way_network_size parameter, #2042
     moved package from core/src/test/java/com/graphhopper/routing/profiles to ev
     removed HintsMap
     removed /change endpoint
diff --git a/core/src/main/java/com/graphhopper/GraphHopper.java b/core/src/main/java/com/graphhopper/GraphHopper.java
index a627abb27..16917cc47 100644
--- a/core/src/main/java/com/graphhopper/GraphHopper.java
+++ b/core/src/main/java/com/graphhopper/GraphHopper.java
@@ -108,7 +108,6 @@ public class GraphHopper implements GraphHopperAPI {
     private int maxRegionSearch = 4;
     // for prepare
     private int minNetworkSize = 200;
-    private int minOneWayNetworkSize = 0;
 
     // preparation handlers
     private final LMPreparationHandler lmPreparationHandler = new LMPreparationHandler();
@@ -234,9 +233,9 @@ public class GraphHopper implements GraphHopperAPI {
         return this;
     }
 
-    public GraphHopper setMinNetworkSize(int minNetworkSize, int minOneWayNetworkSize) {
+    public GraphHopper setMinNetworkSize(int minNetworkSize) {
+        ensureNotLoaded();
         this.minNetworkSize = minNetworkSize;
-        this.minOneWayNetworkSize = minOneWayNetworkSize;
         return this;
     }
 
@@ -534,7 +533,6 @@ public class GraphHopper implements GraphHopperAPI {
 
         // optimizable prepare
         minNetworkSize = ghConfig.getInt("prepare.min_network_size", minNetworkSize);
-        minOneWayNetworkSize = ghConfig.getInt("prepare.min_one_way_network_size", minOneWayNetworkSize);
 
         // profiles
         setProfiles(ghConfig.getProfiles());
@@ -1339,7 +1337,6 @@ public class GraphHopper implements GraphHopperAPI {
         int prevNodeCount = ghStorage.getNodes();
         PrepareRoutingSubnetworks preparation = new PrepareRoutingSubnetworks(ghStorage, encodingManager.fetchEdgeEncoders());
         preparation.setMinNetworkSize(minNetworkSize);
-        preparation.setMinOneWayNetworkSize(minOneWayNetworkSize);
         preparation.doWork();
         int currNodeCount = ghStorage.getNodes();
         logger.info("edges: " + Helper.nf(ghStorage.getEdges()) + ", nodes " + Helper.nf(currNodeCount)
diff --git a/core/src/main/java/com/graphhopper/routing/lm/LandmarkStorage.java b/core/src/main/java/com/graphhopper/routing/lm/LandmarkStorage.java
index 9fdda7f8c..9452ba96a 100644
--- a/core/src/main/java/com/graphhopper/routing/lm/LandmarkStorage.java
+++ b/core/src/main/java/com/graphhopper/routing/lm/LandmarkStorage.java
@@ -20,6 +20,7 @@ package com.graphhopper.routing.lm;
 import com.carrotsearch.hppc.IntArrayList;
 import com.carrotsearch.hppc.IntHashSet;
 import com.carrotsearch.hppc.IntObjectMap;
+import com.carrotsearch.hppc.IntSet;
 import com.carrotsearch.hppc.predicates.IntObjectPredicate;
 import com.carrotsearch.hppc.procedures.IntObjectProcedure;
 import com.graphhopper.coll.MapEntry;
@@ -28,7 +29,10 @@ import com.graphhopper.routing.SPTEntry;
 import com.graphhopper.routing.ev.BooleanEncodedValue;
 import com.graphhopper.routing.subnetwork.SubnetworkStorage;
 import com.graphhopper.routing.subnetwork.TarjansSCCAlgorithm;
-import com.graphhopper.routing.util.*;
+import com.graphhopper.routing.util.AllEdgesIterator;
+import com.graphhopper.routing.util.EdgeFilter;
+import com.graphhopper.routing.util.FlagEncoder;
+import com.graphhopper.routing.util.TraversalMode;
 import com.graphhopper.routing.util.spatialrules.SpatialRule;
 import com.graphhopper.routing.util.spatialrules.SpatialRuleLookup;
 import com.graphhopper.routing.util.spatialrules.SpatialRuleSet;
@@ -233,14 +237,14 @@ public class LandmarkStorage implements Storable<LandmarkStorage> {
 
         byte[] subnetworks = new byte[graph.getNodes()];
         Arrays.fill(subnetworks, (byte) UNSET_SUBNETWORK);
-        EdgeFilter tarjanFilter = DefaultEdgeFilter.outEdges(encoder);
+        EdgeFilter tarjanFilter = EdgeFilter.ALL_EDGES;
         IntHashSet blockedEdges = new IntHashSet();
 
         // the ruleLookup splits certain areas from each other but avoids making this a permanent change so that other algorithms still can route through these regions.
         if (ruleLookup != null && !ruleLookup.getRules().isEmpty()) {
             StopWatch sw = new StopWatch().start();
             blockedEdges = findBorderEdgeIds(ruleLookup);
-            tarjanFilter = new BlockedEdgesFilter(encoder.getAccessEnc(), true, false, blockedEdges);
+            tarjanFilter = new SimpleBlockedEdgesFilter(blockedEdges);
             if (logDetails)
                 LOGGER.info("Made " + blockedEdges.size() + " edges inaccessible. Calculated country cut in " + sw.stop().getSeconds() + "s, " + Helper.getMemInfo());
         }
@@ -249,7 +253,8 @@ public class LandmarkStorage implements Storable<LandmarkStorage> {
 
         // we cannot reuse the components calculated in PrepareRoutingSubnetworks as the edgeIds changed in between (called graph.optimize)
         // also calculating subnetworks from scratch makes bigger problems when working with many oneways
-        TarjansSCCAlgorithm tarjanAlgo = new TarjansSCCAlgorithm(graph, tarjanFilter, true);
+        TarjansSCCAlgorithm tarjanAlgo = new TarjansSCCAlgorithm(graph, encoder.getAccessEnc(), true);
+        tarjanAlgo.setAdditionalEdgeFilter(tarjanFilter);
         List<IntArrayList> graphComponents = tarjanAlgo.findComponents();
         if (logDetails)
             LOGGER.info("Calculated " + graphComponents.size() + " subnetworks via tarjan in " + sw.stop().getSeconds() + "s, " + Helper.getMemInfo());
@@ -899,6 +904,19 @@ public class LandmarkStorage implements Storable<LandmarkStorage> {
         }
     }
 
+    private static class SimpleBlockedEdgesFilter implements EdgeFilter {
+        private final IntSet blockedEdges;
+
+        SimpleBlockedEdgesFilter(IntSet blockedEdges) {
+            this.blockedEdges = blockedEdges;
+        }
+
+        @Override
+        public boolean accept(EdgeIteratorState edgeState) {
+            return !blockedEdges.contains(edgeState.getEdge());
+        }
+    }
+
     private static class BlockedEdgesFilter implements EdgeFilter {
         private final IntHashSet blockedEdges;
         private final BooleanEncodedValue accessEnc;
diff --git a/core/src/main/java/com/graphhopper/routing/subnetwork/PrepareRoutingSubnetworks.java b/core/src/main/java/com/graphhopper/routing/subnetwork/PrepareRoutingSubnetworks.java
index fea9f5d74..66379a503 100644
--- a/core/src/main/java/com/graphhopper/routing/subnetwork/PrepareRoutingSubnetworks.java
+++ b/core/src/main/java/com/graphhopper/routing/subnetwork/PrepareRoutingSubnetworks.java
@@ -19,37 +19,35 @@ package com.graphhopper.routing.subnetwork;
 
 import com.carrotsearch.hppc.IntArrayList;
 import com.carrotsearch.hppc.IntIndexedContainer;
-import com.graphhopper.coll.GHBitSet;
-import com.graphhopper.coll.GHBitSetImpl;
 import com.graphhopper.routing.ev.BooleanEncodedValue;
 import com.graphhopper.routing.util.DefaultEdgeFilter;
-import com.graphhopper.routing.util.EdgeFilter;
 import com.graphhopper.routing.util.FlagEncoder;
 import com.graphhopper.storage.GraphHopperStorage;
-import com.graphhopper.util.*;
+import com.graphhopper.util.EdgeExplorer;
+import com.graphhopper.util.EdgeIterator;
+import com.graphhopper.util.Helper;
+import com.graphhopper.util.StopWatch;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
 
 /**
- * Removes nodes which are not part of the large networks. Ie. mostly nodes with no edges at all but
- * also small subnetworks which could be bugs in OSM data or indicate otherwise disconnected areas
+ * Removes nodes/edges which are not part of the 'main' network(s). I.e. mostly nodes with no edges at all but
+ * also small subnetworks which could be bugs in OSM data or 'islands' or indicate otherwise disconnected areas
  * e.g. via barriers or one way problems - see #86.
  * <p>
  *
  * @author Peter Karich
+ * @author easbar
  */
 public class PrepareRoutingSubnetworks {
     private final Logger logger = LoggerFactory.getLogger(getClass());
     private final GraphHopperStorage ghStorage;
-    private final AtomicInteger maxEdgesPerNode = new AtomicInteger(0);
     private final List<FlagEncoder> encoders;
     private final List<BooleanEncodedValue> accessEncList;
     private int minNetworkSize = 200;
-    private int minOneWayNetworkSize = 0;
     private int subnetworks = -1;
 
     public PrepareRoutingSubnetworks(GraphHopperStorage ghStorage, List<FlagEncoder> encoders) {
@@ -66,35 +64,28 @@ public class PrepareRoutingSubnetworks {
         return this;
     }
 
-    public PrepareRoutingSubnetworks setMinOneWayNetworkSize(int minOnewayNetworkSize) {
-        this.minOneWayNetworkSize = minOnewayNetworkSize;
-        return this;
-    }
-
     public void doWork() {
-        if (minNetworkSize <= 0 && minOneWayNetworkSize <= 0)
+        if (minNetworkSize <= 0) {
+            logger.info("Skipping subnetwork removal: prepare.min_network_size: " + minNetworkSize);
             return;
-
-        logger.info("start finding subnetworks (min:" + minNetworkSize + ", min one way:" + minOneWayNetworkSize + ") " + Helper.getMemInfo());
-        int unvisitedDeadEnds = 0;
+        }
+        StopWatch sw = new StopWatch().start();
+        logger.info("Start removing subnetworks (prepare.min_network_size:" + minNetworkSize + ") " + Helper.getMemInfo());
+        logger.info("Graph nodes: " + Helper.nf(ghStorage.getNodes()));
+        logger.info("Graph edges: " + Helper.nf(ghStorage.getEdges()));
         for (FlagEncoder encoder : encoders) {
-            // mark edges for one vehicle as inaccessible
-            DefaultEdgeFilter filter = DefaultEdgeFilter.allEdges(encoder);
-            if (minOneWayNetworkSize > 0)
-                unvisitedDeadEnds += removeDeadEndUnvisitedNetworks(filter);
-
-            List<IntArrayList> components = findSubnetworks(filter);
-            keepLargeNetworks(filter, components);
-            subnetworks = Math.max(components.size(), subnetworks);
-            logger.info(components.size() + " subnetworks found for " + encoder + ", " + Helper.getMemInfo());
+            logger.info("--- vehicle: '" + encoder.toString() + "'");
+            removeSmallSubNetworks(encoder.getAccessEnc());
         }
-
         markNodesRemovedIfUnreachable();
+        optimize();
+        logger.info("Finished finding and removing subnetworks for " + encoders.size() + " vehicles, took: " + sw.stop().getSeconds() + "s, " + Helper.getMemInfo());
+    }
 
-        logger.info("optimize to remove subnetworks (" + subnetworks + "), "
-                + "unvisited-dead-end-nodes (" + unvisitedDeadEnds + "), "
-                + "maxEdges/node (" + maxEdgesPerNode.get() + ")");
+    private void optimize() {
+        StopWatch sw = new StopWatch().start();
         ghStorage.optimize();
+        logger.info("Optimized storage after subnetwork removal, took: " + sw.stop().getSeconds() + "s," + Helper.getMemInfo());
     }
 
     public int getMaxSubnetworks() {
@@ -102,139 +93,91 @@ public class PrepareRoutingSubnetworks {
     }
 
     /**
-     * This method finds the double linked components according to the specified filter.
+     * Removes components with less than {@link #minNetworkSize} nodes from the graph by disabling access to the nodes
+     * of the removed components (for the given access encoded value). It is important to search for strongly connected
+     * components here (i.e. consider that the graph is directed). For example, small areas like parking lots are
+     * sometimes connected to the whole network through a single one-way road. This is clearly a (mapping) error - but
+     * it causes the routing to fail when starting from the parking lot (and there is no way out from it).
+     * The biggest component is always kept regardless of its size.
+     *
+     * @return number of removed edges
      */
-    List<IntArrayList> findSubnetworks(DefaultEdgeFilter filter) {
-        final BooleanEncodedValue accessEnc = filter.getAccessEnc();
-        final EdgeExplorer explorer = ghStorage.createEdgeExplorer(filter);
-        int locs = ghStorage.getNodes();
-        List<IntArrayList> list = new ArrayList<>(100);
-        final GHBitSet bs = new GHBitSetImpl(locs);
-        for (int start = 0; start < locs; start++) {
-            if (bs.contains(start))
-                continue;
-
-            final IntArrayList intList = new IntArrayList(20);
-            list.add(intList);
-            new BreadthFirstSearch() {
-                int tmpCounter = 0;
-
-                @Override
-                protected GHBitSet createBitSet() {
-                    return bs;
-                }
-
-                @Override
-                protected final boolean goFurther(int nodeId) {
-                    if (tmpCounter > maxEdgesPerNode.get())
-                        maxEdgesPerNode.set(tmpCounter);
-
-                    tmpCounter = 0;
-                    intList.add(nodeId);
-                    return true;
-                }
-
-                @Override
-                protected final boolean checkAdjacent(EdgeIteratorState edge) {
-                    if (edge.get(accessEnc) || edge.getReverse(accessEnc)) {
-                        tmpCounter++;
-                        return true;
-                    }
-                    return false;
-                }
-
-            }.start(explorer, start);
-            intList.trimToSize();
+    int removeSmallSubNetworks(BooleanEncodedValue accessEnc) {
+        // partition graph into strongly connected components using Tarjan's algorithm
+        StopWatch sw = new StopWatch().start();
+        TarjansSCCAlgorithm tarjan = new TarjansSCCAlgorithm(ghStorage, accessEnc, false);
+        List<IntArrayList> components = tarjan.findComponents();
+        int totalNodes = 0;
+        int singleNodeComponents = 0;
+        for (IntArrayList c : components) {
+            totalNodes += c.size();
+            if (c.size() == 1)
+                singleNodeComponents++;
         }
-        return list;
-    }
-
-    /**
-     * Deletes all but the largest subnetworks.
-     */
-    int keepLargeNetworks(DefaultEdgeFilter filter, List<IntArrayList> components) {
-        if (components.size() <= 1)
-            return 0;
-
-        int maxCount = -1;
-        IntIndexedContainer oldComponent = null;
-        int allRemoved = 0;
-        BooleanEncodedValue accessEnc = filter.getAccessEnc();
-        EdgeExplorer explorer = ghStorage.createEdgeExplorer(filter);
+        logger.info("num single: " + singleNodeComponents + " -> non-single: " + (components.size() - singleNodeComponents));
+        logger.info("total checksum: " + totalNodes);
+        logger.info("counting single-node components took: " + sw.stop().getSeconds() + "s");
+        logger.info("Found " + components.size() + " subnetworks (" + singleNodeComponents + " single nodes and "
+                + (components.size() - singleNodeComponents) + " components with more than one node, total nodes: " + totalNodes + "), took: " + sw.stop().getSeconds() + "s");
+
+        sw = new StopWatch().start();
+        // find the biggest component
+        IntArrayList biggest = components.isEmpty() ? new IntArrayList(0) : components.get(0);
         for (IntArrayList component : components) {
-            if (maxCount < 0) {
-                maxCount = component.size();
-                oldComponent = component;
-                continue;
+            if (component.size() > biggest.size()) {
+                biggest = component;
             }
+        }
+        logger.info("finding the biggest component took: " + sw.stop().getSeconds() + "s");
 
-            int removedEdges;
-            if (maxCount < component.size()) {
-                // new biggest area found. remove old
-                removedEdges = removeEdges(explorer, accessEnc, oldComponent, minNetworkSize);
+        // remove all small networks except the biggest (even when its smaller than the given min_network_size)
+        sw = new StopWatch().start();
+        int removedComponents = 0;
+        int removedEdges = 0;
+        int smallestRemaining = biggest.size();
+        int biggestRemoved = 0;
+        EdgeExplorer explorer = ghStorage.createEdgeExplorer(DefaultEdgeFilter.allEdges(accessEnc));
+        for (IntArrayList component : components) {
+            if (component == biggest)
+                continue;
 
-                maxCount = component.size();
-                oldComponent = component;
+            if (component.size() < minNetworkSize) {
+                removedEdges += blockEdgesForComponent(explorer, accessEnc, component);
+                removedComponents++;
+                biggestRemoved = Math.max(biggestRemoved, component.size());
             } else {
-                removedEdges = removeEdges(explorer, accessEnc, component, minNetworkSize);
+                smallestRemaining = Math.min(smallestRemaining, component.size());
             }
-
-            allRemoved += removedEdges;
         }
 
-        if (allRemoved > ghStorage.getAllEdges().length() / 2)
-            throw new IllegalStateException("Too many total edges were removed: " + allRemoved + ", all edges:" + ghStorage.getAllEdges().length());
-        return allRemoved;
-    }
-
-    /**
-     * This method removes networks that will be never be visited by this filter. See #235 for
-     * example, small areas like parking lots are sometimes connected to the whole network through a
-     * one-way road. This is clearly an error - but it causes the routing to fail when a point gets
-     * connected to this small area. This routine removes all these networks from the graph.
-     *
-     * @return number of removed edges
-     */
-    int removeDeadEndUnvisitedNetworks(final DefaultEdgeFilter bothFilter) {
-        StopWatch sw = new StopWatch(bothFilter.getAccessEnc() + " findComponents").start();
-        final EdgeFilter outFilter = DefaultEdgeFilter.outEdges(bothFilter.getAccessEnc());
-
-        // partition graph into strongly connected components using Tarjan's algorithm        
-        TarjansSCCAlgorithm tarjan = new TarjansSCCAlgorithm(ghStorage, outFilter, false);
-        List<IntArrayList> components = tarjan.findComponents();
-        logger.info(sw.stop() + ", size:" + components.size());
+        int allowedRemoved = ghStorage.getEdges() / 2;
+        if (removedEdges > allowedRemoved)
+            throw new IllegalStateException("Too many total edges were removed: " + removedEdges + " out of " + ghStorage.getEdges() + "\n" +
+                    "The maximum number of removed edges is: " + allowedRemoved);
 
-        return removeEdges(bothFilter, components, minOneWayNetworkSize);
+        subnetworks = components.size() - removedComponents;
+        logger.info("Removed " + removedComponents + " subnetworks (biggest removed: " + biggestRemoved + " nodes) -> " +
+                subnetworks + " subnetwork(s) left (smallest: " + smallestRemaining + ", biggest: " + biggest.size() + " nodes)"
+                + ", total removed edges: " + removedEdges + ", took: " + sw.stop().getSeconds() + "s");
+        return removedEdges;
     }
 
     /**
-     * This method removes the access to edges available from the nodes contained in the components.
-     * But only if a components' size is smaller then the specified min value.
-     *
-     * @return number of removed edges
+     * Makes all edges of the given component (the given set of node ids) inaccessible for the given access encoded value.
+     * So far we are not removing the edges entirely from the graph (we could probably do this for edges that are blocked
+     * for *all* vehicles similar to {@link #markNodesRemovedIfUnreachable})
      */
-    int removeEdges(final DefaultEdgeFilter bothFilter, List<IntArrayList> components, int min) {
-        // remove edges determined from nodes but only if less than minimum size
-        EdgeExplorer explorer = ghStorage.createEdgeExplorer(bothFilter);
-        int removedEdges = 0;
-        for (IntArrayList component : components) {
-            removedEdges += removeEdges(explorer, bothFilter.getAccessEnc(), component, min);
-        }
-        return removedEdges;
-    }
-
-    int removeEdges(EdgeExplorer explorer, BooleanEncodedValue accessEnc, IntIndexedContainer component, int min) {
+    int blockEdgesForComponent(EdgeExplorer explorer, BooleanEncodedValue accessEnc, IntIndexedContainer component) {
         int removedEdges = 0;
-        if (component.size() < min) {
-            for (int i = 0; i < component.size(); i++) {
-                EdgeIterator edge = explorer.setBaseNode(component.get(i));
-                while (edge.next()) {
-                    edge.set(accessEnc, false).setReverse(accessEnc, false);
-                    removedEdges++;
-                }
+        for (int i = 0; i < component.size(); i++) {
+            EdgeIterator edge = explorer.setBaseNode(component.get(i));
+            while (edge.next()) {
+                if (!edge.get(accessEnc) && !edge.getReverse(accessEnc))
+                    continue;
+                edge.set(accessEnc, false).setReverse(accessEnc, false);
+                removedEdges++;
             }
         }
-
         return removedEdges;
     }
 
@@ -243,10 +186,14 @@ public class PrepareRoutingSubnetworks {
      */
     void markNodesRemovedIfUnreachable() {
         EdgeExplorer edgeExplorer = ghStorage.createEdgeExplorer();
+        int removedNodes = 0;
         for (int nodeIndex = 0; nodeIndex < ghStorage.getNodes(); nodeIndex++) {
-            if (detectNodeRemovedForAllEncoders(edgeExplorer, nodeIndex))
+            if (detectNodeRemovedForAllEncoders(edgeExplorer, nodeIndex)) {
                 ghStorage.markNodeRemoved(nodeIndex);
+                removedNodes++;
+            }
         }
+        logger.info("Removed " + removedNodes + " nodes from the graph as they aren't used by any vehicle after removing subnetworks");
     }
 
     /**
@@ -261,7 +208,7 @@ public class PrepareRoutingSubnetworks {
         // if no edges are reachable return true
         EdgeIterator iter = edgeExplorerAllEdges.setBaseNode(nodeIndex);
         while (iter.next()) {
-            // if at least on encoder allows one direction return false
+            // if at least one encoder allows one direction return false
             for (BooleanEncodedValue accessEnc : accessEncList) {
                 if (iter.get(accessEnc) || iter.getReverse(accessEnc))
                     return false;
diff --git a/core/src/main/java/com/graphhopper/routing/subnetwork/TarjansSCCAlgorithm.java b/core/src/main/java/com/graphhopper/routing/subnetwork/TarjansSCCAlgorithm.java
index 89a88af22..80c46b625 100644
--- a/core/src/main/java/com/graphhopper/routing/subnetwork/TarjansSCCAlgorithm.java
+++ b/core/src/main/java/com/graphhopper/routing/subnetwork/TarjansSCCAlgorithm.java
@@ -20,9 +20,12 @@ package com.graphhopper.routing.subnetwork;
 import com.carrotsearch.hppc.BitSet;
 import com.carrotsearch.hppc.IntArrayDeque;
 import com.carrotsearch.hppc.IntArrayList;
+import com.graphhopper.routing.ev.BooleanEncodedValue;
+import com.graphhopper.routing.util.DefaultEdgeFilter;
 import com.graphhopper.routing.util.EdgeFilter;
 import com.graphhopper.storage.GraphHopperStorage;
 import com.graphhopper.util.EdgeIterator;
+import com.graphhopper.util.EdgeIteratorState;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -31,35 +34,51 @@ import java.util.Stack;
 /**
  * Implementation of Tarjan's algorithm using an explicit stack. The traditional recursive approach
  * runs into stack overflow pretty quickly. The algorithm is used within GraphHopper to find
- * strongly connected components to detect dead-ends leading to routes not found.
+ * strongly connected components to detect dead-ends leading to routes not found and it is used for landmark
+ * calculation as well.
  * <p>
  * See http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm. See
  * http://www.timl.id.au/?p=327 and http://homepages.ecs.vuw.ac.nz/~djp/files/P05.pdf
  */
 public class TarjansSCCAlgorithm {
-    private final ArrayList<IntArrayList> components = new ArrayList<>();
+    private final List<IntArrayList> components = new ArrayList<>();
     // TODO use just the Graph interface here
     private final GraphHopperStorage graph;
     private final IntArrayDeque nodeStack;
     private final BitSet onStack;
     private final int[] nodeIndex;
     private final int[] nodeLowLink;
-    private final EdgeFilter edgeFilter;
     private final boolean excludeSingleNodeComponents;
+    private final EdgeFilter outFilter;
+    private EdgeFilter edgeFilter;
     private int index = 1;
 
-    public TarjansSCCAlgorithm(GraphHopperStorage ghStorage, final EdgeFilter edgeFilter, boolean excludeSingleNodeComponents) {
+    public TarjansSCCAlgorithm(GraphHopperStorage ghStorage, final BooleanEncodedValue accessEnc, boolean excludeSingleNodeComponents) {
         this.graph = ghStorage;
         this.nodeStack = new IntArrayDeque();
         this.onStack = new BitSet(ghStorage.getNodes());
         this.nodeIndex = new int[ghStorage.getNodes()];
         this.nodeLowLink = new int[ghStorage.getNodes()];
-        this.edgeFilter = edgeFilter;
+        this.outFilter = DefaultEdgeFilter.outEdges(accessEnc);
+        this.edgeFilter = outFilter;
         this.excludeSingleNodeComponents = excludeSingleNodeComponents;
     }
 
     /**
-     * Find and return list of all strongly connected components in g.
+     * Allows adding an additional edge filter to exclude edges while searching for connected components.
+     */
+    public void setAdditionalEdgeFilter(final EdgeFilter additionalFilter) {
+        this.edgeFilter = new EdgeFilter() {
+            @Override
+            public boolean accept(EdgeIteratorState edgeState) {
+                return outFilter.accept(edgeState) && additionalFilter.accept(edgeState);
+            }
+        };
+    }
+
+    /**
+     * Find and return a list of all strongly connected components of g. Components with only a single node will
+     * be excluded from the result depending on {@link #excludeSingleNodeComponents}
      */
     public List<IntArrayList> findComponents() {
         int nodes = graph.getNodes();
@@ -73,7 +92,6 @@ public class TarjansSCCAlgorithm {
 
     /**
      * Find all components reachable from firstNode, add them to 'components'
-     * <p>
      *
      * @param firstNode start search of SCC at this node
      */
diff --git a/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java
index 596661322..0915fd404 100644
--- a/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java
@@ -75,10 +75,6 @@ public abstract class AbstractFlagEncoder implements FlagEncoder {
 
     private ConditionalTagInspector conditionalTagInspector;
 
-    public AbstractFlagEncoder(PMap properties) {
-        throw new RuntimeException("This method must be overridden in derived classes");
-    }
-
     /**
      * @param speedBits    specify the number of bits used for speed
      * @param speedFactor  specify the factor to multiple the stored value (can be used to increase
diff --git a/core/src/main/java/com/graphhopper/util/StopWatch.java b/core/src/main/java/com/graphhopper/util/StopWatch.java
index 8d7007cad..850778ad5 100644
--- a/core/src/main/java/com/graphhopper/util/StopWatch.java
+++ b/core/src/main/java/com/graphhopper/util/StopWatch.java
@@ -84,7 +84,7 @@ public class StopWatch {
             str += name + " ";
         }
 
-        return str + "time:" + getSeconds();
+        return str + "time:" + getSeconds() + "s";
     }
 
     private boolean notStarted() {
diff --git a/docs/core/turn-restrictions.md b/docs/core/turn-restrictions.md
index ffc4f6bdb..9ceb63373 100644
--- a/docs/core/turn-restrictions.md
+++ b/docs/core/turn-restrictions.md
@@ -13,6 +13,9 @@ Turn restrictions are crucial for correct vehicle navigation and help to avoid f
 
 Turn restrictions have to be enabled on a vehicle basis. To enable it for one vehicle add
 `|turn_costs=true` in the config, for example: `graph.flag_encoders=car|turn_costs=true`.
+Or when using the Java API directly you can either create the encoding manager like `EncodingManager.create("car|turn_costs=true")` or
+`new EncodingManager.Builder().add(new CarFlagEncoder(5, 5, 1)` where the last parameter of `CarFlagEncoder` represents
+the maximum turn costs (a value of 1 means the turn can either be legal or forbidden).
 Turn restrictions are not available for every vehicle as they have low relevance
 for some vehicles like `foot`. 
 To enable turn restrictions when using the 'speed mode' additional graph preparation is required, because turn restrictions
diff --git a/graphhopper.sh b/graphhopper.sh
index c0ff15e8f..b9d50f785 100755
--- a/graphhopper.sh
+++ b/graphhopper.sh
@@ -282,7 +282,7 @@ elif [ "$ACTION" = "import" ]; then
 elif [ "$ACTION" = "measurement" ]; then
   ARGS="$GH_WEB_OPTS graph.location=$GRAPH datareader.file=$OSM_FILE \
        measurement.weighting=fastest measurement.ch.node=true measurement.ch.edge=false measurement.lm=true graph.flag_encoders=car|turn_costs=true \
-       prepare.min_network_size=10000 prepare.min_oneway_network_size=10000"
+       prepare.min_network_size=10000"
 
  function startMeasurement {
     execMvn --projects tools -am -DskipTests clean package
diff --git a/reader-osm/src/main/java/com/graphhopper/reader/osm/OSMReader.java b/reader-osm/src/main/java/com/graphhopper/reader/osm/OSMReader.java
index 798f0d282..932a0701b 100644
--- a/reader-osm/src/main/java/com/graphhopper/reader/osm/OSMReader.java
+++ b/reader-osm/src/main/java/com/graphhopper/reader/osm/OSMReader.java
@@ -158,6 +158,7 @@ public class OSMReader implements DataReader, TurnCostParser.ExternalInternalMap
      * compact graph data structure.
      */
     void preProcess(File osmFile) {
+        LOGGER.info("Starting to process OSM file: '" + osmFile + "'");
         try (OSMInput in = openOsmInputFile(osmFile)) {
             long tmpWayCounter = 1;
             long tmpRelationCounter = 1;


Test patch:
diff --git a/core/src/test/java/com/graphhopper/routing/subnetwork/PrepareRoutingSubnetworksTest.java b/core/src/test/java/com/graphhopper/routing/subnetwork/PrepareRoutingSubnetworksTest.java
index 72f9f0635..08f27fb97 100644
--- a/core/src/test/java/com/graphhopper/routing/subnetwork/PrepareRoutingSubnetworksTest.java
+++ b/core/src/test/java/com/graphhopper/routing/subnetwork/PrepareRoutingSubnetworksTest.java
@@ -17,7 +17,7 @@
  */
 package com.graphhopper.routing.subnetwork;
 
-import com.carrotsearch.hppc.IntArrayList;
+import com.graphhopper.routing.ev.BooleanEncodedValue;
 import com.graphhopper.routing.util.*;
 import com.graphhopper.storage.GraphBuilder;
 import com.graphhopper.storage.GraphHopperStorage;
@@ -25,14 +25,14 @@ import com.graphhopper.util.EdgeExplorer;
 import com.graphhopper.util.EdgeIterator;
 import com.graphhopper.util.EdgeIteratorState;
 import com.graphhopper.util.GHUtility;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
-import static org.junit.Assert.*;
+import static org.junit.jupiter.api.Assertions.*;
 
 /**
  * @author Peter Karich
@@ -40,107 +40,47 @@ import static org.junit.Assert.*;
 public class PrepareRoutingSubnetworksTest {
     private final FlagEncoder carFlagEncoder = new CarFlagEncoder();
     private final EncodingManager em = EncodingManager.create(carFlagEncoder);
-
-    GraphHopperStorage createStorage(EncodingManager eman) {
-        return new GraphBuilder(eman).create();
-    }
-
-    GraphHopperStorage createSubnetworkTestStorage() {
-        GraphHopperStorage g = createStorage(em);
-        // big network
-        g.edge(1, 2, 1, true);
-        g.edge(1, 4, 1, false);
-        g.edge(1, 8, 1, true);
-        g.edge(2, 4, 1, true);
-        g.edge(8, 4, 1, false);
-        g.edge(8, 11, 1, true);
-        g.edge(12, 11, 1, true);
-        g.edge(9, 12, 1, false);
-        g.edge(9, 15, 1, true);
-
-        // large network
-        g.edge(0, 13, 1, true);
-        g.edge(0, 3, 1, true);
-        g.edge(0, 7, 1, true);
-        g.edge(3, 7, 1, true);
-        g.edge(3, 5, 1, true);
-        g.edge(13, 5, 1, true);
-
-        // small network
-        g.edge(6, 14, 1, true);
-        g.edge(10, 14, 1, true);
-        return g;
-    }
-
-    GraphHopperStorage createSubnetworkTestStorage2(EncodingManager em) {
-        GraphHopperStorage g = createStorage(em);
-        // large network
+    private final BooleanEncodedValue accessEnc = carFlagEncoder.getAccessEnc();
+
+    private GraphHopperStorage createSubnetworkTestStorage(EncodingManager em) {
+        GraphHopperStorage g = new GraphBuilder(em).create();
+        //         5 - 6
+        //         | /
+        //         4
+        //         | <- (no access flags unless we change it)
+        // 0 - 1 - 3 - 7 - 8
+        // |       |
+        // 2 -------
         g.edge(0, 1, 1, true);
         g.edge(1, 3, 1, true);
         g.edge(0, 2, 1, true);
         g.edge(2, 3, 1, true);
         g.edge(3, 7, 1, true);
         g.edge(7, 8, 1, true);
-
-        // connecting both but do not allow CAR!
+        // connecting both but do no set access yet
         g.edge(3, 4).setDistance(1);
 
-        // small network
         g.edge(4, 5, 1, true);
         g.edge(5, 6, 1, true);
         g.edge(4, 6, 1, true);
         return g;
     }
 
-    @Test
-    public void testFindSubnetworks() {
-        GraphHopperStorage g = createSubnetworkTestStorage();
-        DefaultEdgeFilter filter = DefaultEdgeFilter.allEdges(carFlagEncoder);
-        PrepareRoutingSubnetworks instance = new PrepareRoutingSubnetworks(g, Collections.singletonList(carFlagEncoder));
-        List<IntArrayList> components = instance.findSubnetworks(filter);
-
-        assertEquals(3, components.size());
-
-        // start is at 0 => large network
-        assertEquals(IntArrayList.from(0, 7, 3, 13, 5), components.get(0));
-        // next smallest and unvisited node is 1 => big network
-        assertEquals(IntArrayList.from(1, 8, 4, 2, 11, 12, 9, 15), components.get(1));
-        assertEquals(IntArrayList.from(6, 14, 10), components.get(2));
-    }
-
-    @Test
-    public void testKeepLargestNetworks() {
-        GraphHopperStorage g = createSubnetworkTestStorage();
-        DefaultEdgeFilter filter = DefaultEdgeFilter.allEdges(carFlagEncoder);
-        PrepareRoutingSubnetworks instance = new PrepareRoutingSubnetworks(g, Collections.singletonList(carFlagEncoder));
-        List<IntArrayList> components = instance.findSubnetworks(filter);
-        assertEquals(3, components.size());
-        int removedEdges = instance.keepLargeNetworks(filter, components);
-        assertEquals(8, removedEdges);
-        instance.markNodesRemovedIfUnreachable();
-        g.optimize();
-
-        assertEquals(8, g.getNodes());
-        assertEquals(Arrays.<String>asList(), GHUtility.getProblems(g));
-
-        components = instance.findSubnetworks(filter);
-        assertEquals(1, components.size());
-    }
-
     @Test
     public void testRemoveSubnetworkIfOnlyOneVehicle() {
-        GraphHopperStorage g = createSubnetworkTestStorage2(em);
-        PrepareRoutingSubnetworks instance = new PrepareRoutingSubnetworks(g, em.fetchEdgeEncoders());
+        GraphHopperStorage g = createSubnetworkTestStorage(em);
+        PrepareRoutingSubnetworks instance = new PrepareRoutingSubnetworks(g, Collections.singletonList(carFlagEncoder));
+        // this rules out the upper small network
         instance.setMinNetworkSize(4);
         instance.doWork();
         g.optimize();
         assertEquals(6, g.getNodes());
-        assertEquals(Arrays.<String>asList(), GHUtility.getProblems(g));
+        assertTrue(GHUtility.getProblems(g).isEmpty());
         EdgeExplorer explorer = g.createEdgeExplorer();
         assertEquals(GHUtility.asSet(2, 1, 5), GHUtility.getNeighbors(explorer.setBaseNode(3)));
 
-        // do not remove because small network is big enough
-        g = createSubnetworkTestStorage2(em);
+        // this time we lower the threshold and the small network will remain
+        g = createSubnetworkTestStorage(em);
         instance = new PrepareRoutingSubnetworks(g, em.fetchEdgeEncoders());
         instance.setMinNetworkSize(3);
         instance.doWork();
@@ -152,9 +92,9 @@ public class PrepareRoutingSubnetworksTest {
     public void testRemoveNode() {
         FlagEncoder carEncoder = new CarFlagEncoder();
         BikeFlagEncoder bikeEncoder = new BikeFlagEncoder();
-        EncodingManager em2 = EncodingManager.create(carEncoder, bikeEncoder);
-        GraphHopperStorage g = createSubnetworkTestStorage2(em2);
-        PrepareRoutingSubnetworks instance = new PrepareRoutingSubnetworks(g, em2.fetchEdgeEncoders());
+        EncodingManager em = EncodingManager.create(carEncoder, bikeEncoder);
+        GraphHopperStorage g = createSubnetworkTestStorage(em);
+        PrepareRoutingSubnetworks instance = new PrepareRoutingSubnetworks(g, em.fetchEdgeEncoders());
 
         EdgeExplorer edgeExplorer = g.createEdgeExplorer();
         assertFalse(instance.detectNodeRemovedForAllEncoders(edgeExplorer, 4));
@@ -162,8 +102,12 @@ public class PrepareRoutingSubnetworksTest {
         assertFalse(instance.detectNodeRemovedForAllEncoders(edgeExplorer, 6));
 
         // mark certain edges inaccessible for all encoders
-        for (EdgeIteratorState edge : Arrays.asList(GHUtility.getEdge(g, 5, 6), GHUtility.getEdge(g, 4, 5), GHUtility.getEdge(g, 4, 6))) {
-            for (FlagEncoder encoder : em2.fetchEdgeEncoders()) {
+        for (EdgeIteratorState edge : Arrays.asList(
+                GHUtility.getEdge(g, 5, 6),
+                GHUtility.getEdge(g, 4, 5),
+                GHUtility.getEdge(g, 4, 6))
+        ) {
+            for (FlagEncoder encoder : em.fetchEdgeEncoders()) {
                 edge.set(encoder.getAccessEnc(), false).setReverse(encoder.getAccessEnc(), false);
             }
         }
@@ -177,13 +121,13 @@ public class PrepareRoutingSubnetworksTest {
     public void testRemoveSubnetworkWhenMultipleVehicles() {
         FlagEncoder carEncoder = new CarFlagEncoder();
         BikeFlagEncoder bikeEncoder = new BikeFlagEncoder();
-        EncodingManager em2 = EncodingManager.create(carEncoder, bikeEncoder);
-        GraphHopperStorage g = createSubnetworkTestStorage2(em2);
+        EncodingManager em = EncodingManager.create(carEncoder, bikeEncoder);
+        GraphHopperStorage g = createSubnetworkTestStorage(em);
 
         EdgeIteratorState edge = GHUtility.getEdge(g, 3, 4);
         GHUtility.setProperties(edge, carEncoder, 10, false, false);
         GHUtility.setProperties(edge, bikeEncoder, 5, true, true);
-        PrepareRoutingSubnetworks instance = new PrepareRoutingSubnetworks(g, em2.fetchEdgeEncoders());
+        PrepareRoutingSubnetworks instance = new PrepareRoutingSubnetworks(g, em.fetchEdgeEncoders());
         instance.setMinNetworkSize(5);
         instance.doWork();
         g.optimize();
@@ -195,19 +139,20 @@ public class PrepareRoutingSubnetworksTest {
         EdgeExplorer bikeExplorer = g.createEdgeExplorer(DefaultEdgeFilter.allEdges(bikeEncoder));
         assertEquals(GHUtility.asSet(7, 2, 1, 4), GHUtility.getNeighbors(bikeExplorer.setBaseNode(3)));
 
+        // now we block the edge for both vehicles, in which case the smaller subnetwork gets removed
         edge = GHUtility.getEdge(g, 3, 4);
         GHUtility.setProperties(edge, carEncoder, 10, false, false);
         GHUtility.setProperties(edge, bikeEncoder, 5, false, false);
-        instance = new PrepareRoutingSubnetworks(g, em2.fetchEdgeEncoders());
+        instance = new PrepareRoutingSubnetworks(g, em.fetchEdgeEncoders());
         instance.setMinNetworkSize(5);
         instance.doWork();
         g.optimize();
         assertEquals(6, g.getNodes());
     }
 
-    GraphHopperStorage createDeadEndUnvisitedNetworkStorage(EncodingManager em) {
-        GraphHopperStorage g = createStorage(em);
-        // 0 <-> 1 <-> 2 <-> 3 <-> 4 <- 5 <-> 6
+    GraphHopperStorage createSubnetworkTestStorageWithOneWays(EncodingManager em) {
+        GraphHopperStorage g = new GraphBuilder(em).create();
+        // 0 - 1 - 2 - 3 - 4 <- 5 - 6
         g.edge(0, 1, 1, true);
         g.edge(1, 2, 1, true);
         g.edge(2, 3, 1, true);
@@ -215,7 +160,7 @@ public class PrepareRoutingSubnetworksTest {
         g.edge(5, 4, 1, false);
         g.edge(5, 6, 1, true);
 
-        // 7 -> 8 <-> 9 <-> 10
+        // 7 -> 8 - 9 - 10
         g.edge(7, 8, 1, false);
         g.edge(8, 9, 1, true);
         g.edge(9, 10, 1, true);
@@ -223,37 +168,17 @@ public class PrepareRoutingSubnetworksTest {
         return g;
     }
 
-    GraphHopperStorage createTarjanTestStorage() {
-        GraphHopperStorage g = createStorage(em);
-
-        g.edge(1, 2, 1, false);
-        g.edge(2, 3, 1, false);
-        g.edge(3, 1, 1, false);
-
-        g.edge(4, 2, 1, false);
-        g.edge(4, 3, 1, false);
-        g.edge(4, 5, 1, true);
-        g.edge(5, 6, 1, false);
-
-        g.edge(6, 3, 1, false);
-        g.edge(6, 7, 1, true);
-
-        g.edge(8, 5, 1, false);
-        g.edge(8, 7, 1, false);
-        g.edge(8, 8, 1, false);
-
-        return g;
-    }
-
     @Test
-    public void testRemoveDeadEndUnvisitedNetworks() {
-        GraphHopperStorage g = createDeadEndUnvisitedNetworkStorage(em);
+    public void testRemoveSubNetworks_withOneWays() {
+        GraphHopperStorage g = createSubnetworkTestStorageWithOneWays(em);
         assertEquals(11, g.getNodes());
 
         PrepareRoutingSubnetworks instance = new PrepareRoutingSubnetworks(g, Collections.singletonList(carFlagEncoder)).
-                setMinOneWayNetworkSize(3);
-        int removed = instance.removeDeadEndUnvisitedNetworks(DefaultEdgeFilter.allEdges(carFlagEncoder));
+                setMinNetworkSize(3);
+        int removed = instance.removeSmallSubNetworks(accessEnc);
 
+        // the (7) and the (5,6) components get removed -> 2 remaining components and
+        // 3 removed edges total
         assertEquals(3, removed);
         instance.markNodesRemovedIfUnreachable();
         g.optimize();
@@ -263,12 +188,12 @@ public class PrepareRoutingSubnetworksTest {
 
     @Test
     public void testAddEdgesAfterwards() {
-        GraphHopperStorage g = createDeadEndUnvisitedNetworkStorage(em);
+        GraphHopperStorage g = createSubnetworkTestStorageWithOneWays(em);
         assertEquals(11, g.getNodes());
 
         PrepareRoutingSubnetworks instance = new PrepareRoutingSubnetworks(g, Collections.singletonList(carFlagEncoder)).
-                setMinOneWayNetworkSize(3);
-        int removed = instance.removeDeadEndUnvisitedNetworks(DefaultEdgeFilter.allEdges(carFlagEncoder));
+                setMinNetworkSize(3);
+        int removed = instance.removeSmallSubNetworks(accessEnc);
 
         assertEquals(3, removed);
         instance.markNodesRemovedIfUnreachable();
@@ -281,68 +206,26 @@ public class PrepareRoutingSubnetworksTest {
         assertTrue(isConsistent(g));
     }
 
-    @Test
-    public void testTarjan() {
-        GraphHopperStorage g = createSubnetworkTestStorage();
-
-        // Requires a single vehicle type, otherwise we throw.
-        final EdgeFilter filter = DefaultEdgeFilter.outEdges(carFlagEncoder);
-        TarjansSCCAlgorithm tarjan = new TarjansSCCAlgorithm(g, filter, false);
-
-        List<IntArrayList> components = tarjan.findComponents();
-
-        assertEquals(4, components.size());
-        assertEquals(IntArrayList.from(13, 5, 3, 7, 0), components.get(0));
-        assertEquals(IntArrayList.from(2, 4, 12, 11, 8, 1), components.get(1));
-        assertEquals(IntArrayList.from(10, 14, 6), components.get(2));
-        assertEquals(IntArrayList.from(15, 9), components.get(3));
-    }
-
     // Previous two-pass implementation failed on 1 -> 2 -> 0
     @Test
     public void testNodeOrderingRegression() {
-        // 1 -> 2 -> 0
-        GraphHopperStorage g = createStorage(em);
+        // 1 -> 2 -> 0 - 3 - 4 - 5
+        GraphHopperStorage g = new GraphBuilder(em).create();
         g.edge(1, 2, 1, false);
         g.edge(2, 0, 1, false);
+        g.edge(0, 3, 1, true);
+        g.edge(3, 4, 1, true);
+        g.edge(4, 5, 1, true);
 
         PrepareRoutingSubnetworks instance = new PrepareRoutingSubnetworks(g, Collections.singletonList(carFlagEncoder)).
-                setMinOneWayNetworkSize(2);
-        int removedEdges = instance.removeDeadEndUnvisitedNetworks(DefaultEdgeFilter.allEdges(carFlagEncoder));
+                setMinNetworkSize(2);
+        int removedEdges = instance.removeSmallSubNetworks(accessEnc);
         assertEquals(2, removedEdges);
     }
 
-    @Test
-    public void test481() {
-        // 0->1->3->4->5->6
-        //  2        7<--/
-        GraphHopperStorage g = createStorage(em);
-        g.edge(0, 1, 1, false);
-        g.edge(1, 2, 1, false);
-        g.edge(2, 0, 1, false);
-
-        g.edge(1, 3, 1, false);
-        g.edge(3, 4, 1, false);
-
-        g.edge(4, 5, 1, false);
-        g.edge(5, 6, 1, false);
-        g.edge(6, 7, 1, false);
-        g.edge(7, 4, 1, false);
-
-        PrepareRoutingSubnetworks instance = new PrepareRoutingSubnetworks(g, Collections.singletonList(carFlagEncoder)).
-                setMinOneWayNetworkSize(2).
-                setMinNetworkSize(4);
-        instance.doWork();
-
-        // only one remaining network
-        List<IntArrayList> components = instance.findSubnetworks(DefaultEdgeFilter.allEdges(carFlagEncoder));
-        assertEquals(1, components.size());
-    }
-
     public static boolean isConsistent(GraphHopperStorage storage) {
         EdgeExplorer edgeExplorer = storage.createEdgeExplorer();
-        int nNodes = storage.getNodes();
-        for (int i = 0; i < nNodes; i++) {
+        for (int i = 0; i < storage.getNodes(); i++) {
             if (!check(storage, edgeExplorer, i)) return false;
         }
         return true;
@@ -351,13 +234,13 @@ public class PrepareRoutingSubnetworksTest {
     public static boolean check(GraphHopperStorage storage, EdgeExplorer edgeExplorer, int node) {
         List<Integer> toNodes = new ArrayList<>();
         List<Integer> edges = new ArrayList<>();
-        EdgeIterator edgeIterator = edgeExplorer.setBaseNode(node);
-        while (edgeIterator.next()) {
-            if (edgeIterator.getBaseNode() < 0 || edgeIterator.getAdjNode() < 0) {
+        EdgeIterator iter = edgeExplorer.setBaseNode(node);
+        while (iter.next()) {
+            if (iter.getBaseNode() < 0 || iter.getAdjNode() < 0) {
                 return false;
             }
-            toNodes.add(edgeIterator.getAdjNode());
-            edges.add(edgeIterator.getEdge());
+            toNodes.add(iter.getAdjNode());
+            edges.add(iter.getEdge());
         }
 
         for (int i = 0; i < toNodes.size(); i++) {
diff --git a/core/src/test/java/com/graphhopper/routing/subnetwork/TarjansSCCAlgorithmTest.java b/core/src/test/java/com/graphhopper/routing/subnetwork/TarjansSCCAlgorithmTest.java
new file mode 100644
index 000000000..811bf0c70
--- /dev/null
+++ b/core/src/test/java/com/graphhopper/routing/subnetwork/TarjansSCCAlgorithmTest.java
@@ -0,0 +1,161 @@
+/*
+ *  Licensed to GraphHopper GmbH under one or more contributor
+ *  license agreements. See the NOTICE file distributed with this work for
+ *  additional information regarding copyright ownership.
+ *
+ *  GraphHopper GmbH licenses this file to you under the Apache License,
+ *  Version 2.0 (the "License"); you may not use this file except in
+ *  compliance with the License. You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package com.graphhopper.routing.subnetwork;
+
+import com.carrotsearch.hppc.IntArrayList;
+import com.graphhopper.routing.ev.BooleanEncodedValue;
+import com.graphhopper.routing.util.CarFlagEncoder;
+import com.graphhopper.routing.util.EncodingManager;
+import com.graphhopper.routing.util.FlagEncoder;
+import com.graphhopper.storage.GraphBuilder;
+import com.graphhopper.storage.GraphHopperStorage;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class TarjansSCCAlgorithmTest {
+    private final FlagEncoder carFlagEncoder = new CarFlagEncoder();
+    private final EncodingManager em = EncodingManager.create(carFlagEncoder);
+    private final BooleanEncodedValue accessEnc = carFlagEncoder.getAccessEnc();
+
+    @Test
+    public void testFindComponents() {
+        GraphHopperStorage g = new GraphBuilder(em).create();
+        // big network (has two components actually, because 9->12 is a one-way)
+        //    ---
+        //  /     \
+        // 4 < 1 - 2
+        // |   |
+        // <-- 8 - 11 - 12 < 9 - 15
+        g.edge(1, 2, 1, true);
+        g.edge(1, 4, 1, false);
+        g.edge(1, 8, 1, true);
+        g.edge(2, 4, 1, true);
+        g.edge(8, 4, 1, false);
+        g.edge(8, 11, 1, true);
+        g.edge(12, 11, 1, true);
+        g.edge(9, 12, 1, false);
+        g.edge(9, 15, 1, true);
+
+        // large network
+        // 5 --------
+        // |        |
+        // 3 - 0 - 13
+        //   \ |
+        //     7
+        g.edge(0, 13, 1, true);
+        g.edge(0, 3, 1, true);
+        g.edge(0, 7, 1, true);
+        g.edge(3, 7, 1, true);
+        g.edge(3, 5, 1, true);
+        g.edge(13, 5, 1, true);
+
+        // small network
+        // 6 - 14 - 10
+        g.edge(6, 14, 1, true);
+        g.edge(10, 14, 1, true);
+
+        TarjansSCCAlgorithm tarjan = new TarjansSCCAlgorithm(g, accessEnc, false);
+        List<IntArrayList> components = tarjan.findComponents();
+
+        assertEquals(4, components.size());
+        assertEquals(IntArrayList.from(13, 5, 3, 7, 0), components.get(0));
+        assertEquals(IntArrayList.from(2, 4, 12, 11, 8, 1), components.get(1));
+        assertEquals(IntArrayList.from(10, 14, 6), components.get(2));
+        assertEquals(IntArrayList.from(15, 9), components.get(3));
+    }
+
+    @Test
+    public void test481() {
+        // 0->1->3->4->5->6->7
+        //  \ |      \<-----/
+        //    2
+        GraphHopperStorage g = new GraphBuilder(em).create();
+        g.edge(0, 1, 1, false);
+        g.edge(1, 2, 1, false);
+        g.edge(2, 0, 1, false);
+
+        g.edge(1, 3, 1, false);
+        g.edge(3, 4, 1, false);
+
+        g.edge(4, 5, 1, false);
+        g.edge(5, 6, 1, false);
+        g.edge(6, 7, 1, false);
+        g.edge(7, 4, 1, false);
+
+        TarjansSCCAlgorithm tarjan = new TarjansSCCAlgorithm(g, accessEnc, false);
+        List<IntArrayList> components = tarjan.findComponents();
+
+        assertEquals(3, components.size());
+        assertEquals(IntArrayList.from(2, 1, 0), components.get(2));
+        assertEquals(IntArrayList.from(3), components.get(1));
+        assertEquals(IntArrayList.from(7, 6, 5, 4), components.get(0));
+    }
+
+    @Test
+    public void testTarjan_issue761() {
+        GraphHopperStorage g = new GraphBuilder(em).create();
+        //     11-10-9
+        //     |     |
+        // 0-1-2->3->4->5
+        //        |     |
+        //        6     12
+        //        |     |
+        //        7     13-14
+        //        |       \|
+        //        8        15-16
+
+        // oneway main road
+        g.edge(0, 1, 1, true);
+        g.edge(1, 2, 1, true);
+        g.edge(2, 3, 1, false);
+        g.edge(3, 4, 1, false);
+        g.edge(4, 5, 1, false);
+
+        // going south from main road
+        g.edge(3, 6, 1, true);
+        g.edge(6, 7, 1, true);
+        g.edge(7, 8, 1, true);
+
+        // connects the two nodes 2 and 4
+        g.edge(4, 9, 1, true);
+        g.edge(9, 10, 1, true);
+        g.edge(10, 11, 1, true);
+        g.edge(11, 2, 1, true);
+
+        // eastern part (only connected by a single directed edge to the rest of the graph)
+        g.edge(5, 12, 1, true);
+        g.edge(12, 13, 1, true);
+        g.edge(13, 14, 1, true);
+        g.edge(14, 15, 1, true);
+        g.edge(15, 13, 1, true);
+        g.edge(15, 16, 1, true);
+
+        FlagEncoder encoder = em.fetchEdgeEncoders().iterator().next();
+        TarjansSCCAlgorithm tarjan = new TarjansSCCAlgorithm(g, encoder.getAccessEnc(), false);
+        List<IntArrayList> components = tarjan.findComponents();
+        assertEquals(2, components.size());
+
+        assertEquals(IntArrayList.from(14, 16, 15, 13, 12, 5), components.get(0));
+        assertEquals(IntArrayList.from(8, 7, 6, 3, 4, 9, 10, 11, 2, 1, 0), components.get(1));
+    }
+
+}
\ No newline at end of file
diff --git a/core/src/test/java/com/graphhopper/util/DepthFirstSearchTest.java b/core/src/test/java/com/graphhopper/util/DepthFirstSearchTest.java
index dff85427c..0faa2f14b 100644
--- a/core/src/test/java/com/graphhopper/util/DepthFirstSearchTest.java
+++ b/core/src/test/java/com/graphhopper/util/DepthFirstSearchTest.java
@@ -21,7 +21,6 @@ import com.carrotsearch.hppc.IntArrayList;
 import com.graphhopper.coll.GHBitSet;
 import com.graphhopper.coll.GHBitSetImpl;
 import com.graphhopper.coll.GHIntHashSet;
-import com.graphhopper.coll.GHTBitSet;
 import com.graphhopper.routing.util.DefaultEdgeFilter;
 import com.graphhopper.routing.util.EncodingManager;
 import com.graphhopper.routing.util.FlagEncoder;
diff --git a/reader-osm/src/test/java/com/graphhopper/GraphHopperTest.java b/reader-osm/src/test/java/com/graphhopper/GraphHopperTest.java
index 7c6241526..499c2ae34 100644
--- a/reader-osm/src/test/java/com/graphhopper/GraphHopperTest.java
+++ b/reader-osm/src/test/java/com/graphhopper/GraphHopperTest.java
@@ -73,7 +73,7 @@ public class GraphHopperTest {
     private static final String MOSCOW = DIR + "/moscow.osm.gz";
 
     // when creating GH instances make sure to use this as the GH location such that it will be cleaned between tests
-    private static final String GH_LOCATION = "target/graphhopper-it-gh";
+    private static final String GH_LOCATION = "target/graphhopper-test-gh";
 
     @BeforeEach
     @AfterEach
@@ -87,8 +87,8 @@ public class GraphHopperTest {
             ASTAR + ",false,439",
             DIJKSTRA_BI + ",false,208",
             ASTAR_BI + ",false,172",
-            DIJKSTRA_BI + ",true,29",
-            ASTAR_BI + ",true,29"
+            ASTAR_BI + ",true,33",
+            DIJKSTRA_BI + ",true,30"
     })
     public void testMonacoDifferentAlgorithms(String algo, boolean withCH, int expectedVisitedNodes) {
         final String vehicle = "car";
@@ -100,6 +100,7 @@ public class GraphHopperTest {
         hopper.getCHPreparationHandler()
                 .setCHProfiles(new CHProfile("profile"))
                 .setDisablingAllowed(true);
+        hopper.setMinNetworkSize(0);
         hopper.importOrLoad();
         GHRequest req = new GHRequest(43.727687, 7.418737, 43.74958, 7.436566)
                 .setAlgorithm(algo)
@@ -1090,6 +1091,7 @@ public class GraphHopperTest {
                 new CHProfile(profile1),
                 new CHProfile(profile2)
         );
+        hopper.setMinNetworkSize(0);
         hopper.importOrLoad();
 
         assertEquals(2, hopper.getCHPreparationHandler().getPreparations().size());
@@ -1134,6 +1136,7 @@ public class GraphHopperTest {
                 new CHProfile(profile1),
                 new CHProfile(profile2)
         );
+        hopper.setMinNetworkSize(0);
         hopper.importOrLoad();
 
         assertEquals(2, hopper.getCHPreparationHandler().getPreparations().size());
@@ -1400,6 +1403,7 @@ public class GraphHopperTest {
                         new LMProfile(profile3).setPreparationProfile(profile1)
                 ).
                 setDisablingAllowed(true);
+        hopper.setMinNetworkSize(0);
         hopper.importOrLoad();
 
         // flex
diff --git a/reader-osm/src/test/java/com/graphhopper/reader/osm/GraphHopperOSMTest.java b/reader-osm/src/test/java/com/graphhopper/reader/osm/GraphHopperOSMTest.java
index 98d07cb49..69028cc7d 100644
--- a/reader-osm/src/test/java/com/graphhopper/reader/osm/GraphHopperOSMTest.java
+++ b/reader-osm/src/test/java/com/graphhopper/reader/osm/GraphHopperOSMTest.java
@@ -65,6 +65,7 @@ public class GraphHopperOSMTest {
     private static final String ghLoc = "./target/tmp/ghosm";
     private static final String testOsm = "./src/test/resources/com/graphhopper/reader/osm/test-osm.xml";
     private static final String testOsm3 = "./src/test/resources/com/graphhopper/reader/osm/test-osm3.xml";
+    private static final String testOsm8 = "./src/test/resources/com/graphhopper/reader/osm/test-osm8.xml";
     private GraphHopper instance;
 
     @Before
@@ -196,7 +197,7 @@ public class GraphHopperOSMTest {
             }
         });
 
-        assertEquals(57, indexNodeList.size());
+        assertEquals(47, indexNodeList.size());
         for (int nodeId : indexNodeList) {
             if (!bbox.contains(na.getLatitude(nodeId), na.getLongitude(nodeId)))
                 fail("bbox " + bbox + " should contain " + nodeId);
@@ -427,7 +428,7 @@ public class GraphHopperOSMTest {
                 ).
                 setStoreOnFlush(false).
                 setGraphHopperLocation(ghLoc).
-                setDataReaderFile(testOsm3);
+                setDataReaderFile(testOsm8);
         instance.importOrLoad();
 
         assertEquals(5, instance.getGraphHopperStorage().getNodes());
@@ -435,7 +436,7 @@ public class GraphHopperOSMTest {
 
         // A to D
         GHResponse grsp = instance.route(new GHRequest(11.1, 50, 11.3, 51).setProfile(profile1));
-        assertFalse(grsp.hasErrors());
+        assertFalse(grsp.getErrors().toString(), grsp.hasErrors());
         ResponsePath rsp = grsp.getBest();
         assertEquals(3, rsp.getPoints().getSize());
         // => found A and D
diff --git a/reader-osm/src/test/java/com/graphhopper/reader/osm/OSMReaderTest.java b/reader-osm/src/test/java/com/graphhopper/reader/osm/OSMReaderTest.java
index 7dd591b17..9ad3fc9c2 100644
--- a/reader-osm/src/test/java/com/graphhopper/reader/osm/OSMReaderTest.java
+++ b/reader-osm/src/test/java/com/graphhopper/reader/osm/OSMReaderTest.java
@@ -205,7 +205,9 @@ public class OSMReaderTest {
 
     @Test
     public void testOneWay() {
-        GraphHopper hopper = new GraphHopperFacade(file2).importOrLoad();
+        GraphHopper hopper = new GraphHopperFacade(file2)
+                .setMinNetworkSize(0)
+                .importOrLoad();
         GraphHopperStorage graph = hopper.getGraphHopperStorage();
 
         assertEquals("2014-01-02T01:10:14Z", graph.getProperties().get("datareader.data.date"));
@@ -306,7 +308,9 @@ public class OSMReaderTest {
 
     @Test
     public void testFoot() {
-        GraphHopper hopper = new GraphHopperFacade(file3).importOrLoad();
+        GraphHopper hopper = new GraphHopperFacade(file3)
+                .setMinNetworkSize(0)
+                .importOrLoad();
         Graph graph = hopper.getGraphHopperStorage();
 
         int n10 = AbstractGraphStorageTester.getIdOf(graph, 11.1);
@@ -354,7 +358,7 @@ public class OSMReaderTest {
     @Test
     public void testBarriers() {
         GraphHopper hopper = new GraphHopperFacade(fileBarriers).
-                setMinNetworkSize(0, 0).
+                setMinNetworkSize(0).
                 importOrLoad();
 
         Graph graph = hopper.getGraphHopperStorage();
@@ -440,7 +444,7 @@ public class OSMReaderTest {
     @Test
     public void testBarriersOnTowerNodes() {
         GraphHopper hopper = new GraphHopperFacade(fileBarriers).
-                setMinNetworkSize(0, 0).
+                setMinNetworkSize(0).
                 importOrLoad();
         Graph graph = hopper.getGraphHopperStorage();
         assertEquals(8, graph.getNodes());
@@ -880,7 +884,9 @@ public class OSMReaderTest {
 
     @Test
     public void testDataDateWithinPBF() {
-        GraphHopper hopper = new GraphHopperFacade("test-osm6.pbf").importOrLoad();
+        GraphHopper hopper = new GraphHopperFacade("test-osm6.pbf")
+                .setMinNetworkSize(0)
+                .importOrLoad();
         GraphHopperStorage graph = hopper.getGraphHopperStorage();
 
         assertEquals("2014-01-02T00:10:14Z", graph.getProperties().get("datareader.data.date"));
@@ -936,6 +942,7 @@ public class OSMReaderTest {
             }
         }.setEncodingManager(EncodingManager.create("car,bike")).
                 setProfiles(new Profile("profile").setVehicle("car").setWeighting("fastest")).
+                setMinNetworkSize(0).
                 setGraphHopperLocation(dir).
                 importOrLoad();
 
diff --git a/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMTest.java b/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMTest.java
index 8360e528f..2547295c3 100644
--- a/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMTest.java
+++ b/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMTest.java
@@ -632,9 +632,10 @@ public class RoutingAlgorithmWithOSMTest {
                     setProfiles(profiles).
                     setGraphHopperLocation(graphFile).
                     setEncodingManager(em);
+            hopper.setMinNetworkSize(0);
 
-            if (osmFile.contains("krautsand"))
-                hopper.setMinNetworkSize(0, 0);
+            if (osmFile.contains("moscow"))
+                hopper.setMinNetworkSize(200);
             // avoid that path.getDistance is too different to path.getPoint.calcDistance
             hopper.setWayPointMaxDistance(0);
 
@@ -698,6 +699,7 @@ public class RoutingAlgorithmWithOSMTest {
                 setWayPointMaxDistance(0).
                 setDataReaderFile(DIR + "/monaco.osm.gz").
                 setGraphHopperLocation(graphFile).
+                setMinNetworkSize(0).
                 setProfiles(new Profile("car").setVehicle("car").setWeighting("fastest")).
                 importOrLoad();
         final Graph g = hopper.getGraphHopperStorage();
diff --git a/reader-osm/src/test/resources/com/graphhopper/reader/osm/test-osm8.xml b/reader-osm/src/test/resources/com/graphhopper/reader/osm/test-osm8.xml
new file mode 100644
index 000000000..0e1b43853
--- /dev/null
+++ b/reader-osm/src/test/resources/com/graphhopper/reader/osm/test-osm8.xml
@@ -0,0 +1,62 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="pbf2osm">
+
+    <!--  _>B_>
+         /  |  \
+        A__ D__C
+         \  |  /
+          \_E_/    
+    -->
+
+    <node id="10" lat="11.1" lon="50" uid="24853">
+        <tag k="name" v="A"/>
+    </node>
+    <node id="20" lat="12" lon="51" uid="24854">
+        <tag k="name" v="B"/>
+    </node>
+    <node id="30" lat="11.2" lon="52" uid="24855">
+        <tag k="name" v="C"/>
+    </node>
+    <node id="40" lat="11.3" lon="51" uid="24854">
+        <tag k="name" v="D"/>
+    </node>
+    <node id="50" lat="10" lon="51">
+        <tag k="name" v="E"/>
+    </node>
+
+    <way id="10" uid="85761">
+        <nd ref="10"/>
+        <nd ref="20"/>
+        <nd ref="30"/>
+        <tag k="name" v="A B C"/>
+        <tag k="oneway" v="true"/>
+        <tag k="highway" v="secondary"/>
+    </way>
+
+    <way id="12" uid="85762">
+        <nd ref="10"/>
+        <nd ref="40"/>
+        <nd ref="30"/>
+        <tag k="name" v="A D C"/>
+        <tag k="highway" v="motorway"/>
+    </way>
+
+    <way id="11" uid="85761">
+        <nd ref="10"/>
+        <nd ref="50"/>
+        <nd ref="30"/>
+        <tag k="name" v="A E C"/>
+        <tag k="highway" v="footway"/>
+    </way>
+
+    <way id="13">
+        <nd ref="20"/>
+        <nd ref="40"/>
+        <nd ref="50"/>
+        <tag k="name" v="B D E"/>
+        <tag k="highway" v="motorway"/>
+        <tag k="maxspeed" v="40"/>
+    </way>
+
+    <!-- TODO relations -->
+</osm>
diff --git a/web/src/test/java/com/graphhopper/http/GraphHopperLandmarksTest.java b/web/src/test/java/com/graphhopper/http/GraphHopperLandmarksTest.java
index 62ed7335c..4446d4e03 100644
--- a/web/src/test/java/com/graphhopper/http/GraphHopperLandmarksTest.java
+++ b/web/src/test/java/com/graphhopper/http/GraphHopperLandmarksTest.java
@@ -54,7 +54,6 @@ public class GraphHopperLandmarksTest {
                 putObject("graph.flag_encoders", "car").
                 putObject("datareader.file", "../core/files/belarus-east.osm.gz").
                 putObject("prepare.min_network_size", 0).
-                putObject("prepare.min_one_way_network_size", 0).
                 putObject("routing.ch.disabling_allowed", true).
                 putObject("routing.lm.disabling_allowed", true).
                 putObject("graph.location", DIR)
diff --git a/web/src/test/java/com/graphhopper/http/resources/CustomWeightingRouteResourceLMTest.java b/web/src/test/java/com/graphhopper/http/resources/CustomWeightingRouteResourceLMTest.java
index 2d4f0335e..bf4fae419 100644
--- a/web/src/test/java/com/graphhopper/http/resources/CustomWeightingRouteResourceLMTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/CustomWeightingRouteResourceLMTest.java
@@ -56,7 +56,6 @@ public class CustomWeightingRouteResourceLMTest {
                 putObject("graph.flag_encoders", "car,foot").
                 putObject("routing.lm.disabling_allowed", true).
                 putObject("prepare.min_network_size", 0).
-                putObject("prepare.min_one_way_network_size", 0).
                 putObject("datareader.file", "../core/files/andorra.osm.pbf").
                 putObject("graph.encoded_values", "surface").
                 putObject("graph.location", DIR)
diff --git a/web/src/test/java/com/graphhopper/http/resources/CustomWeightingRouteResourceTest.java b/web/src/test/java/com/graphhopper/http/resources/CustomWeightingRouteResourceTest.java
index d487db2f6..95130cc6f 100644
--- a/web/src/test/java/com/graphhopper/http/resources/CustomWeightingRouteResourceTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/CustomWeightingRouteResourceTest.java
@@ -42,7 +42,6 @@ public class CustomWeightingRouteResourceTest {
                 putObject("graph.flag_encoders", "bike,car").
                 putObject("routing.ch.disabling_allowed", true).
                 putObject("prepare.min_network_size", 0).
-                putObject("prepare.min_one_way_network_size", 0).
                 putObject("datareader.file", "../core/files/north-bayreuth.osm.gz").
                 putObject("graph.location", DIR).
                 putObject("graph.encoded_values", "max_height,max_weight,max_width,hazmat,toll,surface,track_type").
diff --git a/web/src/test/java/com/graphhopper/http/resources/MvtResourceTest.java b/web/src/test/java/com/graphhopper/http/resources/MvtResourceTest.java
index 0ba23251c..cb9043dca 100644
--- a/web/src/test/java/com/graphhopper/http/resources/MvtResourceTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/MvtResourceTest.java
@@ -62,7 +62,6 @@ public class MvtResourceTest {
                 putObject("graph.flag_encoders", "car").
                 putObject("graph.encoded_values", "road_class,road_environment,max_speed,surface").
                 putObject("prepare.min_network_size", 0).
-                putObject("prepare.min_one_way_network_size", 0).
                 putObject("datareader.file", "../core/files/andorra.osm.pbf").
                 putObject("graph.location", DIR).
                 setProfiles(Collections.singletonList(new Profile("car").setVehicle("car").setWeighting("fastest")));
diff --git a/web/src/test/java/com/graphhopper/http/resources/NearestResourceWithEleTest.java b/web/src/test/java/com/graphhopper/http/resources/NearestResourceWithEleTest.java
index 16d57202b..c9698d5bb 100644
--- a/web/src/test/java/com/graphhopper/http/resources/NearestResourceWithEleTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/NearestResourceWithEleTest.java
@@ -50,7 +50,7 @@ public class NearestResourceWithEleTest {
         config.getGraphHopperConfiguration().
                 putObject("graph.elevation.provider", "srtm").
                 putObject("graph.elevation.cachedir", "../core/files/").
-                putObject("prepare.min_one_way_network_size", 0).
+                putObject("prepare.min_network_size", 0).
                 putObject("graph.flag_encoders", "car").
                 putObject("datareader.file", "../core/files/monaco.osm.gz").
                 putObject("graph.location", dir).
diff --git a/web/src/test/java/com/graphhopper/http/resources/PtIsochroneTest.java b/web/src/test/java/com/graphhopper/http/resources/PtIsochroneTest.java
index 4859f4a24..b9c889ea5 100644
--- a/web/src/test/java/com/graphhopper/http/resources/PtIsochroneTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/PtIsochroneTest.java
@@ -50,7 +50,7 @@ public class PtIsochroneTest {
 
     private static final String GRAPH_LOC = "target/PtIsochroneResourceTest";
     private static final ZoneId zoneId = ZoneId.of("America/Los_Angeles");
-    private GeometryFactory geometryFactory = new GeometryFactory();
+    private final GeometryFactory geometryFactory = new GeometryFactory();
     private static final DropwizardAppExtension<GraphHopperServerConfiguration> app = new DropwizardAppExtension<>(GraphHopperApplication.class, createConfig());
 
     private static GraphHopperServerConfiguration createConfig() {
diff --git a/web/src/test/java/com/graphhopper/http/resources/RouteResourceClientHCTest.java b/web/src/test/java/com/graphhopper/http/resources/RouteResourceClientHCTest.java
index c63e2b725..12d222b44 100644
--- a/web/src/test/java/com/graphhopper/http/resources/RouteResourceClientHCTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/RouteResourceClientHCTest.java
@@ -64,7 +64,6 @@ public class RouteResourceClientHCTest {
                 putObject("graph.flag_encoders", "car,bike").
                 putObject("routing.ch.disabling_allowed", true).
                 putObject("prepare.min_network_size", 0).
-                putObject("prepare.min_one_way_network_size", 0).
                 putObject("graph.elevation.provider", "srtm").
                 putObject("graph.elevation.cachedir", "../core/files/").
                 putObject("datareader.file", "../core/files/andorra.osm.pbf").
diff --git a/web/src/test/java/com/graphhopper/http/resources/RouteResourceIssue1574Test.java b/web/src/test/java/com/graphhopper/http/resources/RouteResourceIssue1574Test.java
index d297c2e2c..3e08de020 100644
--- a/web/src/test/java/com/graphhopper/http/resources/RouteResourceIssue1574Test.java
+++ b/web/src/test/java/com/graphhopper/http/resources/RouteResourceIssue1574Test.java
@@ -53,7 +53,6 @@ public class RouteResourceIssue1574Test {
         config.getGraphHopperConfiguration().
                 putObject("graph.flag_encoders", "car").
                 putObject("prepare.min_network_size", 0).
-                putObject("prepare.min_one_way_network_size", 12).
                 putObject("datareader.file", "../core/files/andorra.osm.pbf").
                 putObject("graph.location", DIR)
                 .setProfiles(Collections.singletonList(
diff --git a/web/src/test/java/com/graphhopper/http/resources/RouteResourceProfileSelectionTest.java b/web/src/test/java/com/graphhopper/http/resources/RouteResourceProfileSelectionTest.java
index 03565c185..bc1072dbc 100644
--- a/web/src/test/java/com/graphhopper/http/resources/RouteResourceProfileSelectionTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/RouteResourceProfileSelectionTest.java
@@ -53,7 +53,6 @@ public class RouteResourceProfileSelectionTest {
                 putObject("graph.flag_encoders", "bike,car,foot").
                 putObject("routing.ch.disabling_allowed", true).
                 putObject("prepare.min_network_size", 0).
-                putObject("prepare.min_one_way_network_size", 0).
                 putObject("datareader.file", "../core/files/monaco.osm.gz").
                 putObject("graph.encoded_values", "road_class,surface,road_environment,max_speed").
                 putObject("graph.location", DIR)
diff --git a/web/src/test/java/com/graphhopper/http/resources/RouteResourceTest.java b/web/src/test/java/com/graphhopper/http/resources/RouteResourceTest.java
index c08edc6bc..69b685d9f 100644
--- a/web/src/test/java/com/graphhopper/http/resources/RouteResourceTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/RouteResourceTest.java
@@ -74,7 +74,6 @@ public class RouteResourceTest {
                 putObject("graph.flag_encoders", "car").
                 putObject("routing.ch.disabling_allowed", true).
                 putObject("prepare.min_network_size", 0).
-                putObject("prepare.min_one_way_network_size", 0).
                 putObject("datareader.file", "../core/files/andorra.osm.pbf").
                 putObject("graph.encoded_values", "road_class,surface,road_environment,max_speed").
                 putObject("graph.location", DIR)
diff --git a/web/src/test/java/com/graphhopper/http/resources/RouteResourceTurnCostsTest.java b/web/src/test/java/com/graphhopper/http/resources/RouteResourceTurnCostsTest.java
index 6af565bba..8560f526e 100644
--- a/web/src/test/java/com/graphhopper/http/resources/RouteResourceTurnCostsTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/RouteResourceTurnCostsTest.java
@@ -55,7 +55,6 @@ public class RouteResourceTurnCostsTest {
                 putObject("graph.flag_encoders", "car|turn_costs=true").
                 putObject("routing.ch.disabling_allowed", true).
                 putObject("prepare.min_network_size", 0).
-                putObject("prepare.min_one_way_network_size", 0).
                 putObject("datareader.file", "../core/files/moscow.osm.gz").
                 putObject("graph.encoded_values", "road_class,surface,road_environment,max_speed").
                 putObject("graph.location", DIR)
diff --git a/web/src/test/java/com/graphhopper/http/resources/RouteResourceWithEleTest.java b/web/src/test/java/com/graphhopper/http/resources/RouteResourceWithEleTest.java
index d100daea2..9cf132d76 100644
--- a/web/src/test/java/com/graphhopper/http/resources/RouteResourceWithEleTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/RouteResourceWithEleTest.java
@@ -50,7 +50,7 @@ public class RouteResourceWithEleTest {
         config.getGraphHopperConfiguration().
                 putObject("graph.elevation.provider", "srtm").
                 putObject("graph.elevation.cachedir", "../core/files/").
-                putObject("prepare.min_one_way_network_size", 0).
+                putObject("prepare.min_network_size", 0).
                 putObject("graph.flag_encoders", "car").
                 putObject("datareader.file", "../core/files/monaco.osm.gz").
                 putObject("graph.location", dir).
diff --git a/web/src/test/java/com/graphhopper/http/resources/SPTResourceTest.java b/web/src/test/java/com/graphhopper/http/resources/SPTResourceTest.java
index 3392b1c07..fa7d3ba98 100644
--- a/web/src/test/java/com/graphhopper/http/resources/SPTResourceTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/SPTResourceTest.java
@@ -97,9 +97,9 @@ public class SPTResourceTest {
         String[] lines = rspCsvString.split("\n");
         assertTrue(lines.length > 500);
         assertEquals("prev_node_id,edge_id,node_id,time,distance", lines[0]);
-        assertEquals("-1,-1,1898,0,0", lines[1]);
-        assertEquals("1898,2274,1324,3817,74", lines[2]);
-        assertEquals("1898,2272,263,13496,262", lines[3]);
+        assertEquals("-1,-1,1884,0,0", lines[1]);
+        assertEquals("1884,2274,1324,3817,74", lines[2]);
+        assertEquals("1884,2272,263,13496,262", lines[3]);
     }
 
     @Test