Program: 154066
Project: 154066
Buggy source:
/** 
 * Adds a tile to the cache with an associated tile compute cost. <p> If the specified tile is already in the cache, it will not be cached again.  If by adding this tile, the cache exceeds the memory capacity, older tiles in the cache are removed to keep the cache memory usage under the specified limit.
 * @param owner            The image the tile blongs to.
 * @param tileX            The tile's X index within the image.
 * @param tileY            The tile's Y index within the image.
 * @param tile             The tile to be cached.
 * @param tileCacheMetric  Metric for prioritizing tiles
 */
public synchronized void add(RenderedImage owner,int tileX,int tileY,Raster tile,Object tileCacheMetric){
  if (memoryCapacity == 0) {
    return;
  }
  Object key=SunCachedTile.hashKey(owner,tileX,tileY);
  SunCachedTile ct=(SunCachedTile)cache.get(key);
  if (ct != null) {
    ct.timeStamp=timeStamp++;
    if (ct != first) {
      if (ct == last) {
        last=ct.previous;
        last.next=null;
      }
 else {
        ct.previous.next=ct.next;
        ct.next.previous=ct.previous;
      }
      ct.previous=null;
      ct.next=first;
      first.previous=ct;
      first=ct;
    }
    hitCount++;
    if (diagnostics) {
      ct.action=UPDATE_FROM_ADD;
      setChanged();
      notifyObservers(ct);
    }
  }
 else {
    ct=new SunCachedTile(owner,tileX,tileY,tile,tileCacheMetric);
    ct.timeStamp=timeStamp++;
    ct.previous=null;
    ct.next=first;
    if (first == null && last == null) {
      first=ct;
      last=ct;
    }
 else {
      first.previous=ct;
      first=ct;
    }
    if (cache.put(ct.key,ct) == null) {
      memoryUsage+=ct.memorySize;
      tileCount++;
      if (cacheSortedSet != null) {
        cacheSortedSet.add(ct);
      }
      if (diagnostics) {
        ct.action=ADD;
        setChanged();
        notifyObservers(ct);
      }
    }
    if (memoryUsage > memoryCapacity) {
      memoryControl();
    }
  }
}

Fixed version (ground truth):
/** 
 * Adds a tile to the cache with an associated tile compute cost. <p> If the specified tile is already in the cache, it will not be cached again.  If by adding this tile, the cache exceeds the memory capacity, older tiles in the cache are removed to keep the cache memory usage under the specified limit.
 * @param owner            The image the tile blongs to.
 * @param tileX            The tile's X index within the image.
 * @param tileY            The tile's Y index within the image.
 * @param tile             The tile to be cached.
 * @param tileCacheMetric  Metric for prioritizing tiles
 */
public synchronized void add(RenderedImage owner,int tileX,int tileY,Raster tile,Object tileCacheMetric){
  if (memoryCapacity == 0) {
    return;
  }
  Object key=SunCachedTile.hashKey(owner,tileX,tileY);
  SunCachedTile ct=(SunCachedTile)cache.get(key);
  if (ct != null) {
    ct.timeStamp=timeStamp++;
    if (ct != first) {
      if (ct == last) {
        last=ct.previous;
        last.next=null;
      }
 else {
        ct.previous.next=ct.next;
        ct.next.previous=ct.previous;
      }
      ct.previous=null;
      ct.next=first;
      first.previous=ct;
      first=ct;
    }
    hitCount++;
    if (diagnostics) {
      ct.action=UPDATE_FROM_ADD;
      setChanged();
      notifyObservers(ct);
    }
  }
 else {
    ct=new SunCachedTile(owner,tileX,tileY,tile,tileCacheMetric);
    if (memoryUsage + ct.memorySize > memoryCapacity && ct.memorySize > (long)(memoryCapacity * memoryThreshold)) {
      return;
    }
    ct.timeStamp=timeStamp++;
    ct.previous=null;
    ct.next=first;
    if (first == null && last == null) {
      first=ct;
      last=ct;
    }
 else {
      first.previous=ct;
      first=ct;
    }
    if (cache.put(ct.key,ct) == null) {
      memoryUsage+=ct.memorySize;
      tileCount++;
      if (cacheSortedSet != null) {
        cacheSortedSet.add(ct);
      }
      if (diagnostics) {
        ct.action=ADD;
        setChanged();
        notifyObservers(ct);
      }
    }
    if (memoryUsage > memoryCapacity) {
      memoryControl();
    }
  }
}