@Override
      public void run() {
        numRemovedTTL = 0;
        numRemovedLRU = 0;
        long cleanerStartTime = System.currentTimeMillis();
        LOG.info("AggregateStatsCache is " + getFullPercent() + "% full, with "
            + getCurrentNodes() + " nodes; starting cleaner thread");
        try {
          Iterator<Map.Entry<Key, AggrColStatsList>> mapIterator = cacheStore.entrySet().iterator();
          while (mapIterator.hasNext()) {
            Map.Entry<Key, AggrColStatsList> pair =
                mapIterator.next();
            AggrColStats node;
            AggrColStatsList candidateList = pair.getValue();
            List<AggrColStats> nodes = candidateList.nodes;
            if (nodes.size() == 0) {
              mapIterator.remove();
              continue;
            }
            boolean isLocked = false;
            try {
              isLocked = candidateList.writeLock.tryLock(maxWriterWaitTime, TimeUnit.MILLISECONDS);
              if (isLocked) {
                for (Iterator<AggrColStats> listIterator = nodes.iterator(); listIterator.hasNext();) {
                  node = listIterator.next();
                  // Remove the node if it has expired
                  if (isExpired(node)) {
                    listIterator.remove();
                    numRemovedTTL++;
                    currentNodes.getAndDecrement();
                  }
                }
              }
            } catch (InterruptedException e) {
              LOG.debug("Interrupted Exception ignored ",e);
            } finally {
              if (isLocked) {
                candidateList.writeLock.unlock();
              }
            }
            // We want to make sure this runs at a low priority in the background
            Thread.yield();
          }
          // If the expired nodes did not result in cache being cleanUntil% in size,
          // start removing LRU nodes
          while (getCurrentNodes() / maxCacheNodes > cleanUntil) {
            evictOneNode();
          }
        } finally {
          isCleaning = false;
          LOG.info("Stopping cleaner thread; AggregateStatsCache is now " + getFullPercent()
              + "% full, with " + getCurrentNodes() + " nodes");
          LOG.info("Number of expired nodes removed: " + numRemovedTTL);
          LOG.info("Number of LRU nodes removed: " + numRemovedLRU);
          LOG.info("Cleaner ran for: " + (System.currentTimeMillis() - cleanerStartTime) + "ms");
        }
      }
Cleans the expired nodes or removes LRU nodes of the cache,
until the cache size reduces to cleanUntil% full.
standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/AggregateStatsCache.java