Skip to content

Interactive transactions in IPROTO #2016

@kostja

Description

@kostja

A client transaction can be started with CALL("box.begin").

Vinyl doesn't abort a transaction at fiber yield. But the same fiber may serve different connections of the binary protocol. It means that queries from different connections may end up in the same transaction, or that a subsequent query which is intended for a multi-statement transaction ends up committed prematurely.

All this trouble happens because struct txn is now stored in struct fiber, not in struct session, as well as gc pool.

So it seems time has come to move struct txn, struct region, and struct diag from struct fiber to struct session. Then we will either need to create a technical session for every fiber, or make sure that the rest of the code, which uses fibers, works without struct region gc and struct diag.

How to repeat:

  • begin a transaction on the client, over the binary protocol
  • create another connection
  • send a batch of two queries over the same connection; the queries must use the transactrion and yield
  • observe the second query execute before the first one.

Implementation

The binary protocol

We will extend the binary protocol header with a new key, IPROTO_TRANSACTION_ID.
Each request missing this key, or with key value 0, will run in its own transaction, or, if it's CALL/EVAL, will be able to manually control the transaction flow. In other words, for old clients and drivers, the semantics will stay the same.

We will also add commands for explicit transaction control flow:
IPROTO_BEGIN
IPROTO_COMMIT
IPROTO_ROLLBACK

These transaction will pass IPROTO_TRANSACTION_ID in the header, so they will affect the transaction identified by the supplied id.

IPROTO_BEGIN may miss IPROTO_TRANSACTION_ID. In this case, as well as in case of CALL/EVAL request explicitly starting a transaction by invoking box.begin() and leaving it open, the server will pass an automatically generated id back to the client.

Since, with this enhancement, the client will get an opportunity to flood the server with infinitely many open transaction, a new box dynamic configuration variable needs to be introduced: transaction_max, limiting the number of active transactions.
We also need to reflect the number of active transactions in a statistical variable.

Lua concole

We need a way to store the active transaction id in a Lua console. Since the id can not be stored in the session (a single session may multiplex many transactions), we need a way to store it someplace else - perhaps in the console itself. For that purpose, we perhaps need to extend box.session package to return transaction id, so that Lua console can query it explicitly and save.

Runtime

fiber->gc needs to become a pointer, so that setting active transaction will update it.
Disconnect trigger needs to roll back all transactions active in the connection.
There should be a way to get a list of all active transactions in Lua and explicitly roll them back (by the
system administrator).

Binary log and replication

We may need to introduce transaction id to the binary log to implement synchronous replication. For now, though, since we never have partial transactions in the binary log, and there is a binary log transaction (physical one), we don't need to change anything.

Metadata

Metadata

Assignees

No one assigned

    Labels

    blockedNot ready to be implementedfeatureA new functionality

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions