#ifndef TARANTOOL_BOX_TXN_H_INCLUDED
#define TARANTOOL_BOX_TXN_H_INCLUDED
/*
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * 1. Redistributions of source code must retain the above
 *    copyright notice, this list of conditions and the
 *    following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
#include "index.h"
#include "trigger.h"
#include "session.h"

extern double too_long_threshold;
struct tuple;
struct space;

/**
 * A single statement of a multi-statement
 * transaction: undo and redo info.
 */
struct txn_stmt {
	/** Doubly linked list of all statements. */
	struct rlist next;

	/** Undo info. */
	struct space *space;
	struct tuple *old_tuple;
	struct tuple *new_tuple;

	/** Redo info: the binary log row */
	struct iproto_header *row;
};

struct txn {
	/** Pre-allocated first statement. */
	struct txn_stmt stmt;
	/** List of statements in a transaction. */
	struct rlist stmts;
	 /** Commit and rollback triggers */
	struct rlist on_commit, on_rollback;
	/** Total number of statements in this txn. */
	int n_stmts;
	/**
	 * True if this transaction is running in autocommit mode
	 * (statement end causes an automatic transaction commit).
	 */
	bool autocommit;
	/** Id of the engine involved in multi-statement transaction. */
	uint8_t engine;
	/** Trigger on fiber yield to abort transaction for in-memory engine */
	struct trigger fiber_on_yield;
};

/* Pointer to the current transaction (if any) */
#define in_txn() (session()->txn)

/**
 * Start a new statement. If no current transaction,
 * start a new transaction with autocommit = true.
 */
struct txn *
txn_begin_stmt(struct request *request);

/**
 * End a statement. In autocommit mode, end
 * the current transaction as well.
 */
void
txn_commit_stmt(struct txn *txn, struct port *port);

/**
 * Rollback a statement. In autocommit mode,
 * rolls back the entire transaction.
 */
void
txn_rollback_stmt();

/**
 * Start a transaction explicitly.
 * @pre no transaction is active
 */
struct txn *
txn_begin(bool autocommit);

/**
 * Commit a transaction.
 * @pre txn == in_txn()
 */
void
txn_commit(struct txn *txn);

/** Rollback a transaction, if any. */
void
txn_rollback();

/**
 * Raise an error if this is a multi-statement
 * transaction: DDL can not be part of a multi-statement
 * transaction and must be run in autocommit mode.
 */
void
txn_check_autocommit(struct txn *txn, const char *where);

void
txn_replace(struct txn *txn, struct space *space,
	    struct tuple *old_tuple, struct tuple *new_tuple,
	    enum dup_replace_mode mode);

/** Last statement of the transaction. */
static inline struct txn_stmt *
txn_stmt(struct txn *txn)
{
	return rlist_last_entry(&txn->stmts, struct txn_stmt, next);
}

/**
 * FFI bindings: do not throw exceptions, do not accept extra
 * arguments
 */
extern "C" {

/**
 * @retval 0 - success
 * @retval -1 - failed, perhaps a transaction has already been
 * started
 */
int
boxffi_txn_begin();

/**
 * @retval 0 - success
 * @retval -1 - commit failed
 */
int
boxffi_txn_commit();

void
boxffi_txn_rollback();

} /* extern  "C" */

#endif /* TARANTOOL_BOX_TXN_H_INCLUDED */