From 1b93ea97ac4fb7011e4afb026bb32d0c589aa198 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Fri, 28 Jun 2019 23:43:38 +0200 Subject: [PATCH] Fix concurrent reads issue in MimeTypeUtils cache As of gh-22340, `MimeTypeUtils` has a built-in LRU cache implementation for caching parsed MIME types and avoiding excessive garbage creation at runtime. This implementation, when hit with highly concurrent reads on the same media type (the cache key), can create multiple keys for the same MIME type string. This duplication leads to the cache filling up and evicting entries. When the cache fetches a duplicate key, it is then not associated with a value and the cache can return a `null` value, which is forbidden by the API contract. This commit adds another cache check within the write lock: this avoids creating duplicate entries in the cache and `null` return values. Fixes gh-23211 --- .../main/java/org/springframework/util/MimeTypeUtils.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java b/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java index 428f08c33a3..c73cd4d8de6 100644 --- a/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java +++ b/spring-core/src/main/java/org/springframework/util/MimeTypeUtils.java @@ -443,6 +443,11 @@ public abstract class MimeTypeUtils { } this.lock.writeLock().lock(); try { + // retrying in case of concurrent reads on the same key + if (this.queue.remove(key)) { + this.queue.add(key); + return this.cache.get(key); + } if (this.queue.size() == this.maxSize) { K leastUsed = this.queue.poll(); if (leastUsed != null) {