cdm/src/main/java/ucar/nc2/util/cache/FileCache.java
synchronized void cleanup(int maxElements) {

    try {
      /* int size = counter.get();
      int fsize = files.size();
      if (debug && (size != fsize)) {
        log.warn("FileCache " + name + " counter " + size + " doesnt match files().size=" + fsize);
      } */

      int size = files.size();
      if (size <= minElements) return;

      if (cacheLog.isDebugEnabled()) cacheLog.debug("FileCache {} cleanup started at {} for maxElements={}", name, CalendarDate.present(), maxElements);
      if (debugCleanup)
        System.out.printf(" FileCache %s cleanup started at %s for maxElements=%d%n", name, CalendarDate.present(), maxElements);

      cleanups.incrementAndGet();

      // add unlocked files to the all list
      List<CacheElement.CacheFile> allFiles = new ArrayList<>(size + 10);
      for (CacheElement.CacheFile file : files.values()) {
        if (!file.isLocked.get()) allFiles.add(file);
      }
      Collections.sort(allFiles); // sort so oldest are on top

      // take oldest ones and put on delete list
      int need2delete = size - minElements;
      int minDelete = size - maxElements;
      List<CacheElement.CacheFile> deleteList = new ArrayList<>(need2delete);

      int count = 0;
      Iterator<CacheElement.CacheFile> iter = allFiles.iterator();
      while (iter.hasNext() && (count < need2delete)) {
        CacheElement.CacheFile file = iter.next();
        if (file.isLocked.compareAndSet(false, true)) { // lock it so it isnt used anywhere else
          file.remove(); // remove from the containing element
          deleteList.add(file);
          count++;
        }
      }
      if (count < minDelete) {
        cacheLog.warn("FileCache " + name + " cleanup couldnt remove enough to keep under the maximum= " + maxElements + " due to locked files; currently at = " + (size - count));
        if (debugCleanup)
          System.out.println("FileCache " + name + " cleanup couldnt remove enough to keep under the maximum= " + maxElements + " due to locked files; currently at = " + (size - count));
      }

      // remove empty cache elements
      synchronized (cache) {
        for (CacheElement elem : cache.values()) {
          synchronized (elem) {
            if (elem.list.size() == 0)
              cache.remove(elem.hashKey);
          }
        }
      }

      // now actually close the files
      long start = System.currentTimeMillis();
      for (CacheElement.CacheFile file : deleteList) {
        //counter.decrementAndGet();
        if (null == files.remove(file.ncfile)) {
          if (cacheLog.isDebugEnabled()) cacheLog.debug(" FileCache {} cleanup failed to remove {}%n", name, file.ncfile.getLocation());
        }
        try {
          file.ncfile.setFileCache(null);
          file.ncfile.close();
          file.ncfile = null; // help the gc
        } catch (IOException e) {
          log.error("FileCache " + name + " close failed on " + file.getCacheName());
        }
      }

      long took = System.currentTimeMillis() - start;
      if (cacheLog.isDebugEnabled()) cacheLog.debug(" FileCache {} cleanup had={} removed={} took={} msecs%n", name, size,deleteList.size(), took);
      if (debugCleanup)
        System.out.printf(" FileCache %s cleanup had=%d removed=%d took=%d msecs%n", name, size,deleteList.size(), took);

    } finally {
      // allow scheduling again
      hasScheduled.set(false);
    }
  }
synchronized void cleanup(int maxElements) {

    try {
      /* int size = counter.get();
      int fsize = files.size();
      if (debug && (size != fsize)) {
        log.warn("FileCache " + name + " counter " + size + " doesnt match files().size=" + fsize);
      } */

      int size = files.size();
      if (size <= minElements) return;

      if (cacheLog.isDebugEnabled()) cacheLog.debug("FileCache {} cleanup started at {} for maxElements={}", name, CalendarDate.present(), maxElements);
      if (debugCleanup)
        System.out.printf(" FileCache %s cleanup started at %s for maxElements=%d%n", name, CalendarDate.present(), maxElements);

      cleanups.incrementAndGet();

      // add unlocked files to the all list
      List<CacheElement.CacheFile> allFiles = new ArrayList<>(size + 10);
      for (CacheElement.CacheFile file : files.values()) {
        if (!file.isLocked.get()) allFiles.add(file);
      }
      Collections.sort(allFiles); // sort so oldest are on top

      // take oldest ones and put on delete list
      int need2delete = size - minElements;
      int minDelete = size - maxElements;
      List<CacheElement.CacheFile> deleteList = new ArrayList<>(need2delete);

      int count = 0;
      Iterator<CacheElement.CacheFile> iter = allFiles.iterator();
      while (iter.hasNext() && (count < need2delete)) {
        CacheElement.CacheFile file = iter.next();
        if (file.isLocked.compareAndSet(false, true)) { // lock it so it isnt used anywhere else
          file.remove(); // remove from the containing element
          deleteList.add(file);
          count++;
        }
      }
      if (count < minDelete) {
        cacheLog.warn("FileCache " + name + " cleanup couldnt remove enough to keep under the maximum= " + maxElements + " due to locked files; currently at = " + (size - count));
        if (debugCleanup)
          System.out.println("FileCache " + name + " cleanup couldnt remove enough to keep under the maximum= " + maxElements + " due to locked files; currently at = " + (size - count));
      }

      // remove empty cache elements
      synchronized (cache) {
        for (CacheElement elem : cache.values()) {
          synchronized (elem) {
            if (elem.list.size() == 0)
              cache.remove(elem.hashKey);
          }
        }
      }

      // now actually close the files
      long start = System.currentTimeMillis();
      for (CacheElement.CacheFile file : deleteList) {
        //counter.decrementAndGet();
        if (null == files.remove(file.ncfile)) {
          if (cacheLog.isDebugEnabled()) cacheLog.debug(" FileCache {} cleanup failed to remove {}%n", name, file.ncfile.getLocation());
        }
        try {
          file.ncfile.setFileCache(null);
          file.ncfile.close();
          file.ncfile = null; // help the gc
        } catch (IOException e) {
          log.error("FileCache " + name + " close failed on " + file.getCacheName());
        }
      }

      long took = System.currentTimeMillis() - start;
      if (cacheLog.isDebugEnabled()) cacheLog.debug(" FileCache {} cleanup had={} removed={} took={} msecs%n", name, size,deleteList.size(), took);
      if (debugCleanup)
        System.out.printf(" FileCache %s cleanup had=%d removed=%d took=%d msecs%n", name, size,deleteList.size(), took);

    } finally {
      // allow scheduling again
      hasScheduled.set(false);
    }
  }
Cleanup the cache, bringing it down to minimum number.
Will close the LRU (least recently used) ones first. Will not close locked files.
Normally this is done in a background thread, you dont need to call.
<p/>
We have to synchronize because of clearCache()