An implementation of {@link AccessCoordinator} that uses locking to handleconflicts.
This implementation checks for deadlock whenever an access request is blocked due to a conflict. It selects the youngest transaction as the deadlock victim, determining the age using the originally requested start time for the task associated with the transaction. The implementation does not deny requests that would not result in deadlock. When requests block, it services the requests in the order that they arrive, except for upgrade requests, which it puts ahead of non-upgrade requests. The justification for special treatment of upgrade requests is that an upgrade request is useless if a conflicting request goes first and causes the waiter to lose its read lock.
The methods that this class provides to implement {@code AccessReporter} arenot thread safe, and should either be called from a single thread or else protected with external synchronization.
The {@link #LockingAccessCoordinator constructor} supports the followingconfiguration properties:
- Property: {@value #LOCK_TIMEOUT_PROPERTY}
Default: {@value #DEFAULT_LOCK_TIMEOUT_PROPORTION} times thevalue of the {@code com.sun.sgs.txn.timeout} property, if specified,otherwise times the value of the default transaction timeout. - The maximum number of milliseconds to wait for obtaining a lock. The value must be greater than {@code 0}, and should be less than the transaction timeout.
- Property: {@value #NUM_KEY_MAPS_PROPERTY}
Default: {@value #NUM_KEY_MAPS_DEFAULT} - The number of maps to use for associating keys and maps. The number of maps controls the amount of concurrency, and should typically be set to a value to support concurrent access by the number of active threads. The value must be greater than {@code 0}.
This class uses the {@link Logger} named {@code com.sun.sgs.impl.kernel.LockingAccessCoordinator} to log information at thefollowing logging levels:
- {@link Level#FINER FINER} - Beginning and ending transactions;requesting, waiting for, and returning from lock requests; deadlocks
- {@link Level#FINEST FINEST} - Notifying new lock owners, results ofrequesting locks before waiting, releasing locks, results of attempting to assign locks to waiters, details of checking deadlocks
The implementation of this class uses the following thread synchronization scheme to avoid internal deadlocks:
- Synchronization is only used on {@link Locker} objects and on the {@code Map}s that hold {@code Lock} objects
- A thread can synchronize on at most one locker and one lock at a time, always synchronizing on the locker first
To make it easier to adhere to these rules, the implementation takes the following steps:
- The {@code Lock} class is not synchronized
Callers of non- {@code Object} methods on the {@code Lock} class shouldmake sure that they are synchronized on the associated key map.
- The {@link Locker} class only uses synchronization for getter and settermethods
- Blocks synchronized on a {@code Lock} should not synchronize on anythingelse
The code enforces this requirement by having lock methods not make calls to other classes, and by performing minimal work while synchronized on the associated key map.
- Blocks synchronized on a {@code Locker} should not synchronize on adifferent locker, but can synchronize on a {@code Lock}In fact, only one method synchronizes on a {@code Locker} and on a{@code Lock} -- the {@link #waitForLockInternal waitForLockInternal}method. That method also makes sure that the only synchronized {@code Locker} methods that it calls are on the locker it has alreadysynchronized on. The {@code DeadlockChecker} class also synchronizes onkey maps and lockers, but is called outside of synchronized blocks and only synchronizes on one thing at a time.
- Use assertions to check adherence to the scheme