/**
   * Reduces the number of rows held in this Cache object.
   *
   * <p>Cleanup is done by checking the accessCount of the Rows and removing the rows with the
   * lowest access count.
   *
   * <p>Index operations require that up to 5 recently accessed rows remain in the cache.
   */
  private synchronized void cleanUp() throws IOException {

    int removeCount = cacheMap.size() / 2;
    int accessTarget = cacheMap.getAccessCountCeiling(removeCount, removeCount / 8);
    ObjectCacheHashMap.ObjectCacheIterator it = cacheMap.iterator();
    int savecount = 0;

    for (; it.hasNext(); ) {
      CachedObject r = (CachedObject) it.next();

      if (it.getAccessCount() <= accessTarget) {
        if (!r.isKeepInMemory()) {
          if (r.hasChanged()) {
            rowTable[savecount++] = r;
          }

          it.remove();

          cacheBytesLength -= r.getStorageSize();
        }
      }
    }

    cacheMap.setAccessCountFloor(accessTarget);
    saveRows(savecount);
  }
  /** Adds a row to the cache. */
  public synchronized void put(int key, CachedObject row) throws IOException {

    int storageSize = row.getStorageSize();

    if (cacheMap.size() >= capacity || storageSize + cacheBytesLength > bytesCapacity) {
      cleanUp();
    }

    cacheMap.put(key, row);

    cacheBytesLength += storageSize;
  }
 public int size() {
   return cacheMap.size();
 }