Skip to content

RedisCache synchronises all get(key, valueLoader) calls #2079

Closed
@miensol

Description

@miensol

I was examining the performance in our Spring Boot app. Based on profiling data, I noticed that we have a lot of wait times on RedisCache#get(key, valueLoader) method.

The method signature makes it obvious why this is happening:

public synchronized <T> T get(Object key, Callable<T> valueLoader) {

In case of our app, it causes all cache lookups to be executed sequentially. (Admittedly a great protection for Redis server 😅).

In the past this method wasn't synchronized. It changed in this commit.

Documentation of the Cache interface states:

Return the value to which this cache maps the specified key, obtaining that value from valueLoader if necessary. This method provides a simple substitute for the conventional "if cached, return; otherwise create, cache and return" pattern.

If possible, implementations should ensure that the loading operation is synchronized so that the specified valueLoader is only called once in case of concurrent access on the same key.

Technically speaking, the current synchronized implementation adheres to documentation. However, so would version that is not synchronized.

For comparison, here's how the EhCacheCache is implemented:

    public <T> T get(Object key, Callable<T> valueLoader) {
		Element element = lookup(key);
		if (element != null) {
			return (T) element.getObjectValue();
		}
		else {
			this.cache.acquireWriteLockOnKey(key);
			try {
				element = lookup(key);  // one more attempt with the write lock
				if (element != null) {
					return (T) element.getObjectValue();
				}
				else {
					return loadValue(key, valueLoader);
				}
			}
			finally {
				this.cache.releaseWriteLockOnKey(key);
			}
		}
	}

I'm happy to submit a PR that changes the implementation. However, before doing so, I'd love to ask if the synchronized method was implemented in the current way deliberately and there's and edge case which makes changing it harder?
LV link

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions