@@ -36,6 +36,8 @@ class Accountant implements AutoCloseable {
36
36
*/
37
37
protected final Accountant parent ;
38
38
39
+ private final String name ;
40
+
39
41
/**
40
42
* The amount of memory reserved for this allocator. Releases below this amount of memory will
41
43
* not be returned to the
@@ -57,7 +59,8 @@ class Accountant implements AutoCloseable {
57
59
*/
58
60
private final AtomicLong locallyHeldMemory = new AtomicLong ();
59
61
60
- public Accountant (Accountant parent , long reservation , long maxAllocation ) {
62
+ public Accountant (Accountant parent , String name , long reservation , long maxAllocation ) {
63
+ Preconditions .checkNotNull (name , "name must not be null" );
61
64
Preconditions .checkArgument (reservation >= 0 , "The initial reservation size must be " +
62
65
"non-negative." );
63
66
Preconditions .checkArgument (maxAllocation >= 0 , "The maximum allocation limit must be " +
@@ -68,6 +71,7 @@ public Accountant(Accountant parent, long reservation, long maxAllocation) {
68
71
"reserve memory." );
69
72
70
73
this .parent = parent ;
74
+ this .name = name ;
71
75
this .reservation = reservation ;
72
76
this .allocationLimit .set (maxAllocation );
73
77
@@ -77,28 +81,43 @@ public Accountant(Accountant parent, long reservation, long maxAllocation) {
77
81
if (!outcome .isOk ()) {
78
82
throw new OutOfMemoryException (String .format (
79
83
"Failure trying to allocate initial reservation for Allocator. " +
80
- "Attempted to allocate %d bytes and received an outcome of %s ." , reservation ,
81
- outcome .name ()));
84
+ "Attempted to allocate %d bytes." , reservation ,
85
+ outcome .getStatus (). name ()), outcome . getDetails ( ));
82
86
}
83
87
}
84
88
}
85
89
86
90
/**
87
91
* Attempt to allocate the requested amount of memory. Either completely succeeds or completely
88
- * fails. Constructs a a
89
- * log of delta
90
- *
91
- * <p>If it fails, no changes are made to accounting.
92
+ * fails. If it fails, no changes are made to accounting.
92
93
*
93
94
* @param size The amount of memory to reserve in bytes.
94
- * @return True if the allocation was successful, false if the allocation failed .
95
+ * @return the status and details of allocation at each allocator in the chain .
95
96
*/
96
97
AllocationOutcome allocateBytes (long size ) {
97
- final AllocationOutcome outcome = allocate (size , true , false );
98
- if (!outcome .isOk ()) {
98
+ AllocationOutcome .Status status = allocateBytesInternal (size );
99
+ if (status .isOk ()) {
100
+ return AllocationOutcome .SUCCESS_INSTANCE ;
101
+ } else {
102
+ // Try again, but with details this time.
103
+ // Populating details only on failures avoids performance overhead in the common case (success case).
104
+ AllocationOutcomeDetails details = new AllocationOutcomeDetails ();
105
+ status = allocateBytesInternal (size , details );
106
+ return new AllocationOutcome (status , details );
107
+ }
108
+ }
109
+
110
+ private AllocationOutcome .Status allocateBytesInternal (long size , AllocationOutcomeDetails details ) {
111
+ final AllocationOutcome .Status status = allocate (size ,
112
+ true /*incomingUpdatePeek*/ , false /*forceAllocation*/ , details );
113
+ if (!status .isOk ()) {
99
114
releaseBytes (size );
100
115
}
101
- return outcome ;
116
+ return status ;
117
+ }
118
+
119
+ private AllocationOutcome .Status allocateBytesInternal (long size ) {
120
+ return allocateBytesInternal (size , null /*details*/ );
102
121
}
103
122
104
123
private void updatePeak () {
@@ -126,7 +145,7 @@ private void updatePeak() {
126
145
* @return Whether the allocation fit within limits.
127
146
*/
128
147
boolean forceAllocate (long size ) {
129
- final AllocationOutcome outcome = allocate (size , true , true );
148
+ final AllocationOutcome . Status outcome = allocate (size , true , true , null );
130
149
return outcome .isOk ();
131
150
}
132
151
@@ -152,21 +171,38 @@ boolean forceAllocate(long size) {
152
171
* @param forceAllocation Whether we should force the allocation.
153
172
* @return The outcome of the allocation.
154
173
*/
155
- private AllocationOutcome allocate (final long size , final boolean incomingUpdatePeak , final boolean forceAllocation ) {
174
+ private AllocationOutcome .Status allocate (final long size , final boolean incomingUpdatePeak ,
175
+ final boolean forceAllocation , AllocationOutcomeDetails details ) {
156
176
final long newLocal = locallyHeldMemory .addAndGet (size );
157
177
final long beyondReservation = newLocal - reservation ;
158
178
final boolean beyondLimit = newLocal > allocationLimit .get ();
159
179
final boolean updatePeak = forceAllocation || (incomingUpdatePeak && !beyondLimit );
160
180
161
- AllocationOutcome parentOutcome = AllocationOutcome .SUCCESS ;
181
+ if (details != null ) {
182
+ // Add details if required (used in exceptions and debugging).
183
+ boolean allocationFailed = true ;
184
+ long allocatedLocal = 0 ;
185
+ if (!beyondLimit ) {
186
+ allocatedLocal = size - Math .min (beyondReservation , size );
187
+ allocationFailed = false ;
188
+ }
189
+ details .pushEntry (this , newLocal - size , size , allocatedLocal , allocationFailed );
190
+ }
191
+
192
+ AllocationOutcome .Status parentOutcome = AllocationOutcome .Status .SUCCESS ;
162
193
if (beyondReservation > 0 && parent != null ) {
163
194
// we need to get memory from our parent.
164
195
final long parentRequest = Math .min (beyondReservation , size );
165
- parentOutcome = parent .allocate (parentRequest , updatePeak , forceAllocation );
196
+ parentOutcome = parent .allocate (parentRequest , updatePeak , forceAllocation , details );
166
197
}
167
198
168
- final AllocationOutcome finalOutcome = beyondLimit ? AllocationOutcome .FAILED_LOCAL :
169
- parentOutcome .isOk () ? AllocationOutcome .SUCCESS : AllocationOutcome .FAILED_PARENT ;
199
+ final AllocationOutcome .Status finalOutcome ;
200
+ if (beyondLimit ) {
201
+ finalOutcome = AllocationOutcome .Status .FAILED_LOCAL ;
202
+ } else {
203
+ finalOutcome = parentOutcome .isOk () ? AllocationOutcome .Status .SUCCESS
204
+ : AllocationOutcome .Status .FAILED_PARENT ;
205
+ }
170
206
171
207
if (updatePeak ) {
172
208
updatePeak ();
@@ -206,6 +242,15 @@ public void close() {
206
242
}
207
243
}
208
244
245
+ /**
246
+ * Return the name of the accountant.
247
+ *
248
+ * @return name of accountant
249
+ */
250
+ public String getName () {
251
+ return name ;
252
+ }
253
+
209
254
/**
210
255
* Return the current limit of this Accountant.
211
256
*
0 commit comments