@Override
                  public void onCompletion(Void result, Exception exception) {
                    countDownLatch.countDown();
                    blobAccessInfo.burstGetReferenceCount.decrementAndGet();
                    if (countDownLatch.getCount() == 0) {
                      countDownLatchForBatch.countDown();
                    }
                    if (exception != null) {
                      logger.error("Get and validation of {} failed with ", blobAccessInfo.blobId, exception);
                      failureCount.incrementAndGet();
                    }
                  }
Get threads to assist in consuming blobs from ambry and verifying its content
Get thread also proceeds in multiple phases until {@code totalPutCount} number of blobs have been fetched and
verified. Blobs and its metadata information are fetched from {@code generatedBlobAccessInfos}. On each phase,
the get thread fetches {@code parallelGetCount} number of blobs from the {@code generatedBlobAccessInfos} and
issues random (max of {@code maxBurstCountPerblob} number of burst GET calls(and validates) to Ambry via
{@link PutGetHelper#getBlobAndValidate(String, byte[], Object, Callback, MetricsCollector)}. Each blob is fetched for a maximum of
{@code maxGetCountPerBlob} times. On reaching the threshold, they are removed from the
{@code generatedBlobAccessInfos} and deletion is called via
{@link PutGetHelper#deleteBlobAndValidate(String, Object, Callback, MetricsCollector)} if {@code deleteOnExit} is set. On completion
of one phase, the thread proceeds onto the next phase after sleeping for max of {@code sleepTimeBetweenBatchGetsInMs} ms.
ambry-tools/src/main/java/com/github/ambry/tools/admin/ConcurrencyTestTool.java