-
Notifications
You must be signed in to change notification settings - Fork 618
feat(server): adoption for off-heap memory management in kout module #2704
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
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 @@ public String get(@Context GraphManager manager, | |
| "'{}', 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(), | ||
| (TaskMemoryPool) currentTaskPool); | ||
| MemoryPool currentOperationPool = currentTaskPool.addChildPool("kout-main-operation"); | ||
|
Contributor
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. we can let:
|
||
| }); | ||
|
Contributor
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 { | ||
|
Contributor
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())); | ||
| } | ||
| return manager.serializer(g, measure.measures()).writeList("vertices", ids); | ||
| } finally { | ||
| Optional.ofNullable(queryPool) | ||
|
Contributor
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 if-style |
||
| .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(); | ||
|
Contributor
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()); | ||
|
Contributor
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; | ||
|
Contributor
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(); | ||
|
Contributor
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
Contributor
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 + | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
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, or bind MemoryManager to graph?