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

scalacache.memcached.MemcachedCache.scala Maven / Gradle / Ivy

package scalacache.memcached

import org.slf4j.LoggerFactory
import net.spy.memcached.internal.{ OperationFuture, OperationCompletionListener, GetFuture, GetCompletionListener }
import net.spy.memcached.{ AddrUtil, BinaryConnectionFactory, MemcachedClient }
import scalacache.serialization.Codec
import scalacache.{ LoggingSupport, Cache }

import scala.concurrent.duration.Duration
import scala.util.Success
import scala.concurrent.{ Promise, ExecutionContext }

/**
 * Wrapper around spymemcached
 *
 * @param useLegacySerialization set this to true to use Spymemcached's serialization mechanism
 *                               to maintain compatibility with ScalaCache 0.7.x or earlier.
 */
class MemcachedCache(client: MemcachedClient,
                     keySanitizer: MemcachedKeySanitizer = ReplaceAndTruncateSanitizer(),
                     useLegacySerialization: Boolean = false)(implicit execContext: ExecutionContext = ExecutionContext.global)
    extends Cache[Array[Byte]]
    with MemcachedTTLConverter
    with LoggingSupport {

  override protected final val logger = LoggerFactory.getLogger(getClass.getName)

  /**
   * Get the value corresponding to the given key from the cache
   *
   * @param key cache key
   * @tparam V the type of the corresponding value
   * @return the value, if there is one
   */
  override def get[V](key: String)(implicit codec: Codec[V, Array[Byte]]) = {
    val p = Promise[Option[V]]()
    val f = client.asyncGet(keySanitizer.toValidMemcachedKey(key))
    f.addListener(new GetCompletionListener {
      def onComplete(g: GetFuture[_]): Unit = p.complete {
        val baseResult = f.get
        val result = {
          if (baseResult != null) {
            if (useLegacySerialization)
              Some(baseResult.asInstanceOf[V])
            else
              Some(codec.deserialize(baseResult.asInstanceOf[Array[Byte]]))
          } else None
        }
        logCacheHitOrMiss(key, result)
        Success(result)
      }
    })
    p.future
  }

  /**
   * Insert the given key-value pair into the cache, with an optional Time To Live.
   *
   * @param key cache key
   * @param value corresponding value
   * @param ttl Time To Live
   * @tparam V the type of the corresponding value
   */
  override def put[V](key: String, value: V, ttl: Option[Duration])(implicit codec: Codec[V, Array[Byte]]) = {
    val p = Promise[Unit]()
    val valueToSend = if (useLegacySerialization) value else codec.serialize(value)
    val f = client.set(keySanitizer.toValidMemcachedKey(key), toMemcachedExpiry(ttl), valueToSend)
    f.addListener(new OperationCompletionListener {
      def onComplete(g: OperationFuture[_]): Unit = p.complete {
        logCachePut(key, ttl)
        Success(())
      }
    })
    p.future
  }

  /**
   * Remove the given key and its associated value from the cache, if it exists.
   * If the key is not in the cache, do nothing.
   *
   * @param key cache key
   */
  override def remove(key: String) = {
    val p = Promise[Unit]()
    val f = client.delete(key)
    f.addListener(new OperationCompletionListener {
      def onComplete(g: OperationFuture[_]): Unit = p.complete {
        Success(())
      }
    })
    p.future
  }

  override def removeAll() = {
    val p = Promise[Unit]()
    val f = client.flush()
    f.addListener(new OperationCompletionListener {
      def onComplete(g: OperationFuture[_]): Unit = p.complete {
        Success(())
      }
    })
    p.future
  }

  override def close(): Unit = {
    client.shutdown()
  }

}

object MemcachedCache {

  /**
   * Create a Memcached client connecting to localhost:11211 and use it for caching
   */
  def apply(): MemcachedCache = apply("localhost:11211")

  /**
   * Create a Memcached client connecting to the given host(s) and use it for caching
   *
   * @param addressString Address string, with addresses separated by spaces, e.g. "host1:11211 host2:22322"
   */
  def apply(addressString: String): MemcachedCache =
    apply(new MemcachedClient(new BinaryConnectionFactory(), AddrUtil.getAddresses(addressString)))

  /**
   * Create a cache that uses the given Memcached client
   *
   * @param client Memcached client
   */
  def apply(client: MemcachedClient): MemcachedCache = new MemcachedCache(client)

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy