cdm/src/main/java/ucar/nc2/util/cache/FileCache.java
@Override
  public FileCacheable acquire(FileFactory factory, Object hashKey, DatasetUrl location,
                               int buffer_size, CancelTask cancelTask, Object spiObject) throws IOException {

    if (null == hashKey) hashKey = location.trueurl;
    if (null == hashKey) throw new IllegalArgumentException();

    Tracker t = null;
    if (trackAll) {
      t = new Tracker(hashKey);
      Tracker prev = track.putIfAbsent(hashKey, t);
      if (prev != null) t = prev;
    }

    FileCacheable ncfile = acquireCacheOnly(hashKey);
    if (ncfile != null) {
      hits.incrementAndGet();
      if (t != null) t.hit++;
      return ncfile;
    }
    miss.incrementAndGet();
    if (t != null) t.miss++;

    // open the file
    ncfile = factory.open(location, buffer_size, cancelTask, spiObject);
    if (cacheLog.isDebugEnabled())
      cacheLog.debug("FileCache " + name + " acquire " + hashKey + " " + ncfile.getLocation());
    if (debugPrint) System.out.println("  FileCache " + name + " acquire " + hashKey + " " + ncfile.getLocation());

    // user may have canceled
    if ((cancelTask != null) && (cancelTask.isCancel())) {
      if (ncfile != null) ncfile.close();       // LOOK ??
      return null;
    }

    if (disabled.get()) return ncfile;

    // see if cache element already exists
    // cant use putIfAbsent, because we cant create the CacheElement until we know if doesnt exist
    CacheElement elem;
    synchronized (cache) {
      elem = cache.get(hashKey);
      if (elem == null) cache.put(hashKey, new CacheElement(ncfile, hashKey)); // new element
    }

    // already exists, add to list
    if (elem != null) {
      synchronized (elem) {
        elem.addFile(ncfile); // add to existing list
      }
    }

    // increment the number of files in the cache
    //int count = counter.incrementAndGet();

    // do we need a cleanup ??
    boolean needHard = false;
    boolean needSoft = false;
    synchronized (hasScheduled) {
      if (!hasScheduled.get()) {
        int count = files.size();
        if ((count > hardLimit) && (hardLimit > 0)) {
          needHard = true;
          hasScheduled.getAndSet(true); // tell other threads not to schedule another cleanup

        } else if ((count > softLimit) && (softLimit > 0)) {   // && wantsCleanup) { //
          hasScheduled.getAndSet(true); // tell other threads not to schedule another cleanup
          needSoft = true;
        }
      }
    }

    if (needHard) {
      if (debugCleanup)
        System.out.println("CleanupTask due to hard limit time=" + new Date().getTime()); // +" Thread="+Thread.currentThread().hashCode()
      cleanup(hardLimit);

    } else if (needSoft) {
      schedule(new CleanupTask(), 100); // immediate cleanup in 100 msec

      if (debugCleanup) System.out.println("CleanupTask scheduled due to soft limit time=" + new Date());
    }

    return ncfile;
  }
@Override
  public FileCacheable acquire(FileFactory factory, Object hashKey, DatasetUrl location,
                               int buffer_size, CancelTask cancelTask, Object spiObject) throws IOException {

    if (null == hashKey) hashKey = location.trueurl;
    if (null == hashKey) throw new IllegalArgumentException();

    Tracker t = null;
    if (trackAll) {
      t = new Tracker(hashKey);
      Tracker prev = track.putIfAbsent(hashKey, t);
      if (prev != null) t = prev;
    }

    FileCacheable ncfile = acquireCacheOnly(hashKey);
    if (ncfile != null) {
      hits.incrementAndGet();
      if (t != null) t.hit++;
      return ncfile;
    }
    miss.incrementAndGet();
    if (t != null) t.miss++;

    // open the file
    ncfile = factory.open(location, buffer_size, cancelTask, spiObject);
    if (cacheLog.isDebugEnabled())
      cacheLog.debug("FileCache " + name + " acquire " + hashKey + " " + ncfile.getLocation());
    if (debugPrint) System.out.println("  FileCache " + name + " acquire " + hashKey + " " + ncfile.getLocation());

    // user may have canceled
    if ((cancelTask != null) && (cancelTask.isCancel())) {
      if (ncfile != null) ncfile.close();       // LOOK ??
      return null;
    }

    if (disabled.get()) return ncfile;

    // see if cache element already exists
    // cant use putIfAbsent, because we cant create the CacheElement until we know if doesnt exist
    CacheElement elem;
    synchronized (cache) {
      elem = cache.get(hashKey);
      if (elem == null) cache.put(hashKey, new CacheElement(ncfile, hashKey)); // new element
    }

    // already exists, add to list
    if (elem != null) {
      synchronized (elem) {
        elem.addFile(ncfile); // add to existing list
      }
    }

    // increment the number of files in the cache
    //int count = counter.incrementAndGet();

    // do we need a cleanup ??
    boolean needHard = false;
    boolean needSoft = false;
    synchronized (hasScheduled) {
      if (!hasScheduled.get()) {
        int count = files.size();
        if ((count > hardLimit) && (hardLimit > 0)) {
          needHard = true;
          hasScheduled.getAndSet(true); // tell other threads not to schedule another cleanup

        } else if ((count > softLimit) && (softLimit > 0)) {   // && wantsCleanup) { //
          hasScheduled.getAndSet(true); // tell other threads not to schedule another cleanup
          needSoft = true;
        }
      }
    }

    if (needHard) {
      if (debugCleanup)
        System.out.println("CleanupTask due to hard limit time=" + new Date().getTime()); // +" Thread="+Thread.currentThread().hashCode()
      cleanup(hardLimit);

    } else if (needSoft) {
      schedule(new CleanupTask(), 100); // immediate cleanup in 100 msec

      if (debugCleanup) System.out.println("CleanupTask scheduled due to soft limit time=" + new Date());
    }

    return ncfile;
  }
@ Override public FileCacheable acquire ( FileFactory factory , Object hashKey , DatasetUrl location , int buffer_size , CancelTask cancelTask , Object spiObject ) throws IOException { if ( null == hashKey ) hashKey = location . trueurl ; if ( null == hashKey ) throw new IllegalArgumentException ( ) ; Tracker t = null ; if ( trackAll ) { t = new Tracker ( hashKey ) ; Tracker prev = track . putIfAbsent ( hashKey , t ) ; if ( prev != null ) t = prev ; } FileCacheable ncfile = acquireCacheOnly ( hashKey ) ; if ( ncfile != null ) { hits . incrementAndGet ( ) ; if ( t != null ) t . hit ++ ; return ncfile ; } miss . incrementAndGet ( ) ; if ( t != null ) t . miss ++ ; // open the file
 ncfile = factory . open ( location , buffer_size , cancelTask , spiObject ) ; if ( cacheLog . isDebugEnabled ( ) ) cacheLog . debug ( "FileCache " + name + " acquire " + hashKey + " " + ncfile . getLocation ( ) ) ; if ( debugPrint ) System . out . println ( "  FileCache " + name + " acquire " + hashKey + " " + ncfile . getLocation ( ) ) ; // user may have canceled
 if ( ( cancelTask != null ) && ( cancelTask . isCancel ( ) ) ) { if ( ncfile != null ) ncfile . close ( ) ; // LOOK ??
 return null ; } if ( disabled . get ( ) ) return ncfile ; // see if cache element already exists
 // cant use putIfAbsent, because we cant create the CacheElement until we know if doesnt exist
 CacheElement elem ; synchronized ( cache ) { elem = cache . get ( hashKey ) ; if ( elem == null ) cache . put ( hashKey , new CacheElement ( ncfile , hashKey ) ) ; // new element
 } // already exists, add to list
 if ( elem != null ) { synchronized ( elem ) { elem . addFile ( ncfile ) ; // add to existing list
 } } // increment the number of files in the cache
 //int count = counter.incrementAndGet();
 // do we need a cleanup ??
 boolean needHard = false ; boolean needSoft = false ; synchronized ( hasScheduled ) { if ( ! hasScheduled . get ( ) ) { int count = files . size ( ) ; if ( ( count > hardLimit ) && ( hardLimit > 0 ) ) { needHard = true ; hasScheduled . getAndSet ( true ) ; // tell other threads not to schedule another cleanup
 } else if ( ( count > softLimit ) && ( softLimit > 0 ) ) { // && wantsCleanup) { //
 hasScheduled . getAndSet ( true ) ; // tell other threads not to schedule another cleanup
 needSoft = true ; } } } if ( needHard ) { if ( debugCleanup ) System . out . println ( "CleanupTask due to hard limit time=" + new Date ( ) . getTime ( ) ) ; // +" Thread="+Thread.currentThread().hashCode()
 cleanup ( hardLimit ) ; } else if ( needSoft ) { schedule ( new CleanupTask ( ) , 100 ) ; // immediate cleanup in 100 msec
 if ( debugCleanup ) System . out . println ( "CleanupTask scheduled due to soft limit time=" + new Date ( ) ) ; } return ncfile ; }
Acquire a FileCacheable from the cache, and lock it so no one else can use it.
If not already in cache, open it the FileFactory, and put in cache.
<p/>
App should  call FileCacheable.close when done, and the file is then released instead of closed.
<p/>
If cache size goes over maxElement, then immediately (actually in 100 msec) schedule a cleanup in a background thread.
This means that the cache should never get much larger than maxElement, unless you have them all locked.

@param factory     use this factory to open the file if not in the cache; may not be null
@param hashKey     unique key for this file. If null, the location will be used
@param location    file location, may also used as the cache name, will be passed to the NetcdfFileFactory
@param buffer_size RandomAccessFile buffer size, if <= 0, use default size
@param cancelTask  user can cancel, ok to be null.
@param spiObject   passed to the factory if object needs to be recreated
@return FileCacheable corresponding to location.
@throws IOException on error
Acquire a FileCacheable from the cache and lock it so no one else can use it . If not already in cache open it the FileFactory and put in cache . <p / > App should call FileCacheable . close when done and the file is then released instead of closed . <p / > If cache size goes over maxElement then immediately ( actually in 100 msec ) schedule a cleanup in a background thread . This means that the cache should never get much larger than maxElement unless you have them all locked .