27
27
import org .apache .hugegraph .memory .MemoryManager ;
28
28
import org .apache .hugegraph .memory .consumer .MemoryConsumer ;
29
29
import org .apache .hugegraph .memory .pool .impl .MemoryPoolStats ;
30
+ import org .jetbrains .annotations .TestOnly ;
30
31
import org .slf4j .Logger ;
31
32
import org .slf4j .LoggerFactory ;
32
33
33
34
public abstract class AbstractMemoryPool implements MemoryPool {
34
35
35
36
private static final Logger LOG = LoggerFactory .getLogger (AbstractMemoryPool .class );
36
- private final Queue <MemoryPool > children =
37
+ protected final Queue <MemoryPool > children =
37
38
new PriorityQueue <>((o1 , o2 ) -> (int ) (o2 .getFreeBytes () - o1 .getFreeBytes ()));
38
39
protected final MemoryManager memoryManager ;
39
- protected final ReentrantLock arbitrationLock = new ReentrantLock ();
40
- protected final Condition condition = arbitrationLock .newCondition ();
40
+ // Allocation, deAllocation, arbitration must be serial which is controlled by this lock.
41
+ protected final ReentrantLock memoryActionLock = new ReentrantLock ();
42
+ protected final Condition condition = memoryActionLock .newCondition ();
41
43
protected final AtomicBoolean isBeingArbitrated = new AtomicBoolean (false );
42
44
protected final MemoryPoolStats stats ;
43
45
protected boolean isClosed = false ;
@@ -60,7 +62,7 @@ public long tryToReclaimLocalMemory(long neededBytes) {
60
62
long totalReclaimedBytes = 0 ;
61
63
long currentNeededBytes = neededBytes ;
62
64
try {
63
- this .arbitrationLock .lock ();
65
+ this .memoryActionLock .lock ();
64
66
this .isBeingArbitrated .set (true );
65
67
for (MemoryPool child : this .children ) {
66
68
long reclaimedMemory = child .tryToReclaimLocalMemory (currentNeededBytes );
@@ -79,20 +81,23 @@ public long tryToReclaimLocalMemory(long neededBytes) {
79
81
totalReclaimedBytes , neededBytes );
80
82
return totalReclaimedBytes ;
81
83
} finally {
82
- this .stats .setNumShrinks (this .stats .getNumShrinks () + 1 );
84
+ if (totalReclaimedBytes > 0 ) {
85
+ this .stats .setNumShrinks (this .stats .getNumShrinks () + 1 );
86
+ }
83
87
this .stats .setAllocatedBytes (
84
88
this .stats .getAllocatedBytes () - totalReclaimedBytes );
85
89
this .isBeingArbitrated .set (false );
86
- this .arbitrationLock .unlock ();
87
90
this .condition .signalAll ();
91
+ this .memoryActionLock .unlock ();
88
92
}
89
93
}
90
94
91
95
/**
92
96
* called when one layer pool is successfully executed and exited.
93
97
*/
94
98
@ Override
95
- public synchronized void releaseSelf (String reason ) {
99
+ public void releaseSelf (String reason ) {
100
+ this .memoryActionLock .lock ();
96
101
try {
97
102
if (this .isBeingArbitrated .get ()) {
98
103
this .condition .await ();
@@ -109,6 +114,7 @@ public synchronized void releaseSelf(String reason) {
109
114
LOG .error ("Failed to release self because " , e );
110
115
Thread .currentThread ().interrupt ();
111
116
} finally {
117
+ this .memoryActionLock .unlock ();
112
118
// Make these objs be GCed by JVM quickly.
113
119
this .parent = null ;
114
120
this .children .clear ();
@@ -198,4 +204,9 @@ public MemoryPool findRootQueryPool() {
198
204
}
199
205
return getParentPool ().findRootQueryPool ();
200
206
}
207
+
208
+ @ TestOnly
209
+ public int getChildrenCount () {
210
+ return this .children .size ();
211
+ }
201
212
}
0 commit comments