NAME

Melian - Perl client to the Melian cache

VERSION

version 0.004

SYNOPSIS

use Melian;

#-----------------------------------------------
# OO INTERFACE (easy, name-based)
#-----------------------------------------------
my $melian = Melian->new(
    'dsn' => 'unix:///tmp/melian.sock',
);

my $row = $melian->fetch_by_string_from( 'cats', 'name', 'Pixel' );

# Using IDs directly (faster)
my $row2 = $melian->fetch_by_string( 1, 1, 'Pixel' );

#-----------------------------------------------
# FUNCTIONAL INTERFACE (fastest)
#-----------------------------------------------
use Melian qw(fetch_by_string_with);

my $conn = Melian->create_connection(
    'dsn' => 'unix:///tmp/melian.sock',
);

# Must use IDs in functional mode
my $row3 = fetch_by_string_with( $conn, 1, 1, 'Pixel' );

DESCRIPTION

Melian is a tiny, fast, no-nonsense Perl client for the Melian cache server.

Melian (the server) keeps full table snapshots in memory. Lookups are done entirely inside the server and returned as small JSON blobs. Think of it as a super-fast read-only lookup service.

This module gives you two ways to talk to Melian:

Object-Oriented Mode (easy)

Use table names and column names:

$melian->fetch_by_string_from( 'cats', 'name', 'Pixel' );

Behind the scenes, the module:

  • Looks up the table ID in the schema

  • Looks up the column ID in the schema

  • Builds the binary request to the server

  • Reads the reply and decodes JSON

This is the most convenient way. It is a little slower, because there is some name lookup and method dispatch each time.

Functional Mode (fastest)

Use this when you want raw speed:

my $conn = Melian->create_connection(...);
my $row = fetch_by_string_with( $conn, $table_id, $column_id, $key );

This avoids:

  • Method calls

  • Object construction

  • Lookup of table IDs and column IDs

It is simply: "write a request to the socket, read a response."

If you're chasing microseconds, this is the mode for you.

SCHEMA

Melian needs a schema so it knows which table IDs and column IDs correspond to which names. A schema looks something like:

people#0|60|id:int

Or:

people#0|60|id:int,cats#1|45|id:int;name:string

The format is simple:

  • table_name#table_id

  • |refresh_period_in_seconds

  • |column_name#column_id:column_type (multiple columns separated by ;)

You do NOT need to write this schema unless you want to. If you do not supply one, Melian will request it automatically from the server at startup.

Accessing table and column IDs

Once the client is constructed:

my $schema = $melian->schema();

Each table entry contains:

{
    name    => "cats",
    id      => 1,
    period  => 45,
    indexes => [
        { id => 0, column => "id",   type => "int"    },
        { id => 1, column => "name", type => "string" },
    ],
}

If you use the functional API, you probably want to extract these once at startup and store them in constants:

use constant {
    'CAT_ID_TABLE'    => 1,
    'CAT_ID_COLUMN'   => 0, # integer ID
    'CAT_NAME_COLUMN' => 1, # string column
};

This saves name lookups on every request.

METHODS

new(...)

my $melian = Melian->new(
    'dsn'         => 'unix:///tmp/melian.sock',
    'timeout'     => 1, # Only relevant for TCP/IP
    'schema_spec' => 'people#0|60|id:int',
);

Creates a new client and automatically loads the schema.

You may specify:

  • schema — already-parsed schema hashref

  • schema_spec — inline schema description

  • schema_file — path to JSON schema file

  • nothing — Melian will ask the server for the schema

connect()

Opens the underlying socket. Called automatically by new().

disconnect()

Closes the socket.

fetch_raw($table_id, $column_id, $key_bytes)

Fetches a raw JSON string. Does NOT decode it. Assumes input is encoded correctly.

fetch_raw_from($table_name, $column_name, $key_bytes)

Same as above, but uses names instead of IDs.

fetch_by_string($table_id, $column_id, $string_key)

Fetches JSON from the server and decodes into a Perl hashref.

fetch_by_string_from($table_name, $column_name, $string_key)

Name-based version.

fetch_by_int($table_id, $column_id, $int)

Same as fetch_by_string, but the key is packed as a 32-bit integer.

fetch_by_int_from($table_name, $column_name, $int)

Name-based version.

FUNCTIONS

These functions form the high-speed functional interface. They require a socket returned by create_connection().

create_connection(%args)

Returns a raw socket connected to the server. Same options as new(), but no object is created.

fetch_raw_with($conn, $table_id, $column_id, $key_bytes)

fetch_by_string_with($conn, $table_id, $column_id, $string_key)

fetch_by_int_with($conn, $table_id, $column_id, $int)

These behave like the corresponding OO methods but skip object overhead and schema lookup.

table_of($schema, $table_name)

my $table_data = table_of( $schema, 'cats' );
my $table_id   = $table_data->{'id'};

Fetches the table information from the schema.

column_id_of($table_data, $column_name)

my $table_data = table_of( $schema, 'cats' );
my $column_id  = column_id_of( $table_data, 'name' );

Fetches the ID of a column from a given table metadata.

load_schema_from_describe($conn)

my $schema = load_schema_from_describe($conn);

This helps you retrieve the schema if you're using the functional interface. You can then use this schema to determine table and column IDs.

PERFORMANCE NOTES

  • OO mode is convenient but has overhead from name lookups and method calls.

  • ID-based OO mode is faster because it skips name lookups.

  • Functional mode is the fastest and is roughly equivalent to calling syswrite and sysread directly in Perl.

  • If you care about performance, resolve table and column IDs once at startup.

AUTHORS

  • Sawyer X

  • Gonzalo Diethelm

COPYRIGHT AND LICENSE

This software is Copyright (c) 2025 by Sawyer X.

This is free software, licensed under:

The MIT (X11) License