All Downloads are FREE. Search and download functionalities are using the official Maven repository.

lson.core_2.11.0.9.71.source-code.Cache.scala Maven / Gradle / Ivy

The newest version!
//: ----------------------------------------------------------------------------
//: Copyright (C) 2017 Verizon.  All Rights Reserved.
//:
//:   Licensed under the Apache License, Version 2.0 (the "License");
//:   you may not use this file except in compliance with the License.
//:   You may obtain a copy of the License at
//:
//:       http://www.apache.org/licenses/LICENSE-2.0
//:
//:   Unless required by applicable law or agreed to in writing, software
//:   distributed under the License is distributed on an "AS IS" BASIS,
//:   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//:   See the License for the specific language governing permissions and
//:   limitations under the License.
//:
//: ----------------------------------------------------------------------------
package nelson

import java.util.concurrent.TimeUnit
import scala.concurrent.duration.Duration

/**
 * Main public entry point for creating in-memory cache.
 *
 * Default cache has no means to remove anything. It keeps entries forever (but they can be overriden)
 *
 * Behavior can be customized with following options:
 *    - limit maximum number of elements to cache
 *      once limit is reached older elements will be removed, typically using "last recently used" strategy
 *    - "ttl since update" for object in cache
 *      Prevents from keeping stale objects in the cache
 *    - "ttl since last use"
 *      Prevents from wasting memory on unused objects
 *
 * ConcurrencyLevel hint is Guava-specific hint to guide the allowed concurrency among update operations.
 * Default value is 4 (for guava 13.0)
 *
 * From Guava docs:
 *   Used as a hint for internal sizing. The table is internally partitioned to try to permit the indicated number of
 *   concurrent updates without contention. Because assignment of entries to these partitions is not necessarily uniform,
 *   the actual concurrency observed may vary. Ideally, you should choose a value to accommodate as many threads as will
 *   ever concurrently modify the table. Using a significantly higher value than you need can waste space and time,
 *   and a significantly lower value can lead to thread contention. But overestimates and underestimates within an order
 *   of magnitude do not usually have much noticeable impact. A value of one permits only one thread to modify the cache
 *   at a time, but since read operations and cache loading computations can proceed concurrently, this still yields
 *   higher concurrency than full synchronization.
 */
object Cache {
  def apply[K, V](maximumSize: Option[Int] = None,
                  concurrencyLevel: Option[Int] = None,
                  expireAfterWrite: Option[Duration] = None,
                  expireAfterAccess: Option[Duration] = None): Cache[K, V] =
    (new GuavaCacheBuilder[K, V]()).
      maximumSize(maximumSize).
      concurrencyLevel(concurrencyLevel).
      expireAfterAccess(expireAfterAccess).
      expireAfterWrite(expireAfterWrite).build()
}

/**
 * Basic cache API providing get/put operations
 */
trait Cache[K, V] {
  def get(key: K): Option[V]
  def put(key: K, value: V): Unit
  def invalidate(key: K): Unit
}

/**
 * Basic CacheBuilder API for constructing cache instances.
 * API is subset of what Google's Guava libraries is providing
 */
trait CacheBuilder[K, V] {
  def build(): Cache[K, V]

  def maximumSize(n: Int): CacheBuilder[K, V]
  def concurrencyLevel(n: Int): CacheBuilder[K, V]
  def expireAfterWrite(duration: Duration): CacheBuilder[K, V]
  def expireAfterAccess(duration: Duration): CacheBuilder[K, V]
}

/**************** Specific Guava based cache implementation ******************/

class GuavaCache[K, V](private val cache:com.google.common.cache.Cache[K,V]) extends Cache[K, V] {
  def get(key: K):Option[V] = Option(cache.getIfPresent(key))
  def put(key: K, value:V) = cache.put(key, value)
  def invalidate(key: K) = cache.invalidate(key)

}

class GuavaCacheBuilder[K, V] extends CacheBuilder[K, V] {
  val builder:com.google.common.cache.CacheBuilder[K, V] =
    com.google.common.cache.CacheBuilder.newBuilder().asInstanceOf[com.google.common.cache.CacheBuilder[K, V]]

  def build(): Cache[K, V] = new GuavaCache[K, V](builder.build[K, V]())

  def maximumSize(n: Int) = new GuavaCacheBuilder[K, V] {
    override val builder = GuavaCacheBuilder.this.builder.maximumSize(n.toLong)
  }

  def concurrencyLevel(n: Int) = new GuavaCacheBuilder[K, V] {
    override val builder = GuavaCacheBuilder.this.builder.concurrencyLevel(n)
  }

  def expireAfterWrite(duration: Duration) = new GuavaCacheBuilder[K, V] {
    override val builder = GuavaCacheBuilder.this.builder.expireAfterWrite(duration.toMicros, TimeUnit.MICROSECONDS)
  }

  def expireAfterAccess(duration: Duration) = new GuavaCacheBuilder[K, V] {
    override val builder = GuavaCacheBuilder.this.builder.expireAfterAccess(duration.toMicros, TimeUnit.MICROSECONDS)
  }

  /**
   * Helper methods to deal with optional parameters
   */

  def maximumSize(n: Option[Int]): GuavaCacheBuilder[K,V] =
    n.map {v => maximumSize(v)}.getOrElse(this)

  def concurrencyLevel(n: Option[Int]): GuavaCacheBuilder[K,V] =
    n.map {v => concurrencyLevel(v)}.getOrElse(this)

  def expireAfterWrite(duration: Option[Duration]): GuavaCacheBuilder[K,V] =
    duration.map(expireAfterWrite).getOrElse(this)

  def expireAfterAccess(duration: Option[Duration]): GuavaCacheBuilder[K,V]  =
    duration.map(expireAfterAccess).getOrElse(this)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy