package Riap::Transaction; # just to make PodWeaver happy

our $VERSION = '1.1.13'; # VERSION

1;
# ABSTRACT: Transactions over Riap


__END__
=pod

=head1 NAME

Riap::Transaction - Transactions over Riap

=head1 VERSION

version 1.1.13

=head1 DESCRIPTION

This documentation specifies a set of Riap actions and other conventions to do
transaction/undo over Riap.

Transaction management is done on the server side. There should be a transaction
manager on the server which records transactions, perform
begin/commit/rollback/recovery. It is the responsibility of the transaction
manager and the functions to implement the integrity and reliability (ACID)
properties of the transaction. Some implementation might not be ACID-compliant
(e.g. leave out the I [isolation] property).

Server can choose to limit duration of transaction. Transactions which is in
progress for too long (not commited or rolled back) can be automatically rolled
back and then become unknown. Server can maintain a global (server-wide)
transaction list, or a per-user one.

A transaction begins when client issues C<begin_tx> request. Initially
transaction status is B<I> (B<In progress>). When an action fails, transaction
status will be B<A> (B<Aborted>) and eventually will be B<R> (B<Rolled back>).
If all actions succeed and C<commit_tx> request also succeeds, status of
transaction will be B<C> (B<Committed>).

There is also a transaction status of B<E> (B<prEpared>) when dealing with
two-phase commit. (Note: the letter "P" is avoided because it is ambiguous
between Prepared and in-Progress).

Rolled back transaction can be forgotten/deleted immediately from the server.
Undo journal of committed transactions should still be remembered for a certain
period of time, to allow undo. Server can set a global/per-user limit for the
number of remembered committed transactions. A forgotten committed transaction
can no longer be undone.

=head2 Action: begin_tx

Additional Riap request keys: C<tx_id> (str, required, must be less than 200
characters to identify this transaction and to refer in future Riap requests; ID
should ideally be hard to guess by other clients, something like a UUID or
longer), C<summary> (str, optional, to give textual summary about this
transaction, should not be more than 1024 characters), C<twopc> (bool, optional,
defaults to false, whether server should start a transaction that can
participate in distributed transaction using two-phase commit protocol).

This action is used when client wants to start a new transaction on the server.
Initial status of the transaction should be B<I> (B<In progress>). Upon success,
server must return status 200.

Server can return one of these error statuses upon failure:

=over 4

=item * 400 (no tx_id given, invalid tx_id)

=item * 409 (another transaction with the same ID already exists)

=item * 412 (there are already too many transactions being started, either
globally on the server or for the particular client; or, client request
transaction with twopc=true and server does not support distributed transaction)

=item * 507 (insufficient disk space or other resources)

=item * 500 (general server-side error).

=back

C<tx_id> should be passed as a Riap request key to every subsequent C<call>
request or any one of transaction-management actions described on this list,
until the transaction is committed or rolled back.

Only C<call> requests fulfilling one of these conditions can be served
successfully:

=over 4

=item * call to pure functions

Because they do not cause any side effects and need not be logged in journal.

=item * dry-run call to functions supporting dry-run

Because this also should not cause any side effects).

=item * call to functions supporting transaction, undo, and idempotency.

Currently all three features must be supported by the function (C<tx>, C<undo>,
C<idempotency>).

=back

Some servers, in order to maintain ACID property, might even require that all
subsequent C<call> requests be inside some transaction. Call requests for other
cases will qualify as an error condition to cause an in-progress transaction to
become aborted (pending rollback). Further requests to aborted transaction will
fail with status 480 until transaction is aborted.

Request with C<tx_id> unknown by the server should result in 484 (no such
transaction) status.

Failed function call (4xx and 5xx responses) or failure in recording undo data
(status 532) will cause the transaction status to be set to B<aborted>. An
aborted transaction will cause all subsequent requests for this transaction to
be ignored, until transaction is rolled back (either manually or automatically
by the server). Before rollback occurs, server must return 480 (transaction
aborted) as response for each request. A C<commit_tx> request should also be
interpreted as a rollback in this situation.

