60
60
import java .util .function .ToLongBiFunction ;
61
61
62
62
import org .ehcache .Cache ;
63
- import org .ehcache .CachePersistenceException ;
64
63
import org .ehcache .PersistentCacheManager ;
65
64
import org .ehcache .config .builders .CacheConfigurationBuilder ;
66
65
import org .ehcache .config .builders .CacheEventListenerConfigurationBuilder ;
@@ -104,8 +103,6 @@ public class EhcacheDiskCache<K, V> implements ICache<K, V> {
104
103
// Unique id associated with this cache.
105
104
private final static String UNIQUE_ID = UUID .randomUUID ().toString ();
106
105
private final static String THREAD_POOL_ALIAS_PREFIX = "ehcachePool" ;
107
- private final static int MINIMUM_MAX_SIZE_IN_BYTES = 1024 * 100 ; // 100KB
108
-
109
106
// A Cache manager can create many caches.
110
107
private final PersistentCacheManager cacheManager ;
111
108
@@ -127,13 +124,18 @@ public class EhcacheDiskCache<K, V> implements ICache<K, V> {
127
124
private final Serializer <K , byte []> keySerializer ;
128
125
private final Serializer <V , byte []> valueSerializer ;
129
126
127
+ final static int MINIMUM_MAX_SIZE_IN_BYTES = 1024 * 100 ; // 100KB
128
+ final static String CACHE_DATA_CLEANUP_DURING_INITIALIZATION_EXCEPTION = "Failed to delete ehcache disk cache under "
129
+ + "path: %s during initialization. Please clean this up manually and restart the process" ;
130
+
130
131
/**
131
132
* Used in computeIfAbsent to synchronize loading of a given key. This is needed as ehcache doesn't provide a
132
133
* computeIfAbsent method.
133
134
*/
134
135
Map <ICacheKey <K >, CompletableFuture <Tuple <ICacheKey <K >, V >>> completableFutureMap = new ConcurrentHashMap <>();
135
136
136
- private EhcacheDiskCache (Builder <K , V > builder ) {
137
+ @ SuppressForbidden (reason = "Ehcache uses File.io" )
138
+ EhcacheDiskCache (Builder <K , V > builder ) {
137
139
this .keyType = Objects .requireNonNull (builder .keyType , "Key type shouldn't be null" );
138
140
this .valueType = Objects .requireNonNull (builder .valueType , "Value type shouldn't be null" );
139
141
this .expireAfterAccess = Objects .requireNonNull (builder .getExpireAfterAcess (), "ExpireAfterAccess value shouldn't " + "be null" );
@@ -151,6 +153,18 @@ private EhcacheDiskCache(Builder<K, V> builder) {
151
153
if (this .storagePath == null || this .storagePath .isBlank ()) {
152
154
throw new IllegalArgumentException ("Storage path shouldn't be null or empty" );
153
155
}
156
+ // Delete all the previous disk cache related files/data. We don't persist data between process restart for
157
+ // now which is why need to do this. Clean up in case there was a non graceful restart and we had older disk
158
+ // cache data still lying around.
159
+ Path ehcacheDirectory = Paths .get (this .storagePath );
160
+ if (Files .exists (ehcacheDirectory )) {
161
+ try {
162
+ logger .info ("Found older disk cache data lying around during initialization under path: {}" , this .storagePath );
163
+ IOUtils .rm (ehcacheDirectory );
164
+ } catch (IOException e ) {
165
+ throw new OpenSearchException (String .format (CACHE_DATA_CLEANUP_DURING_INITIALIZATION_EXCEPTION , this .storagePath ), e );
166
+ }
167
+ }
154
168
if (builder .threadPoolAlias == null || builder .threadPoolAlias .isBlank ()) {
155
169
this .threadPoolAlias = THREAD_POOL_ALIAS_PREFIX + "DiskWrite#" + UNIQUE_ID ;
156
170
} else {
@@ -175,6 +189,11 @@ private EhcacheDiskCache(Builder<K, V> builder) {
175
189
}
176
190
}
177
191
192
+ // Package private for testing
193
+ PersistentCacheManager getCacheManager () {
194
+ return this .cacheManager ;
195
+ }
196
+
178
197
@ SuppressWarnings ({ "rawtypes" })
179
198
private Cache <ICacheKey , ByteArrayWrapper > buildCache (Duration expireAfterAccess , Builder <K , V > builder ) {
180
199
// Creating the cache requires permissions specified in plugin-security.policy
@@ -255,7 +274,7 @@ Map<ICacheKey<K>, CompletableFuture<Tuple<ICacheKey<K>, V>>> getCompletableFutur
255
274
}
256
275
257
276
@ SuppressForbidden (reason = "Ehcache uses File.io" )
258
- private PersistentCacheManager buildCacheManager () {
277
+ PersistentCacheManager buildCacheManager () {
259
278
// In case we use multiple ehCaches, we can define this cache manager at a global level.
260
279
// Creating the cache manager also requires permissions specified in plugin-security.policy
261
280
return AccessController .doPrivileged ((PrivilegedAction <PersistentCacheManager >) () -> {
@@ -444,20 +463,21 @@ public void refresh() {
444
463
@ Override
445
464
@ SuppressForbidden (reason = "Ehcache uses File.io" )
446
465
public void close () {
447
- cacheManager .removeCache (this .diskCacheAlias );
448
- cacheManager .close ();
449
466
try {
450
- cacheManager .destroyCache (this .diskCacheAlias );
451
- // Delete all the disk cache related files/data
452
- Path ehcacheDirectory = Paths .get (this .storagePath );
453
- if (Files .exists (ehcacheDirectory )) {
467
+ cacheManager .close ();
468
+ } catch (Exception e ) {
469
+ logger .error (() -> new ParameterizedMessage ("Exception occurred while trying to close ehcache manager" ), e );
470
+ }
471
+ // Delete all the disk cache related files/data in case it is present
472
+ Path ehcacheDirectory = Paths .get (this .storagePath );
473
+ if (Files .exists (ehcacheDirectory )) {
474
+ try {
454
475
IOUtils .rm (ehcacheDirectory );
476
+ } catch (IOException e ) {
477
+ logger .error (() -> new ParameterizedMessage ("Failed to delete ehcache disk cache data under path: {}" , this .storagePath ));
455
478
}
456
- } catch (CachePersistenceException e ) {
457
- throw new OpenSearchException ("Exception occurred while destroying ehcache and associated data" , e );
458
- } catch (IOException e ) {
459
- logger .error (() -> new ParameterizedMessage ("Failed to delete ehcache disk cache data under path: {}" , this .storagePath ));
460
479
}
480
+
461
481
}
462
482
463
483
/**
0 commit comments