123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- /** Definition of the pqxx::robusttransaction class.
- *
- * pqxx::robusttransaction is a slower but safer transaction class.
- *
- * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/robusttransaction instead.
- *
- * Copyright (c) 2000-2019, Jeroen T. Vermeulen.
- *
- * See COPYING for copyright license. If you did not receive a file called
- * COPYING with this source code, please notify the distributor of this mistake,
- * or contact the author.
- */
- #ifndef PQXX_H_ROBUSTTRANSACTION
- #define PQXX_H_ROBUSTTRANSACTION
- #include "pqxx/compiler-public.hxx"
- #include "pqxx/compiler-internal-pre.hxx"
- #include "pqxx/dbtransaction.hxx"
- // Methods tested in eg. test module test01 are marked with "//[t01]".
- namespace pqxx
- {
- namespace internal
- {
- /// Helper base class for the @c robusttransaction class template.
- class PQXX_LIBEXPORT PQXX_NOVTABLE basic_robusttransaction :
- public dbtransaction
- {
- public:
- /// Isolation level is read_committed by default.
- using isolation_tag = isolation_traits<read_committed>;
- virtual ~basic_robusttransaction() =0; //[t16]
- protected:
- basic_robusttransaction(
- connection_base &C,
- const std::string &IsolationLevel,
- const std::string &table_name=std::string{}); //[t16]
- private:
- using IDType = unsigned long;
- IDType m_record_id = 0;
- std::string m_xid;
- std::string m_log_table;
- std::string m_sequence;
- int m_backendpid = -1;
- virtual void do_begin() override; //[t18]
- virtual void do_commit() override; //[t16]
- virtual void do_abort() override; //[t18]
- PQXX_PRIVATE void CreateLogTable();
- PQXX_PRIVATE void CreateTransactionRecord();
- PQXX_PRIVATE std::string sql_delete() const;
- PQXX_PRIVATE void DeleteTransactionRecord() noexcept;
- PQXX_PRIVATE bool CheckTransactionRecord();
- };
- } // namespace internal
- /**
- * @ingroup transaction
- *
- * @{
- */
- /// Slightly slower, better-fortified version of transaction
- /** robusttransaction is similar to transaction, but spends more effort (and
- * performance!) to deal with the hopefully rare case that the connection to
- * the backend is lost just as the current transaction is being committed. In
- * this case, there is no way to determine whether the backend managed to
- * commit the transaction before noticing the loss of connection.
- *
- * In such cases, this class tries to reconnect to the database and figure out
- * what happened. It will need to store and manage some information (pretty
- * much a user-level transaction log) in the back-end for each and every
- * transaction just on the off chance that this problem might occur.
- * This service level was made optional since you may not want to pay this
- * overhead where it is not necessary. Certainly the use of this class makes
- * no sense for local connections, or for transactions that read the database
- * but never modify it, or for noncritical database manipulations.
- *
- * Besides being slower, it's theoretically possible that robusttransaction
- * actually fails more instead of less often than a normal transaction. This is
- * due to the added work and complexity. What robusttransaction tries to
- * achieve is to be more deterministic, not more successful per se.
- *
- * When a user first uses a robusttransaction in a database, the class will
- * attempt to create a log table there to keep vital transaction-related state
- * information in. This table, located in that same database, will be called
- * pqxxlog_*user*, where *user* is the PostgreSQL username for that user. If
- * the log table can not be created, the transaction fails immediately.
- *
- * If the user does not have permission to create the log table, the database
- * administrator may create one for him beforehand, and give ownership (or at
- * least full insert/update rights) to the user. The table must contain two
- * non-unique fields (which will never be null): "name" (of text type,
- * @c varchar(256) by default) and "date" (of @c timestamp type). Older
- * versions of robusttransaction also added a unique "id" field; this field is
- * now obsolete and the log table's implicit oids are used instead. The log
- * tables' names may be made configurable in a future version of libpqxx.
- *
- * The transaction log table contains records describing unfinished
- * transactions, i.e. ones that have been started but not, as far as the client
- * knows, committed or aborted. This can mean any of the following:
- *
- * <ol>
- * <li> The transaction is in progress. Since backend transactions can't run
- * for extended periods of time, this can only be the case if the log record's
- * timestamp (compared to the server's clock) is not very old, provided of
- * course that the server's system clock hasn't just made a radical jump.
- * <li> The client's connection to the server was lost, just when the client was
- * committing the transaction, and the client so far has not been able to
- * re-establish the connection to verify whether the transaction was actually
- * completed or rolled back by the server. This is a serious (and luckily a
- * rare) condition and requires manual inspection of the database to determine
- * what happened. The robusttransaction will emit clear and specific warnings
- * to this effect, and will identify the log record describing the transaction
- * in question.
- * <li> The transaction was completed (either by commit or by rollback), but the
- * client's connection was durably lost just as it tried to clean up the log
- * record. Again, robusttransaction will emit a clear and specific warning to
- * tell you about this and request that the record be deleted as soon as
- * possible.
- * <li> The client has gone offline at any time while in one of the preceding
- * states. This also requires manual intervention, but the client obviously is
- * not able to issue a warning.
- * </ol>
- *
- * It is safe to drop a log table when it is not in use (ie., it is empty or all
- * records in it represent states 2-4 above). Each robusttransaction will
- * attempt to recreate the table at its next time of use.
- */
- template<isolation_level ISOLATIONLEVEL=read_committed>
- class robusttransaction : public internal::basic_robusttransaction
- {
- public:
- using isolation_tag = isolation_traits<ISOLATIONLEVEL>;
- /// Constructor
- /** Creates robusttransaction of given name
- * @param C Connection that this robusttransaction should live inside.
- * @param Name optional human-readable name for this transaction
- */
- explicit robusttransaction(
- connection_base &C,
- const std::string &Name=std::string{}) :
- namedclass{fullname("robusttransaction",isolation_tag::name()), Name},
- internal::basic_robusttransaction(C, isolation_tag::name())
- { Begin(); }
- virtual ~robusttransaction() noexcept
- { End(); }
- };
- /**
- * @}
- */
- } // namespace pqxx
- #include "pqxx/compiler-internal-post.hxx"
- #endif
|