Skip to content

OF-3084 OF-3088: Refactor Cache Locking implementation#2811

Merged
guusdk merged 1 commit into
igniterealtime:mainfrom
guusdk:OF-3084_OF-3088_Deprecate-lock
Jun 11, 2025
Merged

OF-3084 OF-3088: Refactor Cache Locking implementation#2811
guusdk merged 1 commit into
igniterealtime:mainfrom
guusdk:OF-3084_OF-3088_Deprecate-lock

Conversation

@guusdk

@guusdk guusdk commented Jun 11, 2025

Copy link
Copy Markdown
Member

Based on the single responsibility principle, the CacheFactory should not be managing Locks. Instead, Caches should do that themselves.

Back in 2019, the method in CacheFactory that generates locks was marked as deprecated because of that, with a removal note in the distant future: 5.0.0.

As 5.0.0 is upon us, the deprecated code has now been removed. The cache locking implementation has been moved to a dedicated class (LocalCache) that is used by caches directly.

This commit attempts to achieve the desired removal of deprecated methods with a minimum of refactoring.

Further improvements may be desired (e.g. not storing locks for all caches in one shared data structure, but rather in a per-cache data structure).

Based on the single responsibility principle, the CacheFactory should not be managing Locks. Instead, Caches should do that themselves.

Back in 2019, the method in CacheFactory that generates locks was marked as deprecated because of that, with a removal note in the distant future: 5.0.0.

As 5.0.0 is upon us, the deprecated code has now been removed. The cache locking implementation has been moved to a dedicated class (`LocalCache`) that is used by caches directly.

This commit attempts to achieve the desired removal of deprecated methods with a minimum of refactoring.

Further improvements may be desired (e.g. not storing locks for all caches in one shared data structure, but rather in a per-cache data structure).
@guusdk guusdk requested a review from GregDThomas June 11, 2025 10:32
@guusdk

guusdk commented Jun 11, 2025

Copy link
Copy Markdown
Member Author

I've prepared a corresponding change in the Hazelcast plugin here: igniterealtime/openfire-hazelcast-plugin#115

@guusdk

guusdk commented Jun 11, 2025

Copy link
Copy Markdown
Member Author

I've smoke-tested the clustered cache modifications with the https://github.com/surevine/openfire-docker-compose/ project.

@guusdk guusdk merged commit 6a5d048 into igniterealtime:main Jun 11, 2025
63 of 65 checks passed
@guusdk

guusdk commented Jun 11, 2025

Copy link
Copy Markdown
Member Author

As I'd like to dogfood this test, I'm merging this without waiting for a review. Don't let that stop anyone from reviewing after-the-fact. :)

@GregDThomas GregDThomas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of hopefully helpful comments too

}

private ReentrantLock lookupLockForAcquire(CacheKey cacheKey) {
CacheKey mutex = interner.intern(cacheKey); // Ensure that the mutex used in the next line is the same for objects that are equal.

@GregDThomas GregDThomas Jun 16, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be tempted to put this behind a getRepresentativeInstance(cacheKey) method, or similar, as you've done it twice already. Possibly as a method of CacheKey.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've read this three times but I still don't get what you mean :)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry - let me be more explicit.
I think this logic belongs in CacheKey and not LocalLock. So .. add a method to CacheKey

public CacheKey getRepresentativeInstance() {
  return interner.intern(this);
}

and invoke that from here (and the other place).

Taking that further, I might also be tempted to make the constructor private, and add a factory method to CacheKey ...

public static CacheKey createCacheKey(Cache cache, Object key) {
  final CacheKey instance = new CacheKey(cache, key);
  return  interner.intern(CacheKey);
}

So it's impossible to obtain anything other than the representative instance of the class.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, now I see. I've opened a new PR for this: #2821

*/
class CacheKey
{
final String cacheName;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That'd probably lead to introducing a getter and setter for that field As this is package protected, having direct access to the field is an acceptable compromise maybe? It's slightly less code (for something that I don't expect to be used much anyway).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants