ProductPromotion
Logo

Scala

made by https://0x3d.site

GitHub - monix/shade: Memcached client for Scala
Memcached client for Scala. Contribute to monix/shade development by creating an account on GitHub.
Visit Site

GitHub - monix/shade: Memcached client for Scala

GitHub - monix/shade: Memcached client for Scala

Shade - Memcached Client for Scala

Build Status Join the chat at https://gitter.im/monix/shade

Overview

Shade is a Memcached client based on the de-facto Java library SpyMemcached.

The interface exposed is very Scala-ish, as you have a choice between making asynchronous calls, with results wrapped as Scala Futures, or blocking calls. The performance is stellar as it benefits from the optimizations that went into SpyMemcached over the years. Shade also fixes some problems with SpyMemcached's architecture, choices that made sense in the context of Java, but don't make so much sense in the context of Scala (TODO: add details).

The client is production quality. Supported for Scala versions: 2.10, 2.11 and 2.12.

Release Notes

Maintainers

These are the people maintaining this project that you can annoy:

  • Alex: @alexandru
  • Lloyd: @lloydmeta

Usage From SBT

dependencies += "io.monix" %% "shade" % "1.10.0"

Initializing the Memcached Client

To initialize a Memcached client, you need a configuration object. Checkout the Configuration case class.

import shade.memcached._
import scala.concurrent.ExecutionContext.Implicits.global

val memcached =
  Memcached(Configuration("127.0.0.1:11211"))

As you can see, you also need an ExecutionContext passed explicitly. As an implementation detail, the execution context represents the thread-pool in which requests get processed.

Simple non-blocking requests

Useful imports:

import concurrent.duration._ // for specifying timeouts
import concurrent.Future

Setting a key:

val op: Future[Unit] = memcached.set("username", "Alex", 1.minute)

Adding a key that will only set it if the key is missing (returns true if the key was added, or false if the key was already there):

val op: Future[Boolean] = memcached.add("username", "Alex", 1.minute)

Deleting a key (returns true if a key was deleted, or false if the key was missing):

val op: Future[Boolean] = memcached.delete("username")

Fetching a key:

val result: Future[Option[String]] = memcached.get[String]("username")

As you can see, for fetching a key the get() method needs an explicit type parameter, otherwise it doesn't know how to deserialize it. More on this below.

Blocking requests

Sometimes working with Futures is painful for quick hacks, therefore add(), set(), delete() and get() have blocking versions in the form of awaitXXX():

memcached.awaitGet("username") match {
  case Some(username) => println(s"Hello, $username")
  case None =>
    memcached.awaitSet("username", "Alex", 1.minute)
}

Compare-and-set

Sometimes you want to have some sort of synchronization for modifying values safely, like incrementing a counter. Memcached supports Compare-And-Swap atomic operations and so does this client.

val op: Future[Boolean] =
  memcached.compareAndSet("username", Some("Alex"), "Amalia", 1.minute)

This will return either true or false if the operation was a success or not. But working with compareAndSet is too low level, so the client also provides these helpers:

def incrementCounter: Future[Int] =
  memcached.transformAndGet[Int]("counter", 1.minute) {
    case Some(existing) => existing + 1
    case None => 1
  }

The above returns the new, incremented value. In case you want the old value to be returned, do this:

def incrementCounter: Future[Option[Int]] =
  memcached.getAndTransform[Int]("counter", 1.minute) {
    case Some(existing) => existing + 1
    case None => 1
  }

Serializing/Deserializing

Storing values in Memcached and retrieving values involves serializing and deserializing those values into bytes. Methods such as get(), set(), add() take an implicit parameter of type Codec[T] which is a type-class that specifies how to serialize and deserialize values of type T.

By default, Shade provides default implementations of Codec[T] for primitives, such as Strings and numbers. Checkout Codec.scala to see those defaults.

For more complex types, a default implementation based on Java's ObjectOutputStream and ObjectInputStream exist (also in Codec.scala).

However, because serializing/deserializing values like this is problematic (you can end up with lots of errors related to the ClassLoader used), this codec is available as part of the MemcachedCodecs trait (also in Codec.scala) and it either needs to be imported or mixed-in.

The import works like so:

import shade.memcached.MemcachedCodecs._

But this can land you in trouble because of the ClassLoader. For example in a Play 2.x application, in development mode the code is recompiled when changes happen and the whole environment gets restarted. If you do a plain import, you'll get ClassCastException or other weird errors. You can solve this by mixing-in MemcachedCodecs in whatever trait, class or object you want to do requests, as in:

case class User(id: Int, name: String, age: Int)

trait HelloController extends Controller with MemcachedCodecs {
   def memcached: Memcached // to be injected

   // a Play 2.2 standard controller action
   def userInfo(id: Int) = Action.async {
     for (user <-  memcached.get[User]("user-" + id)) yield
       Ok(views.showUserDetails(user))
   }

   // ...
}

Or, in case you want to optimize serialization/deserialization, you can always implement your own Codec[T], like:

// hackish example
implicit object UserCodec extends Codec[User] {
  def serialize(user: User): Array[Byte] =
    s"${user.id}|${user.name}|${user.age}".getBytes("utf-8")

  def deserialize(data: Array[Byte]): User = {
    val str = new String(data, "utf-8")
    val Array(id, name, age) = str.split("|")
    User(id.toInt, name, age.toInt)
  }
}

More Resources
to explore the angular.

mail [email protected] to add your project or resources here 🔥.

Related Articles
to learn about angular.

FAQ's
to learn more about Angular JS.

mail [email protected] to add more queries here 🔍.

More Sites
to check out once you're finished browsing here.

0x3d
https://www.0x3d.site/
0x3d is designed for aggregating information.
NodeJS
https://nodejs.0x3d.site/
NodeJS Online Directory
Cross Platform
https://cross-platform.0x3d.site/
Cross Platform Online Directory
Open Source
https://open-source.0x3d.site/
Open Source Online Directory
Analytics
https://analytics.0x3d.site/
Analytics Online Directory
JavaScript
https://javascript.0x3d.site/
JavaScript Online Directory
GoLang
https://golang.0x3d.site/
GoLang Online Directory
Python
https://python.0x3d.site/
Python Online Directory
Swift
https://swift.0x3d.site/
Swift Online Directory
Rust
https://rust.0x3d.site/
Rust Online Directory
Scala
https://scala.0x3d.site/
Scala Online Directory
Ruby
https://ruby.0x3d.site/
Ruby Online Directory
Clojure
https://clojure.0x3d.site/
Clojure Online Directory
Elixir
https://elixir.0x3d.site/
Elixir Online Directory
Elm
https://elm.0x3d.site/
Elm Online Directory
Lua
https://lua.0x3d.site/
Lua Online Directory
C Programming
https://c-programming.0x3d.site/
C Programming Online Directory
C++ Programming
https://cpp-programming.0x3d.site/
C++ Programming Online Directory
R Programming
https://r-programming.0x3d.site/
R Programming Online Directory
Perl
https://perl.0x3d.site/
Perl Online Directory
Java
https://java.0x3d.site/
Java Online Directory
Kotlin
https://kotlin.0x3d.site/
Kotlin Online Directory
PHP
https://php.0x3d.site/
PHP Online Directory
React JS
https://react.0x3d.site/
React JS Online Directory
Angular
https://angular.0x3d.site/
Angular JS Online Directory