private void correctInconsistentPending(int targetDistBits) {
            boolean maybeInconsistent = true;
            long bucketsSplit = 0, bucketsMerged = 0;
            long pendingBefore = progressToken.getPendingBucketCount();
            ProgressToken p = progressToken;

            // Optimization: before doing any splitting/merging at all, we check
            // to see if we can't simply just reset the entire internal state
            // with the new distribution bit count. This ensures that if we go
            // from eg. 1 bit to 20 bits, we won't have to perform a grueling
            // half a million splits to cover the same bucket space as that 1
            // single-bit bucket once did
            if (isLosslessResetPossible()) {
                if (log.isLoggable(Level.FINE)) {
                    log.log(Level.FINE, "At start of bucket space and all " +
                            "buckets have no progress; doing a lossless reset " +
                            "instead of splitting/merging");
                }
                assert(p.getActiveBucketCount() == 0);
                p.clearAllBuckets();
                p.setBucketCursor(0);
                return;
            }

            while (maybeInconsistent) {
                BucketId lastMergedBucket = null;
                maybeInconsistent = false;
                // Make a shallow working copy of the bucket map. BucketKeyWrapper
                // keys are considered immutable, and should thus not be at risk
                // for being changed during the inner loop
                // Do separate passes for splitting and merging just to make
                // absolutely sure that the two ops won't step on each others'
                // toes. This isn't wildly efficient, but the data sets in question
                // are presumed to be low in size and this is presumed to be a very
                // infrequent operation
                TreeMap<ProgressToken.BucketKeyWrapper, ProgressToken.BucketEntry> buckets
                        = new TreeMap<ProgressToken.BucketKeyWrapper, ProgressToken.BucketEntry>(p.getBuckets());
                for (Map.Entry<ProgressToken.BucketKeyWrapper, ProgressToken.BucketEntry> entry
                        : buckets.entrySet()) {
                    assert(entry.getValue().getState() == ProgressToken.BucketState.BUCKET_PENDING);
                    BucketId pending = new BucketId(ProgressToken.keyToBucketId(entry.getKey().key()));
                    if (pending.getUsedBits() < targetDistBits) {
                        if (pending.getUsedBits() + 1 < targetDistBits) {
                            maybeInconsistent = true; // Do another pass
                        }
                        p.splitPendingBucket(pending);
                        ++bucketsSplit;
                    }
                }

                // Make new map copy with potentially split buckets
                buckets = new TreeMap<ProgressToken.BucketKeyWrapper, ProgressToken.BucketEntry>(p.getBuckets());
                for (Map.Entry<ProgressToken.BucketKeyWrapper, ProgressToken.BucketEntry> entry
                        : buckets.entrySet()) {
                    assert(entry.getValue().getState() == ProgressToken.BucketState.BUCKET_PENDING);
                    BucketId pending = new BucketId(ProgressToken.keyToBucketId(entry.getKey().key()));
                    if (pending.getUsedBits() > targetDistBits) {
                        // If this is the right sibling of an already merged left sibling,
                        // it's already been merged away, so we should skip it
                        if (lastMergedBucket != null) {
                            BucketId rightCheck = new BucketId(lastMergedBucket.getUsedBits(),
                                    lastMergedBucket.getId() | (1L << (lastMergedBucket.getUsedBits() - 1)));
                            if (pending.equals(rightCheck)) {
                                if (log.isLoggable(Level.FINEST)) {
                                    log.log(Level.FINEST, "Skipped " + pending +
                                            ", as it was right sibling of " + lastMergedBucket);
                                }
                                continue;
                            }
                        }
                        if (pending.getUsedBits() - 1 > targetDistBits) {
                            maybeInconsistent = true; // Do another pass
                        }
                        p.mergePendingBucket(pending);
                        ++bucketsMerged;

                        lastMergedBucket = pending;
                    }
                }
            }
            if ((bucketsSplit > 0 || bucketsMerged > 0) && log.isLoggable(Level.FINE)) {
                log.log(Level.FINE, "Existing progress' pending buckets had inconsistent " +
                        "distribution bits; performed " + bucketsSplit + " split ops and " +
                        bucketsMerged + " merge ops. Pending: " + pendingBefore + " -> " +
                        p.getPendingBucketCount());
            }
            totalBucketsSplit += bucketsSplit;
            totalBucketsMerged += bucketsMerged;
        }
Ensure that a given <code>ProgressToken</code> instance only has
buckets pending that have a used-bits count of that of the
<code>targetDistCits</code>. This is done by splitting or merging
all inconsistent buckets until the desired state is reached.

Time complexity is approx <i>O(4bn)</i> where <i>b</i> is the maximum
delta of bits to change anywhere in the set of pending and <i>n</i>
is the number of pending. This includes the time spent making shallow
map copies.

@param targetDistBits The desired distribution bit count of the buckets
documentapi/src/main/java/com/yahoo/documentapi/VisitorIterator.java