This is an automated email from the ASF dual-hosted git repository.
isapego pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new ab8a6b82839 IGNITE-25488 C++ Client: Add transaction timeouts (#6352)
ab8a6b82839 is described below
commit ab8a6b82839e6d1d30329aec38fb32945aa075e9
Author: Ed Rakhmankulov <[email protected]>
AuthorDate: Tue Aug 5 16:25:48 2025 +0300
IGNITE-25488 C++ Client: Add transaction timeouts (#6352)
---
.../client/detail/transaction/transactions_impl.h | 10 ++--
.../client/transaction/transaction_options.h | 63 ++++++++++++++++++++++
.../cpp/ignite/client/transaction/transactions.cpp | 6 ++-
.../cpp/ignite/client/transaction/transactions.h | 21 +++++++-
.../cpp/tests/client-test/transactions_test.cpp | 52 ++++++++++++++++++
5 files changed, 146 insertions(+), 6 deletions(-)
diff --git
a/modules/platforms/cpp/ignite/client/detail/transaction/transactions_impl.h
b/modules/platforms/cpp/ignite/client/detail/transaction/transactions_impl.h
index ea052b51976..a58ac2520a7 100644
--- a/modules/platforms/cpp/ignite/client/detail/transaction/transactions_impl.h
+++ b/modules/platforms/cpp/ignite/client/detail/transaction/transactions_impl.h
@@ -19,6 +19,7 @@
#include "ignite/client/detail/cluster_connection.h"
#include "ignite/client/detail/transaction/transaction_impl.h"
+#include "ignite/client/transaction/transaction_options.h"
#include "ignite/common/detail/config.h"
#include "ignite/common/ignite_result.h"
@@ -53,11 +54,12 @@ public:
* Starts a new transaction asynchronously.
*
* @param callback Callback to be called with a new transaction or error
upon completion of asynchronous operation.
+ * @param tx_opts Transaction options.
*/
- IGNITE_API void begin_async(ignite_callback<transaction> callback) {
- auto writer_func = [this](protocol::writer &writer, auto) {
- writer.write_bool(false); // readOnly.
- writer.write(std::int64_t(0)); // timeoutMillis.
+ IGNITE_API void begin_async(transaction_options tx_opts,
ignite_callback<transaction> callback) {
+ auto writer_func = [this, &tx_opts](protocol::writer &writer, auto) {
+ writer.write_bool(tx_opts.is_read_only());
+ writer.write(tx_opts.get_timeout_millis());
writer.write(m_connection->get_observable_timestamp());
};
diff --git
a/modules/platforms/cpp/ignite/client/transaction/transaction_options.h
b/modules/platforms/cpp/ignite/client/transaction/transaction_options.h
new file mode 100644
index 00000000000..436576beb3e
--- /dev/null
+++ b/modules/platforms/cpp/ignite/client/transaction/transaction_options.h
@@ -0,0 +1,63 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+/**
+ * Transaction options.
+ */
+class transaction_options {
+public:
+ /**
+ * Transaction timeout.
+ *
+ * @return Transaction timeout in milliseconds.
+ */
+ [[nodiscard]] std::int64_t get_timeout_millis() const { return
m_timeout_millis; }
+
+ /**
+ * Sets new value for transaction timeout.
+ *
+ * @param timeout_millis Transaction timeout in milliseconds.
+ * @return Reference to this for chaining.
+ */
+ transaction_options & set_timeout_millis(std::int64_t timeout_millis) {
+ m_timeout_millis = timeout_millis;
+ return *this;
+ }
+
+ /**
+ * Transaction allow only read operations.
+ *
+ * @return True if only read operation are allowed false otherwise.
+ */
+ [[nodiscard]] bool is_read_only() const { return m_read_only; }
+
+ /**
+ * Change transaction to be read-only or read-write.
+ *
+ * @param read_only True if transaction should read-only, false if
read-write.
+ * @return Reference to this for chaining.
+ */
+ transaction_options & set_read_only(bool read_only) {
+ m_read_only = read_only;
+ return *this;
+ }
+private:
+ std::int64_t m_timeout_millis = 0;
+ bool m_read_only = false;
+};
diff --git a/modules/platforms/cpp/ignite/client/transaction/transactions.cpp
b/modules/platforms/cpp/ignite/client/transaction/transactions.cpp
index 2253eff7c4e..eb71d029a99 100644
--- a/modules/platforms/cpp/ignite/client/transaction/transactions.cpp
+++ b/modules/platforms/cpp/ignite/client/transaction/transactions.cpp
@@ -20,8 +20,12 @@
namespace ignite {
+void transactions::begin_async(transaction_options tx_opts,
ignite_callback<transaction> callback) {
+ m_impl->begin_async(tx_opts, std::move(callback));
+}
+
void transactions::begin_async(ignite_callback<transaction> callback) {
- m_impl->begin_async(std::move(callback));
+ m_impl->begin_async({}, std::move(callback));
}
} // namespace ignite
diff --git a/modules/platforms/cpp/ignite/client/transaction/transactions.h
b/modules/platforms/cpp/ignite/client/transaction/transactions.h
index 4ff5993f727..e418ea1cc84 100644
--- a/modules/platforms/cpp/ignite/client/transaction/transactions.h
+++ b/modules/platforms/cpp/ignite/client/transaction/transactions.h
@@ -18,6 +18,7 @@
#pragma once
#include "ignite/client/transaction/transaction.h"
+#include "ignite/client/transaction/transaction_options.h"
#include "ignite/common/detail/config.h"
#include "ignite/common/ignite_result.h"
@@ -40,15 +41,33 @@ public:
// Delete
transactions() = delete;
+ /**
+ * Starts a new transaction.
+ *
+ * @param tx_opts Transaction options.
+ * @return A new transaction.
+ */
+ IGNITE_API transaction begin(transaction_options tx_opts) {
+ return sync<transaction>([this, &tx_opts](auto callback) {
begin_async(tx_opts, std::move(callback)); });
+ }
+
/**
* Starts a new transaction.
*
* @return A new transaction.
*/
IGNITE_API transaction begin() {
- return sync<transaction>([this](auto callback) {
begin_async(std::move(callback)); });
+ return begin({});
}
+ /**
+ * Starts a new transaction asynchronously.
+ *
+ * @param tx_opts Transaction options.
+ * @param callback Callback to be called with a new transaction or error
upon completion of asynchronous operation.
+ */
+ IGNITE_API void begin_async(transaction_options tx_opts,
ignite_callback<transaction> callback);
+
/**
* Starts a new transaction asynchronously.
*
diff --git a/modules/platforms/cpp/tests/client-test/transactions_test.cpp
b/modules/platforms/cpp/tests/client-test/transactions_test.cpp
index 7c38a716898..c7fe62153bd 100644
--- a/modules/platforms/cpp/tests/client-test/transactions_test.cpp
+++ b/modules/platforms/cpp/tests/client-test/transactions_test.cpp
@@ -434,3 +434,55 @@ TEST_F(transactions_test, record_view_remove_all_exact) {
auto values2 = record_view.remove_all(nullptr, {value0});
ASSERT_TRUE(values2.empty());
}
+
+TEST_F(transactions_test, tx_successful_when_timeout_does_not_exceed) {
+ auto record_view =
m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
+
+ int64_t key = 42;
+ std::string val = "Lorem ipsum";
+
+ auto tx_opts =
transaction_options().set_timeout_millis(10'000L).set_read_only(false);
+ auto tx = m_client.get_transactions().begin(tx_opts);
+
+ record_view.insert(&tx, get_tuple(key, val));
+
+ tx.commit();
+
+ auto value = record_view.get(nullptr, get_tuple(42));
+
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(key, value->get<int64_t>(KEY_COLUMN));
+ EXPECT_EQ(val, value->get<std::string>(VAL_COLUMN));
+}
+
+
+TEST_F(transactions_test, tx_failed_when_timeout_exceeds) {
+ auto record_view =
m_client.get_tables().get_table(TABLE_1)->get_record_binary_view();
+
+ auto timeout_ms = 1'000L;
+
+ int64_t key = 42;
+ std::string val = "Lorem ipsum";
+ auto tx_opts = transaction_options()
+ .set_timeout_millis(timeout_ms)
+ .set_read_only(false);
+
+ auto tx = m_client.get_transactions().begin(tx_opts);
+
+ record_view.insert(&tx, get_tuple(key, val));
+
+ std::this_thread::sleep_for(std::chrono::milliseconds{timeout_ms * 2});
+
+ EXPECT_THROW(
+ {
+ try {
+ // TODO change to check tx.commit when IGNITE-24233 is
implemented
+ // tx.commit();
+ auto rec = record_view.get(&tx, get_tuple(key));
+ } catch (const ignite_error& e) {
+ EXPECT_EQ(e.get_status_code(),
error::code::TX_ALREADY_FINISHED_WITH_TIMEOUT);
+ throw;
+ }
+ },
+ ignite_error);
+}