-
Notifications
You must be signed in to change notification settings - Fork 0
HDDS-12356. OM Gatekeeper Prototype #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
szetszwo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@errose28 , thanks for the suggestion! Please see the comments inlined.
| */ | ||
| public final class LockInfo implements Comparable<LockInfo> { | ||
| private final String key; | ||
| private final boolean isWriteLock; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use an enum is better than a boolean; see "Never Use Booleans for Something That Has Two States Now, but Might Have More Later".
| public AutoCloseable lock(OmLockInfo lockInfo) throws InterruptedException, TimeoutException { | ||
| // Common case is 1 volume, 1 bucket, and at most 2 key locks. | ||
| List<Lock> locks = new ArrayList<>(4); | ||
|
|
||
| Optional<LockInfo> optionalVolumeLock = lockInfo.getVolumeLock(); | ||
| Optional<LockInfo> optionalBucketLock = lockInfo.getBucketLock(); | ||
| Optional<Set<LockInfo>> optionalKeyLocks = lockInfo.getKeyLocks(); | ||
|
|
||
| if (optionalVolumeLock.isPresent()) { | ||
| LockInfo volumeLockInfo = optionalVolumeLock.get(); | ||
| if (volumeLockInfo.isWriteLock()) { | ||
| locks.add(volumeLocks.get(volumeLockInfo.getKey()).writeLock()); | ||
| } else { | ||
| locks.add(volumeLocks.get(volumeLockInfo.getKey()).readLock()); | ||
| } | ||
| } | ||
|
|
||
| if (optionalBucketLock.isPresent()) { | ||
| LockInfo bucketLockInfo = optionalBucketLock.get(); | ||
| if (bucketLockInfo.isWriteLock()) { | ||
| locks.add(bucketLocks.get(bucketLockInfo.getKey()).writeLock()); | ||
| } else { | ||
| locks.add(bucketLocks.get(bucketLockInfo.getKey()).readLock()); | ||
| } | ||
| } | ||
|
|
||
| if (optionalKeyLocks.isPresent()) { | ||
| for (Lock keyLock: keyLocks.bulkGet(optionalKeyLocks.get())) { | ||
| locks.add(keyLock); | ||
| } | ||
| } | ||
|
|
||
| acquireLocks(locks); | ||
| return () -> releaseLocks(locks); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lock overhead probably is quite high in this method.
|
|
||
| @Override | ||
| public int compareTo(@NotNull LockInfo other) { | ||
| return Integer.compare(hashCode(), other.hashCode()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sort by hashCode won't work with guava Striped. For example
- the number of stripe: 1024.
- hash code A = 1
- hash code B = 1025.
compareTo will return non-zero but they are mapped to the same lock.
| private final LockInfo volumeLock; | ||
| private final LockInfo bucketLock; | ||
| private final Set<LockInfo> keyLocks; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we require locking on two or more volumes/buckets later on, it will require a lot of code change.
| private void acquireLocks(List<Lock> locks) throws TimeoutException, InterruptedException { | ||
| List<Lock> acquiredLocks = new ArrayList<>(locks.size()); | ||
| for (Lock lock: locks) { | ||
| if (lock.tryLock(timeoutMillis, TimeUnit.MILLISECONDS)) { | ||
| try { | ||
| acquiredLocks.add(lock); | ||
| } catch (Throwable e) { | ||
| // We acquired this lock but were unable to add it to our acquired locks list. | ||
| lock.unlock(); | ||
| releaseLocks(acquiredLocks); | ||
| throw e; | ||
| } | ||
| } else { | ||
| releaseLocks(acquiredLocks); | ||
| throw new TimeoutException("Failed to acquire lock after the given timeout."); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concurrently, if the lock.tryLock(..) is interrupted, the partial lock won't be released. Getting everything right with timeout is not easy.
What changes were proposed in this pull request?
Prototype for the granular locking framework OBS implementation. The following aspects are considered in this design:
OmLockInfowill be consumed by all of the ~100 OM requests, so it should be as minimal as possible.OmRequestGatekeeperprovides one public method with a simple contract, and an initial implementation that is as simple as possible.Since this is prototype/demonstration code, see inline for comments on how the pieces will fit together.
What is the link to the Apache JIRA
HDDS-12356
How was this patch tested?
N/A, for demonstration and discussion only.