@Override
  public void run2() {
    try {
      boolean warningLogged = false;
      while (getLatchCount() > 0) {
        int sleepMillis = SLEEP_PERIOD;
        // reduce the first log time from 15secs so that higher layers can
        // report sooner to user
        if (!warningLogged) {
          sleepMillis = SLEEP_PERIOD / 2;
        }
        if (regions.isEmpty()) {
          break;
        }
        Thread.sleep(sleepMillis);

        if (membershipChanged) {
          membershipChanged = false;
          for (Iterator<RegionStatus> itr = regions.iterator(); itr.hasNext();) {
            RegionStatus region = itr.next();
            try {
              region.logWaitingForMembers();
            } catch (RegionDestroyedException e) {
              itr.remove();
            }
          }
          warningLogged = true;
        }
      }

    } catch (InterruptedException e) {
      // Log and bail
      logger.error(e.getMessage(), e);
    } finally {
      if (!regions.isEmpty()) {

        /*
         * Our job is done. Stop listening to the bucket advisors.
         */
        removeListeners();
        /*
         * Make sure the recovery completion message was printed to the log.
         */

        for (RegionStatus region : regions) {
          if (!region.loggedDoneMessage) {
            region.logDoneMessage();
          }
        }

        regions.clear();
      }
    }
  }
Writes a consolidated log entry every SLEEP_PERIOD that summarizes which buckets are still
waiting on persistent members for the region.
geode-core/src/main/java/org/apache/geode/internal/cache/partitioned/PersistentBucketRecoverer.java