Coverage Summary for Class: NodeManager (org.ethereum.net)
Class |
Method, %
|
Line, %
|
NodeManager |
0%
(0/11)
|
0%
(0/37)
|
NodeManager$NodeHandlerWithReputation |
0%
(0/2)
|
0%
(0/4)
|
Total |
0%
(0/13)
|
0%
(0/41)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2017 RSK Labs Ltd.
4 * (derived from ethereumJ library, Copyright (c) 2016 <ether.camp>)
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 package org.ethereum.net;
21
22 import co.rsk.net.discovery.PeerExplorer;
23 import org.ethereum.config.SystemProperties;
24 import org.ethereum.net.rlpx.Node;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 import java.util.*;
29 import java.util.concurrent.ConcurrentHashMap;
30 import java.util.stream.Collectors;
31
32 /**
33 * The central class for Peer Discovery machinery.
34 * <p>
35 * The NodeManager manages info on all the Nodes discovered by the peer discovery
36 * protocol, routes protocol messages to the corresponding NodeHandlers and
37 * supplies the info about discovered Nodes and their usage statistics
38 * <p>
39 * Created by Anton Nashatyrev on 16.07.2015.
40 */
41 public class NodeManager {
42 private static final Logger logger = LoggerFactory.getLogger("discover");
43
44 private static final long MAX_NODES = 2000;
45 protected static final long NODES_TRIM_THRESHOLD = MAX_NODES + 1000;
46
47 // to avoid checking for null
48 private static final NodeStatistics DUMMY_STAT = new NodeStatistics();
49
50 private final PeerExplorer peerExplorer;
51
52 private Map<String, NodeHandler> nodeHandlerMap = new ConcurrentHashMap<>();
53
54 private boolean discoveryEnabled;
55
56 public NodeManager(PeerExplorer peerExplorer, SystemProperties config) {
57 this.peerExplorer = peerExplorer;
58 this.discoveryEnabled = config.isPeerDiscoveryEnabled();
59
60 for (Node node : config.peerActive()) {
61 NodeHandler handler = new NodeHandler(node);
62 handler.getNodeStatistics().setPredefined(true);
63 createNodeHandler(node);
64 }
65 }
66
67 private synchronized NodeHandler getNodeHandler(Node n) {
68 String key = n.getHexId();
69 NodeHandler handler = nodeHandlerMap.get(key);
70 return (handler != null) ? handler : createNodeHandler(n);
71 }
72
73 private NodeHandler createNodeHandler(Node n) {
74 NodeHandler handler = new NodeHandler(n);
75 purgeNodeHandlers();
76 nodeHandlerMap.put(n.getHexId(), handler);
77 return handler;
78 }
79
80 public NodeStatistics getNodeStatistics(Node n) {
81 return discoveryEnabled ? getNodeHandler(n).getNodeStatistics() : DUMMY_STAT;
82 }
83
84 public synchronized List<NodeHandler> getNodes(Set<String> nodesInUse) {
85 List<NodeHandler> handlers = new ArrayList<>();
86
87 List<Node> foundNodes = this.peerExplorer.getNodes();
88 if (this.discoveryEnabled && !foundNodes.isEmpty()) {
89 logger.debug("{} Nodes retrieved from the PE.", foundNodes.size());
90 foundNodes.stream().filter(n -> !nodeHandlerMap.containsKey(n.getHexId())).forEach(this::createNodeHandler);
91 }
92
93 for(NodeHandler handler : this.nodeHandlerMap.values()) {
94 if(!nodesInUse.contains(handler.getNode().getHexId())) {
95 handlers.add(handler);
96 }
97 }
98 return handlers;
99 }
100
101 private void purgeNodeHandlers() {
102 if (nodeHandlerMap.size() > NODES_TRIM_THRESHOLD) {
103 //I create a stream
104 List<NodeHandler> toRemove = nodeHandlerMap.values().stream()
105 //collect all reputations first to avoid concurrency issues
106 .map(NodeHandlerWithReputation::new)
107 //sort by reputation
108 .sorted(Comparator.comparingInt(o -> o.reputation))
109 //and just keep the ones that exceeds the MAX_NODES
110 .limit(nodeHandlerMap.size() - MAX_NODES)
111 .map(o -> o.nodeHandler)
112 .collect(Collectors.toList());
113 //Remove them
114 nodeHandlerMap.values().removeAll(toRemove);
115 }
116 }
117
118 private static class NodeHandlerWithReputation {
119 private NodeHandler nodeHandler;
120 private int reputation;
121
122 private NodeHandlerWithReputation(NodeHandler nodeHandler) {
123 this.nodeHandler = nodeHandler;
124 this.reputation = nodeHandler.getNodeStatistics().getReputation();
125 }
126 }
127 }