@Test
  public void testSanityWithSerde() throws Exception {
    setupSimpleWithSerde(4);

    Assert.assertEquals(4, supplier.getBaseBuffers().size());
    assertIndexMatchesVals();

    setupSimpleWithSerde(2);

    Assert.assertEquals(8, supplier.getBaseBuffers().size());
    assertIndexMatchesVals();
  }
  @Test
  public void testmaxIntsInBuffer() throws Exception {
    Assert.assertEquals(
        CompressedPools.BUFFER_SIZE, CompressedVSizeIntsIndexedSupplier.maxIntsInBufferForBytes(1));
    Assert.assertEquals(
        CompressedPools.BUFFER_SIZE / 2,
        CompressedVSizeIntsIndexedSupplier.maxIntsInBufferForBytes(2));
    Assert.assertEquals(
        CompressedPools.BUFFER_SIZE / 4,
        CompressedVSizeIntsIndexedSupplier.maxIntsInBufferForBytes(4));

    Assert.assertEquals(CompressedPools.BUFFER_SIZE, 0x10000); // nearest power of 2 is 2^14
    Assert.assertEquals(1 << 14, CompressedVSizeIntsIndexedSupplier.maxIntsInBufferForBytes(3));
  }
  private void setupSimple(final int chunkSize) {
    CloseQuietly.close(indexed);

    vals = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16};

    supplier =
        CompressedVSizeIntsIndexedSupplier.fromList(
            Ints.asList(vals),
            Ints.max(vals),
            chunkSize,
            ByteOrder.nativeOrder(),
            compressionStrategy);

    indexed = supplier.get();
  }
 @Test
 public void testChunkTooBig() throws Exception {
   for (int maxValue : MAX_VALUES) {
     final int maxChunkSize = CompressedVSizeIntsIndexedSupplier.maxIntsInBufferForValue(maxValue);
     try {
       setupLargeChunks(maxChunkSize + 1, 10 * (maxChunkSize + 1), maxValue);
       Assert.fail();
     } catch (IllegalArgumentException e) {
       Assert.assertTrue("chunk too big for maxValue " + maxValue, true);
     }
   }
 }
  @Test
  public void testLargeChunks() throws Exception {
    for (int maxValue : MAX_VALUES) {
      final int maxChunkSize = CompressedVSizeIntsIndexedSupplier.maxIntsInBufferForValue(maxValue);

      setupLargeChunks(maxChunkSize, 10 * maxChunkSize, maxValue);
      Assert.assertEquals(10, supplier.getBaseBuffers().size());
      assertIndexMatchesVals();

      setupLargeChunks(maxChunkSize, 10 * maxChunkSize + 1, maxValue);
      Assert.assertEquals(11, supplier.getBaseBuffers().size());
      assertIndexMatchesVals();

      setupLargeChunks(1, 0xFFFF, maxValue);
      Assert.assertEquals(0xFFFF, supplier.getBaseBuffers().size());
      assertIndexMatchesVals();

      setupLargeChunks(maxChunkSize / 2, 10 * (maxChunkSize / 2) + 1, maxValue);
      Assert.assertEquals(11, supplier.getBaseBuffers().size());
      assertIndexMatchesVals();
    }
  }
  private void makeWithSerde(final int chunkSize) throws IOException {
    CloseQuietly.close(indexed);

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    final CompressedVSizeIntsIndexedSupplier theSupplier =
        CompressedVSizeIntsIndexedSupplier.fromList(
            Ints.asList(vals), Ints.max(vals), chunkSize, byteOrder, compressionStrategy);
    theSupplier.writeToChannel(Channels.newChannel(baos));

    final byte[] bytes = baos.toByteArray();
    Assert.assertEquals(theSupplier.getSerializedSize(), bytes.length);

    supplier = CompressedVSizeIntsIndexedSupplier.fromByteBuffer(ByteBuffer.wrap(bytes), byteOrder);
    indexed = supplier.get();
  }
  // This test attempts to cause a race condition with the DirectByteBuffers, it's non-deterministic
  // in causing it,
  // which sucks but I can't think of a way to deterministically cause it...
  @Test
  public void testConcurrentThreadReads() throws Exception {
    setupSimple(4);

    final AtomicReference<String> reason = new AtomicReference<>("none");

    final int numRuns = 1000;
    final CountDownLatch startLatch = new CountDownLatch(1);
    final CountDownLatch stopLatch = new CountDownLatch(2);
    final AtomicBoolean failureHappened = new AtomicBoolean(false);
    new Thread(
            new Runnable() {
              @Override
              public void run() {
                try {
                  startLatch.await();
                } catch (InterruptedException e) {
                  failureHappened.set(true);
                  reason.set("interrupt.");
                  stopLatch.countDown();
                  return;
                }

                try {
                  for (int i = 0; i < numRuns; ++i) {
                    for (int j = 0; j < indexed.size(); ++j) {
                      final long val = vals[j];
                      final long indexedVal = indexed.get(j);
                      if (Longs.compare(val, indexedVal) != 0) {
                        failureHappened.set(true);
                        reason.set(String.format("Thread1[%d]: %d != %d", j, val, indexedVal));
                        stopLatch.countDown();
                        return;
                      }
                    }
                  }
                } catch (Exception e) {
                  e.printStackTrace();
                  failureHappened.set(true);
                  reason.set(e.getMessage());
                }

                stopLatch.countDown();
              }
            })
        .start();

    final IndexedInts indexed2 = supplier.get();
    try {
      new Thread(
              new Runnable() {
                @Override
                public void run() {
                  try {
                    startLatch.await();
                  } catch (InterruptedException e) {
                    stopLatch.countDown();
                    return;
                  }

                  try {
                    for (int i = 0; i < numRuns; ++i) {
                      for (int j = indexed2.size() - 1; j >= 0; --j) {
                        final long val = vals[j];
                        final long indexedVal = indexed2.get(j);
                        if (Longs.compare(val, indexedVal) != 0) {
                          failureHappened.set(true);
                          reason.set(String.format("Thread2[%d]: %d != %d", j, val, indexedVal));
                          stopLatch.countDown();
                          return;
                        }
                      }
                    }
                  } catch (Exception e) {
                    e.printStackTrace();
                    reason.set(e.getMessage());
                    failureHappened.set(true);
                  }

                  stopLatch.countDown();
                }
              })
          .start();

      startLatch.countDown();

      stopLatch.await();
    } finally {
      CloseQuietly.close(indexed2);
    }

    if (failureHappened.get()) {
      Assert.fail("Failure happened.  Reason: " + reason.get());
    }
  }