public Set getKeysLocally(Integer bucketId, boolean allowTombstones)
      throws PRLocallyDestroyedException, ForceReattemptException {
    if (logger.isDebugEnabled()) {
      logger.debug("handleRemoteGetKeys: bucketId: {}{}{}", partitionedRegion.getPRId(),
          PartitionedRegion.BUCKET_ID_SEPARATOR, bucketId);
    }
    Set ret = Collections.EMPTY_SET;
    final BucketRegion r = getInitializedBucketForId(null, bucketId);
    invokeBucketReadHook();
    try {
      if (r != null) {
        // A copy is made so that the bucket is free to move
        ret = new HashSet(r.keySet(allowTombstones));
        checkIfBucketMoved(r);
      }
    } catch (RegionDestroyedException rde) {
      if (partitionedRegion.isLocallyDestroyed || partitionedRegion.isClosed) {
        throw new PRLocallyDestroyedException(rde);
      } else {
        getPartitionedRegion().checkReadiness();
        if (r.isBucketDestroyed()) {
          // bucket moved by rebalance
          throw new ForceReattemptException("Bucket removed during keySet", rde);
        } else {
          throw new RegionDestroyedException(
              String.format("Unable to fetch keys on %s",
                  partitionedRegion),
              partitionedRegion.getFullPath(), rde);
        }
      }
    }
    return ret;
  }
Get the local keys for a given bucket. This operation should be as efficient as possible, by
avoiding making copies of the returned set. The returned set can and should reflect concurrent
changes (no ConcurrentModificationExceptions).

@param allowTombstones whether to include destroyed entries in the result
@return The <code>Set</code> of keys for bucketId or {@link Collections#EMPTY_SET} if no keys
        are present
@throws PRLocallyDestroyedException if the PartitionRegion is locally destroyed
geode-core/src/main/java/org/apache/geode/internal/cache/PartitionedRegionDataStore.java