public void gcTombstoneKeys(final LocalRegion r, final Set<Object> tombstoneKeys) {
    if (r.getServerProxy() == null) {
      // if the region does not have a server proxy
      // then it will not have any tombstones to gc for the server.
      return;
    }
    if (logger.isDebugEnabled()) {
      logger.debug("gcTombstoneKeys invoked for region {} and keys {}", r, tombstoneKeys);
    }
    final TombstoneSweeper sweeper = getSweeper(r);
    final List<Tombstone> removals = new ArrayList<>(tombstoneKeys.size());
    sweeper.removeUnexpiredIf(t -> {
      if (t.region == r) {
        if (tombstoneKeys.contains(t.entry.getKey())) {
          removals.add(t);
          return true;
        }
      }
      return false;
    });

    for (Tombstone t : removals) {
      // TODO - RVV - to support persistent client regions
      // we need to actually record this as a destroy on disk, because
      // the GCC RVV doesn't make sense on the client.
      t.region.getRegionMap().removeTombstone(t.entry, t);
    }
  }
client tombstone removal is key-based if the server is a PR. This is due to the server having
separate version vectors for each bucket. In the client this causes the version vector to make
no sense, so we have to send it a collection of the keys removed on the server and then we
brute-force remove any of them that are tombstones on the client

@param r the region affected
@param tombstoneKeys the keys removed on the server
geode-core/src/main/java/org/apache/geode/internal/cache/TombstoneService.java