From c57f770b4e5c38c1a224f52c33a241148c2fad02 Mon Sep 17 00:00:00 2001 From: Paolo Di Tommaso Date: Wed, 18 Sep 2024 22:56:21 +0200 Subject: [PATCH] Remove BiCacheStore data structure Signed-off-by: Paolo Di Tommaso --- .../service/cache/AbstractCacheStore.groovy | 23 +------ .../wave/service/cache/BiCacheStore.groovy | 64 ------------------ .../service/cache/impl/CacheProvider.groovy | 3 +- .../cache/impl/LocalCacheProvider.groovy | 53 --------------- .../cache/impl/RedisCacheProvider.groovy | 55 ---------------- .../cache/impl/LocalCacheProviderTest.groovy | 41 ------------ .../cache/impl/RedisCacheProviderTest.groovy | 66 ------------------- 7 files changed, 2 insertions(+), 303 deletions(-) delete mode 100644 src/main/groovy/io/seqera/wave/service/cache/BiCacheStore.groovy diff --git a/src/main/groovy/io/seqera/wave/service/cache/AbstractCacheStore.groovy b/src/main/groovy/io/seqera/wave/service/cache/AbstractCacheStore.groovy index b78e4f535..e1b142766 100644 --- a/src/main/groovy/io/seqera/wave/service/cache/AbstractCacheStore.groovy +++ b/src/main/groovy/io/seqera/wave/service/cache/AbstractCacheStore.groovy @@ -28,7 +28,7 @@ import io.seqera.wave.service.cache.impl.CacheProvider * * @author Paolo Di Tommaso */ -abstract class AbstractCacheStore implements CacheStore, BiCacheStore { +abstract class AbstractCacheStore implements CacheStore { private EncodingStrategy encodingStrategy @@ -101,25 +101,4 @@ abstract class AbstractCacheStore implements CacheStore, BiCacheSto delegate.clear() } - @Override - void biPut(String key, V value, Duration ttl) { - delegate.biPut(key0(key), serialize(value), ttl) - } - - @Override - void biRemove(String key) { - delegate.biRemove(key0(key)) - } - - @Override - Set biKeysFor(V value) { - final keys = delegate.biKeysFor(serialize(value)) - return keys.collect( (it) -> it.replace(getPrefix(),'') ) - } - - @Override - String biKeyFind(V value, boolean sorted) { - final result = delegate.biKeyFind(serialize(value), sorted) - result ? result.replace(getPrefix(),'') : null - } } diff --git a/src/main/groovy/io/seqera/wave/service/cache/BiCacheStore.groovy b/src/main/groovy/io/seqera/wave/service/cache/BiCacheStore.groovy deleted file mode 100644 index 546c2166d..000000000 --- a/src/main/groovy/io/seqera/wave/service/cache/BiCacheStore.groovy +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Wave, containers provisioning service - * Copyright (c) 2023-2024, Seqera Labs - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package io.seqera.wave.service.cache - -import java.time.Duration - -/** - * A cache store implementing a bi-direction key-value access, - * it allows retrieving all keys for a given value in time O(2) - * - * @author Paolo Di Tommaso - */ -interface BiCacheStore { - - /** - * Add a bi-directional key-value - * - * @param key The entry key - * @param value The entry value - * @param ttl The entry time-to-live. - */ - void biPut(K key, V value, Duration ttl) - - /** - * Remove an entry for the given value. - * - * @param key The key of entry to be removed - */ - void biRemove(K key) - - /** - * Get all key for the given value. - * - * @param value The value for which find corresponding keys - * @return A set of keys associated with the specified value or an empty set otherwise. - */ - Set biKeysFor(V value) - - /** - * Find a key in the cache for the given value. - * - * @param value The value for which find corresponding key - * @param sorted When true, the list of keys is sorted before getting the first value - * @return A key associated with the specified value or null if not key is found - */ - K biKeyFind(V value, boolean sorted) - -} diff --git a/src/main/groovy/io/seqera/wave/service/cache/impl/CacheProvider.groovy b/src/main/groovy/io/seqera/wave/service/cache/impl/CacheProvider.groovy index 3b8dcb80a..0e458c75b 100644 --- a/src/main/groovy/io/seqera/wave/service/cache/impl/CacheProvider.groovy +++ b/src/main/groovy/io/seqera/wave/service/cache/impl/CacheProvider.groovy @@ -18,7 +18,6 @@ package io.seqera.wave.service.cache.impl -import io.seqera.wave.service.cache.BiCacheStore import io.seqera.wave.service.cache.CacheStore /** @@ -26,5 +25,5 @@ import io.seqera.wave.service.cache.CacheStore * * @author Paolo Di Tommaso */ -interface CacheProvider extends CacheStore, BiCacheStore { +interface CacheProvider extends CacheStore { } diff --git a/src/main/groovy/io/seqera/wave/service/cache/impl/LocalCacheProvider.groovy b/src/main/groovy/io/seqera/wave/service/cache/impl/LocalCacheProvider.groovy index 09f0c0cfa..0659f7335 100644 --- a/src/main/groovy/io/seqera/wave/service/cache/impl/LocalCacheProvider.groovy +++ b/src/main/groovy/io/seqera/wave/service/cache/impl/LocalCacheProvider.groovy @@ -99,57 +99,4 @@ class LocalCacheProvider implements CacheProvider { store.clear() } - // =============== bi-cache store implementation =============== - - private Map> index = new HashMap<>() - - @Override - void biPut(String key, String value, Duration ttl) { - synchronized (this) { - this.put(key, value, ttl) - final id = value.hashCode() - def set = index.get(id) - if( set==null ) { - set=new HashSet() - index.put(id, set) - } - set.add(key) - } - } - - @Override - void biRemove(String key) { - synchronized (this) { - final entry = store.remove(key) - if( !entry ) - return - final id = entry.value.hashCode() - final set = index.get(id) - if( set ) { - set.remove(key) - } - } - } - - @Override - Set biKeysFor(String value) { - final id = value.hashCode() - return index.get(id) ?: Set.of() - } - - String biKeyFind(String value, boolean sorted) { - final id = value.hashCode() - final list = biKeysFor(value).toList() - final keys = sorted ? list.toSorted() : list.shuffled() - final itr = keys.iterator() - while( itr.hasNext() ) { - final result = itr.next() - // verify the key still exists - if( get(result)!=null ) - return result - // if not exist, remove it from the set - index.get(id)?.remove(result) - } - return null - } } diff --git a/src/main/groovy/io/seqera/wave/service/cache/impl/RedisCacheProvider.groovy b/src/main/groovy/io/seqera/wave/service/cache/impl/RedisCacheProvider.groovy index e597a96f8..a551f5083 100644 --- a/src/main/groovy/io/seqera/wave/service/cache/impl/RedisCacheProvider.groovy +++ b/src/main/groovy/io/seqera/wave/service/cache/impl/RedisCacheProvider.groovy @@ -24,7 +24,6 @@ import groovy.transform.CompileStatic import io.micronaut.context.annotation.Requires import jakarta.inject.Inject import jakarta.inject.Singleton -import org.apache.commons.codec.digest.DigestUtils import redis.clients.jedis.Jedis import redis.clients.jedis.JedisPool import redis.clients.jedis.params.SetParams @@ -90,58 +89,4 @@ class RedisCacheProvider implements CacheProvider { } } - // =============== bi-cache store implementation =============== - - @Override - void biPut(String key, String value, Duration ttl) { - final id = DigestUtils.sha256Hex(value) - try( Jedis conn=pool.getResource() ) { - final params = new SetParams().nx().ex(ttl.toSeconds()) - final tx = conn.multi() - tx.set(key, value, params) - tx.sadd(id, key) - tx.exec() - } - } - - @Override - void biRemove(String key) { - try( Jedis conn=pool.getResource() ) { - final value = conn.get(key) - final tx = conn.multi() - tx.del(key) - if( value ) { - final id = DigestUtils.sha256Hex(value) - tx.srem(id, key) - } - tx.exec() - } - } - - @Override - Set biKeysFor(String value) { - final id = DigestUtils.sha256Hex(value) - try( Jedis conn=pool.getResource() ) { - return conn.smembers(id) - } - } - - @Override - String biKeyFind(String value, boolean sorted) { - final id = DigestUtils.sha256Hex(value) - final list = biKeysFor(value).toList() - final keys = sorted ? list.toSorted() : list.shuffled() - final itr = keys.iterator() - while( itr.hasNext() ) { - final key = itr.next() - // verify the key still exists - if( get(key)!=null ) - return key - // if the key is not found, remove it from the set - try( Jedis conn=pool.getResource() ) { - conn.srem(id, key) - } - } - return null - } } diff --git a/src/test/groovy/io/seqera/wave/service/cache/impl/LocalCacheProviderTest.groovy b/src/test/groovy/io/seqera/wave/service/cache/impl/LocalCacheProviderTest.groovy index 5c2a14956..d1eaee375 100644 --- a/src/test/groovy/io/seqera/wave/service/cache/impl/LocalCacheProviderTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/cache/impl/LocalCacheProviderTest.groovy @@ -80,45 +80,4 @@ class LocalCacheProviderTest extends Specification { localCacheProvider.get('key') == 'new-value' } - def 'should add and find keys for values' () { - when: - localCacheProvider.biPut('x1', 'a', Duration.ofMinutes(1)) - localCacheProvider.biPut('x2', 'b', Duration.ofMinutes(1)) - localCacheProvider.biPut('x3', 'a', Duration.ofMinutes(1)) - localCacheProvider.biPut('x4', 'c', Duration.ofMinutes(1)) - - then: - localCacheProvider.biKeysFor('a') == ['x1', 'x3'] as Set - localCacheProvider.biKeysFor('c') == ['x4'] as Set - localCacheProvider.biKeysFor('d') == [] as Set - - when: - localCacheProvider.biRemove('x1') - then: - localCacheProvider.biKeysFor('a') == ['x3'] as Set - - when: - localCacheProvider.biRemove('x3') - then: - localCacheProvider.biKeysFor('a') == [] as Set - } - - def 'should add and find keys for values' () { - when: - localCacheProvider.biPut('x1', 'a', Duration.ofMillis(100)) - localCacheProvider.biPut('x2', 'b', Duration.ofMinutes(1)) - localCacheProvider.biPut('x3', 'a', Duration.ofMinutes(1)) - localCacheProvider.biPut('x4', 'c', Duration.ofMinutes(1)) - - then: - localCacheProvider.biKeyFind('a', true) == 'x1' - and: - localCacheProvider.biKeysFor('a') == ['x1','x3'] as Set - and: - sleep 500 - and: - localCacheProvider.biKeyFind('a', true) == 'x3' - localCacheProvider.biKeysFor('a') == ['x3'] as Set - - } } diff --git a/src/test/groovy/io/seqera/wave/service/cache/impl/RedisCacheProviderTest.groovy b/src/test/groovy/io/seqera/wave/service/cache/impl/RedisCacheProviderTest.groovy index 79c679b7e..6f548d7f4 100644 --- a/src/test/groovy/io/seqera/wave/service/cache/impl/RedisCacheProviderTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/cache/impl/RedisCacheProviderTest.groovy @@ -89,70 +89,4 @@ class RedisCacheProviderTest extends Specification implements RedisTestContainer redisCacheProvider.get('key') == 'new-value' } - def 'should add and find keys for values' () { - when: - redisCacheProvider.biPut('x1', 'a', Duration.ofMinutes(1)) - redisCacheProvider.biPut('x2', 'b', Duration.ofMinutes(1)) - redisCacheProvider.biPut('x3', 'a', Duration.ofMinutes(1)) - redisCacheProvider.biPut('x4', 'c', Duration.ofMinutes(1)) - - then: - redisCacheProvider.biKeysFor('a') == ['x1', 'x3'] as Set - redisCacheProvider.biKeysFor('c') == ['x4'] as Set - redisCacheProvider.biKeysFor('d') == [] as Set - - when: - redisCacheProvider.biRemove('x1') - then: - redisCacheProvider.biKeysFor('a') == ['x3'] as Set - - when: - redisCacheProvider.biRemove('x3') - then: - redisCacheProvider.biKeysFor('a') == [] as Set - - cleanup: - redisCacheProvider.clear() - } - - def 'should add and find single key for value' () { - when: - redisCacheProvider.biPut('x1', 'a', Duration.ofSeconds(1)) - redisCacheProvider.biPut('x2', 'b', Duration.ofMinutes(1)) - redisCacheProvider.biPut('x3', 'a', Duration.ofMinutes(1)) - redisCacheProvider.biPut('x4', 'c', Duration.ofMinutes(1)) - - then: - redisCacheProvider.biKeyFind('a', true) == 'x1' - and: - redisCacheProvider.biKeysFor('a') == ['x1','x3'] as Set - and: - sleep 1500 - and: - redisCacheProvider.biKeyFind('a', true) == 'x3' - redisCacheProvider.biKeysFor('a') == ['x3'] as Set - - cleanup: - redisCacheProvider.clear() - } - - def 'should update expiration when re-putting the value' () { - when: - redisCacheProvider.biPut('x1', 'a', Duration.ofSeconds(1)) - then: - redisCacheProvider.biKeyFind('a', true) == 'x1' - - when: - sleep 500 - redisCacheProvider.biPut('x1', 'a', Duration.ofSeconds(1)) - sleep 500 - redisCacheProvider.biPut('x1', 'a', Duration.ofSeconds(1)) - sleep 500 - then: - redisCacheProvider.biKeyFind('a', true) == 'x1' - - cleanup: - redisCacheProvider.clear() - } - }