Skip to content

Commit efe8ead

Browse files
committed
optimize InetUtil and BackupManager
1 parent 7c5bdf7 commit efe8ead

6 files changed

Lines changed: 230 additions & 133 deletions

File tree

framework/src/main/java/org/tron/common/backup/BackupManager.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,7 @@ public class BackupManager implements EventHandler {
5252
ExecutorServiceManager.newSingleThreadScheduledExecutor(esName);
5353

5454
private final String dnsEsName = "backup-dns-refresh";
55-
private final ScheduledExecutorService dnsExecutorService =
56-
ExecutorServiceManager.newSingleThreadScheduledExecutor(dnsEsName);
55+
private ScheduledExecutorService dnsExecutorService;
5756

5857
@Setter
5958
private MessageHandler messageHandler;
@@ -128,6 +127,7 @@ public void init() {
128127
}, 1000, keepAliveInterval, TimeUnit.MILLISECONDS);
129128

130129
if (!domainIpCache.isEmpty()) {
130+
dnsExecutorService = ExecutorServiceManager.newSingleThreadScheduledExecutor(dnsEsName);
131131
dnsExecutorService.scheduleWithFixedDelay(() -> {
132132
try {
133133
refreshMemberIps();
@@ -174,7 +174,9 @@ public void handleEvent(UdpEvent udpEvent) {
174174

175175
public void stop() {
176176
ExecutorServiceManager.shutdownAndAwaitTermination(executorService, esName);
177-
ExecutorServiceManager.shutdownAndAwaitTermination(dnsExecutorService, dnsEsName);
177+
if (dnsExecutorService != null) {
178+
ExecutorServiceManager.shutdownAndAwaitTermination(dnsExecutorService, dnsEsName);
179+
}
178180
}
179181

180182
@Override

framework/src/main/java/org/tron/core/config/args/InetUtil.java

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@
55
import java.net.UnknownHostException;
66
import java.util.ArrayList;
77
import java.util.HashMap;
8+
import java.util.LinkedHashMap;
89
import java.util.List;
910
import java.util.Map;
1011
import java.util.concurrent.ExecutionException;
1112
import java.util.concurrent.ExecutorService;
1213
import java.util.concurrent.Future;
14+
import java.util.concurrent.TimeUnit;
15+
import java.util.concurrent.TimeoutException;
16+
import java.util.function.BiFunction;
1317
import lombok.extern.slf4j.Slf4j;
1418
import org.tron.common.es.ExecutorServiceManager;
1519
import org.tron.p2p.dns.lookup.LookUpTxt;
@@ -20,6 +24,13 @@ public class InetUtil {
2024

2125
private static final String DNS_POOL_NAME = "args-dns-lookup";
2226
private static final int DNS_POOL_MAX_SIZE = 10;
27+
// Per-lookup wall-clock budget. After this, the entry is treated as unresolvable.
28+
private static final long DNS_LOOKUP_TIMEOUT_SECONDS = 10;
29+
30+
// Overridable in tests so worker threads (parallel path) can use a non-network lookup.
31+
// Reset to LookUpTxt::lookUpIp after each test that overrides it.
32+
public static volatile BiFunction<String, Boolean, InetAddress> dnsLookup =
33+
LookUpTxt::lookUpIp;
2334

2435
/**
2536
* Converts a list of {@code ipOrDomain:port} config strings into resolved {@link
@@ -48,10 +59,13 @@ public static List<InetSocketAddress> resolveInetSocketAddressList(
4859
return result;
4960
}
5061

51-
// Collect entries whose host part is a domain name (not an IP literal).
62+
// Single pass: parse every entry once; collect domain entries for DNS resolution.
63+
LinkedHashMap<String, InetSocketAddress> parsedMap = new LinkedHashMap<>();
5264
List<String> domainEntries = new ArrayList<>();
5365
for (String item : ipOrDomainWithPortList) {
54-
if (!isIpLiteral(NetUtil.parseInetSocketAddress(item).getHostString())) {
66+
InetSocketAddress parsed = NetUtil.parseInetSocketAddress(item);
67+
parsedMap.put(item, parsed);
68+
if (!isIpLiteral(parsed.getHostString())) {
5569
domainEntries.add(item);
5670
}
5771
}
@@ -69,12 +83,17 @@ public static List<InetSocketAddress> resolveInetSocketAddressList(
6983
for (int i = 0; i < domainEntries.size(); i++) {
7084
String entry = domainEntries.get(i);
7185
try {
72-
resolvedDomains.put(entry, futures.get(i).get());
86+
resolvedDomains.put(entry,
87+
futures.get(i).get(DNS_LOOKUP_TIMEOUT_SECONDS, TimeUnit.SECONDS));
7388
} catch (InterruptedException e) {
7489
Thread.currentThread().interrupt();
7590
logger.warn("DNS lookup interrupted for: {}", entry);
91+
break;
7692
} catch (ExecutionException e) {
7793
logger.warn("Failed to resolve address, skip: {}", entry);
94+
} catch (TimeoutException e) {
95+
logger.warn("DNS lookup timed out after {}s, skip: {}", DNS_LOOKUP_TIMEOUT_SECONDS,
96+
entry);
7897
}
7998
}
8099
ExecutorServiceManager.shutdownAndAwaitTermination(dnsPool, DNS_POOL_NAME);
@@ -84,8 +103,9 @@ public static List<InetSocketAddress> resolveInetSocketAddressList(
84103
}
85104

86105
// Build the result list preserving the original config order.
87-
for (String item : ipOrDomainWithPortList) {
88-
InetSocketAddress parsed = NetUtil.parseInetSocketAddress(item);
106+
for (Map.Entry<String, InetSocketAddress> entry : parsedMap.entrySet()) {
107+
String item = entry.getKey();
108+
InetSocketAddress parsed = entry.getValue();
89109
InetSocketAddress resolved = isIpLiteral(parsed.getHostString())
90110
? parsed
91111
: resolvedDomains.get(item);
@@ -109,9 +129,9 @@ private static InetSocketAddress resolveInetSocketAddress(String ipOrDomainWithP
109129
InetSocketAddress parsed = NetUtil.parseInetSocketAddress(ipOrDomainWithPort);
110130
String host = parsed.getHostString();
111131
int port = parsed.getPort();
112-
InetAddress address = LookUpTxt.lookUpIp(host, true);
132+
InetAddress address = dnsLookup.apply(host, true);
113133
if (address == null) {
114-
address = LookUpTxt.lookUpIp(host, false);
134+
address = dnsLookup.apply(host, false);
115135
}
116136
if (address == null) {
117137
return null;
@@ -138,9 +158,9 @@ public static InetAddress resolveInetAddress(String ipOrDomain) {
138158
return null;
139159
}
140160
}
141-
InetAddress address = LookUpTxt.lookUpIp(ipOrDomain, true);
161+
InetAddress address = dnsLookup.apply(ipOrDomain, true);
142162
if (address == null) {
143-
address = LookUpTxt.lookUpIp(ipOrDomain, false);
163+
address = dnsLookup.apply(ipOrDomain, false);
144164
}
145165
return address;
146166
}

framework/src/test/java/org/tron/common/backup/BackupManagerTest.java

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package org.tron.common.backup;
22

3-
import static org.mockito.Mockito.mockStatic;
4-
53
import java.lang.reflect.Field;
64
import java.lang.reflect.Method;
75
import java.net.InetAddress;
@@ -13,13 +11,13 @@
1311
import java.util.Set;
1412
import java.util.concurrent.ExecutorService;
1513
import java.util.concurrent.ScheduledExecutorService;
14+
import java.util.function.BiFunction;
1615
import org.junit.After;
1716
import org.junit.Assert;
1817
import org.junit.Before;
1918
import org.junit.Rule;
2019
import org.junit.Test;
2120
import org.junit.rules.TemporaryFolder;
22-
import org.mockito.MockedStatic;
2321
import org.tron.common.TestConstants;
2422
import org.tron.common.backup.BackupManager.BackupStatusEnum;
2523
import org.tron.common.backup.message.KeepAliveMessage;
@@ -28,14 +26,15 @@
2826
import org.tron.common.parameter.CommonParameter;
2927
import org.tron.common.utils.PublicMethod;
3028
import org.tron.core.config.args.Args;
31-
import org.tron.p2p.dns.lookup.LookUpTxt;
29+
import org.tron.core.config.args.InetUtil;
3230

3331
public class BackupManagerTest {
3432

3533
@Rule
3634
public TemporaryFolder temporaryFolder = new TemporaryFolder();
3735
private BackupManager manager;
3836
private BackupServer backupServer;
37+
private BiFunction<String, Boolean, InetAddress> savedLookup;
3938

4039
@Before
4140
public void setUp() throws Exception {
@@ -44,10 +43,12 @@ public void setUp() throws Exception {
4443
CommonParameter.getInstance().setBackupPort(PublicMethod.chooseRandomPort());
4544
manager = new BackupManager();
4645
backupServer = new BackupServer(manager);
46+
savedLookup = InetUtil.dnsLookup;
4747
}
4848

4949
@After
5050
public void tearDown() {
51+
InetUtil.dnsLookup = savedLookup;
5152
Args.clearParam();
5253
}
5354

@@ -157,10 +158,9 @@ public void testInitResolvesDomainsToMembers() throws Exception {
157158
CommonParameter.getInstance().setBackupMembers(
158159
Collections.singletonList("node.example.com"));
159160
InetAddress resolved = InetAddress.getByName("1.2.3.4");
160-
try (MockedStatic<LookUpTxt> mock = mockStatic(LookUpTxt.class)) {
161-
mock.when(() -> LookUpTxt.lookUpIp("node.example.com", true)).thenReturn(resolved);
162-
manager.init();
163-
}
161+
InetUtil.dnsLookup = (host, ipv4) ->
162+
("node.example.com".equals(host) && ipv4) ? resolved : null;
163+
manager.init();
164164
Set<String> members = getField(manager, "members");
165165
Map<String, String> cache = getField(manager, "domainIpCache");
166166
Assert.assertTrue(members.contains("1.2.3.4"));
@@ -172,11 +172,8 @@ public void testInitResolvesDomainsToMembers() throws Exception {
172172
public void testInitSkipsUnresolvableDomain() throws Exception {
173173
CommonParameter.getInstance().setBackupMembers(
174174
Collections.singletonList("bad.invalid.domain"));
175-
try (MockedStatic<LookUpTxt> mock = mockStatic(LookUpTxt.class)) {
176-
mock.when(() -> LookUpTxt.lookUpIp("bad.invalid.domain", true)).thenReturn(null);
177-
mock.when(() -> LookUpTxt.lookUpIp("bad.invalid.domain", false)).thenReturn(null);
178-
manager.init();
179-
}
175+
InetUtil.dnsLookup = (host, ipv4) -> null;
176+
manager.init();
180177
Set<String> members = getField(manager, "members");
181178
Map<String, String> cache = getField(manager, "domainIpCache");
182179
Assert.assertTrue("unresolvable domain should be silently dropped", members.isEmpty());
@@ -190,10 +187,9 @@ public void testInitSkipsDomainResolvingToLocalIp() throws Exception {
190187
CommonParameter.getInstance().setBackupMembers(
191188
Collections.singletonList("self.local.host"));
192189
InetAddress selfAddr = InetAddress.getByName(localIp);
193-
try (MockedStatic<LookUpTxt> mock = mockStatic(LookUpTxt.class)) {
194-
mock.when(() -> LookUpTxt.lookUpIp("self.local.host", true)).thenReturn(selfAddr);
195-
manager.init();
196-
}
190+
InetUtil.dnsLookup = (host, ipv4) ->
191+
("self.local.host".equals(host) && ipv4) ? selfAddr : null;
192+
manager.init();
197193
Set<String> members = getField(manager, "members");
198194
Assert.assertFalse("domain resolving to local IP should not be in members",
199195
members.contains(localIp));
@@ -210,10 +206,9 @@ public void testRefreshMemberIpsIpChanged() throws Exception {
210206
cache.put("peer.tron.network", "1.1.1.1");
211207

212208
InetAddress newAddr = InetAddress.getByName("2.2.2.2");
213-
try (MockedStatic<LookUpTxt> mock = mockStatic(LookUpTxt.class)) {
214-
mock.when(() -> LookUpTxt.lookUpIp("peer.tron.network", true)).thenReturn(newAddr);
215-
invokeRefreshMemberIps(manager);
216-
}
209+
InetUtil.dnsLookup = (host, ipv4) ->
210+
("peer.tron.network".equals(host) && ipv4) ? newAddr : null;
211+
invokeRefreshMemberIps(manager);
217212
Assert.assertFalse(members.contains("1.1.1.1"));
218213
Assert.assertTrue(members.contains("2.2.2.2"));
219214
Assert.assertEquals("2.2.2.2", cache.get("peer.tron.network"));
@@ -227,10 +222,9 @@ public void testRefreshMemberIpsIpUnchanged() throws Exception {
227222
cache.put("peer.tron.network", "1.1.1.1");
228223

229224
InetAddress sameAddr = InetAddress.getByName("1.1.1.1");
230-
try (MockedStatic<LookUpTxt> mock = mockStatic(LookUpTxt.class)) {
231-
mock.when(() -> LookUpTxt.lookUpIp("peer.tron.network", true)).thenReturn(sameAddr);
232-
invokeRefreshMemberIps(manager);
233-
}
225+
InetUtil.dnsLookup = (host, ipv4) ->
226+
("peer.tron.network".equals(host) && ipv4) ? sameAddr : null;
227+
invokeRefreshMemberIps(manager);
234228
Assert.assertTrue(members.contains("1.1.1.1"));
235229
Assert.assertEquals("1.1.1.1", cache.get("peer.tron.network"));
236230
}
@@ -242,11 +236,8 @@ public void testRefreshMemberIpsDnsFailure() throws Exception {
242236
members.add("1.1.1.1");
243237
cache.put("peer.tron.network", "1.1.1.1");
244238

245-
try (MockedStatic<LookUpTxt> mock = mockStatic(LookUpTxt.class)) {
246-
mock.when(() -> LookUpTxt.lookUpIp("peer.tron.network", true)).thenReturn(null);
247-
mock.when(() -> LookUpTxt.lookUpIp("peer.tron.network", false)).thenReturn(null);
248-
invokeRefreshMemberIps(manager);
249-
}
239+
InetUtil.dnsLookup = (host, ipv4) -> null;
240+
invokeRefreshMemberIps(manager);
250241
Assert.assertTrue("old IP should be kept on DNS failure", members.contains("1.1.1.1"));
251242
Assert.assertEquals("1.1.1.1", cache.get("peer.tron.network"));
252243
}

framework/src/test/java/org/tron/core/config/args/ArgsTest.java

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515

1616
package org.tron.core.config.args;
1717

18-
import static org.mockito.Mockito.mockStatic;
19-
2018
import com.google.common.collect.Lists;
2119
import com.typesafe.config.Config;
2220
import com.typesafe.config.ConfigFactory;
@@ -28,13 +26,14 @@
2826
import java.util.Arrays;
2927
import java.util.HashMap;
3028
import java.util.Map;
29+
import java.util.function.BiFunction;
3130
import lombok.extern.slf4j.Slf4j;
3231
import org.junit.After;
3332
import org.junit.Assert;
33+
import org.junit.Before;
3434
import org.junit.Rule;
3535
import org.junit.Test;
3636
import org.junit.rules.ExpectedException;
37-
import org.mockito.MockedStatic;
3837
import org.tron.common.TestConstants;
3938
import org.tron.common.args.GenesisBlock;
4039
import org.tron.common.parameter.CommonParameter;
@@ -44,20 +43,26 @@
4443
import org.tron.common.utils.PublicMethod;
4544
import org.tron.core.config.Configuration;
4645
import org.tron.core.exception.TronError;
47-
import org.tron.p2p.dns.lookup.LookUpTxt;
4846

4947
@Slf4j
5048
public class ArgsTest {
5149

5250
private final String privateKey = PublicMethod.getRandomPrivateKey();
5351
private String address;
5452
private LocalWitnesses localWitnesses;
53+
private BiFunction<String, Boolean, InetAddress> savedLookup;
5554

5655
@Rule
5756
public ExpectedException thrown = ExpectedException.none();
5857

58+
@Before
59+
public void saveLookup() {
60+
savedLookup = InetUtil.dnsLookup;
61+
}
62+
5963
@After
6064
public void destroy() {
65+
InetUtil.dnsLookup = savedLookup;
6166
Args.clearParam();
6267
}
6368

@@ -440,17 +445,14 @@ public void testCheckBackupMembersUnresolvableDomainThrows() throws Exception {
440445
Arrays.asList("bad.invalid.domain"));
441446
Method method = Args.class.getDeclaredMethod("checkBackupMembers");
442447
method.setAccessible(true);
443-
try (MockedStatic<LookUpTxt> mock = mockStatic(LookUpTxt.class)) {
444-
mock.when(() -> LookUpTxt.lookUpIp("bad.invalid.domain", true)).thenReturn(null);
445-
mock.when(() -> LookUpTxt.lookUpIp("bad.invalid.domain", false)).thenReturn(null);
446-
try {
447-
method.invoke(null);
448-
Assert.fail("Expected InvocationTargetException wrapping TronError");
449-
} catch (InvocationTargetException ex) {
450-
Assert.assertTrue(ex.getCause() instanceof TronError);
451-
Assert.assertEquals(TronError.ErrCode.PARAMETER_INIT,
452-
((TronError) ex.getCause()).getErrCode());
453-
}
448+
InetUtil.dnsLookup = (host, ipv4) -> null;
449+
try {
450+
method.invoke(null);
451+
Assert.fail("Expected InvocationTargetException wrapping TronError");
452+
} catch (InvocationTargetException ex) {
453+
Assert.assertTrue(ex.getCause() instanceof TronError);
454+
Assert.assertEquals(TronError.ErrCode.PARAMETER_INIT,
455+
((TronError) ex.getCause()).getErrCode());
454456
}
455457
}
456458

@@ -462,10 +464,9 @@ public void testCheckBackupMembersResolvableDomainPasses() throws Exception {
462464
Method method = Args.class.getDeclaredMethod("checkBackupMembers");
463465
method.setAccessible(true);
464466
InetAddress mockAddr = InetAddress.getByName("5.5.5.5");
465-
try (MockedStatic<LookUpTxt> mock = mockStatic(LookUpTxt.class)) {
466-
mock.when(() -> LookUpTxt.lookUpIp("peer.tron.network", true)).thenReturn(mockAddr);
467-
method.invoke(null);
468-
}
467+
InetUtil.dnsLookup = (host, ipv4) ->
468+
("peer.tron.network".equals(host) && ipv4) ? mockAddr : null;
469+
method.invoke(null);
469470
}
470471
}
471472

0 commit comments

Comments
 (0)