public Set<K> keySet() throws IOException {
   try {
     acquireAllReadLocks();
     return map.keySet();
   } finally {
     releaseAllReadLocks();
   }
 }
 public Collection<V> values() throws IOException {
   try {
     acquireAllReadLocks();
     return map.values();
   } finally {
     releaseAllReadLocks();
   }
 }
 public Set<Entry<K, V>> entrySet() throws IOException {
   try {
     acquireAllReadLocks();
     return map.entrySet();
   } finally {
     releaseAllReadLocks();
   }
 }
 public boolean containsValue(Object value) throws IOException {
   try {
     acquireAllReadLocks();
     return map.containsValue(value);
   } finally {
     releaseAllReadLocks();
   }
 }
 public synchronized void clear() {
   try {
     acquireAllWriteLocks();
     map.clear();
   } finally {
     releaseAllWriteLocks();
   }
 }
 public boolean containsKey(Object key) {
   try {
     acquireAllReadLocks();
     return map.isEmpty();
   } finally {
     releaseAllReadLocks();
   }
 }
 public V get(Object key) throws IOException {
   ReadWriteLock l = getLock(key);
   l.readLock().lock();
   try {
     return map.get(key);
   } finally {
     l.readLock().unlock();
   }
 }
 public V put(K key, V value) throws IOException {
   ReadWriteLock l = getLock(key);
   l.writeLock().lock();
   try {
     return map.put(key, value);
   } finally {
     l.writeLock().unlock();
   }
 }
 public V remove(Object key) throws IOException {
   ReadWriteLock l = getLock(key);
   l.writeLock().lock();
   try {
     return map.remove(key);
   } finally {
     l.writeLock().unlock();
   }
 }
 public boolean isEmpty() {
   // TODO: should we even bother locking for such a simple method?
   try {
     acquireAllReadLocks();
     // do our business
     return map.isEmpty();
   } finally {
     releaseAllReadLocks();
   }
 }
 public int size() {
   // TODO: once size is cached in FileSystemHashMap, we can eliminate
   // the need to acquire all the locks
   try {
     acquireAllReadLocks();
     return map.size();
   } finally {
     releaseAllReadLocks();
   }
 }
  public void putAll(Map<? extends K, ? extends V> m) throws IOException {

    // build a list of the indicies of the locks needed to perform
    // this operation, then acquire all those locks
    Set<Integer> need = new HashSet<Integer>(m.size());
    for (Object o : m.keySet()) {
      need.add(this.getLockIndex(o));
    }
    try {
      acquireWriteLocks(need);
      map.putAll(m);
    } finally {
      releaseAllWriteLocks();
    }
  }