/mongodb/src/main/java/org/restheart/mongodb/db/sessions/TxnClientSessionFactory.java

https://github.com/SoftInstigate/restheart · Java · 191 lines · 119 code · 28 blank · 44 comment · 7 complexity · e3b5aa5603d90faad58b6613726d65c9 MD5 · raw file

  1. /*-
  2. * ========================LICENSE_START=================================
  3. * restheart-mongodb
  4. * %%
  5. * Copyright (C) 2014 - 2020 SoftInstigate
  6. * %%
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Affero General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. * =========================LICENSE_END==================================
  20. */
  21. package org.restheart.mongodb.db.sessions;
  22. import com.mongodb.ClientSessionOptions;
  23. import com.mongodb.ReadConcern;
  24. import com.mongodb.ReadPreference;
  25. import com.mongodb.TransactionOptions;
  26. import com.mongodb.WriteConcern;
  27. import io.undertow.server.HttpServerExchange;
  28. import java.util.UUID;
  29. import static org.bson.assertions.Assertions.notNull;
  30. import static org.restheart.exchange.ExchangeKeys.CLIENT_SESSION_KEY;
  31. import static org.restheart.exchange.ExchangeKeys.TXNID_KEY;
  32. import static org.restheart.mongodb.db.sessions.Txn.TransactionStatus.IN;
  33. import org.slf4j.Logger;
  34. import org.slf4j.LoggerFactory;
  35. /**
  36. *
  37. * @author Andrea Di Cesare <andrea@softinstigate.com>
  38. */
  39. public class TxnClientSessionFactory extends ClientSessionFactory {
  40. private static final Logger LOGGER = LoggerFactory
  41. .getLogger(TxnClientSessionFactory.class);
  42. public static TxnClientSessionFactory getInstance() {
  43. return TxnClientSessionFactoryHolder.INSTANCE;
  44. }
  45. private static class TxnClientSessionFactoryHolder {
  46. private static final TxnClientSessionFactory INSTANCE
  47. = new TxnClientSessionFactory();
  48. }
  49. private TxnClientSessionFactory() {
  50. }
  51. /**
  52. *
  53. * @param exchange
  54. * @return
  55. * @throws IllegalArgumentException
  56. */
  57. @Override
  58. public ClientSessionImpl getClientSession(HttpServerExchange exchange)
  59. throws IllegalArgumentException {
  60. String _sid = exchange.getQueryParameters()
  61. .get(CLIENT_SESSION_KEY).getFirst();
  62. UUID sid;
  63. try {
  64. sid = UUID.fromString(_sid);
  65. } catch (IllegalArgumentException iae) {
  66. throw new IllegalArgumentException("Invalid session id");
  67. }
  68. if (exchange.getQueryParameters()
  69. .containsKey(TXNID_KEY)) {
  70. String _txnId = exchange.getQueryParameters()
  71. .get(TXNID_KEY).getFirst();
  72. long txnId = -1;
  73. try {
  74. txnId = Long.parseLong(_txnId);
  75. } catch (NumberFormatException nfe) {
  76. throw new IllegalArgumentException("Invalid txn");
  77. }
  78. var cs = getTxnClientSession(sid,
  79. new Txn(txnId, Txn.TransactionStatus.IN));
  80. LOGGER.debug("Request is executed in session {} with {}",
  81. _sid,
  82. cs.getTxnServerStatus());
  83. if (cs.getTxnServerStatus().getStatus() == IN) {
  84. cs.setMessageSentInCurrentTransaction(true);
  85. if (!cs.hasActiveTransaction()) {
  86. cs.startTransaction();
  87. }
  88. }
  89. return cs;
  90. } else {
  91. LOGGER.debug("Request is executed in session {}", _sid);
  92. return super.getClientSession(sid);
  93. }
  94. }
  95. /**
  96. *
  97. * Warn: requires a round trip to the server
  98. *
  99. * @param sid
  100. * @return
  101. */
  102. public TxnClientSessionImpl getTxnClientSession(UUID sid) {
  103. return getTxnClientSession(sid, TxnsUtils.getTxnServerStatus(sid));
  104. }
  105. /**
  106. *
  107. * @param sid
  108. * @param txnServerStatus
  109. * @return
  110. */
  111. public TxnClientSessionImpl getTxnClientSession(UUID sid, Txn txnServerStatus) {
  112. var options = Sid.getSessionOptions(sid);
  113. ClientSessionOptions cso = ClientSessionOptions
  114. .builder()
  115. .causallyConsistent(options.isCausallyConsistent())
  116. .build();
  117. var cs = createClientSession(
  118. sid,
  119. cso,
  120. mClient.getReadConcern(),
  121. mClient.getWriteConcern(),
  122. mClient.getReadPreference(),
  123. null);
  124. if (txnServerStatus != null) {
  125. cs.setTxnServerStatus(txnServerStatus);
  126. cs.setTransactionState(txnServerStatus.getStatus());
  127. cs.setServerSessionTransactionNumber(txnServerStatus.getTxnId());
  128. ((ServerSessionImpl) cs.getServerSession())
  129. .setTransactionNumber(txnServerStatus.getTxnId());
  130. }
  131. return cs;
  132. }
  133. TxnClientSessionImpl createClientSession(
  134. UUID sid,
  135. final ClientSessionOptions options,
  136. final ReadConcern readConcern,
  137. final WriteConcern writeConcern,
  138. final ReadPreference readPreference,
  139. final Txn txnServerStatus) {
  140. notNull("readConcern", readConcern);
  141. notNull("writeConcern", writeConcern);
  142. notNull("readPreference", readPreference);
  143. // TODO allow request to specify session and txn options
  144. ClientSessionOptions mergedOptions = ClientSessionOptions
  145. .builder(options)
  146. .causallyConsistent(true)
  147. .defaultTransactionOptions(
  148. TransactionOptions.merge(
  149. options.getDefaultTransactionOptions(),
  150. TransactionOptions.builder()
  151. .readConcern(readConcern)
  152. .writeConcern(writeConcern)
  153. .readPreference(readPreference)
  154. .build()))
  155. .build();
  156. return new TxnClientSessionImpl(
  157. new SimpleServerSessionPool(SessionsUtils.getCluster(), sid),
  158. mClient,
  159. mergedOptions,
  160. SessionsUtils.getMongoClientDelegate(),
  161. txnServerStatus);
  162. }
  163. }