-
Notifications
You must be signed in to change notification settings - Fork 527
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(server): adoption for off-heap memory management in kout module #2704
base: master
Are you sure you want to change the base?
Changes from all commits
4d4cb22
29b7845
a402ddb
88604cf
a342870
db3ee80
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,7 @@ | |
import java.util.HashSet; | ||
import java.util.Iterator; | ||
import java.util.List; | ||
import java.util.Optional; | ||
import java.util.Set; | ||
|
||
import org.apache.hugegraph.HugeGraph; | ||
|
@@ -34,6 +35,9 @@ | |
import org.apache.hugegraph.backend.id.Id; | ||
import org.apache.hugegraph.backend.query.QueryResults; | ||
import org.apache.hugegraph.core.GraphManager; | ||
import org.apache.hugegraph.memory.MemoryManager; | ||
import org.apache.hugegraph.memory.pool.MemoryPool; | ||
import org.apache.hugegraph.memory.pool.impl.TaskMemoryPool; | ||
import org.apache.hugegraph.structure.HugeVertex; | ||
import org.apache.hugegraph.traversal.algorithm.HugeTraverser; | ||
import org.apache.hugegraph.traversal.algorithm.KoutTraverser; | ||
|
@@ -93,27 +97,40 @@ | |
"'{}', max degree '{}', capacity '{}' and limit '{}'", | ||
graph, source, direction, edgeLabel, depth, | ||
nearest, maxDegree, capacity, limit); | ||
MemoryPool queryPool = MemoryManager.getInstance().addQueryMemoryPool(); | ||
Optional.ofNullable(queryPool).ifPresent(pool -> { | ||
MemoryPool currentTaskPool = pool.addChildPool("kout-main-task"); | ||
MemoryManager.getInstance() | ||
.bindCorrespondingTaskMemoryPool(Thread.currentThread().getName(), | ||
Check warning on line 104 in hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KoutAPI.java Codecov / codecov/patchhugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KoutAPI.java#L102-L104
|
||
(TaskMemoryPool) currentTaskPool); | ||
MemoryPool currentOperationPool = currentTaskPool.addChildPool("kout-main-operation"); | ||
}); | ||
Check warning on line 107 in hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KoutAPI.java Codecov / codecov/patchhugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KoutAPI.java#L106-L107
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add a method like |
||
|
||
ApiMeasurer measure = new ApiMeasurer(); | ||
try { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. prefer to add a wrapper method for MemoryPool init-and-gc, then call the original method? |
||
ApiMeasurer measure = new ApiMeasurer(); | ||
|
||
Id sourceId = VertexAPI.checkAndParseVertexId(source); | ||
Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); | ||
Id sourceId = VertexAPI.checkAndParseVertexId(source); | ||
Directions dir = Directions.convert(EdgeAPI.parseDirection(direction)); | ||
|
||
HugeGraph g = graph(manager, graph); | ||
HugeGraph g = graph(manager, graph); | ||
|
||
Set<Id> ids; | ||
try (KoutTraverser traverser = new KoutTraverser(g)) { | ||
ids = traverser.kout(sourceId, dir, edgeLabel, depth, | ||
nearest, maxDegree, capacity, limit); | ||
measure.addIterCount(traverser.vertexIterCounter.get(), | ||
traverser.edgeIterCounter.get()); | ||
} | ||
Set<Id> ids; | ||
try (KoutTraverser traverser = new KoutTraverser(g)) { | ||
ids = traverser.kout(sourceId, dir, edgeLabel, depth, | ||
nearest, maxDegree, capacity, limit); | ||
measure.addIterCount(traverser.vertexIterCounter.get(), | ||
traverser.edgeIterCounter.get()); | ||
} | ||
|
||
if (count_only) { | ||
return manager.serializer(g, measure.measures()) | ||
.writeMap(ImmutableMap.of("vertices_size", ids.size())); | ||
if (count_only) { | ||
return manager.serializer(g, measure.measures()) | ||
.writeMap(ImmutableMap.of("vertices_size", ids.size())); | ||
Check warning on line 127 in hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KoutAPI.java Codecov / codecov/patchhugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/traversers/KoutAPI.java#L126-L127
|
||
} | ||
return manager.serializer(g, measure.measures()).writeList("vertices", ids); | ||
} finally { | ||
Optional.ofNullable(queryPool) | ||
.ifPresent(pool -> MemoryManager.getInstance().gcQueryMemoryPool(pool)); | ||
} | ||
return manager.serializer(g, measure.measures()).writeList("vertices", ids); | ||
} | ||
|
||
@POST | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -260,6 +260,7 @@ private Iterator<HugeVertex> queryVerticesByIds(IdQuery query) { | |
return QueryResults.emptyIterator(); | ||
} | ||
if (needCacheVertex(vertex)) { | ||
vertex.convertIdToOnHeapIfNeeded(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's ok to just call convert in HeapCache.update(), at the same time, we avoid modifying the code everywhere |
||
this.verticesCache.update(vertex.id(), vertex); | ||
} | ||
return QueryResults.iterator(vertex); | ||
|
@@ -295,6 +296,7 @@ private Iterator<HugeVertex> queryVerticesByIds(IdQuery query) { | |
for (HugeVertex vertex : listIterator.list()) { | ||
// Skip large vertex | ||
if (needCacheVertex(vertex)) { | ||
vertex.convertIdToOnHeapIfNeeded(); | ||
this.verticesCache.update(vertex.id(), vertex); | ||
} | ||
} | ||
|
@@ -353,6 +355,7 @@ protected Iterator<HugeEdge> queryEdgesFromBackend(Query query) { | |
if (edges.isEmpty()) { | ||
this.edgesCache.update(cacheKey, Collections.emptyList()); | ||
} else if (edges.size() <= MAX_CACHE_EDGES_PER_QUERY) { | ||
edges.forEach(HugeEdge::convertIdToOnHeapIfNeeded); | ||
this.edgesCache.update(cacheKey, edges); | ||
} | ||
|
||
|
@@ -378,6 +381,7 @@ protected void commitMutation2Backend(BackendMutation... mutations) { | |
vertexIds[vertexOffset++] = vertex.id(); | ||
if (needCacheVertex(vertex)) { | ||
// Update cache | ||
vertex.convertIdToOnHeapIfNeeded(); | ||
this.verticesCache.updateIfPresent(vertex.id(), vertex); | ||
} else { | ||
// Skip large vertex | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -176,6 +176,9 @@ private void clearCache(boolean notify) { | |
private void updateCache(SchemaElement schema) { | ||
this.resetCachedAllIfReachedCapacity(); | ||
|
||
// convert schema.id to on heap if needed. | ||
schema.convertIdToOnHeapIfNeeded(); | ||
|
||
// update id cache | ||
Id prefixedId = generateId(schema.type(), schema.id()); | ||
this.idCache.update(prefixedId, schema); | ||
|
@@ -204,14 +207,20 @@ private void invalidateCache(HugeType type, Id id) { | |
this.arrayCaches.remove(type, id); | ||
} | ||
|
||
/** | ||
* Ids used in cache must be on-heap object | ||
*/ | ||
private static Id generateId(HugeType type, Id id) { | ||
// NOTE: it's slower performance to use: | ||
// String.format("%x-%s", type.code(), name) | ||
return IdGenerator.of(type.string() + "-" + id.asString()); | ||
return new IdGenerator.StringId(type.string() + "-" + id.asString()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add a OnHeapIdGenerator.of() class? |
||
} | ||
|
||
/** | ||
* Ids used in cache must be on-heap object | ||
*/ | ||
private static Id generateId(HugeType type, String name) { | ||
return IdGenerator.of(type.string() + "-" + name); | ||
return new IdGenerator.StringId(type.string() + "-" + name); | ||
} | ||
|
||
@Override | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -77,7 +77,7 @@ public class MemoryManager { | |
private final MemoryArbitrator memoryArbitrator; | ||
private final ExecutorService arbitrateExecutor; | ||
|
||
private static MemoryMode MEMORY_MODE = MemoryMode.ENABLE_OFF_HEAP_MANAGEMENT; | ||
private static MemoryMode MEMORY_MODE = MemoryMode.DISABLE_MEMORY_MANAGEMENT; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MEMORY_MODE style is only for const var, and if there is only a single MemoryManager, also remove static mark: |
||
|
||
private MemoryManager() { | ||
this.memoryArbitrator = new MemoryArbitratorImpl(this); | ||
|
@@ -89,6 +89,10 @@ private MemoryManager() { | |
} | ||
|
||
public MemoryPool addQueryMemoryPool() { | ||
if (MEMORY_MODE == MemoryMode.DISABLE_MEMORY_MANAGEMENT) { | ||
return null; | ||
} | ||
|
||
int count = queryMemoryPools.size(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. expect this.xx stype There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the difference between QueryMemoryPool and MemoryPool? if no difference, just naming MemoryPool is ok. |
||
String poolName = | ||
QUERY_MEMORY_POOL_NAME_PREFIX + DELIMINATOR + count + DELIMINATOR + | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we bind a MemoryPool for each graph