marina

Erlang CI

High-performance Erlang client for Apache Cassandra and ScyllaDB, speaking the CQL binary protocol directly over TCP.

Features

Requirements

Installation

Pin to the latest tag (recommended):

{deps, [
    {marina, {git, "https://github.com/lpgauth/marina.git", {tag, "0.4.0"}}}
]}.

Or follow master:

{deps, [
    {marina, {git, "https://github.com/lpgauth/marina.git", {branch, "master"}}}
]}.

Configuration

All settings are read from the marina application env.

Name Type Default Description
backlog_sizepos_integer()1024 Per-connection shackle backlog.
bootstrap_ips[string()]["127.0.0.1"] IPs tried in order until one responds with system.peers.
compressionboolean()false Negotiate LZ4 compression on every connection.
keyspaceundefined | binary()undefined Default keyspace; issued as USE … after startup.
passwordbinary()undefined Password for PasswordAuthenticator.
pool_sizepos_integer()16 Number of shackle connections per node.
pool_strategyrandom | round_robinrandom Shackle's strategy for picking a connection from a per-node pool.
portpos_integer()9042 Server port.
reconnectboolean()true Auto-reconnect closed connections.
reconnect_time_maxpos_integer() | infinity120000 Upper bound on the reconnect backoff (ms).
reconnect_time_minpos_integer()1500 Lower bound on the reconnect backoff (ms).
socket_options[gen_tcp:option()] see marina_internal.hrlgen_tcp options applied to every connection.
strategyrandom | token_awaretoken_aware Node selection: random, or Murmur3-hash the routing_key to the replica.
usernamebinary()undefined Username for PasswordAuthenticator.

Usage

Start the application, then call the query API:

1> marina_app:start().
{ok, [granderl, metal, shackle, foil, marina, ...]}

2> marina:query(<<"SELECT id, name FROM users LIMIT 1">>, #{timeout => 1000}).
{ok, {result, _Metadata, 1, [[<<"…">>, <<"alice">>]]}}

3> marina:query(<<"SELECT * FROM users WHERE id = ?">>,
                #{values      => [Uuid],
                  routing_key => Uuid,
                  timeout     => 1000}).
{ok, {result, _Metadata, 1, [Row]}}

4> marina:reusable_query(<<"SELECT * FROM users WHERE id = ?">>,
                         #{values => [Uuid], timeout => 1000}).
{ok, {result, _Metadata, 1, [Row]}}

5> marina:batch([
        {query, <<"INSERT INTO kv (k, v) VALUES (1, 'a')">>, []},
        {query, <<"INSERT INTO kv (k, v) VALUES (2, 'b')">>, []}
   ], #{batch_type => logged, timeout => 1000}).
{ok, undefined}

API surface

Synchronous:

Asynchronous (return a shackle:request_id(), consume via marina:receive_response/1):

Query options

query_opts() is a map; unknown keys are ignored.

Key Type Default
batch_typelogged | unlogged | counterlogged
consistency_level?CONSISTENCY_*?CONSISTENCY_ONE
page_sizepos_integer() unset
paging_statebinary() unset
pidpid()self()
routing_keyinteger() | binary()undefined
skip_metadataboolean()false
timeoutpos_integer()1000
values[binary()]undefined

Architecture notes

Development

make compile     # rebar3 compile with strict warnings
make xref        # cross-reference analysis
make dialyzer    # success typing
make eunit       # unit + integration tests (expects ScyllaDB at 172.18.0.2:9042)
make test        # xref + eunit + dialyzer
make bench       # ring-lookup micro-benchmark

The bundled Dockerfile produces the CI image (lpgauth/erlang-scylla:28.3.1-6.2.3-amd64) by layering OTP 28.3.1 (from the official erlang image) on top of scylladb/scylla:6.2.3. For local integration tests, run that image or a plain ScyllaDB container on 172.18.0.2:9042.

License

MIT — see LICENSE.