Hazelcast C++ Client
Hazelcast C++ Client Library
transactions.cpp
1 /*
2  * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <boost/uuid/uuid_io.hpp>
18 
19 #include <hazelcast/client/txn/client_transaction_util.h>
20 #include "hazelcast/client/txn/TransactionProxy.h"
21 #include "hazelcast/client/transaction_options.h"
22 #include "hazelcast/util/Util.h"
23 #include "hazelcast/client/spi/impl/ClientInvocation.h"
24 #include "hazelcast/client/connection/ClientConnectionManagerImpl.h"
25 #include "hazelcast/client/proxy/TransactionalMapImpl.h"
26 #include "hazelcast/client/proxy/TransactionalMultiMapImpl.h"
27 #include "hazelcast/client/proxy/TransactionalListImpl.h"
28 #include "hazelcast/client/proxy/TransactionalQueueImpl.h"
29 #include "hazelcast/client/proxy/TransactionalSetImpl.h"
30 #include "hazelcast/client/imap.h"
31 #include "hazelcast/client/multi_map.h"
32 #include "hazelcast/client/ilist.h"
33 #include "hazelcast/client/iqueue.h"
34 #include "hazelcast/client/iset.h"
35 #include "hazelcast/client/transaction_context.h"
36 #include "hazelcast/client/spi/impl/ClientTransactionManagerServiceImpl.h"
37 #include "hazelcast/client/protocol/codec/codecs.h"
38 
39 namespace hazelcast {
40 namespace client {
41 namespace txn {
42 TransactionProxy::TransactionProxy(
43  transaction_options& txn_options,
44  spi::ClientContext& client_context,
45  std::shared_ptr<connection::Connection> connection)
46  : options_(txn_options)
47  , client_context_(client_context)
48  , connection_(connection)
49  , thread_id_(util::get_current_thread_id())
50  , state_(TxnState::NO_TXN)
51 {}
52 
53 TransactionProxy::TransactionProxy(const TransactionProxy& rhs)
54  : options_(rhs.options_)
55  , client_context_(rhs.client_context_)
56  , connection_(rhs.connection_)
57  , thread_id_(rhs.thread_id_)
58  , txn_id_(rhs.txn_id_)
59  , state_(rhs.state_)
60  , start_time_(rhs.start_time_)
61 {
62  transaction_exists_.store(rhs.transaction_exists_.load());
63 }
64 
65 boost::uuids::uuid
66 TransactionProxy::get_txn_id() const
67 {
68  return txn_id_;
69 }
70 
71 TxnState
72 TransactionProxy::get_state() const
73 {
74  return state_;
75 }
76 
77 std::chrono::milliseconds
78 TransactionProxy::get_timeout() const
79 {
80  return options_.get_timeout();
81 }
82 
83 boost::future<void>
84 TransactionProxy::begin()
85 {
86  try {
87  if (state_ == TxnState::ACTIVE) {
88  BOOST_THROW_EXCEPTION(exception::illegal_state(
89  "TransactionProxy::begin()", "Transaction is already active"));
90  }
91  check_thread();
92  if (transaction_exists_) {
93  BOOST_THROW_EXCEPTION(
94  exception::illegal_state("TransactionProxy::begin()",
95  "Nested transactions are not allowed!"));
96  }
97  transaction_exists_.store(true);
98  start_time_ = std::chrono::steady_clock::now();
99  auto request = protocol::codec::transaction_create_encode(
100  std::chrono::duration_cast<std::chrono::milliseconds>(get_timeout())
101  .count(),
102  options_.get_durability(),
103  static_cast<int32_t>(options_.get_transaction_type()),
104  thread_id_);
105  return invoke(request).then(
106  boost::launch::sync, [=](boost::future<protocol::ClientMessage> f) {
107  try {
108  auto msg = f.get();
109  // skip header
110  msg.rd_ptr(msg.RESPONSE_HEADER_LEN);
111  this->txn_id_ = msg.get<boost::uuids::uuid>();
112  this->state_ = TxnState::ACTIVE;
113  } catch (exception::iexception&) {
114  transaction_exists_.store(false);
115  throw;
116  }
117  });
118  } catch (exception::iexception&) {
119  transaction_exists_.store(false);
120  throw;
121  }
122 }
123 
124 boost::future<void>
125 TransactionProxy::commit()
126 {
127  try {
128  if (state_ != TxnState::ACTIVE) {
129  BOOST_THROW_EXCEPTION(exception::illegal_state(
130  "TransactionProxy::commit()", "Transaction is not active"));
131  }
132  state_ = TxnState::COMMITTING;
133  check_thread();
134  check_timeout();
135 
136  auto request =
137  protocol::codec::transaction_commit_encode(txn_id_, thread_id_);
138  return invoke(request).then(
139  boost::launch::sync, [=](boost::future<protocol::ClientMessage> f) {
140  try {
141  f.get();
142  state_ = TxnState::COMMITTED;
143  } catch (exception::iexception&) {
144  transaction_exists_.store(false);
145  client_transaction_util::transaction_exception_factory()
146  ->rethrow(std::current_exception(),
147  "TransactionProxy::commit() failed");
148  }
149  });
150  } catch (...) {
151  state_ = TxnState::COMMIT_FAILED;
152  transaction_exists_.store(false);
153  client_transaction_util::transaction_exception_factory()->rethrow(
154  std::current_exception(), "TransactionProxy::commit() failed");
155  return boost::make_ready_future();
156  }
157 }
158 
159 boost::future<void>
160 TransactionProxy::rollback()
161 {
162  try {
163  if (state_ == TxnState::NO_TXN || state_ == TxnState::ROLLED_BACK) {
164  BOOST_THROW_EXCEPTION(exception::illegal_state(
165  "TransactionProxy::rollback()", "Transaction is not active"));
166  }
167  state_ = TxnState::ROLLING_BACK;
168  check_thread();
169  try {
170  auto request =
171  protocol::codec::transaction_rollback_encode(txn_id_, thread_id_);
172  return invoke(request).then(
173  boost::launch::sync,
174  [=](boost::future<protocol::ClientMessage> f) {
175  try {
176  state_ = TxnState::ROLLED_BACK;
177  transaction_exists_.store(false);
178  f.get();
179  } catch (exception::iexception& e) {
180  HZ_LOG(
181  client_context_.get_logger(),
182  warning,
183  boost::str(
184  boost::format(
185  "Exception while rolling back the transaction. "
186  "Exception: %1%") %
187  e));
188  }
189  });
190  } catch (exception::iexception& exception) {
191  HZ_LOG(client_context_.get_logger(),
192  warning,
193  boost::str(boost::format(
194  "Exception while rolling back the transaction. "
195  "Exception: %1%") %
196  exception));
197  }
198  state_ = TxnState::ROLLED_BACK;
199  transaction_exists_.store(false);
200  } catch (exception::iexception&) {
201  transaction_exists_.store(false);
202  client_transaction_util::transaction_exception_factory()->rethrow(
203  std::current_exception(), "TransactionProxy::rollback() failed");
204  }
205  return boost::make_ready_future();
206 }
207 
208 serialization::pimpl::SerializationService&
209 TransactionProxy::get_serialization_service()
210 {
211  return client_context_.get_serialization_service();
212 }
213 
214 std::shared_ptr<connection::Connection>
215 TransactionProxy::get_connection()
216 {
217  return connection_;
218 }
219 
220 void
221 TransactionProxy::check_thread()
222 {
223  if (thread_id_ != util::get_current_thread_id()) {
224  BOOST_THROW_EXCEPTION(exception::illegal_state(
225  "TransactionProxy::checkThread()",
226  "Transaction cannot span multiple threads!"));
227  }
228 }
229 
230 void
231 TransactionProxy::check_timeout()
232 {
233  if (start_time_ + options_.get_timeout() <
234  std::chrono::steady_clock::now()) {
235  BOOST_THROW_EXCEPTION(exception::transaction(
236  "TransactionProxy::checkTimeout()", "Transaction is timed-out!"));
237  }
238 }
239 
240 TxnState::TxnState(state value)
241  : value(value)
242 {
243  values.resize(9);
244  values[0] = NO_TXN;
245  values[1] = ACTIVE;
246  values[2] = PREPARING;
247  values[3] = PREPARED;
248  values[4] = COMMITTING;
249  values[5] = COMMITTED;
250  values[6] = COMMIT_FAILED;
251  values[7] = ROLLING_BACK;
252  values[8] = ROLLED_BACK;
253 }
254 
255 TxnState::operator int() const
256 {
257  return value;
258 }
259 
260 void
261 TxnState::operator=(int i)
262 {
263  value = values[i];
264 }
265 
266 boost::future<protocol::ClientMessage>
267 TransactionProxy::invoke(protocol::ClientMessage& request)
268 {
269  return client_transaction_util::invoke(
270  request,
271  boost::uuids::to_string(get_txn_id()),
272  client_context_,
273  connection_);
274 }
275 
276 spi::ClientContext&
277 TransactionProxy::get_client_context() const
278 {
279  return client_context_;
280 }
281 
282 const std::shared_ptr<util::exception_util::runtime_exception_factory>
283  client_transaction_util::exceptionFactory(
284  new class transaction_exception_factory());
285 
286 boost::future<protocol::ClientMessage>
287 client_transaction_util::invoke(
288  protocol::ClientMessage& request,
289  const std::string& object_name,
290  spi::ClientContext& client,
291  const std::shared_ptr<connection::Connection>& connection)
292 {
293  try {
294  std::shared_ptr<spi::impl::ClientInvocation> clientInvocation =
295  spi::impl::ClientInvocation::create(
296  client, request, object_name, connection);
297  return clientInvocation->invoke();
298  } catch (exception::iexception&) {
299  transaction_exception_factory()->rethrow(
300  std::current_exception(), "ClientTransactionUtil::invoke failed");
301  return boost::make_ready_future(protocol::ClientMessage(0));
302  }
303 }
304 
305 const std::shared_ptr<util::exception_util::runtime_exception_factory>&
306 client_transaction_util::transaction_exception_factory()
307 {
308  return exceptionFactory;
309 }
310 
311 void
312 client_transaction_util::transaction_exception_factory::rethrow(
313  std::exception_ptr throwable,
314  const std::string& message)
315 {
316  try {
317  std::rethrow_exception(throwable);
318  } catch (...) {
319  std::throw_with_nested(
320  boost::enable_current_exception(exception::transaction(
321  "transaction_exceptionFactory::create", message)));
322  }
323 }
324 } // namespace txn
325 
326 namespace proxy {
327 TransactionalMapImpl::TransactionalMapImpl(
328  const std::string& name,
329  txn::TransactionProxy& transaction_proxy)
330  : TransactionalObject(imap::SERVICE_NAME, name, transaction_proxy)
331 {}
332 
333 boost::future<bool>
334 TransactionalMapImpl::contains_key_data(const serialization::pimpl::data& key)
335 {
336  auto request = protocol::codec::transactionalmap_containskey_encode(
337  get_name(), get_transaction_id(), util::get_current_thread_id(), key);
338 
339  return invoke_and_get_future<bool>(request);
340 }
341 
342 boost::future<boost::optional<serialization::pimpl::data>>
343 TransactionalMapImpl::get_data(const serialization::pimpl::data& key)
344 {
345  auto request = protocol::codec::transactionalmap_get_encode(
346  get_name(), get_transaction_id(), util::get_current_thread_id(), key);
347 
348  return invoke_and_get_future<boost::optional<serialization::pimpl::data>>(
349  request);
350 }
351 
352 boost::future<int>
353 TransactionalMapImpl::size()
354 {
355  auto request = protocol::codec::transactionalmap_size_encode(
356  get_name(), get_transaction_id(), util::get_current_thread_id());
357 
358  return invoke_and_get_future<int>(request);
359 }
360 
361 boost::future<bool>
362 TransactionalMapImpl::is_empty()
363 {
364  auto request = protocol::codec::transactionalmap_isempty_encode(
365  get_name(), get_transaction_id(), util::get_current_thread_id());
366 
367  return invoke_and_get_future<bool>(request);
368 }
369 
370 boost::future<boost::optional<serialization::pimpl::data>>
371 TransactionalMapImpl::put_data(const serialization::pimpl::data& key,
372  const serialization::pimpl::data& value)
373 {
374 
375  auto request = protocol::codec::transactionalmap_put_encode(
376  get_name(),
377  get_transaction_id(),
378  util::get_current_thread_id(),
379  key,
380  value,
381  std::chrono::duration_cast<std::chrono::milliseconds>(get_timeout())
382  .count());
383 
384  return invoke_and_get_future<boost::optional<serialization::pimpl::data>>(
385  request);
386 }
387 
388 boost::future<void>
389 TransactionalMapImpl::set_data(const serialization::pimpl::data& key,
390  const serialization::pimpl::data& value)
391 {
392  auto request = protocol::codec::transactionalmap_set_encode(
393  get_name(),
394  get_transaction_id(),
395  util::get_current_thread_id(),
396  key,
397  value);
398 
399  return to_void_future(invoke(request));
400 }
401 
402 boost::future<boost::optional<serialization::pimpl::data>>
403 TransactionalMapImpl::put_if_absent_data(
404  const serialization::pimpl::data& key,
405  const serialization::pimpl::data& value)
406 {
407  auto request = protocol::codec::transactionalmap_putifabsent_encode(
408  get_name(),
409  get_transaction_id(),
410  util::get_current_thread_id(),
411  key,
412  value);
413 
414  return invoke_and_get_future<boost::optional<serialization::pimpl::data>>(
415  request);
416 }
417 
418 boost::future<boost::optional<serialization::pimpl::data>>
419 TransactionalMapImpl::replace_data(const serialization::pimpl::data& key,
420  const serialization::pimpl::data& value)
421 {
422  auto request = protocol::codec::transactionalmap_replace_encode(
423  get_name(),
424  get_transaction_id(),
425  util::get_current_thread_id(),
426  key,
427  value);
428 
429  return invoke_and_get_future<boost::optional<serialization::pimpl::data>>(
430  request);
431 }
432 
433 boost::future<bool>
434 TransactionalMapImpl::replace_data(const serialization::pimpl::data& key,
435  const serialization::pimpl::data& old_value,
436  const serialization::pimpl::data& new_value)
437 {
438  auto request = protocol::codec::transactionalmap_replaceifsame_encode(
439  get_name(),
440  get_transaction_id(),
441  util::get_current_thread_id(),
442  key,
443  old_value,
444  new_value);
445 
446  return invoke_and_get_future<bool>(request);
447 }
448 
449 boost::future<boost::optional<serialization::pimpl::data>>
450 TransactionalMapImpl::remove_data(const serialization::pimpl::data& key)
451 {
452  auto request = protocol::codec::transactionalmap_remove_encode(
453  get_name(), get_transaction_id(), util::get_current_thread_id(), key);
454 
455  return invoke_and_get_future<boost::optional<serialization::pimpl::data>>(
456  request);
457 }
458 
459 boost::future<void>
460 TransactionalMapImpl::delete_entry_data(const serialization::pimpl::data& key)
461 {
462  auto request = protocol::codec::transactionalmap_delete_encode(
463  get_name(), get_transaction_id(), util::get_current_thread_id(), key);
464 
465  return to_void_future(invoke(request));
466 }
467 
468 boost::future<bool>
469 TransactionalMapImpl::remove_data(const serialization::pimpl::data& key,
470  const serialization::pimpl::data& value)
471 {
472  auto request = protocol::codec::transactionalmap_removeifsame_encode(
473  get_name(),
474  get_transaction_id(),
475  util::get_current_thread_id(),
476  key,
477  value);
478 
479  return invoke_and_get_future<bool>(request);
480 }
481 
482 boost::future<std::vector<serialization::pimpl::data>>
483 TransactionalMapImpl::key_set_data()
484 {
485  auto request = protocol::codec::transactionalmap_keyset_encode(
486  get_name(), get_transaction_id(), util::get_current_thread_id());
487 
488  return invoke_and_get_future<std::vector<serialization::pimpl::data>>(
489  request);
490 }
491 
492 boost::future<std::vector<serialization::pimpl::data>>
493 TransactionalMapImpl::key_set_data(const serialization::pimpl::data& predicate)
494 {
495  auto request = protocol::codec::transactionalmap_keysetwithpredicate_encode(
496  get_name(),
497  get_transaction_id(),
498  util::get_current_thread_id(),
499  predicate);
500 
501  return invoke_and_get_future<std::vector<serialization::pimpl::data>>(
502  request);
503 }
504 
505 boost::future<std::vector<serialization::pimpl::data>>
506 TransactionalMapImpl::values_data()
507 {
508  auto request = protocol::codec::transactionalmap_values_encode(
509  get_name(), get_transaction_id(), util::get_current_thread_id());
510 
511  return invoke_and_get_future<std::vector<serialization::pimpl::data>>(
512  request);
513 }
514 
515 boost::future<std::vector<serialization::pimpl::data>>
516 TransactionalMapImpl::values_data(const serialization::pimpl::data& predicate)
517 {
518  auto request = protocol::codec::transactionalmap_valueswithpredicate_encode(
519  get_name(),
520  get_transaction_id(),
521  util::get_current_thread_id(),
522  predicate);
523 
524  return invoke_and_get_future<std::vector<serialization::pimpl::data>>(
525  request);
526 }
527 
528 TransactionalMultiMapImpl::TransactionalMultiMapImpl(
529  const std::string& name,
530  txn::TransactionProxy& transaction_proxy)
531  : TransactionalObject(multi_map::SERVICE_NAME, name, transaction_proxy)
532 {}
533 
534 boost::future<bool>
535 TransactionalMultiMapImpl::put_data(const serialization::pimpl::data& key,
536  const serialization::pimpl::data& value)
537 {
538  auto request = protocol::codec::transactionalmultimap_put_encode(
539  get_name(),
540  get_transaction_id(),
541  util::get_current_thread_id(),
542  key,
543  value);
544 
545  return invoke_and_get_future<bool>(request);
546 }
547 
548 boost::future<std::vector<serialization::pimpl::data>>
549 TransactionalMultiMapImpl::get_data(const serialization::pimpl::data& key)
550 {
551  auto request = protocol::codec::transactionalmultimap_get_encode(
552  get_name(), get_transaction_id(), util::get_current_thread_id(), key);
553 
554  return invoke_and_get_future<std::vector<serialization::pimpl::data>>(
555  request);
556 }
557 
558 boost::future<bool>
559 TransactionalMultiMapImpl::remove(const serialization::pimpl::data& key,
560  const serialization::pimpl::data& value)
561 {
562  auto request = protocol::codec::transactionalmultimap_removeentry_encode(
563  get_name(),
564  get_transaction_id(),
565  util::get_current_thread_id(),
566  key,
567  value);
568 
569  return invoke_and_get_future<bool>(request);
570 }
571 
572 boost::future<std::vector<serialization::pimpl::data>>
573 TransactionalMultiMapImpl::remove_data(const serialization::pimpl::data& key)
574 {
575  auto request = protocol::codec::transactionalmultimap_remove_encode(
576  get_name(), get_transaction_id(), util::get_current_thread_id(), key);
577 
578  return invoke_and_get_future<std::vector<serialization::pimpl::data>>(
579  request);
580 }
581 
582 boost::future<int>
583 TransactionalMultiMapImpl::value_count(const serialization::pimpl::data& key)
584 {
585  auto request = protocol::codec::transactionalmultimap_valuecount_encode(
586  get_name(), get_transaction_id(), util::get_current_thread_id(), key);
587 
588  return invoke_and_get_future<int>(request);
589 }
590 
591 boost::future<int>
592 TransactionalMultiMapImpl::size()
593 {
594  auto request = protocol::codec::transactionalmultimap_size_encode(
595  get_name(), get_transaction_id(), util::get_current_thread_id());
596 
597  return invoke_and_get_future<int>(request);
598 }
599 
600 TransactionalListImpl::TransactionalListImpl(const std::string& object_name,
601  txn::TransactionProxy& context)
602  : TransactionalObject(ilist::SERVICE_NAME, object_name, context)
603 {}
604 
605 boost::future<bool>
606 TransactionalListImpl::add(const serialization::pimpl::data& e)
607 {
608  auto request = protocol::codec::transactionallist_add_encode(
609  get_name(), get_transaction_id(), util::get_current_thread_id(), e);
610 
611  return invoke_and_get_future<bool>(request);
612 }
613 
614 boost::future<bool>
615 TransactionalListImpl::remove(const serialization::pimpl::data& e)
616 {
617  auto request = protocol::codec::transactionallist_remove_encode(
618  get_name(), get_transaction_id(), util::get_current_thread_id(), e);
619 
620  return invoke_and_get_future<bool>(request);
621 }
622 
623 boost::future<int>
624 TransactionalListImpl::size()
625 {
626  auto request = protocol::codec::transactionallist_size_encode(
627  get_name(), get_transaction_id(), util::get_current_thread_id());
628 
629  return invoke_and_get_future<int>(request);
630 }
631 
632 TransactionalSetImpl::TransactionalSetImpl(
633  const std::string& name,
634  txn::TransactionProxy& transaction_proxy)
635  : TransactionalObject(iset::SERVICE_NAME, name, transaction_proxy)
636 {}
637 
638 boost::future<bool>
639 TransactionalSetImpl::add_data(const serialization::pimpl::data& e)
640 {
641  auto request = protocol::codec::transactionalset_add_encode(
642  get_name(), get_transaction_id(), util::get_current_thread_id(), e);
643 
644  return invoke_and_get_future<bool>(request);
645 }
646 
647 boost::future<bool>
648 TransactionalSetImpl::remove_data(const serialization::pimpl::data& e)
649 {
650  auto request = protocol::codec::transactionalset_remove_encode(
651  get_name(), get_transaction_id(), util::get_current_thread_id(), e);
652 
653  return invoke_and_get_future<bool>(request);
654 }
655 
656 boost::future<int>
657 TransactionalSetImpl::size()
658 {
659  auto request = protocol::codec::transactionalset_size_encode(
660  get_name(), get_transaction_id(), util::get_current_thread_id());
661 
662  return invoke_and_get_future<int>(request);
663 }
664 
665 TransactionalObject::TransactionalObject(const std::string& service_name,
666  const std::string& object_name,
667  txn::TransactionProxy& context)
668  : proxy::SerializingProxy(context.get_client_context(), object_name)
669  , service_name_(service_name)
670  , name_(object_name)
671  , context_(context)
672 {}
673 
674 TransactionalObject::~TransactionalObject() = default;
675 
676 const std::string&
677 TransactionalObject::get_service_name()
678 {
679  return service_name_;
680 }
681 
682 const std::string&
683 TransactionalObject::get_name()
684 {
685  return name_;
686 }
687 
688 boost::future<void>
689 TransactionalObject::destroy()
690 {
691  on_destroy();
692  auto request =
693  protocol::codec::client_destroyproxy_encode(name_, service_name_);
694  return to_void_future(
695  invoke_on_connection(request, context_.get_connection()));
696 }
697 
698 void
699 TransactionalObject::on_destroy()
700 {}
701 
702 boost::uuids::uuid
703 TransactionalObject::get_transaction_id() const
704 {
705  return context_.get_txn_id();
706 }
707 
708 std::chrono::milliseconds
709 TransactionalObject::get_timeout() const
710 {
711  return context_.get_timeout();
712 }
713 } // namespace proxy
714 
715 transaction_context::transaction_context(
716  spi::impl::ClientTransactionManagerServiceImpl& transaction_manager,
717  const transaction_options& txn_options)
718  : options_(txn_options)
719  , txn_connection_(transaction_manager.connect())
720  , transaction_(options_, transaction_manager.get_client(), txn_connection_)
721 {}
722 
723 boost::uuids::uuid
725 {
726  return transaction_.get_txn_id();
727 }
728 
729 boost::future<void>
731 {
732  return transaction_.begin();
733 }
734 
735 boost::future<void>
737 {
738  return transaction_.commit();
739 }
740 
741 boost::future<void>
743 {
744  return transaction_.rollback();
745 }
746 
748  : timeout_(std::chrono::minutes(2))
749  , durability_(1)
750  , transaction_type_(transaction_type::TWO_PHASE)
751 {}
752 
755 {
756  return transaction_type_;
757 }
758 
761 {
762  transaction_type_ = type;
763  return *this;
764 }
765 
766 std::chrono::milliseconds
768 {
769  return timeout_;
770 }
771 
773 transaction_options::set_timeout(std::chrono::milliseconds duration)
774 {
775  if (duration.count() <= 0) {
776  BOOST_THROW_EXCEPTION(exception::illegal_state(
777  "TransactionOptions::setTimeout", "Timeout must be positive!"));
778  }
779  timeout_ = duration;
780  return *this;
781 }
782 
783 int
785 {
786  return durability_;
787 }
788 
791 {
792  if (num_machines < 0) {
793  BOOST_THROW_EXCEPTION(
794  exception::illegal_state("TransactionOptions::setDurability",
795  "Durability cannot be negative!"));
796  }
797  this->durability_ = num_machines;
798  return *this;
799 }
800 } // namespace client
801 } // namespace hazelcast
802 
803 namespace std {
804 std::size_t
805 hash<std::pair<std::string, std::string>>::operator()(
806  const std::pair<std::string, std::string>& val) const noexcept
807 {
808  return std::hash<std::string>{}(val.first + val.second);
809 }
810 } // namespace std
boost::future< void > begin_transaction()
Begins a transaction.
boost::future< void > commit_transaction()
Commits a transaction.
boost::future< void > rollback_transaction()
Begins a transaction.
boost::uuids::uuid get_txn_id() const
Contains the configuration for a Hazelcast transaction.
transaction_options & set_timeout(std::chrono::milliseconds duration)
The timeout determines the maximum lifespan of a transaction.
transaction_options & set_transaction_type(transaction_type transaction_type)
Sets the TransactionType.
transaction_type get_transaction_type() const
std::chrono::milliseconds get_timeout() const
transaction_options & set_durability(int num_machines)
Sets the transaction durability.
transaction_options()
Creates a new default configured TransactionsOptions.