Other possible error conditions 480 (transaction is already committed, no
further data is allowed).

Riap requests which does not incorporate C<tx_id> key should not be affected by
transaction management.

=head2 Action: commit_tx

Additional required Riap request keys: C<tx_id>.

This action commits the transaction. Server must return 200 upon success.

If transaction status is aborted, will rollback transaction instead.

Server can return one of these statuses upon failure: 484 (no such transaction),
480 (transaction already committed or rolled back), 532 (failure in committing),
500 (general error).

Upon failure of this request, will try to abort and rollback transaction.

=head2 Action: B<savepoint_tx>

Additional required Riap request keys: C<tx_id>, C<tx_spid> (an arbitrary string
up to 64 characters)

Define a savepoint. Transaction can be rolled back to a certain savepoint.

Defining savepoint with the same name as previously defined one will cause the
previous savepoint to be forgotten (thus future rollback mentioning the
savepoint will rollback to the new savepoint instead of the old).

Server may impose the maximum number of savepoints in a transaction.

Possible error statuses: 480, 484, 532, 500.

Upon failure of this request, transaction status is set to aborted.

=head2 Action: B<rollback_tx>

Additional required Riap request keys: C<tx_id>

Optional Riap request keys: C<tx_spid>

Rollback the transaction, or (if C<tx_spid> is specified) rollback to a specific
savepoint. If savepoint is unknown, transaction will be aborted.

Possible error statuses: 480, 484, 532, 500.

Upon failure of this request, transaction status is set to aborted.

=head2 Action: B<release_tx_savepoint>

Additional required Riap request keys: C<tx_id>, C<tx_spid>

Possible error statuses: 480, 484, 532, 500.

Upon failure of this request, transaction status is set to aborted.

=head2 Action: B<prepare_tx>

Additional required Riap request keys: C<tx_id>

Prepare transaction during distribution transaction. Usually called by an
external transaction manager during the first phase of two-phase commit
protocol.

Possible error statuses: 412 (distributed transaction not supported), 480, 484,
532, 500.

Upon failure of this request, transaction status is set to aborted.

=head2 Action: B<list_txs>

Additional required Riap request keys: C<tx_id>

List client's transactions. Should return an array containing transaction ID's.

Optional request key: C<detail> (bool, default false, is set to true will return
an array of result records instead), C<status> (str, filter by transaction
status).

Example:

 # Riap request
 {"action":"list_txs", "uri":"/", "detail":1}

 # result
 [200, "OK",
  [
   {"tx_id": "TX1", "status":"committed", "start_time":1336043060,
    "finish_time":1336043065, "summary":"Some summary"},
   {"tx_id": "TX2", "status":"committed", "start_time":1336043070,
    "finish_time":1336043071, "summary":null},
   {"tx_id": "TX3", "status":"in progress", "start_time":1336043090,
    "finish_time":null, "summary":"Some summary"},
  ]
 ]

=head2 Action: B<undo>

Optional Riap request keys: C<tx_id>.

Undo a committed transaction (defaults to the newest committed transaction).
Transaction must already be committed. Will do nothing if transaction is already
undone.

=head2 Action: B<redo>

Optional Riap request keys: C<tx_id>.

Redo a committed transaction (defaults to the newest undone committed
transaction). Transaction must already be committed . Will do nothing if
transaction is not undone.

=head2 Action: B<discard_tx>

Additional required Riap request keys: C<tx_id>.

Discard a committed transaction from the transaction manager. Transaction must
be already committed. If transaction is in progress or aborted, it will be
rolled back.

=head2 Action: B<discard_all_txs>

Additional required Riap request keys: none.

Discard all committed transactions for this client.

=head1 SPECIFICATION VERSION

 1.1

=head1 ABSTRACT

This document specifies doing transactions/undo over Riap.

=head1 FAQ

=head1 SEE ALSO

L<Riap>

L<Rinci::function::Transaction>

Transaction behavior is modelled after that of Postgres.

=head1 AUTHOR

Steven Haryanto <stevenharyanto@gmail.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2012 by Steven Haryanto.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut

