Skip to content

Commit 47dd046

Browse files
committed
refactor(pd): refactor common module
1 parent 0946d5d commit 47dd046

10 files changed

Lines changed: 400 additions & 55 deletions

File tree

hugegraph-pd/hg-pd-client/src/main/java/org/apache/hugegraph/pd/client/ClientCache.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ private GraphCache getGraphCache(String graphName) {
6161
if ((graph = caches.get(graphName)) == null) {
6262
synchronized (caches) {
6363
if ((graph = caches.get(graphName)) == null) {
64-
graph = new GraphCache();
64+
Metapb.Graph.Builder builder = Metapb.Graph.newBuilder().setGraphName(graphName);
65+
Metapb.Graph g = builder.build();
66+
graph = new GraphCache(g);
6567
caches.put(graphName, graph);
6668
}
6769
}

hugegraph-pd/hg-pd-common/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,10 @@
4444
<artifactId>commons-collections4</artifactId>
4545
<version>4.4</version>
4646
</dependency>
47+
<dependency>
48+
<groupId>org.apache.logging.log4j</groupId>
49+
<artifactId>log4j-slf4j-impl</artifactId>
50+
<version>${log4j2.version}</version>
51+
</dependency>
4752
</dependencies>
4853
</project>
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.hugegraph.pd.common;
19+
20+
import java.io.Closeable;
21+
import java.io.IOException;
22+
import java.util.Map;
23+
import java.util.concurrent.ConcurrentHashMap;
24+
import java.util.concurrent.ConcurrentMap;
25+
import java.util.concurrent.Executors;
26+
import java.util.concurrent.ScheduledExecutorService;
27+
import java.util.concurrent.ScheduledFuture;
28+
import java.util.concurrent.TimeUnit;
29+
30+
public class Cache<T> implements Closeable {
31+
32+
ScheduledExecutorService ex =
33+
Executors.newSingleThreadScheduledExecutor(new DefaultThreadFactory("hg-cache"));
34+
private ConcurrentMap<String, CacheValue> map = new ConcurrentHashMap();
35+
private ScheduledFuture<?> future;
36+
private Runnable checker = () -> {
37+
for (Map.Entry<String, CacheValue> e : map.entrySet()) {
38+
if (e.getValue().getValue() == null) {
39+
map.remove(e.getKey());
40+
}
41+
}
42+
};
43+
44+
public Cache() {
45+
future = ex.scheduleWithFixedDelay(checker, 1, 1, TimeUnit.SECONDS);
46+
}
47+
48+
public CacheValue put(String key, T value, long ttl) {
49+
return map.put(key, new CacheValue(value, ttl));
50+
}
51+
52+
public T get(String key) {
53+
CacheValue value = map.get(key);
54+
if (value == null) {
55+
return null;
56+
}
57+
T t = value.getValue();
58+
if (t == null) {
59+
map.remove(key);
60+
}
61+
return t;
62+
}
63+
64+
public boolean keepAlive(String key, long ttl) {
65+
CacheValue value = map.get(key);
66+
if (value == null) {
67+
return false;
68+
}
69+
value.keepAlive(ttl);
70+
return true;
71+
}
72+
73+
@Override
74+
public void close() throws IOException {
75+
try {
76+
future.cancel(true);
77+
ex.shutdownNow();
78+
} catch (Exception e) {
79+
try {
80+
ex.shutdownNow();
81+
} catch (Exception ex) {
82+
83+
}
84+
}
85+
}
86+
87+
private class CacheValue {
88+
89+
private final T value;
90+
long outTime;
91+
92+
protected CacheValue(T value, long ttl) {
93+
this.value = value;
94+
this.outTime = System.currentTimeMillis() + ttl;
95+
}
96+
97+
protected T getValue() {
98+
if (System.currentTimeMillis() >= outTime) {
99+
return null;
100+
}
101+
return value;
102+
}
103+
104+
protected void keepAlive(long ttl) {
105+
this.outTime = System.currentTimeMillis() + ttl;
106+
}
107+
108+
}
109+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.hugegraph.pd.common;
19+
20+
import io.grpc.Metadata;
21+
22+
public class Consts {
23+
24+
public static final Metadata.Key<String> CREDENTIAL_KEY = Metadata.Key.of("credential",
25+
Metadata.ASCII_STRING_MARSHALLER);
26+
public static final Metadata.Key<String> TOKEN_KEY = Metadata.Key.of("Pd-Token",
27+
Metadata.ASCII_STRING_MARSHALLER);
28+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.hugegraph.pd.common;
19+
20+
import java.util.concurrent.ThreadFactory;
21+
import java.util.concurrent.atomic.AtomicInteger;
22+
23+
public class DefaultThreadFactory implements ThreadFactory {
24+
25+
private final AtomicInteger number = new AtomicInteger(1);
26+
private final String prefix;
27+
28+
public DefaultThreadFactory(String prefix) {
29+
this.prefix = prefix + "-";
30+
}
31+
32+
@Override
33+
public Thread newThread(Runnable r) {
34+
Thread t = new Thread(r, prefix + number.getAndIncrement());
35+
t.setDaemon(true);
36+
t.setPriority(Thread.NORM_PRIORITY);
37+
return t;
38+
}
39+
}

hugegraph-pd/hg-pd-common/src/main/java/org/apache/hugegraph/pd/common/GraphCache.java

Lines changed: 94 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,27 @@
1717

1818
package org.apache.hugegraph.pd.common;
1919

20+
import java.util.List;
2021
import java.util.Map;
22+
import java.util.Objects;
2123
import java.util.concurrent.ConcurrentHashMap;
2224
import java.util.concurrent.atomic.AtomicBoolean;
2325
import java.util.concurrent.locks.ReentrantReadWriteLock;
26+
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
2427

25-
import com.google.common.collect.Range;
26-
28+
import org.apache.commons.collections4.CollectionUtils;
2729
import org.apache.hugegraph.pd.grpc.Metapb.Graph;
2830
import org.apache.hugegraph.pd.grpc.Metapb.Partition;
2931

32+
import com.google.common.collect.Range;
3033
import com.google.common.collect.RangeMap;
3134
import com.google.common.collect.TreeRangeMap;
3235

3336
import lombok.Data;
37+
import lombok.extern.slf4j.Slf4j;
3438

3539
@Data
40+
@Slf4j
3641
public class GraphCache {
3742

3843
private Graph graph;
@@ -41,13 +46,30 @@ public class GraphCache {
4146
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
4247
private Map<Integer, AtomicBoolean> state = new ConcurrentHashMap<>();
4348
private Map<Integer, Partition> partitions = new ConcurrentHashMap<>();
44-
private RangeMap<Long, Integer> range = new SynchronizedRangeMap<Long, Integer>().rangeMap;
49+
private volatile RangeMap<Long, Integer> range = TreeRangeMap.create();
4550

4651
public GraphCache(Graph graph) {
4752
this.graph = graph;
4853
}
4954

50-
public GraphCache() {
55+
public void init(List<Partition> ps) {
56+
Map<Integer, Partition> gps = new ConcurrentHashMap<>(ps.size(), 1);
57+
if (!CollectionUtils.isEmpty(ps)) {
58+
WriteLock lock = getLock().writeLock();
59+
try {
60+
lock.lock();
61+
for (Partition p : ps) {
62+
gps.put(p.getId(), p);
63+
range.put(Range.closedOpen(p.getStartKey(), p.getEndKey()), p.getId());
64+
}
65+
} catch (Exception e) {
66+
log.warn("init graph with error:", e);
67+
} finally {
68+
lock.unlock();
69+
}
70+
}
71+
setPartitions(gps);
72+
5173
}
5274

5375
public Partition getPartition(Integer id) {
@@ -59,58 +81,87 @@ public Partition addPartition(Integer id, Partition p) {
5981
}
6082

6183
public Partition removePartition(Integer id) {
84+
Partition p = partitions.get(id);
85+
if (p != null) {
86+
RangeMap<Long, Integer> range = getRange();
87+
if (Objects.equals(p.getId(), range.get(p.getStartKey())) &&
88+
Objects.equals(p.getId(), range.get(p.getEndKey() - 1))) {
89+
WriteLock lock = getLock().writeLock();
90+
lock.lock();
91+
try {
92+
range.remove(range.getEntry(p.getStartKey()).getKey());
93+
} catch (Exception e) {
94+
log.warn("remove partition with error:", e);
95+
} finally {
96+
lock.unlock();
97+
}
98+
}
99+
}
62100
return partitions.remove(id);
63101
}
64102

65-
public class SynchronizedRangeMap<K extends Comparable<K>, V> {
66-
67-
private final RangeMap<K, V> rangeMap = TreeRangeMap.create();
68-
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
69-
70-
public void put(Range<K> range, V value) {
71-
lock.writeLock().lock();
72-
try {
73-
rangeMap.put(range, value);
74-
} finally {
75-
lock.writeLock().unlock();
103+
public void removePartitions() {
104+
getState().clear();
105+
RangeMap<Long, Integer> range = getRange();
106+
WriteLock lock = getLock().writeLock();
107+
try {
108+
lock.lock();
109+
if (range != null) {
110+
range.clear();
76111
}
112+
} catch (Exception e) {
113+
log.warn("remove partition with error:", e);
114+
} finally {
115+
lock.unlock();
77116
}
117+
getPartitions().clear();
118+
getInitialized().set(false);
119+
}
78120

79-
public V get(K key) {
80-
lock.readLock().lock();
81-
try {
82-
return rangeMap.get(key);
83-
} finally {
84-
lock.readLock().unlock();
85-
}
86-
}
121+
/*
122+
* 需要外部加写锁
123+
* */
124+
public void reset() {
125+
partitions.clear();
126+
try {
127+
range.clear();
128+
} catch (Exception e) {
87129

88-
public void remove(Range<K> range) {
89-
lock.writeLock().lock();
90-
try {
91-
rangeMap.remove(range);
92-
} finally {
93-
lock.writeLock().unlock();
94-
}
95130
}
131+
}
96132

97-
public Map.Entry<Range<K>, V> getEntry(K key) {
98-
lock.readLock().lock();
99-
try {
100-
return rangeMap.getEntry(key);
101-
} finally {
102-
lock.readLock().unlock();
103-
}
133+
public boolean updatePartition(Partition partition) {
134+
int partId = partition.getId();
135+
Partition p = getPartition(partId);
136+
if (p != null && p.equals(partition)) {
137+
return false;
104138
}
105-
106-
public void clear() {
107-
lock.writeLock().lock();
139+
WriteLock lock = getLock().writeLock();
140+
try {
141+
lock.lock();
142+
RangeMap<Long, Integer> range = getRange();
143+
addPartition(partId, partition);
108144
try {
109-
rangeMap.clear();
110-
} finally {
111-
lock.writeLock().unlock();
145+
if (p != null) {
146+
// The old [1-3) is overwritten by [2-3). When [1-3) becomes [1-2), the
147+
// original [1-3) should not be deleted.
148+
// Only when it is confirmed that the old start and end are both your own can
149+
// the old be deleted (i.e., before it is overwritten).
150+
if (Objects.equals(partId, range.get(partition.getStartKey())) &&
151+
Objects.equals(partId, range.get(partition.getEndKey() - 1))) {
152+
range.remove(range.getEntry(partition.getStartKey()).getKey());
153+
}
154+
}
155+
range.put(Range.closedOpen(partition.getStartKey(), partition.getEndKey()), partId);
156+
} catch (Exception e) {
157+
log.warn("update partition with error:", e);
112158
}
159+
} catch (Exception e) {
160+
throw new RuntimeException(e);
161+
} finally {
162+
lock.unlock();
113163
}
164+
return true;
114165
}
115166

116167
}

0 commit comments

Comments
 (0)