/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.drill.exec.physical.impl.join;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import org.apache.drill.test.BaseTest;
import org.junit.Assert;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class TestPostBuildCalculationsImpl extends BaseTest {
  @Test
  public void testProbeTooBig() {
    final int minProbeRecordsPerBatch = 10;

    final int computedProbeRecordsPerBatch =
      HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl.computeProbeRecordsPerBatch(
        100,
        2,
        100,
        minProbeRecordsPerBatch,
        70,
        40,
        200);

    Assert.assertEquals(minProbeRecordsPerBatch, computedProbeRecordsPerBatch);
  }

  @Test
  public void testComputedShouldBeMin() {
    final int minProbeRecordsPerBatch = 10;

    final int computedProbeRecordsPerBatch =
      HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl.computeProbeRecordsPerBatch(
        100,
        2,
        100,
        minProbeRecordsPerBatch,
        50,
        40,
        200);

    Assert.assertEquals(minProbeRecordsPerBatch, computedProbeRecordsPerBatch);
  }

  @Test
  public void testComputedProbeRecordsPerBatch() {
    final int minProbeRecordsPerBatch = 10;

    final int computedProbeRecordsPerBatch =
      HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl.computeProbeRecordsPerBatch(
        200,
        2,
        100,
        minProbeRecordsPerBatch,
        50,
        50,
        200);

    Assert.assertEquals(25, computedProbeRecordsPerBatch);
  }

  @Test
  public void testComputedProbeRecordsPerBatchRoundUp() {
    final int minProbeRecordsPerBatch = 10;

    final int computedProbeRecordsPerBatch =
      HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl.computeProbeRecordsPerBatch(
        200,
        2,
        100,
        minProbeRecordsPerBatch,
        50,
        51,
        199);

    Assert.assertEquals(25, computedProbeRecordsPerBatch);
  }

  @Test(expected = IllegalStateException.class)
  public void testHasProbeDataButProbeEmpty() {
    final Map<String, Long> keySizes = org.apache.drill.common.map.CaseInsensitiveMap.newHashMap();

    final PartitionStatImpl partition1 = new PartitionStatImpl();
    final PartitionStatImpl partition2 = new PartitionStatImpl();
    final HashJoinMemoryCalculator.PartitionStatSet buildPartitionStatSet =
      new HashJoinMemoryCalculator.PartitionStatSet(partition1, partition2);

    final int recordsPerPartitionBatchBuild = 10;

    addBatches(partition1, recordsPerPartitionBatchBuild,
      10, 4);
    addBatches(partition2, recordsPerPartitionBatchBuild,
      10, 4);

    final double fragmentationFactor = 2.0;
    final double safetyFactor = 1.5;

    final int maxBatchNumRecordsProbe = 3;
    final int recordsPerPartitionBatchProbe = 5;
    final long partitionProbeBatchSize = 15;
    final long maxProbeBatchSize = 60;

    final HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl calc =
      new HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl(
        true,
        new ConditionalMockBatchSizePredictor(
          Lists.newArrayList(maxBatchNumRecordsProbe, recordsPerPartitionBatchProbe),
          Lists.newArrayList(maxProbeBatchSize, partitionProbeBatchSize),
          true),
        290, // memoryAvailable
        20, // maxOutputBatchSize
        maxBatchNumRecordsProbe,
        recordsPerPartitionBatchProbe,
        buildPartitionStatSet, // buildPartitionStatSet
        keySizes, // keySizes
        new MockHashTableSizeCalculator(10), // hashTableSizeCalculator
        new MockHashJoinHelperSizeCalculator(10), // hashJoinHelperSizeCalculator
        fragmentationFactor, // fragmentationFactor
        safetyFactor, // safetyFactor
        .75, // loadFactor
        false, false); // reserveHash

    calc.initialize(true);
  }

  @Test
  public void testProbeEmpty() {
    final Map<String, Long> keySizes = org.apache.drill.common.map.CaseInsensitiveMap.newHashMap();

    final PartitionStatImpl partition1 = new PartitionStatImpl();
    final PartitionStatImpl partition2 = new PartitionStatImpl();
    final HashJoinMemoryCalculator.PartitionStatSet buildPartitionStatSet =
      new HashJoinMemoryCalculator.PartitionStatSet(partition1, partition2);

    final int recordsPerPartitionBatchBuild = 10;

    addBatches(partition1, recordsPerPartitionBatchBuild,
      10, 4);
    addBatches(partition2, recordsPerPartitionBatchBuild,
      10, 4);

    final double fragmentationFactor = 2.0;
    final double safetyFactor = 1.5;

    final int maxBatchNumRecordsProbe = 3;
    final int recordsPerPartitionBatchProbe = 5;
    final long partitionProbeBatchSize = 40;
    final long maxProbeBatchSize = 10000;

    final HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl calc =
      new HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl(
        true,
        new ConditionalMockBatchSizePredictor(),
        50,
        1000,
        maxBatchNumRecordsProbe,
        recordsPerPartitionBatchProbe,
        buildPartitionStatSet,
        keySizes,
        new MockHashTableSizeCalculator(10),
        new MockHashJoinHelperSizeCalculator(10),
        fragmentationFactor,
        safetyFactor,
        .75,
        true, false);

    calc.initialize(true);

    Assert.assertFalse(calc.shouldSpill());
    Assert.assertFalse(calc.shouldSpill());
  }

  @Test
  public void testHasNoProbeDataButProbeNonEmptyFirstCycle() {
    testHasNoProbeDataButProbeNonEmptyHelper(true);
  }

  @Test
  public void testHasNoProbeDataButProbeNonEmptyNotFirstCycle() {
    testHasNoProbeDataButProbeNonEmptyHelper(false);
  }

  private void testHasNoProbeDataButProbeNonEmptyHelper(final boolean firstCycle) {
    final Map<String, Long> keySizes = org.apache.drill.common.map.CaseInsensitiveMap.newHashMap();

    final PartitionStatImpl partition1 = new PartitionStatImpl();
    final PartitionStatImpl partition2 = new PartitionStatImpl();
    final HashJoinMemoryCalculator.PartitionStatSet buildPartitionStatSet =
      new HashJoinMemoryCalculator.PartitionStatSet(partition1, partition2);

    final int recordsPerPartitionBatchBuild = 10;

    addBatches(partition1, recordsPerPartitionBatchBuild,
      10, 4);
    addBatches(partition2, recordsPerPartitionBatchBuild,
      10, 4);

    final double fragmentationFactor = 2.0;
    final double safetyFactor = 1.5;

    final int maxBatchNumRecordsProbe = 3;
    final int recordsPerPartitionBatchProbe = 5;
    final long partitionProbeBatchSize = 15;
    final long maxProbeBatchSize = 60;
    final long accountedProbeBatchSize = (firstCycle? 0: maxProbeBatchSize);

    final HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl calc =
      new HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl(
        firstCycle,
        new ConditionalMockBatchSizePredictor(
          Lists.newArrayList(maxBatchNumRecordsProbe, recordsPerPartitionBatchProbe),
          Lists.newArrayList(maxProbeBatchSize, partitionProbeBatchSize),
          false),
        230 + accountedProbeBatchSize,
        20,
        maxBatchNumRecordsProbe,
        recordsPerPartitionBatchProbe,
        buildPartitionStatSet,
        keySizes,
        new MockHashTableSizeCalculator(10),
        new MockHashJoinHelperSizeCalculator(10),
        fragmentationFactor,
        safetyFactor,
        .75,
        false, false);

    calc.initialize(false);

    long expected = accountedProbeBatchSize
      + 160 // in memory partitions
      + 20 // max output batch size
      + 2 * 10 // Hash Table
      + 2 * 10; // Hash join helper
    Assert.assertFalse(calc.shouldSpill());
    Assert.assertEquals(expected, calc.getConsumedMemory());
    Assert.assertNull(calc.next());
  }

  @Test
  public void testProbingAndPartitioningBuildAllInMemoryNoSpillFirstCycle() {
    testProbingAndPartitioningBuildAllInMemoryNoSpillHelper(true);
  }

  @Test
  public void testProbingAndPartitioningBuildAllInMemoryNoSpillNotFirstCycle() {
    testProbingAndPartitioningBuildAllInMemoryNoSpillHelper(false);
  }

  private void testProbingAndPartitioningBuildAllInMemoryNoSpillHelper(final boolean firstCycle) {
    final Map<String, Long> keySizes = org.apache.drill.common.map.CaseInsensitiveMap.newHashMap();

    final PartitionStatImpl partition1 = new PartitionStatImpl();
    final PartitionStatImpl partition2 = new PartitionStatImpl();
    final HashJoinMemoryCalculator.PartitionStatSet buildPartitionStatSet =
      new HashJoinMemoryCalculator.PartitionStatSet(partition1, partition2);

    final int recordsPerPartitionBatchBuild = 10;

    addBatches(partition1, recordsPerPartitionBatchBuild,
      10, 4);
    addBatches(partition2, recordsPerPartitionBatchBuild,
      10, 4);

    final double fragmentationFactor = 2.0;
    final double safetyFactor = 1.5;

    final int maxBatchNumRecordsProbe = 3;
    final int recordsPerPartitionBatchProbe = 5;
    final long partitionProbeBatchSize = 15;
    final long maxProbeBatchSize = 60;
    final long accountedProbeBatchSize = (firstCycle? 0: maxProbeBatchSize);

    final HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl calc =
      new HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl(
        firstCycle,
        new ConditionalMockBatchSizePredictor(
          Lists.newArrayList(maxBatchNumRecordsProbe, recordsPerPartitionBatchProbe),
          Lists.newArrayList(maxProbeBatchSize, partitionProbeBatchSize),
          true),
        230 + accountedProbeBatchSize,
        20,
        maxBatchNumRecordsProbe,
        recordsPerPartitionBatchProbe,
        buildPartitionStatSet,
        keySizes,
        new MockHashTableSizeCalculator(10),
        new MockHashJoinHelperSizeCalculator(10),
        fragmentationFactor,
        safetyFactor,
        .75,
        false, false);

    calc.initialize(false);

    long expected = accountedProbeBatchSize
      + 160 // in memory partitions
      + 20 // max output batch size
      + 2 * 10 // Hash Table
      + 2 * 10; // Hash join helper
    Assert.assertFalse(calc.shouldSpill());
    Assert.assertEquals(expected, calc.getConsumedMemory());
    Assert.assertNull(calc.next());
  }

  @Test
  public void testProbingAndPartitioningBuildAllInMemorySpillFirstCycle() {
    testProbingAndPartitioningBuildAllInMemorySpillHelper(true);
  }

  @Test
  public void testProbingAndPartitioningBuildAllInMemorySpillNotFirstCycle() {
    testProbingAndPartitioningBuildAllInMemorySpillHelper(false);
  }

  private void testProbingAndPartitioningBuildAllInMemorySpillHelper(final boolean firstCycle) {
    final Map<String, Long> keySizes = org.apache.drill.common.map.CaseInsensitiveMap.newHashMap();

    final PartitionStatImpl partition1 = new PartitionStatImpl();
    final PartitionStatImpl partition2 = new PartitionStatImpl();
    final HashJoinMemoryCalculator.PartitionStatSet buildPartitionStatSet =
      new HashJoinMemoryCalculator.PartitionStatSet(partition1, partition2);

    final int recordsPerPartitionBatchBuild = 10;

    addBatches(partition1, recordsPerPartitionBatchBuild,
      10, 4);
    addBatches(partition2, recordsPerPartitionBatchBuild,
      10, 4);

    final double fragmentationFactor = 2.0;
    final double safetyFactor = 1.5;

    final int maxBatchNumRecordsProbe = 3;
    final int recordsPerPartitionBatchProbe = 5;
    final long partitionProbeBatchSize = 15;
    final long maxProbeBatchSize = 60;
    final long accountedProbeBatchSize = (firstCycle? 0: maxProbeBatchSize);

    HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl calc =
      new HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl(
        firstCycle,
        new ConditionalMockBatchSizePredictor(
          Lists.newArrayList(maxBatchNumRecordsProbe, recordsPerPartitionBatchProbe),
          Lists.newArrayList(maxProbeBatchSize, partitionProbeBatchSize),
          true),
        210 + accountedProbeBatchSize,
        20,
        maxBatchNumRecordsProbe,
        recordsPerPartitionBatchProbe,
        buildPartitionStatSet,
        keySizes,
        new MockHashTableSizeCalculator(10),
        new MockHashJoinHelperSizeCalculator(10),
        fragmentationFactor,
        safetyFactor,
        .75,
        false, false);

    calc.initialize(false);

    long expected = accountedProbeBatchSize
      + 160 // in memory partitions
      + 20 // max output batch size
      + 2 * 10 // Hash Table
      + 2 * 10; // Hash join helper
    Assert.assertTrue(calc.shouldSpill());
    Assert.assertEquals(expected, calc.getConsumedMemory());
    partition1.spill();

    expected = accountedProbeBatchSize
      + 80 // in memory partitions
      + 20 // max output batch size
      + 10 // Hash Table
      + 10 // Hash join helper
      + 15; // partition batch size
    Assert.assertFalse(calc.shouldSpill());
    Assert.assertEquals(expected, calc.getConsumedMemory());
    Assert.assertNotNull(calc.next());
  }

  @Test
  public void testProbingAndPartitioningBuildAllInMemoryNoSpillWithHashFirstCycle() {
    testProbingAndPartitioningBuildAllInMemoryNoSpillWithHashHelper(true);
  }

  @Test
  public void testProbingAndPartitioningBuildAllInMemoryNoSpillWithHashNotFirstCycle() {
    testProbingAndPartitioningBuildAllInMemoryNoSpillWithHashHelper(false);
  }

  private void testProbingAndPartitioningBuildAllInMemoryNoSpillWithHashHelper(final boolean firstCycle) {
    final Map<String, Long> keySizes = org.apache.drill.common.map.CaseInsensitiveMap.newHashMap();

    final PartitionStatImpl partition1 = new PartitionStatImpl();
    final PartitionStatImpl partition2 = new PartitionStatImpl();
    final HashJoinMemoryCalculator.PartitionStatSet buildPartitionStatSet =
      new HashJoinMemoryCalculator.PartitionStatSet(partition1, partition2);

    partition1.spill();
    partition2.spill();

    final double fragmentationFactor = 2.0;
    final double safetyFactor = 1.5;

    final int maxBatchNumRecordsProbe = 3;
    final int recordsPerPartitionBatchProbe = 5;
    final long partitionProbeBatchSize = 15;
    final long maxProbeBatchSize = 60;
    final long accountedProbeBatchSize = (firstCycle? 0: maxProbeBatchSize);

    HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl calc =
      new HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl(
        firstCycle,
        new ConditionalMockBatchSizePredictor(
          Lists.newArrayList(maxBatchNumRecordsProbe, recordsPerPartitionBatchProbe),
          Lists.newArrayList(maxProbeBatchSize, partitionProbeBatchSize),
          true),
        120 + accountedProbeBatchSize,
        20,
        maxBatchNumRecordsProbe,
        recordsPerPartitionBatchProbe,
        buildPartitionStatSet,
        keySizes,
        new MockHashTableSizeCalculator(10),
        new MockHashJoinHelperSizeCalculator(10),
        fragmentationFactor,
        safetyFactor,
        .75,
        true, false);

    calc.initialize(false);

    long expected = accountedProbeBatchSize // probe batch
      + 2 * 5 * 3 // partition batches
      + 20; // max output batch size
    Assert.assertFalse(calc.shouldSpill());
    Assert.assertEquals(expected, calc.getConsumedMemory());
    Assert.assertNotNull(calc.next());
  }

  @Test
  public void testProbingAndPartitioningBuildAllInMemoryWithSpillFirstCycle() {
    testProbingAndPartitioningBuildAllInMemoryWithSpillHelper(true);
  }

  @Test
  public void testProbingAndPartitioningBuildAllInMemoryWithSpillNotFirstCycle() {
    testProbingAndPartitioningBuildAllInMemoryWithSpillHelper(false);
  }

  private void testProbingAndPartitioningBuildAllInMemoryWithSpillHelper(final boolean firstCycle) {
    final Map<String, Long> keySizes = org.apache.drill.common.map.CaseInsensitiveMap.newHashMap();

    final PartitionStatImpl partition1 = new PartitionStatImpl();
    final PartitionStatImpl partition2 = new PartitionStatImpl();
    final HashJoinMemoryCalculator.PartitionStatSet buildPartitionStatSet =
      new HashJoinMemoryCalculator.PartitionStatSet(partition1, partition2);

    final int recordsPerPartitionBatchBuild = 10;

    addBatches(partition1, recordsPerPartitionBatchBuild, 10, 4);
    addBatches(partition2, recordsPerPartitionBatchBuild, 10, 4);

    final double fragmentationFactor = 2.0;
    final double safetyFactor = 1.5;

    final long hashTableSize = 10;
    final long hashJoinHelperSize = 10;
    final int maxBatchNumRecordsProbe = 3;
    final int recordsPerPartitionBatchProbe = 5;
    final long partitionProbeBatchSize = 15;
    final long maxProbeBatchSize = 60;
    final long accountedProbeBatchSize = (firstCycle? 0: maxProbeBatchSize);

    HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl calc =
      new HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl(
        firstCycle,
        new ConditionalMockBatchSizePredictor(
          Lists.newArrayList(maxBatchNumRecordsProbe, recordsPerPartitionBatchProbe),
          Lists.newArrayList(maxProbeBatchSize, partitionProbeBatchSize),
          true),
        140 + accountedProbeBatchSize,
        20,
        maxBatchNumRecordsProbe,
        recordsPerPartitionBatchProbe,
        buildPartitionStatSet,
        keySizes,
        new MockHashTableSizeCalculator(hashTableSize),
        new MockHashJoinHelperSizeCalculator(hashJoinHelperSize),
        fragmentationFactor,
        safetyFactor,
        .75,
        false, false);

    calc.initialize(false);

    long expected = accountedProbeBatchSize
      + 80 // in memory partition
      + 10 // hash table size
      + 10 // hash join helper size
      + 15 // max partition probe batch size
      + 20; // outgoing batch size

    Assert.assertTrue(calc.shouldSpill());
    partition1.spill();
    Assert.assertFalse(calc.shouldSpill());
    Assert.assertEquals(expected, calc.getConsumedMemory());
    Assert.assertNotNull(calc.next());
  }

  @Test
  public void testProbingAndPartitioningBuildSomeInMemoryFirstCycle() {
    testProbingAndPartitioningBuildSomeInMemoryHelper(true);
  }

  @Test
  public void testProbingAndPartitioningBuildSomeInMemoryNotFirstCycle() {
    testProbingAndPartitioningBuildSomeInMemoryHelper(false);
  }

  private void testProbingAndPartitioningBuildSomeInMemoryHelper(final boolean firstCycle) {
    final Map<String, Long> keySizes = org.apache.drill.common.map.CaseInsensitiveMap.newHashMap();

    final PartitionStatImpl partition1 = new PartitionStatImpl();
    final PartitionStatImpl partition2 = new PartitionStatImpl();
    final PartitionStatImpl partition3 = new PartitionStatImpl();
    final PartitionStatImpl partition4 = new PartitionStatImpl();
    final HashJoinMemoryCalculator.PartitionStatSet buildPartitionStatSet =
      new HashJoinMemoryCalculator.PartitionStatSet(partition1, partition2, partition3, partition4);

    final int recordsPerPartitionBatchBuild = 10;

    partition1.spill();
    partition2.spill();
    addBatches(partition3, recordsPerPartitionBatchBuild, 10, 4);
    addBatches(partition4, recordsPerPartitionBatchBuild, 10, 4);

    final double fragmentationFactor = 2.0;
    final double safetyFactor = 1.5;

    final long hashTableSize = 10;
    final long hashJoinHelperSize = 10;
    final int maxBatchNumRecordsProbe = 3;
    final int recordsPerPartitionBatchProbe = 5;
    final long partitionProbeBatchSize = 15;
    final long maxProbeBatchSize = 60;
    final long accountedProbeBatchSize = (firstCycle? 0: maxProbeBatchSize);

    HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl calc =
      new HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl(
        firstCycle,
        new ConditionalMockBatchSizePredictor(
          Lists.newArrayList(maxBatchNumRecordsProbe, recordsPerPartitionBatchProbe),
          Lists.newArrayList(maxProbeBatchSize, partitionProbeBatchSize),
          true),
        170 + accountedProbeBatchSize,
        20,
        maxBatchNumRecordsProbe,
        recordsPerPartitionBatchProbe,
        buildPartitionStatSet,
        keySizes,
        new MockHashTableSizeCalculator(hashTableSize),
        new MockHashJoinHelperSizeCalculator(hashJoinHelperSize),
        fragmentationFactor,
        safetyFactor,
        .75,
        false, false);

    calc.initialize(false);

    long expected = accountedProbeBatchSize
      + 80 // in memory partition
      + 10 // hash table size
      + 10 // hash join helper size
      + 15 * 3 // max batch size for each spill probe partition
      + 20;
    Assert.assertTrue(calc.shouldSpill());
    partition3.spill();
    Assert.assertFalse(calc.shouldSpill());
    Assert.assertEquals(expected, calc.getConsumedMemory());
    Assert.assertNotNull(calc.next());
  }

  @Test
  public void testProbingAndPartitioningBuildNoneInMemoryFirstCycle() {
    testProbingAndPartitioningBuildNoneInMemoryHelper(true);
  }

  @Test
  public void testProbingAndPartitioningBuildNoneInMemoryNotFirstCycle() {
    testProbingAndPartitioningBuildNoneInMemoryHelper(false);
  }

  private void testProbingAndPartitioningBuildNoneInMemoryHelper(final boolean firstCycle) {
    final Map<String, Long> keySizes = org.apache.drill.common.map.CaseInsensitiveMap.newHashMap();

    final PartitionStatImpl partition1 = new PartitionStatImpl();
    final PartitionStatImpl partition2 = new PartitionStatImpl();
    final HashJoinMemoryCalculator.PartitionStatSet buildPartitionStatSet =
      new HashJoinMemoryCalculator.PartitionStatSet(partition1, partition2);

    partition1.spill();
    partition2.spill();

    final double fragmentationFactor = 2.0;
    final double safetyFactor = 1.5;

    final long hashTableSize = 10;
    final long hashJoinHelperSize = 10;
    final int maxBatchNumRecordsProbe = 3;
    final int recordsPerPartitionBatchProbe = 5;
    final long partitionProbeBatchSize = 15;
    final long maxProbeBatchSize = 60;
    final long accountedProbeBatchSize = (firstCycle? 0: maxProbeBatchSize);

    HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl calc =
      new HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl(
        firstCycle,
        new ConditionalMockBatchSizePredictor(
          Lists.newArrayList(maxBatchNumRecordsProbe, recordsPerPartitionBatchProbe),
          Lists.newArrayList(maxProbeBatchSize, partitionProbeBatchSize),
          true),
        110 + accountedProbeBatchSize,
        20,
        maxBatchNumRecordsProbe,
        recordsPerPartitionBatchProbe,
        buildPartitionStatSet,
        keySizes,
        new MockHashTableSizeCalculator(hashTableSize),
        new MockHashJoinHelperSizeCalculator(hashJoinHelperSize),
        fragmentationFactor,
        safetyFactor,
        .75,
        false, false);

    calc.initialize(false);
    Assert.assertFalse(calc.shouldSpill());
    Assert.assertEquals(50 + accountedProbeBatchSize, calc.getConsumedMemory());
    Assert.assertNotNull(calc.next());
  }

  @Test // Make sure I don't fail
  public void testMakeDebugString()
  {
    final Map<String, Long> keySizes = org.apache.drill.common.map.CaseInsensitiveMap.newHashMap();

    final PartitionStatImpl partition1 = new PartitionStatImpl();
    final PartitionStatImpl partition2 = new PartitionStatImpl();
    final PartitionStatImpl partition3 = new PartitionStatImpl();
    final PartitionStatImpl partition4 = new PartitionStatImpl();
    final HashJoinMemoryCalculator.PartitionStatSet buildPartitionStatSet =
      new HashJoinMemoryCalculator.PartitionStatSet(partition1, partition2, partition3, partition4);

    final int recordsPerPartitionBatchBuild = 10;

    partition1.spill();
    partition2.spill();
    addBatches(partition3, recordsPerPartitionBatchBuild, 10, 4);
    addBatches(partition4, recordsPerPartitionBatchBuild, 10, 4);

    final double fragmentationFactor = 2.0;
    final double safetyFactor = 1.5;

    final long hashTableSize = 10;
    final long hashJoinHelperSize = 10;
    final int maxBatchNumRecordsProbe = 3;
    final int recordsPerPartitionBatchProbe = 5;
    final long partitionProbeBatchSize = 15;
    final long maxProbeBatchSize = 60;

    HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl calc =
      new HashJoinMemoryCalculatorImpl.PostBuildCalculationsImpl(
        true,
        new ConditionalMockBatchSizePredictor(
          Lists.newArrayList(maxBatchNumRecordsProbe, recordsPerPartitionBatchProbe),
          Lists.newArrayList(maxProbeBatchSize, partitionProbeBatchSize),
          true),
        230,
        20,
        maxBatchNumRecordsProbe,
        recordsPerPartitionBatchProbe,
        buildPartitionStatSet,
        keySizes,
        new MockHashTableSizeCalculator(hashTableSize),
        new MockHashJoinHelperSizeCalculator(hashJoinHelperSize),
        fragmentationFactor,
        safetyFactor,
        .75,
        false, false);

    calc.initialize(false);
  }

  private void addBatches(PartitionStatImpl partitionStat,
                          int recordsPerPartitionBatchBuild,
                          long batchSize,
                          int numBatches) {
    for (int counter = 0; counter < numBatches; counter++) {
      partitionStat.add(new HashJoinMemoryCalculator.BatchStat(
        recordsPerPartitionBatchBuild, batchSize));
    }
  }

  public static class MockHashTableSizeCalculator implements HashTableSizeCalculator {
    private final long size;

    public MockHashTableSizeCalculator(final long size) {
      this.size = size;
    }

    @Override
    public long calculateSize(HashJoinMemoryCalculator.PartitionStat partitionStat,
                              Map<String, Long> keySizes,
                              double loadFactor, double safetyFactor, double fragmentationFactor) {
      return size;
    }

    @Override
    public double getDoublingFactor() {
      return HashTableSizeCalculatorConservativeImpl.HASHTABLE_DOUBLING_FACTOR;
    }

    @Override
    public String getType() {
      return null;
    }
  }

  public static class MockHashJoinHelperSizeCalculator implements HashJoinHelperSizeCalculator {
    private final long size;

    public MockHashJoinHelperSizeCalculator(final long size)
    {
      this.size = size;
    }

    @Override
    public long calculateSize(HashJoinMemoryCalculator.PartitionStat partitionStat, double fragmentationFactor) {
      return size;
    }
  }

  public static class ConditionalMockBatchSizePredictor implements BatchSizePredictor {
    private final List<Integer> recordsPerBatch;
    private final List<Long> batchSize;

    private boolean hasData;
    private boolean updateable;

    public ConditionalMockBatchSizePredictor() {
      recordsPerBatch = new ArrayList<>();
      batchSize = new ArrayList<>();
      hasData = false;
      updateable = true;
    }

    public ConditionalMockBatchSizePredictor(final List<Integer> recordsPerBatch,
                                             final List<Long> batchSize,
                                             final boolean hasData) {
      this.recordsPerBatch = Preconditions.checkNotNull(recordsPerBatch);
      this.batchSize = Preconditions.checkNotNull(batchSize);

      Preconditions.checkArgument(recordsPerBatch.size() == batchSize.size());

      this.hasData = hasData;
      updateable = true;
    }

    @Override
    public long getBatchSize() {
      return batchSize.get(0);
    }

    @Override
    public int getNumRecords() {
      return 0;
    }

    @Override
    public boolean hadDataLastTime() {
      return hasData;
    }

    @Override
    public void updateStats() {
      Preconditions.checkState(updateable);
      updateable = false;
      hasData = true;
    }

    @Override
    public long predictBatchSize(int desiredNumRecords, boolean reserveHash) {
      Preconditions.checkState(hasData);

      for (int index = 0; index < recordsPerBatch.size(); index++) {
        if (desiredNumRecords == recordsPerBatch.get(index)) {
          return batchSize.get(index);
        }
      }

      throw new IllegalArgumentException();
    }
  }
}
