in memory/memory-core/src/main/java/org/apache/arrow/memory/BaseAllocator.java [571:717]
private void verifyAllocator(
final IdentityHashMap<AllocationManager, BaseAllocator> buffersSeen) {
// The remaining tests can only be performed if we're in debug mode.
if (!DEBUG) {
return;
}
synchronized (DEBUG_LOCK) {
final long allocated = getAllocatedMemory();
// verify my direct descendants
final Set<BaseAllocator> childSet = childAllocators.keySet();
for (final BaseAllocator childAllocator : childSet) {
childAllocator.verifyAllocator(buffersSeen);
}
/*
* Verify my relationships with my descendants.
*
* The sum of direct child allocators' owned memory must be <= my allocated memory; my
* allocated memory also
* includes ArrowBuf's directly allocated by me.
*/
long childTotal = 0;
for (final BaseAllocator childAllocator : childSet) {
childTotal += Math.max(childAllocator.getAllocatedMemory(), childAllocator.reservation);
}
if (childTotal > getAllocatedMemory()) {
if (historicalLog != null) {
historicalLog.logHistory(logger);
}
logger.debug("allocator[" + name + "] child event logs BEGIN");
for (final BaseAllocator childAllocator : childSet) {
if (childAllocator.historicalLog != null) {
childAllocator.historicalLog.logHistory(logger);
}
}
logger.debug("allocator[" + name + "] child event logs END");
throw new IllegalStateException(
"Child allocators own more memory ("
+ childTotal
+ ") than their parent (name = "
+ name
+ " ) has allocated ("
+ getAllocatedMemory()
+ ')');
}
// Furthermore, the amount I've allocated should be that plus buffers I've allocated.
long bufferTotal = 0;
final Set<@KeyFor("this.childLedgers") BufferLedger> ledgerSet =
childLedgers != null ? childLedgers.keySet() : null;
if (ledgerSet != null) {
for (final BufferLedger ledger : ledgerSet) {
if (!ledger.isOwningLedger()) {
continue;
}
final AllocationManager am = ledger.getAllocationManager();
/*
* Even when shared, ArrowBufs are rewrapped, so we should never see the same instance
* twice.
*/
final BaseAllocator otherOwner = buffersSeen.get(am);
if (otherOwner != null) {
throw new IllegalStateException(
"This allocator's ArrowBuf already owned by another " + "allocator");
}
buffersSeen.put(am, this);
bufferTotal += am.getSize();
}
}
// Preallocated space has to be accounted for
final Set<@KeyFor("this.reservations") Reservation> reservationSet =
reservations != null ? reservations.keySet() : null;
long reservedTotal = 0;
if (reservationSet != null) {
for (final Reservation reservation : reservationSet) {
if (!reservation.isUsed()) {
reservedTotal += reservation.getSize();
}
}
}
if (bufferTotal + reservedTotal + childTotal != getAllocatedMemory()) {
final StringBuilder sb = new StringBuilder();
sb.append("allocator[");
sb.append(name);
sb.append("]\nallocated: ");
sb.append(Long.toString(allocated));
sb.append(" allocated - (bufferTotal + reservedTotal + childTotal): ");
sb.append(Long.toString(allocated - (bufferTotal + reservedTotal + childTotal)));
sb.append('\n');
if (bufferTotal != 0) {
sb.append("buffer total: ");
sb.append(Long.toString(bufferTotal));
sb.append('\n');
dumpBuffers(sb, ledgerSet);
}
if (childTotal != 0) {
sb.append("child total: ");
sb.append(Long.toString(childTotal));
sb.append('\n');
for (final BaseAllocator childAllocator : childSet) {
sb.append("child allocator[");
sb.append(childAllocator.name);
sb.append("] owned ");
sb.append(Long.toString(childAllocator.getAllocatedMemory()));
sb.append('\n');
}
}
if (reservedTotal != 0) {
sb.append(String.format("reserved total : %d bytes.", reservedTotal));
if (reservationSet != null) {
for (final Reservation reservation : reservationSet) {
if (reservation.historicalLog != null) {
reservation.historicalLog.buildHistory(sb, 0, true);
}
sb.append('\n');
}
}
}
logger.debug(sb.toString());
final long allocated2 = getAllocatedMemory();
if (allocated2 != allocated) {
throw new IllegalStateException(
String.format(
"allocator[%s]: allocated t1 (%d) + allocated t2 (%d). Someone released memory while in verification.",
name, allocated, allocated2));
}
throw new IllegalStateException(
String.format(
"allocator[%s]: buffer space (%d) + prealloc space (%d) + child space (%d) != allocated (%d)",
name, bufferTotal, reservedTotal, childTotal, allocated));
}
}
}