@VisibleForTesting
  static Key extractKey(String cacheKeys, Configuration conf) {
    // generate key elements in a certain order, so that the Key instances are comparable
    List<Object> elements = Lists.newArrayList();
    elements.add(conf.get(HiveConf.ConfVars.METASTORE_URIS.varname, ""));
    elements.add(conf.get(HiveCatalog.HIVE_CONF_CATALOG, "hive"));
    if (cacheKeys == null || cacheKeys.isEmpty()) {
      return Key.of(elements);
    }

    Set<KeyElementType> types = Sets.newTreeSet(Comparator.comparingInt(Enum::ordinal));
    Map<String, String> confElements = Maps.newTreeMap();
    for (String element : cacheKeys.split(",", -1)) {
      String trimmed = element.trim();
      if (trimmed.toLowerCase(Locale.ROOT).startsWith(CONF_ELEMENT_PREFIX)) {
        String key = trimmed.substring(CONF_ELEMENT_PREFIX.length());
        ValidationException.check(
            !confElements.containsKey(key), "Conf key element %s already specified", key);
        confElements.put(key, conf.get(key));
      } else {
        KeyElementType type = KeyElementType.valueOf(trimmed.toUpperCase());
        switch (type) {
          case UGI:
          case USER_NAME:
            ValidationException.check(
                !types.contains(type), "%s key element already specified", type.name());
            types.add(type);
            break;
          default:
            throw new ValidationException("Unknown key element %s", trimmed);
        }
      }
    }
    for (KeyElementType type : types) {
      switch (type) {
        case UGI:
          try {
            elements.add(UserGroupInformation.getCurrentUser());
          } catch (IOException e) {
            throw new UncheckedIOException(e);
          }
          break;
        case USER_NAME:
          try {
            elements.add(UserGroupInformation.getCurrentUser().getUserName());
          } catch (IOException e) {
            throw new UncheckedIOException(e);
          }
          break;
        default:
          throw new RuntimeException("Unexpected key element " + type.name());
      }
    }
    for (String key : confElements.keySet()) {
      elements.add(ConfElement.of(key, confElements.get(key)));
    }
    return Key.of(elements);
  }
A ClientPool that caches the underlying HiveClientPool instances.

<p>The following key elements are supported and can be specified via {@link
CatalogProperties#CLIENT_POOL_CACHE_KEYS}:

<ul>
  <li>ugi - the Hadoop UserGroupInformation instance that represents the current user using the
      cache.
  <li>user_name - similar to UGI but only includes the user's name determined by
      UserGroupInformation#getUserName.
  <li>conf - name of an arbitrary configuration. The value of the configuration will be extracted
      from catalog properties and added to the cache key. A conf element should start with a
      "conf:" prefix which is followed by the configuration name. E.g. specifying "conf:a.b.c"
      will add "a.b.c" to the key, and so that configurations with different default catalog
      wouldn't share the same client pool. Multiple conf elements can be specified.
</ul>
iceberg/iceberg-catalog/src/main/java/org/apache/iceberg/hive/CachedClientPool.java