Skip to content

Commit b2b718b

Browse files
committed
add InetAddress#negativeCache manipulation #17 #19
1 parent 6db29fc commit b2b718b

File tree

6 files changed

+228
-20
lines changed

6 files changed

+228
-20
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.alibaba.dcm;
2+
3+
import java.io.Serializable;
4+
import java.util.ArrayList;
5+
import java.util.List;
6+
7+
import javax.annotation.concurrent.Immutable;
8+
9+
/**
10+
* JVM whole dns cache info, including negative cache.
11+
*
12+
* @author Jerry Lee (oldratlee at gmail dot com)
13+
* @see DnsCacheEntry
14+
* @since 1.2.0
15+
*/
16+
@Immutable
17+
public class DnsCache implements Serializable {
18+
private static final long serialVersionUID = -8614746635950970028L;
19+
20+
private final List<DnsCacheEntry> cache;
21+
private final List<DnsCacheEntry> negativeCache;
22+
23+
public DnsCache(List<DnsCacheEntry> cache, List<DnsCacheEntry> negativeCache) {
24+
this.cache = cache;
25+
this.negativeCache = negativeCache;
26+
}
27+
28+
public List<DnsCacheEntry> getCache() {
29+
// defensive copy
30+
return new ArrayList<DnsCacheEntry>(cache);
31+
}
32+
33+
public List<DnsCacheEntry> getNegativeCache() {
34+
// defensive copy
35+
return new ArrayList<DnsCacheEntry>(negativeCache);
36+
}
37+
38+
@Override
39+
public String toString() {
40+
return "DnsCache{" +
41+
"cache=" + cache +
42+
", negativeCache=" + negativeCache +
43+
'}';
44+
}
45+
46+
@Override
47+
public boolean equals(Object o) {
48+
if (this == o) return true;
49+
if (o == null || getClass() != o.getClass()) return false;
50+
51+
DnsCache dnsCache = (DnsCache) o;
52+
53+
if (cache != null ? !cache.equals(dnsCache.cache) : dnsCache.cache != null)
54+
return false;
55+
return !(negativeCache != null ? !negativeCache.equals(dnsCache.negativeCache) : dnsCache.negativeCache != null);
56+
57+
}
58+
59+
@Override
60+
public int hashCode() {
61+
int result = cache != null ? cache.hashCode() : 0;
62+
result = 31 * result + (negativeCache != null ? negativeCache.hashCode() : 0);
63+
return result;
64+
}
65+
}

src/main/java/com/alibaba/dcm/DnsCacheEntry.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88

99
import javax.annotation.concurrent.Immutable;
1010

