This is a utility class that offers fine grained locking for various Collection Operations This class is designed for single threaded operation. It's safe for multiple threads to use it but internally it is synchronized so that only one thread can perform any operation.
| 38 | * internally it is synchronized so that only one thread can perform any operation. |
| 39 | */ |
| 40 | public class LockTree { |
| 41 | private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); |
| 42 | private final Node root = new Node(null, LockLevel.CLUSTER, null); |
| 43 | |
| 44 | public final Map<String, Lock> allLocks = new HashMap<>(); |
| 45 | |
| 46 | private class LockImpl implements Lock { |
| 47 | final Node node; |
| 48 | final String id; |
| 49 | |
| 50 | LockImpl(Node node) { |
| 51 | this.node = node; |
| 52 | this.id = UUID.randomUUID().toString(); |
| 53 | } |
| 54 | |
| 55 | @Override |
| 56 | public void unlock() { |
| 57 | synchronized (LockTree.this) { |
| 58 | if (node.unlock(this)) { |
| 59 | allLocks.remove(id); |
| 60 | } |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | @Override |
| 65 | public String id() { |
| 66 | return id; |
| 67 | } |
| 68 | |
| 69 | @Override |
| 70 | public boolean validateSubpath(int lockLevel, List<String> path) { |
| 71 | return node.validateSubpath(lockLevel, path); |
| 72 | } |
| 73 | |
| 74 | @Override |
| 75 | public String toString() { |
| 76 | return StrUtils.join(node.constructPath(new ArrayDeque<>()), '/'); |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | /** |
| 81 | * This class is used to mark nodes for which acquiring a lock was attempted but didn't succeed. |
| 82 | * Lock acquisition failure needs to be "remembered" to trigger failures to acquire a competing |
| 83 | * lock until the Session is replaced, to prevent tasks enqueued later (and dequeued later once |
| 84 | * the busy lock got released) from being executed before earlier tasks that failed to execute |
| 85 | * because the lock wasn't available earlier when they attempted to acquire it. |
| 86 | * |
| 87 | * <p>A new Session is created each time the iteration over the queue tasks is restarted starting |
| 88 | * at the oldest non running or completed tasks. |
| 89 | */ |
| 90 | public class Session { |
| 91 | private SessionNode root = new SessionNode(LockLevel.CLUSTER); |
| 92 | |
| 93 | public Lock lock( |
| 94 | CollectionParams.CollectionAction action, List<String> path, String callingLockId) { |
| 95 | if (action.lockLevel == LockLevel.NONE) return FREELOCK; |
| 96 | Node startingNode = LockTree.this.root; |
| 97 | SessionNode startingSession = root; |
nothing calls this directly
no test coverage detected
searching dependent graphs…