private void verifyAllocator()

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));
      }
    }
  }