11+
/**
12+
* @author Jerry Lee (oldratlee at gmail dot com)
13+
* @see DnsCache
14+
*/
1115
@Immutable
1216
public final class DnsCacheEntry implements Serializable {
1317
private static final long serialVersionUID = -7476648934387757732L;

src/main/java/com/alibaba/dcm/DnsCacheManipulator.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
/**
1313
* Setting dns (in fact dns cache).
14+
* <p/>
15+
* Throw {@link DnsCacheManipulatorException} if operation fail for all methods.
1416
*
1517
* @author Jerry Lee (oldratlee at gmail dot com)
1618
* @see DnsCacheEntry
@@ -133,8 +135,37 @@ public static DnsCacheEntry getDnsCache(String host) {
133135
*
134136
* @return dns cache entries
135137
* @throws DnsCacheManipulatorException Operation fail
138+
* @deprecated use {@link #listDnsCache} instead.
136139
*/
140+
@Deprecated
137141
public static List<DnsCacheEntry> getAllDnsCache() {
142+
return listDnsCache();
143+
}
144+
145+
/**
146+
* Get all dns cache entries.
147+
*
148+
* @return dns cache entries
149+
* @throws DnsCacheManipulatorException Operation fail
150+
* @see #getWholeDnsCache()
151+
* @since 1.2.0
152+
*/
153+
public static List<DnsCacheEntry> listDnsCache() {
154+
try {
155+
return InetAddressCacheUtil.listInetAddressCache().getCache();
156+
} catch (Exception e) {
157+
throw new DnsCacheManipulatorException("Fail to getAllDnsCache, cause: " + e.toString(), e);
158+
}
159+
}
160+
161+
/**
162+
* Get whole dns cache info.
163+
*
164+
* @return dns cache entries
165+
* @throws DnsCacheManipulatorException Operation fail
166+
* @since 1.2.0
167+
*/
168+
public static DnsCache getWholeDnsCache() {
138169
try {
139170
return InetAddressCacheUtil.listInetAddressCache();
140171
} catch (Exception e) {

src/main/java/com/alibaba/dcm/internal/InetAddressCacheUtil.java

Lines changed: 69 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.alibaba.dcm.internal;
22

3+
import com.alibaba.dcm.DnsCache;
34
import com.alibaba.dcm.DnsCacheEntry;
45

56
import java.lang.reflect.Constructor;
@@ -14,6 +15,7 @@
1415
import java.util.Map;
1516
import java.util.regex.Pattern;
1617

18+
import javax.annotation.Nullable;
1719
import javax.annotation.concurrent.GuardedBy;
1820

1921
/**
@@ -41,10 +43,11 @@ public static void setInetAddressCache(String host, String[] ips, long expiratio
4143
IllegalAccessException, InstantiationException, InvocationTargetException,
4244
ClassNotFoundException, NoSuchFieldException {
4345
host = host.toLowerCase();
44-
Object entry = createCacheEntry(host, ips, expiration);
46+
Object entry = newCacheEntry(host, ips, expiration);
4547

4648
synchronized (getAddressCacheFieldOfInetAddress()) {
47-
getCacheFiledOfInetAddress$CacheEntry().put(host, entry);
49+
getCacheFiledOfAddressCacheFiledOfInetAddress().put(host, entry);
50+
getCacheFiledOfNegativeCacheFiledOfInetAddress().remove(host);
4851
}
4952
}
5053

@@ -53,11 +56,12 @@ public static void removeInetAddressCache(String host)
5356
host = host.toLowerCase();
5457

5558
synchronized (getAddressCacheFieldOfInetAddress()) {
56-
getCacheFiledOfInetAddress$CacheEntry().remove(host);
59+
getCacheFiledOfAddressCacheFiledOfInetAddress().remove(host);
60+
getCacheFiledOfNegativeCacheFiledOfInetAddress().remove(host);
5761
}
5862
}
5963

60-
static Object createCacheEntry(String host, String[] ips, long expiration)
64+
static Object newCacheEntry(String host, String[] ips, long expiration)
6165
throws UnknownHostException, ClassNotFoundException, NoSuchMethodException,
6266
IllegalAccessException, InvocationTargetException, InstantiationException {
6367
String className = "java.net.InetAddress$CacheEntry";
@@ -80,35 +84,71 @@ static Object createCacheEntry(String host, String[] ips, long expiration)
8084
/**
8185
* @return {@link InetAddress.Cache#cache} in {@link InetAddress#addressCache}
8286
*/
83-
@SuppressWarnings("unchecked")
8487
@GuardedBy("getAddressCacheFieldOfInetAddress()")
85-
static Map<String, Object> getCacheFiledOfInetAddress$CacheEntry()
88+
static Map<String, Object> getCacheFiledOfAddressCacheFiledOfInetAddress()
89+
throws NoSuchFieldException, IllegalAccessException {
90+
return getCacheFiledOfInetAddress$Cache0(getAddressCacheFieldOfInetAddress());
91+
}
92+
93+
/**
94+
* @return {@link InetAddress.Cache#cache} in {@link InetAddress#negativeCache}
95+
*/
96+
@GuardedBy("getAddressCacheFieldOfInetAddress()")
97+
static Map<String, Object> getCacheFiledOfNegativeCacheFiledOfInetAddress()
98+
throws NoSuchFieldException, IllegalAccessException {
99+
return getCacheFiledOfInetAddress$Cache0(getNegativeCacheFieldOfInetAddress());
100+
}
101+
102+
@SuppressWarnings("unchecked")
103+
static Map<String, Object> getCacheFiledOfInetAddress$Cache0(Object inetAddressCache)
86104
throws NoSuchFieldException, IllegalAccessException {
87-
final Object inetAddressCache = getAddressCacheFieldOfInetAddress();
88105
Class clazz = inetAddressCache.getClass();
89106

90107
final Field cacheMapField = clazz.getDeclaredField("cache");
91108
cacheMapField.setAccessible(true);
92109
return (Map<String, Object>) cacheMapField.get(inetAddressCache);
93110
}
94111

95-
static volatile Object ADDRESS_CACHE = null;
96-
97112
/**
98113
* @return {@link InetAddress#addressCache}
99114
*/
100115
static Object getAddressCacheFieldOfInetAddress()
101116
throws NoSuchFieldException, IllegalAccessException {
102-
if (ADDRESS_CACHE == null) {
117+
return getAddressCacheFieldsOfInetAddress0()[0];
118+
}
119+
120+
/**
121+
* @return {@link InetAddress#negativeCache}
122+
*/
123+
static Object getNegativeCacheFieldOfInetAddress()
124+
throws NoSuchFieldException, IllegalAccessException {
125+
return getAddressCacheFieldsOfInetAddress0()[1];
126+
}
127+
128+
static volatile Object[] ADDRESS_CACHE_AND_NEGATIVE_CACHE = null;
129+
130+
/**
131+
* @return {@link InetAddress#addressCache} and {@link InetAddress#negativeCache}
132+
*/
133+
static Object[] getAddressCacheFieldsOfInetAddress0()
134+
throws NoSuchFieldException, IllegalAccessException {
135+
if (ADDRESS_CACHE_AND_NEGATIVE_CACHE == null) {
103136
synchronized (InetAddressCacheUtil.class) {
104-
if (ADDRESS_CACHE == null) { // double check
137+
if (ADDRESS_CACHE_AND_NEGATIVE_CACHE == null) { // double check
105138
final Field cacheField = InetAddress.class.getDeclaredField("addressCache");
106139
cacheField.setAccessible(true);
107-
ADDRESS_CACHE = cacheField.get(InetAddress.class);
140+
141+
final Field negativeCacheField = InetAddress.class.getDeclaredField("negativeCache");
142+
negativeCacheField.setAccessible(true);
143+
144+
ADDRESS_CACHE_AND_NEGATIVE_CACHE = new Object[]{
145+
cacheField.get(InetAddress.class),
146+
negativeCacheField.get(InetAddress.class)
147+
};
108148
}
109149
}
110150
}
111-
return ADDRESS_CACHE;
151+
return ADDRESS_CACHE_AND_NEGATIVE_CACHE;
112152
}
113153

114154
static InetAddress[] toInetAddressArray(String host, String[] ips) throws UnknownHostException {
@@ -136,31 +176,39 @@ static byte[] ip2ByteArray(String ip) {
136176
return address;
137177
}
138178

179+
@Nullable
139180
public static DnsCacheEntry getInetAddressCache(String host)
140181
throws NoSuchFieldException, IllegalAccessException {
141182
host = host.toLowerCase();
142183

143184
Object cacheEntry;
144185
synchronized (getAddressCacheFieldOfInetAddress()) {
145-
cacheEntry = getCacheFiledOfInetAddress$CacheEntry().get(host);
186+
cacheEntry = getCacheFiledOfAddressCacheFiledOfInetAddress().get(host);
146187
}
147188
return inetAddress$CacheEntry2DnsCacheEntry(host, cacheEntry);
148189
}
149190

150-
public static List<DnsCacheEntry> listInetAddressCache()
191+
public static DnsCache listInetAddressCache()
151192
throws NoSuchFieldException, IllegalAccessException {
152-
List<DnsCacheEntry> list = new ArrayList<DnsCacheEntry>();
153193

154194
final Map<String, Object> cache;
195+
final Map<String, Object> negativeCache;
155196
synchronized (getAddressCacheFieldOfInetAddress()) {
156-
cache = new HashMap<String, Object>(getCacheFiledOfInetAddress$CacheEntry());
197+
cache = new HashMap<String, Object>(getCacheFiledOfAddressCacheFiledOfInetAddress());
198+
negativeCache = new HashMap<String, Object>(getCacheFiledOfNegativeCacheFiledOfInetAddress());
157199
}
158200

201+
List<DnsCacheEntry> retCache = new ArrayList<DnsCacheEntry>();
159202
for (Map.Entry<String, Object> entry : cache.entrySet()) {
160203
final String host = entry.getKey();
161-
list.add(inetAddress$CacheEntry2DnsCacheEntry(host, entry.getValue()));
204+
retCache.add(inetAddress$CacheEntry2DnsCacheEntry(host, entry.getValue()));
205+
}
206+
List<DnsCacheEntry> retNegativeCache = new ArrayList<DnsCacheEntry>();
207+
for (Map.Entry<String, Object> entry : negativeCache.entrySet()) {
208+
final String host = entry.getKey();
209+
retNegativeCache.add(inetAddress$CacheEntry2DnsCacheEntry(host, entry.getValue()));
162210
}
163-
return list;
211+
return new DnsCache(retCache, retNegativeCache);
164212
}
165213

166214

@@ -212,7 +260,8 @@ public static List<DnsCacheEntry> listInetAddressCache()
212260

213261
public static void clearInetAddressCache() throws NoSuchFieldException, IllegalAccessException {
214262
synchronized (getAddressCacheFieldOfInetAddress()) {
215-
getCacheFiledOfInetAddress$CacheEntry().clear();
263+
getCacheFiledOfAddressCacheFiledOfInetAddress().clear();
264+
getCacheFiledOfNegativeCacheFiledOfInetAddress().clear();
216265
}
217266
}
218267

src/test/java/com/alibaba/dcm/DnsCacheEntryTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,13 @@ public void test_getter() throws Exception {
6363
assertEquals("1.1.1.1", entryIps.getIp());
6464
assertArrayEquals(new String[]{"1.1.1.1", "2.2.2.2"}, entryIps.getIps());
6565
}
66+
67+
@Test
68+
public void test_toString() throws Exception {
69+
final Date expiration = new Date();
70+
DnsCacheEntry entry = new DnsCacheEntry("a.com", new String[]{"1.1.1.1"}, expiration);
71+
72+
String expected = String.format("DnsCacheEntry{host='a.com', ips=[1.1.1.1], expiration=%s}", expiration);
73+
assertEquals(expected, entry.toString());
74+
}
6675
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.alibaba.dcm;
2+
3+
import org.junit.Test;
4+
5+
import java.util.ArrayList;
6+
import java.util.Arrays;
7+
import java.util.Date;
8+
9+
import static org.junit.Assert.*;
10+
11+
/**
12+
* @author Jerry Lee (oldratlee at gmail dot com)
13+
*/
14+
public class DnsCacheTest {
15+
@Test
16+
public void test_equals() throws Exception {
17+
final Date expiration = new Date();
18+
DnsCacheEntry entry1 = new DnsCacheEntry("a.com", new String[]{"1.1.1.1"}, expiration);
19+
DnsCacheEntry entry2 = new DnsCacheEntry("b.com", new String[]{"1.1.1.2"}, expiration);
20+
DnsCacheEntry entry3 = new DnsCacheEntry("c.com", new String[]{"1.1.1.2"}, expiration);
21+
DnsCacheEntry entry4 = new DnsCacheEntry("d.com", new String[]{"1.1.1.2"}, expiration);
22+
23+
DnsCache dnsCache1 = new DnsCache(
24+
Arrays.asList(entry1, entry2),
25+
Arrays.asList(entry3));
26+
DnsCache dnsCache2 = new DnsCache(
27+
Arrays.asList(entry1, entry2),
28+
Arrays.asList(entry4));
29+
30+
assertNotEquals(dnsCache1, dnsCache2);
31+
}
32+
33+
@Test
34+
public void test_toString() throws Exception {
35+
final Date expiration = new Date();
36+
DnsCacheEntry entry1 = new DnsCacheEntry("a.com", new String[]{"1.1.1.1"}, expiration);
37+
DnsCacheEntry entry2 = new DnsCacheEntry("b.com", new String[]{"1.1.1.2"}, expiration);
38+
DnsCacheEntry entry3 = new DnsCacheEntry("c.com", new String[]{"1.1.1.2"}, expiration);
39+
40+
DnsCache dnsCache = new DnsCache(
41+
Arrays.asList(entry1, entry2),
42+
Arrays.asList(entry3));
43+
44+
String expected = String.format("DnsCache{cache=[DnsCacheEntry{host='a.com', ips=[1.1.1.1], expiration=%s}" +
45+
", DnsCacheEntry{host='b.com', ips=[1.1.1.2], expiration=%<s}]" +
46+
", negativeCache=[DnsCacheEntry{host='c.com', ips=[1.1.1.2], expiration=%<s}]}", expiration);
47+
48+
assertEquals(expected, dnsCache.toString());
49+
}
50+
}

0 commit comments

Comments
 (0)