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

com.twitter.finagle.memcached.protocol.text.server.ResponseToBuf.scala Maven / Gradle / Ivy

There is a newer version: 24.2.0
Show newest version
package com.twitter.finagle.memcached.protocol.text.server

import com.twitter.finagle.memcached.protocol._
import com.twitter.finagle.memcached.protocol.text.EncodingConstants._
import com.twitter.io.{Buf, BufByteWriter, ByteWriter}
import java.nio.charset.StandardCharsets

/**
 * Used by the server.
 */
private[finagle] object ResponseToBuf {

  private[this] val ZERO = Buf.Utf8("0")
  private[this] val VALUE = Buf.Utf8("VALUE")

  private[this] val STORED = Buf.Utf8("STORED")
  private[this] val NOT_STORED = Buf.Utf8("NOT_STORED")
  private[this] val EXISTS = Buf.Utf8("EXISTS")
  private[this] val NOT_FOUND = Buf.Utf8("NOT_FOUND")
  private[this] val DELETED = Buf.Utf8("DELETED")

  private[this] def encodeResponse(response: Seq[Buf]): Buf = {
    // + 2 to estimated size for DELIMITER.
    val bw = BufByteWriter.dynamic(10 * response.size + 2)
    response.foreach { token =>
      bw.writeBytes(token)
      bw.writeBytes(SPACE)
    }
    bw.writeBytes(DELIMITER)

    bw.owned()
  }

  private[this] def writeResponseWithData(
    response: Seq[Buf],
    data: Buf,
    casUnique: Option[Buf],
    bw: ByteWriter
  ): bw.type = {
    response.foreach { token =>
      bw.writeBytes(token)
      bw.writeBytes(SPACE)
    }

    bw.writeBytes(data.length.toString.getBytes(StandardCharsets.US_ASCII))

    casUnique.foreach { token =>
      bw.writeBytes(SPACE)
      bw.writeBytes(token)
    }

    bw.writeBytes(DELIMITER)
    bw.writeBytes(data)
    bw.writeBytes(DELIMITER)
    bw
  }

  private[this] def encodeResponseLines(lines: Seq[Seq[Buf]]): Buf = {
    // + 5 to estimated size for END + DELIMITER.
    val bw = BufByteWriter.dynamic(100 * lines.size + 5)

    lines.foreach { tokens =>
      tokens.foreach { token =>
        bw.writeBytes(token)
        bw.writeBytes(SPACE)
      }
      bw.writeBytes(DELIMITER)
    }
    bw.writeBytes(END)
    bw.writeBytes(DELIMITER)
    bw.owned()
  }

  def encode(message: Response): Buf = message match {
    case Stored => encodeResponse(Seq(STORED))
    case NotStored => encodeResponse(Seq(NOT_STORED))
    case Exists => encodeResponse(Seq(EXISTS))
    case Deleted => encodeResponse(Seq(DELETED))
    case NotFound => encodeResponse(Seq(NOT_FOUND))
    case NoOp => encodeResponse(Nil)
    case Number(value) => encodeResponse(Seq(Buf.Utf8(value.toString)))
    case Error(cause) =>
      val formatted: Seq[Array[Byte]] = ExceptionHandler.format(cause)
      encodeResponse(formatted.map { Buf.ByteArray.Owned(_) })
    case _: ValuesAndErrors =>
      throw new IllegalStateException("ValuesAndErrors is expected only on the client side")
    case InfoLines(lines) =>
      val statLines = lines map { line =>
        val key = line.key
        val values = line.values
        Seq(key) ++ values
      }
      encodeResponseLines(statLines)
    case Values(values) =>
      // + 5 to estimated size for END + DELIMITER.
      val bw = BufByteWriter.dynamic(100 * values.size + 5)

      values.foreach {
        case Value(key, value, casUnique, Some(flags)) =>
          writeResponseWithData(Seq(VALUE, key, flags), value, casUnique, bw)
        case Value(key, value, casUnique, None) =>
          writeResponseWithData(Seq(VALUE, key, ZERO), value, casUnique, bw)
      }
      bw.writeBytes(END)
      bw.writeBytes(DELIMITER)
      bw.owned()
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy