private BucketMembershipObserverResults waitForOwnersGetPrimary(int expectedCount,
        Collection<InternalDistributedMember> expectedOwners, String partitionName)
        throws InterruptedException {
      boolean problematicDeparture = false;
      synchronized (this) {
        while (true) {
          bucketToMonitor.getCancelCriterion().checkCancelInProgress(null);

          // If any departures, need to rethink much...
          boolean oldDepartures = departures.get();
          if (oldDepartures) {
            verifyBucketNodes(expectedOwners, partitionName);
            if (expectedOwners.isEmpty()) {
              problematicDeparture = true; // need to pick new victims
            }

            // need to pick new victims
            arrivals.set(expectedOwners.size());
            departures.set(false);

            if (problematicDeparture) {
              if (logger.isDebugEnabled()) {
                logger.debug("Bucket observer found departed members - retrying");
              }
            }
            break;
          }

          // Look for success...
          int oldArrivals = arrivals.get();
          if (oldArrivals >= expectedCount) {
            // success!
            break;
          }

          if (logger.isDebugEnabled()) {
            logger.debug("Waiting for bucket {} to finish being created",
                partitionedRegion.bucketStringForLogs(bucketToMonitor.getId()));
          }

          partitionedRegion.checkReadiness();

          int creationWaitMillis = 5 * 1000;
          wait(creationWaitMillis);

          if (oldArrivals == arrivals.get() && oldDepartures == departures.get()) {
            logger.warn(
                "Time out waiting {} ms for creation of bucket for partitioned region {}. Members requested to create the bucket are: {}",
                creationWaitMillis, partitionedRegion.getFullPath(), expectedOwners);
          }
        }
      }

      if (problematicDeparture) {
        return new BucketMembershipObserverResults(true, null);
      }

      InternalDistributedMember primary = bucketToMonitor.getBucketAdvisor().getPrimary();
      if (primary == null) {
        /*
         * Handle a race where nobody has the bucket. We can't return a null member here because we
         * haven't created the bucket, need to let the higher level code loop.
         */
        return new BucketMembershipObserverResults(true, null);
      }
      return new BucketMembershipObserverResults(false, primary);
    }
Wait for expected number of owners to be recognized. When the expected number have been seen,
then fetch the primary and report it. If while waiting for the owners to be recognized there
is a departure which compromises redundancy

@param expectedCount the number of bucket owners to wait for
@param expectedOwners the list of owners used when a departure is detected
@return if no problematic departures are detected, the primary
geode-core/src/main/java/org/apache/geode/internal/cache/PRHARedundancyProvider.java