MCR-3695 MCRMetadataManager: per-object locking for write methods#2929
Open
sebhofmann wants to merge 3 commits intomainfrom
Open
MCR-3695 MCRMetadataManager: per-object locking for write methods#2929sebhofmann wants to merge 3 commits intomainfrom
sebhofmann wants to merge 3 commits intomainfrom
Conversation
Introduce a per-MCRObjectID lock primitive on MCRMetadataManager: - Public lock(MCRObjectID) returns an AutoCloseable MCRObjectLock for use with try-with-resources. - Backed by ConcurrentHashMap<MCRObjectID, LockEntry> with reference counting; entries dropped at refcount 0. - ReentrantLock per entry — EventHandlers can re-enter update() on the same id without deadlock. - tryLock with configurable timeout (MCR.Metadata.Manager.LockTimeoutSeconds, default 60 s); throws MCRPersistenceException on timeout. - All six write methods (update/create/delete x MCRObject/MCRDerivate) acquire the lock automatically; checkModificationDates now sits inside the locked critical section, so the optimistic-lock check is reliable. - MCRPIService.register() and MCRPIService.updateFlag() wrap their retrieve-mutate-update spans in caller-side lock(id) to fix the PI flag race that motivated this work.
AutoCloseable strongly recommends idempotent close. A second close() on the same handle previously corrupted refcount/unlock state. Guard with a closed flag (handle is single-thread by contract).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Link to jira
Summary
Introduces a per-
MCRObjectIDlock primitive onMCRMetadataManagerso that all write methods (update/create/delete×MCRObject/MCRDerivate) are atomic, and exposes the lock as an opt-inMCRMetadataManager.lock(MCRObjectID)API for callers that need to protect their own read-modify-write spans across multiple manager calls.The optimistic
checkModificationDatescheck was a TOCTOU because it lived outside any lock; it now sits inside the locked critical section and is finally reliable.MCRPIService.register()andMCRPIService.updateFlag()use the new caller-sidelock(id)to fix the PI flag race that motivated this work — concurrent flag mutations no longer silently lose entries.Design highlights
MCRMetadataManager.lock(MCRObjectID)returns anAutoCloseableMCRObjectLock(try-with-resources).ConcurrentHashMap<MCRObjectID, LockEntry>+ reference counting; entries dropped at refcount 0 (no map growth).ReentrantLockper entry — EventHandlers can re-enterupdate()on the same id without deadlock.tryLockwith configurable timeout; throwsMCRPersistenceExceptionon timeout — caller can retry, surface, or abort.Configuration
MCR.Metadata.Manager.LockTimeoutSeconds60MCRPersistenceExceptionScope
modifyDate— bothMCRPersistenceException, which the API already declared.Pull Request Checklist (Author)
Ticket & Documentation
fixed-versionis correctly set in the ticket and matches the PR's target branch (main).Feature & Improvement Specific Checks
lock()+ property inmycore.properties)Bugfix-Specific Checks
(N/A — improvement, not bugfix)
Testing
CI=true mvn clean installgreen).MCR Conventions & Metadata
mycore.properties.mycore.properties.Multi-Repo Considerations
MIRrequired?Test plan
MCRMetadataManagerLockTest— 5 unit tests on the lock primitive: reentrancy, cross-id parallelism, timeout, refcount cleanup, mutual exclusion.MCRMetadataManagerConcurrentUpdateTest— 2 deterministic integration tests against a real metadata store. Both fail without the auto-lock:updateBlocksWhileExternalLockHeld— caller holdslock(id)on a separate thread; main-threadupdate(id)must block until release.forcedRaceProducesExactlyOneWinner—CyclicBarrierforces both threads to retrieve at the samemodifyDatesnapshot before either persists; with the lock, one wins and the other is rejected as stale; without the lock, lost update.CI=true mvn clean installgreen on this branch.