public void reserveDiscardBlocksBasedOnFreeList(int mergeListIx, DiscardContext ctx) {
      if (data == null) return; // not allocated yet
      FreeList freeList = freeLists[mergeListIx];
      freeList.lock.lock();
      try {
        int freeHeaderIx = freeList.listHead;
        while (freeHeaderIx >= 0) {
          boolean reserved = false;
          if (ctx.remainingToFind > 0) {
            int headerToFreeIx = getBuddyHeaderIx(mergeListIx, freeHeaderIx);
            long reserveResult = reserveBlockContents(mergeListIx, headerToFreeIx,
                ctx.victimHeaders, ctx.victimCount, true);
            int reservedCount = getFirstInt(reserveResult), moveSize = getSecondInt(reserveResult);
            reserved = (moveSize != FAILED_TO_RESERVE);
            if (!reserved) {
              // We cannot abandon the attempt here; the concurrent operations might have released
              // all the buffer comprising our buddy block, necessitating a merge into a higher
              // list. That may deadlock with another thread locking its own victims (one can only
              // take list locks separately, or moving DOWN). The alternative would be to release
              // the free list lock before reserving, however iterating the list that way is
              // difficult (we'd have to keep track of things on the main path to avoid re-trying
              // the same headers repeatedly - we'd rather keep track of extra things on failure).
              prepareAbandonUnfinishedMoveAttempt(ctx, reservedCount);
            } else {
              ctx.victimCount += reservedCount;
              ctx.addBaseHeader(freeHeaderIx);
            }
          }
          int nextFreeHeaderIx = getNextFreeListItem(offsetFromHeaderIndex(freeHeaderIx));
          if (reserved) {
            removeBlockFromFreeList(freeList, freeHeaderIx, mergeListIx);
            if (assertsEnabled) {
              checkHeader(freeHeaderIx, mergeListIx, false);
            }
            setHeaderNoBufAlloc(freeHeaderIx, mergeListIx, CasLog.Src.NEW_BASE);
          }
          if (ctx.remainingToFind == 0) break;
          freeHeaderIx = nextFreeHeaderIx;
        }
      } finally {
        freeList.lock.unlock();
      }
      // See the above. Release the headers after unlocking.
      for (int i = 0; i < ctx.abandonedCount; ++i) {
        abandonOneHeaderBeingMoved(ctx.abandonedHeaders[i], CasLog.Src.ABANDON_AT_END);
      }
      ctx.abandonedCount = 0;
    }
Reserves the blocks to use to merge into larger blocks.
@param mergeListIx The free list to reserve base blocks from.
llap-server/src/java/org/apache/hadoop/hive/llap/cache/BuddyAllocator.java