package com.github.marschall.memoryfilesystem; import java.io.IOException; import java.nio.channels.FileLockInterruptionException; import java.nio.channels.OverlappingFileLockException; import java.util.Map.Entry; import java.util.NavigableMap; import java.util.TreeMap; final class LockSet { private final NavigableMap<Long, MemoryFileLock> locks; LockSet() { this.locks = new TreeMap<>(); } MemoryFileLock tryLock(MemoryFileLock lock) { return this.tryPut(lock); } private MemoryFileLock tryPut(MemoryFileLock lock) { Entry<Long, MemoryFileLock> ceilingEntry = this.locks.ceilingEntry(lock.position()); Entry<Long, MemoryFileLock> floorEntry = this.locks.floorEntry(lock.position()); if (ceilingEntry != null && ceilingEntry.getValue().overlaps(lock.position(), lock.size())) { return null; } if (floorEntry != null && floorEntry.getValue().overlaps(lock.position(), lock.size())) { return null; } this.locks.put(lock.position(), lock); return lock; } MemoryFileLock lock(MemoryFileLock lock) throws IOException { if (Thread.currentThread().isInterrupted()) { throw new FileLockInterruptionException(); } MemoryFileLock returnValue = this.tryLock(lock); if (returnValue == null) { throw new OverlappingFileLockException(); } return returnValue; } void remove(MemoryFileLock lock) { // no need to check for return value because FileLock#release // can be invoked several times from multiple threads this.locks.remove(lock.position()); lock.invalidate(); } }