Skip to content

Commit 701210c

Browse files
Introduce graphStore container in mem. tracker
1 parent 09aef90 commit 701210c

File tree

4 files changed

+175
-15
lines changed

4 files changed

+175
-15
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Neo4j is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
package org.neo4j.gds.mem;
21+
22+
import org.neo4j.gds.api.graph.store.catalog.GraphStoreAddedEvent;
23+
import org.neo4j.gds.api.graph.store.catalog.GraphStoreRemovedEvent;
24+
25+
import java.util.concurrent.ConcurrentHashMap;
26+
import java.util.concurrent.atomic.AtomicLong;
27+
import java.util.stream.Stream;
28+
29+
class GraphStoreMemoryContainer {
30+
31+
private final ConcurrentHashMap<String, ConcurrentHashMap<String,Long>> graphStoresMemory = new ConcurrentHashMap<>();
32+
private final AtomicLong graphStoreReservedMemory = new AtomicLong();
33+
private static final ConcurrentHashMap<String,Long> EMPTY_HASH_MAP =new ConcurrentHashMap<>();
34+
35+
long addGraph(GraphStoreAddedEvent graphStoreAddedEvent){
36+
var addedGraphMemory = graphStoreAddedEvent.memoryInBytes();
37+
var graphsMemory = graphStoreReservedMemory.addAndGet(addedGraphMemory);
38+
graphStoresMemory.putIfAbsent(graphStoreAddedEvent.user(), new ConcurrentHashMap<>());
39+
graphStoresMemory.get(graphStoreAddedEvent.user()).put(graphStoreAddedEvent.graphName(),graphStoreAddedEvent.memoryInBytes());
40+
return graphsMemory;
41+
}
42+
43+
long removeGraph(GraphStoreRemovedEvent graphStoreRemovedEvent){
44+
var graphMemoryToRemove = graphStoreRemovedEvent.memoryInBytes();
45+
var graphsMemoryAfterRemoval = graphStoreReservedMemory.addAndGet(-graphMemoryToRemove);
46+
graphStoresMemory.get(graphStoreRemovedEvent.user()).remove(graphStoreRemovedEvent.graphName());
47+
return graphsMemoryAfterRemoval;
48+
}
49+
50+
long graphStoreReservedMemory(){
51+
return graphStoreReservedMemory.get();
52+
}
53+
54+
Stream<UserEntityMemory> listGraphs(String user){
55+
return graphStoresMemory
56+
.getOrDefault(user, EMPTY_HASH_MAP)
57+
.entrySet()
58+
.stream()
59+
.map( entry -> new UserEntityMemory(user, entry.getKey(), entry.getValue()));
60+
}
61+
62+
Stream<UserEntityMemory> listGraphs(){
63+
return graphStoresMemory.keySet().stream().flatMap(this::listGraphs);
64+
}
65+
66+
}

progress-tracking/src/main/java/org/neo4j/gds/mem/MemoryTracker.java

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,15 @@
3131
import org.neo4j.gds.core.utils.progress.UserTask;
3232
import org.neo4j.gds.logging.Log;
3333

34-
import java.util.concurrent.atomic.AtomicLong;
3534
import java.util.concurrent.atomic.LongAdder;
3635

3736
import static org.neo4j.gds.utils.StringFormatting.formatWithLocale;
3837

