package org.seqcode.data.readdb; import java.util.*; import java.util.concurrent.locks .*; /** * Static class to maintain locks on objects within the JVM. We need this because... * - multiple threads can have a read lock on an object at once; synchronized doesn't * do this * - the java.io locking stuff only locks between processes, not within the JVM */ public class Lock { private static Map<String,ReentrantReadWriteLock> locks = Collections.synchronizedMap(new HashMap<String,ReentrantReadWriteLock>()); private static Map<Thread,Set<java.util.concurrent.locks.Lock>> threadlocks = Collections.synchronizedMap(new HashMap<Thread,Set<java.util.concurrent.locks.Lock>>()); private static int rlcount = 0; /** * blocks to acquire a shared lock to the specified file. * The locking is implemented in java, so it's only * good for keeping out other threads. It's keyed off the file name * you provide, so make sure you always generate the filename in the same way. */ protected static java.util.concurrent.locks.Lock readLock(String fname) { Thread t = Thread.currentThread(); synchronized(threadlocks) { if (!threadlocks.containsKey(t)) { threadlocks.put(t, new HashSet<java.util.concurrent.locks.Lock>()); } } java.util.concurrent.locks.Lock lock = null; synchronized(locks) { if (!locks.containsKey(fname)) { locks.put(fname, new ReentrantReadWriteLock()); } lock = locks.get(fname).readLock(); lock.lock(); } threadlocks.get(t).add(lock); // System.err.println("READLOCK by " + t + " of " + fname + " as " + lock); return lock; } protected static java.util.concurrent.locks.Lock writeLock(String fname) { Thread t = Thread.currentThread(); synchronized(threadlocks) { if (!threadlocks.containsKey(t)) { threadlocks.put(t, new HashSet<java.util.concurrent.locks.Lock>()); } } java.util.concurrent.locks.Lock rl = null, lock = null; synchronized(locks) { if (!locks.containsKey(fname)) { locks.put(fname, new ReentrantReadWriteLock()); } rl = locks.get(fname).readLock(); rl.unlock(); threadlocks.get(t).remove(rl); lock = locks.get(fname).writeLock(); lock.lock(); } threadlocks.get(t).add(lock); // System.err.println("WRITELOCK by " + t + " of " + fname + " as " + lock); return lock; } /* call to ensure that all a thread's locks have been released */ protected static void releaseLocks() { Thread t = Thread.currentThread(); if (threadlocks.containsKey(t)) { for (java.util.concurrent.locks.Lock l : threadlocks.get(t)) { // System.err.println("UNLOCK of " + l + " by " + t); l.unlock(); } threadlocks.get(t).clear(); } if (rlcount++ > 1000) { rlcount = 0; if (locks.size() > 10000) { synchronized(locks) { /* cleanup loop so that we don't have an ever-expanding data structure */ Collection<String> keys = locks.keySet(); for (String k : keys) { ReentrantReadWriteLock l = locks.get(k); if (l.getReadLockCount() == 0 && !l.isWriteLocked()) { locks.remove(k); } } } } } } }