diff --git a/build.gradle b/build.gradle index 3a1f9473..a93f9ef0 100644 --- a/build.gradle +++ b/build.gradle @@ -104,6 +104,7 @@ dependencies { implementation 'org.apache.commons:commons-collections4:4.3' implementation 'javax.annotation:javax.annotation-api:1.3.2' implementation 'org.bouncycastle:bcprov-jdk15on:1.61' + implementation 'com.github.ben-manes.caffeine:caffeine:2.8.5' implementation "org.slf4j:slf4j-api:$slf4jVersion" implementation "org.apache.logging.log4j:log4j-slf4j-impl:2.11.1" diff --git a/src/main/kotlin/io/emeraldpay/dshackle/cache/HeightCache.kt b/src/main/kotlin/io/emeraldpay/dshackle/cache/HeightCache.kt index a4041e58..6e8e646a 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/cache/HeightCache.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/cache/HeightCache.kt @@ -15,41 +15,35 @@ */ package io.emeraldpay.dshackle.cache +import com.github.benmanes.caffeine.cache.Caffeine import io.emeraldpay.dshackle.data.BlockContainer import io.emeraldpay.dshackle.data.BlockId import io.emeraldpay.dshackle.reader.Reader -import org.slf4j.LoggerFactory import reactor.core.publisher.Mono -import java.util.concurrent.ConcurrentHashMap /** * Memory cache for blocks heights, keeps mapping height->hash. */ open class HeightCache( - val maxSize: Int = 256 + maxSize: Int = 512 ) : Reader { - companion object { - private val log = LoggerFactory.getLogger(HeightCache::class.java) - } - - private val heights = ConcurrentHashMap() + private val heights = Caffeine.newBuilder() + .maximumSize(maxSize.toLong()) + .build() override fun read(key: Long): Mono { - return Mono.justOrEmpty(heights[key]) + return Mono.justOrEmpty(heights.getIfPresent(key)) } open fun add(block: BlockContainer): BlockId? { - val existing = heights[block.height] - heights[block.height] = block.hash - - // evict old numbers if full - var dropHeight = block.height - maxSize - while (heights.size > maxSize && dropHeight < block.height) { - heights.remove(dropHeight) - dropHeight++ - } - - return existing + val previousId = heights.getIfPresent(block.height) + heights.put(block.height, block.hash) + return previousId } + + fun purge() { + heights.cleanUp() + } + } \ No newline at end of file diff --git a/src/test/groovy/io/emeraldpay/dshackle/cache/HeightCacheSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/cache/HeightCacheSpec.groovy index 31bd45bf..cbf386d0 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/cache/HeightCacheSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/cache/HeightCacheSpec.groovy @@ -72,6 +72,7 @@ class HeightCacheSpec extends Specification { block.timestamp = Instant.now() cache.add(BlockContainer.from(block)) } + cache.purge() def act1 = cache.read(100).block() def act2 = cache.read(101).block()