private synchronized void init() {
    if (clientPoolCache == null) {
      // Since Caffeine does not ensure that removalListener will be involved after expiration
      // We use a scheduler with one thread to clean up expired clients.
      clientPoolCache =
          Caffeine.newBuilder()
              .expireAfterAccess(evictionInterval, TimeUnit.MILLISECONDS)
              .removalListener((ignored, value, cause) -> ((HiveClientPool) value).close())
              .scheduler(
                  Scheduler.forScheduledExecutorService(
                      ThreadPools.newScheduledPool("hive-metastore-cleaner", 1)))
              .build();
    }
  }
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