robusttransaction.hxx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /** Definition of the pqxx::robusttransaction class.
  2. *
  3. * pqxx::robusttransaction is a slower but safer transaction class.
  4. *
  5. * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/robusttransaction instead.
  6. *
  7. * Copyright (c) 2000-2019, Jeroen T. Vermeulen.
  8. *
  9. * See COPYING for copyright license. If you did not receive a file called
  10. * COPYING with this source code, please notify the distributor of this mistake,
  11. * or contact the author.
  12. */
  13. #ifndef PQXX_H_ROBUSTTRANSACTION
  14. #define PQXX_H_ROBUSTTRANSACTION
  15. #include "pqxx/compiler-public.hxx"
  16. #include "pqxx/compiler-internal-pre.hxx"
  17. #include "pqxx/dbtransaction.hxx"
  18. // Methods tested in eg. test module test01 are marked with "//[t01]".
  19. namespace pqxx
  20. {
  21. namespace internal
  22. {
  23. /// Helper base class for the @c robusttransaction class template.
  24. class PQXX_LIBEXPORT PQXX_NOVTABLE basic_robusttransaction :
  25. public dbtransaction
  26. {
  27. public:
  28. /// Isolation level is read_committed by default.
  29. using isolation_tag = isolation_traits<read_committed>;
  30. virtual ~basic_robusttransaction() =0; //[t16]
  31. protected:
  32. basic_robusttransaction(
  33. connection_base &C,
  34. const std::string &IsolationLevel,
  35. const std::string &table_name=std::string{}); //[t16]
  36. private:
  37. using IDType = unsigned long;
  38. IDType m_record_id = 0;
  39. std::string m_xid;
  40. std::string m_log_table;
  41. std::string m_sequence;
  42. int m_backendpid = -1;
  43. virtual void do_begin() override; //[t18]
  44. virtual void do_commit() override; //[t16]
  45. virtual void do_abort() override; //[t18]
  46. PQXX_PRIVATE void CreateLogTable();
  47. PQXX_PRIVATE void CreateTransactionRecord();
  48. PQXX_PRIVATE std::string sql_delete() const;
  49. PQXX_PRIVATE void DeleteTransactionRecord() noexcept;
  50. PQXX_PRIVATE bool CheckTransactionRecord();
  51. };
  52. } // namespace internal
  53. /**
  54. * @ingroup transaction
  55. *
  56. * @{
  57. */
  58. /// Slightly slower, better-fortified version of transaction
  59. /** robusttransaction is similar to transaction, but spends more effort (and
  60. * performance!) to deal with the hopefully rare case that the connection to
  61. * the backend is lost just as the current transaction is being committed. In
  62. * this case, there is no way to determine whether the backend managed to
  63. * commit the transaction before noticing the loss of connection.
  64. *
  65. * In such cases, this class tries to reconnect to the database and figure out
  66. * what happened. It will need to store and manage some information (pretty
  67. * much a user-level transaction log) in the back-end for each and every
  68. * transaction just on the off chance that this problem might occur.
  69. * This service level was made optional since you may not want to pay this
  70. * overhead where it is not necessary. Certainly the use of this class makes
  71. * no sense for local connections, or for transactions that read the database
  72. * but never modify it, or for noncritical database manipulations.
  73. *
  74. * Besides being slower, it's theoretically possible that robusttransaction
  75. * actually fails more instead of less often than a normal transaction. This is
  76. * due to the added work and complexity. What robusttransaction tries to
  77. * achieve is to be more deterministic, not more successful per se.
  78. *
  79. * When a user first uses a robusttransaction in a database, the class will
  80. * attempt to create a log table there to keep vital transaction-related state
  81. * information in. This table, located in that same database, will be called
  82. * pqxxlog_*user*, where *user* is the PostgreSQL username for that user. If
  83. * the log table can not be created, the transaction fails immediately.
  84. *
  85. * If the user does not have permission to create the log table, the database
  86. * administrator may create one for him beforehand, and give ownership (or at
  87. * least full insert/update rights) to the user. The table must contain two
  88. * non-unique fields (which will never be null): "name" (of text type,
  89. * @c varchar(256) by default) and "date" (of @c timestamp type). Older
  90. * versions of robusttransaction also added a unique "id" field; this field is
  91. * now obsolete and the log table's implicit oids are used instead. The log
  92. * tables' names may be made configurable in a future version of libpqxx.
  93. *
  94. * The transaction log table contains records describing unfinished
  95. * transactions, i.e. ones that have been started but not, as far as the client
  96. * knows, committed or aborted. This can mean any of the following:
  97. *
  98. * <ol>
  99. * <li> The transaction is in progress. Since backend transactions can't run
  100. * for extended periods of time, this can only be the case if the log record's
  101. * timestamp (compared to the server's clock) is not very old, provided of
  102. * course that the server's system clock hasn't just made a radical jump.
  103. * <li> The client's connection to the server was lost, just when the client was
  104. * committing the transaction, and the client so far has not been able to
  105. * re-establish the connection to verify whether the transaction was actually
  106. * completed or rolled back by the server. This is a serious (and luckily a
  107. * rare) condition and requires manual inspection of the database to determine
  108. * what happened. The robusttransaction will emit clear and specific warnings
  109. * to this effect, and will identify the log record describing the transaction
  110. * in question.
  111. * <li> The transaction was completed (either by commit or by rollback), but the
  112. * client's connection was durably lost just as it tried to clean up the log
  113. * record. Again, robusttransaction will emit a clear and specific warning to
  114. * tell you about this and request that the record be deleted as soon as
  115. * possible.
  116. * <li> The client has gone offline at any time while in one of the preceding
  117. * states. This also requires manual intervention, but the client obviously is
  118. * not able to issue a warning.
  119. * </ol>
  120. *
  121. * It is safe to drop a log table when it is not in use (ie., it is empty or all
  122. * records in it represent states 2-4 above). Each robusttransaction will
  123. * attempt to recreate the table at its next time of use.
  124. */
  125. template<isolation_level ISOLATIONLEVEL=read_committed>
  126. class robusttransaction : public internal::basic_robusttransaction
  127. {
  128. public:
  129. using isolation_tag = isolation_traits<ISOLATIONLEVEL>;
  130. /// Constructor
  131. /** Creates robusttransaction of given name
  132. * @param C Connection that this robusttransaction should live inside.
  133. * @param Name optional human-readable name for this transaction
  134. */
  135. explicit robusttransaction(
  136. connection_base &C,
  137. const std::string &Name=std::string{}) :
  138. namedclass{fullname("robusttransaction",isolation_tag::name()), Name},
  139. internal::basic_robusttransaction(C, isolation_tag::name())
  140. { Begin(); }
  141. virtual ~robusttransaction() noexcept
  142. { End(); }
  143. };
  144. /**
  145. * @}
  146. */
  147. } // namespace pqxx
  148. #include "pqxx/compiler-internal-post.hxx"
  149. #endif