Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove BiCacheStore data structure #653

Merged
merged 1 commit into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import io.seqera.wave.service.cache.impl.CacheProvider
*
* @author Paolo Di Tommaso <[email protected]>
*/
abstract class AbstractCacheStore<V> implements CacheStore<String,V>, BiCacheStore<String,V> {
abstract class AbstractCacheStore<V> implements CacheStore<String,V> {

private EncodingStrategy<V> encodingStrategy

Expand Down Expand Up @@ -101,25 +101,4 @@ abstract class AbstractCacheStore<V> implements CacheStore<String,V>, 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<String> 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
}
}
64 changes: 0 additions & 64 deletions src/main/groovy/io/seqera/wave/service/cache/BiCacheStore.groovy

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@

package io.seqera.wave.service.cache.impl

import io.seqera.wave.service.cache.BiCacheStore
import io.seqera.wave.service.cache.CacheStore

/**
* Define an cache interface alias to be used by cache implementation providers
*
* @author Paolo Di Tommaso <[email protected]>
*/
interface CacheProvider<K,V> extends CacheStore<K,V>, BiCacheStore<K,V> {
interface CacheProvider<K,V> extends CacheStore<K,V> {
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,57 +99,4 @@ class LocalCacheProvider implements CacheProvider<String,String> {
store.clear()
}

// =============== bi-cache store implementation ===============

private Map<Integer,Set<String>> 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<String>()
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<String> biKeysFor(String value) {
final id = value.hashCode()
return index.get(id) ?: Set.<String>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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -90,58 +89,4 @@ class RedisCacheProvider implements CacheProvider<String,String> {
}
}

// =============== 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<String> 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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}

}
Loading