ytsaurus-api
The transport-independent YTsaurus client interface: one API, two transports.
Pre-release, published from 0.3.0. The interface is the one thing here that
is expensive to change later and it has not settled: the version is 0.x and
it may change in a patch release. It is on crates.io because
ytsaurus-rpc and ytsaurus-client's create_client /
create_rpc_client return this crate's TableClient and could not be published
otherwise.
Why
YTsaurus reaches its dynamic tables two ways, and the C++ client does not make callers pick an API to go with the transport. It has one interface and two constructors:
IClientPtr ; // HTTP
IClientPtr ; // RPC proxy
This crate is the Rust equivalent of what those return, and the layering copies the C++ because that layering is the reason it works:
| C++ | here |
|---|---|
yt/yt/client/api — the interface |
this crate |
yt/yt/client/api/rpc_proxy — one implementation |
ytsaurus-rpc |
yt/cpp/mapreduce — the wrapper with both constructors |
ytsaurus-client |
So the constructors live in ytsaurus-client, which depends on both, and
choosing a transport is one line:
use ;
#
The interface is synchronous
Deliberately, and it is the decision here worth arguing about. The C++ wrapper blocks, every other crate in this workspace is synchronous, and a MapReduce job is a synchronous, single-purpose process.
Async callers lose nothing. ytsaurus_rpc::Client is untouched and is still
the only way to get concurrent in-flight requests — which is the entire reason
the RPC proxy exists. What this interface buys is portability between
transports, not concurrency; the blocking facade drives one call at a time.
The row model
Column names, not ids. The RPC wire format numbers its values and resolves them through a name table, HTTP names them directly, and a caller should not have to know which.
use ;
let row = new.with.with;
assert_eq!;
Rows keep the order their columns were added in, because a key row's column
order is the table's key order — sorting them would ask for a different row.
Strings are bytes rather than String: a YTsaurus column may legitimately hold
something that is not UTF-8.
What it covers, and what it does not
The dynamic-table surface both transports implement: lookup_rows,
select_rows, insert_rows, delete_rows, and tablet transactions.
Cypress, operations and file I/O stay on ytsaurus-client. The RPC crate
deliberately does not implement them, and an interface with half its methods
unavailable on one transport would be worse than two honest APIs.
One asymmetry, and the cluster reports it
Tablet transactions are RPC-only. They are sticky — a transaction belongs to the proxy that created it, and every later call in it must reach that same proxy — and an HTTP client routes each request independently. Ask an HTTP client for one and a real cluster answers:
Sticky transaction … is not found, this usually means that you use tablet transactions within HTTP API; consider using RPC API instead
So the HTTP implementation refuses up front with Error::Unsupported and quotes
that advice, rather than failing on the second call. This is one of the reasons
CreateRpcClient exists in the C++ at all.
Everything else — reads, and writes outside a transaction — works on both.
Checked against a real cluster
Runs the same code over each transport against one cluster and compares the results row for row. The two are wire-level unrelated — YSON over HTTP, the row wire protocol over bus — so "they behave the same" is a claim that needs running, and this is the first differential test in this repository between two independent implementations of the same operations.