3938
public class MemoryTracker implements TaskStoreListener, GraphStoreAddedEventListener, GraphStoreRemovedEventListener {
4039
private final long initialMemory;
41-
42-
private final AtomicLong graphStoresMemory = new AtomicLong();
43-
44-
private final ObjectLongMap<JobId> memoryInUse = new ObjectLongHashMap<>();
45-
private final Log log;
40+
private final GraphStoreMemoryContainer graphStoreMemoryContainer = new GraphStoreMemoryContainer();
41+
private final ObjectLongMap<JobId> memoryInUse = new ObjectLongHashMap<>();
42+
private final Log log;
4643

4744
public MemoryTracker(long initialMemory, Log log) {
4845
this.log = log;
@@ -71,7 +68,7 @@ public synchronized void tryToTrack(JobId jobId, long memoryEstimate) throws Mem
7168
public synchronized long availableMemory() {
7269
var reservedMemory = new LongAdder();
7370
memoryInUse.values().forEach((LongProcedure) reservedMemory::add);
74-
return initialMemory - (reservedMemory.longValue() + graphStoresMemory.longValue());
71+
return initialMemory - (reservedMemory.longValue() + graphStoreMemoryContainer.graphStoreReservedMemory());
7572
}
7673

7774
@Override
@@ -100,24 +97,23 @@ private static void assertPositiveInitialMemory(long initialMemory) {
10097

10198
@Override
10299
public void onGraphStoreAdded(GraphStoreAddedEvent graphStoreAddedEvent) {
103-
var addedGraphMemory = graphStoreAddedEvent.memoryInBytes();
104-
var graphsMemory = graphStoresMemory.addAndGet(addedGraphMemory);
100+
var graphsMemory = graphStoreMemoryContainer.addGraph(graphStoreAddedEvent);
105101
log.debug(
106102
"Added graph %s, which added another %s bytes, now there are %s bytes occupied by projected graphs",
107103
graphStoreAddedEvent.graphName(),
108-
addedGraphMemory,
104+
graphStoreAddedEvent.memoryInBytes(),
109105
graphsMemory
110106
);
111107
}
112108

113109
@Override
114-
public void onGraphStoreRemoved(GraphStoreRemovedEvent graphStoreAddedEvent) {
115-
var graphMemoryToRemove = graphStoreAddedEvent.memoryInBytes();
116-
var graphsMemoryAfterRemoval = graphStoresMemory.addAndGet(-graphMemoryToRemove);
110+
public void onGraphStoreRemoved(GraphStoreRemovedEvent graphStoreRemovedEvent) {
111+
112+
var graphsMemoryAfterRemoval= graphStoreMemoryContainer.removeGraph(graphStoreRemovedEvent);
117113
log.debug(
118114
"Removed graph %s, which freed %s bytes, there are still %s bytes occupied by projected graphs",
119-
graphStoreAddedEvent.graphName(),
120-
graphMemoryToRemove,
115+
graphStoreRemovedEvent.graphName(),
116+
graphStoreRemovedEvent.memoryInBytes(),
121117
graphsMemoryAfterRemoval
122118
);
123119
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Neo4j is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
package org.neo4j.gds.mem;
21+
22+
public record UserEntityMemory(String user, String graph, long memoryInBytes) {
23+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Neo4j is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
package org.neo4j.gds.mem;
21+
22+
import org.junit.jupiter.api.Test;
23+
import org.neo4j.gds.api.graph.store.catalog.GraphStoreAddedEvent;
24+
import org.neo4j.gds.api.graph.store.catalog.GraphStoreRemovedEvent;
25+
26+
import static org.assertj.core.api.Assertions.assertThat;
27+
28+
class GraphStoreMemoryContainerTest {
29+
30+
@Test
31+
void shouldAddGraphs(){
32+
GraphStoreMemoryContainer graphStoreMemoryContainer=new GraphStoreMemoryContainer();
33+
assertThat(graphStoreMemoryContainer.addGraph(new GraphStoreAddedEvent("foo","DB","buzz",10))).isEqualTo(10);
34+
assertThat(graphStoreMemoryContainer.addGraph(new GraphStoreAddedEvent("foo","DB","buzz2",20))).isEqualTo(30);
35+
assertThat(graphStoreMemoryContainer.graphStoreReservedMemory()).isEqualTo(30L);
36+
37+
}
38+
39+
@Test
40+
void shouldRemoveGraphs(){
41+
GraphStoreMemoryContainer graphStoreMemoryContainer=new GraphStoreMemoryContainer();
42+
graphStoreMemoryContainer.addGraph(new GraphStoreAddedEvent("foo","DB","buzz",10));
43+
graphStoreMemoryContainer.addGraph(new GraphStoreAddedEvent("foo","DB","buzz2",20));
44+
assertThat(graphStoreMemoryContainer.removeGraph(new GraphStoreRemovedEvent("foo","DB","buzz2",20))).isEqualTo(10);
45+
}
46+
47+
@Test
48+
void shouldListForUser(){
49+
GraphStoreMemoryContainer graphStoreMemoryContainer=new GraphStoreMemoryContainer();
50+
graphStoreMemoryContainer.addGraph(new GraphStoreAddedEvent("Alice","DB","graph1",10));
51+
graphStoreMemoryContainer.addGraph(new GraphStoreAddedEvent("Alice","DB","graph2",15));
52+
53+
graphStoreMemoryContainer.addGraph(new GraphStoreAddedEvent("Bob","DB","graph3",20));
54+
var aliceList =graphStoreMemoryContainer.listGraphs("Alice").toList();
55+
assertThat(aliceList).hasSize(2);
56+
assertThat(aliceList.stream().map(UserEntityMemory::graph).toList()).containsExactlyInAnyOrder("graph1","graph2");
57+
assertThat(aliceList.stream().map(UserEntityMemory::memoryInBytes).toList()).containsExactlyInAnyOrder(10L,15L);
58+
59+
}
60+
61+
@Test
62+
void shouldListAll(){
63+
GraphStoreMemoryContainer graphStoreMemoryContainer=new GraphStoreMemoryContainer();
64+
graphStoreMemoryContainer.addGraph(new GraphStoreAddedEvent("Alice","DB","graph1",10));
65+
graphStoreMemoryContainer.addGraph(new GraphStoreAddedEvent("Alice","DB","graph2",15));
66+
67+
graphStoreMemoryContainer.addGraph(new GraphStoreAddedEvent("Bob","DB","graph3",20));
68+
var graphList =graphStoreMemoryContainer.listGraphs().toList();
69+
assertThat(graphList).hasSize(3);
70+
assertThat(graphList.stream().map(UserEntityMemory::graph).toList()).containsExactlyInAnyOrder("graph1","graph2","graph3");
71+
assertThat(graphList.stream().map(UserEntityMemory::memoryInBytes).toList()).containsExactlyInAnyOrder(10L,15L,20L);
72+
73+
}
74+
75+
}

0 commit comments

Comments
 (0)