Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
0d0bc20
Support max_inflight_actions in CMS (#42068)
stanislav-shchetinin Jun 30, 2026
6891079
Compact fulltext indexes - index build support (#42791)
vitalif Jun 30, 2026
1c6ff38
Improve database status message and fix pools add command (#42097)
mregrock Jun 30, 2026
33e22ec
fix cert update in tvm cred provider (#43095)
Shfdis Jun 30, 2026
41d6a90
E2e for iam (#43098)
Shfdis Jun 30, 2026
b66ec7b
Unary handle retries (#41715)
Shfdis Jun 30, 2026
11114a3
Fix flaky tests (#43823)
Shfdis Jun 30, 2026
cbf8568
LOGBROKER-10406 Add sdk + api + viewer support (#43044)
kuzin57 Jun 30, 2026
8c45444
LOGBROKER-10354 Added option to specify last offset to read from part…
shokhor Jun 30, 2026
d3395ad
LBREQUESTS-5513 Fix cpu bound SendImpl() (#43959)
kuzin57 Jun 30, 2026
3b8b3d2
decommit protocol, console part (#41839)
vporyadke Jun 30, 2026
4dab7ea
Added MLP consumer support to PQv1 SDK (#44015)
nshestakov Jun 30, 2026
6745a8c
Long-running operation for ANALYZE (#41825)
azevaykin Jun 30, 2026
025a5ac
Cpp iterator support (#40601)
Shfdis Jun 30, 2026
47a5d8d
Topic deferred publish API (#44524)
Alek5andr-Kotov Jun 30, 2026
cfe4130
LOGBROKER-10406 Add checks on sdk & fixed issue (#44534)
kuzin57 Jun 30, 2026
50a4c61
Node shutdown hint (#43236)
Shfdis Jun 30, 2026
c428f29
Set not null: GetRequest in SchemeShard (#44020)
flown4qqqq Jun 30, 2026
587f3d4
LOGBROKER-10406 Fix mirrorer & sdk (#44560)
kuzin57 Jun 30, 2026
89d4efe
add api to interact with query stats (#44507)
Shfdis Jun 30, 2026
b3cfc9c
iam generic provider: fix exception handling (#44719)
yumkam Jun 30, 2026
8f6d3fc
YQ-5434 Fx deadlock on RunFederationDiscoveryImpl() (#44796)
kardymonds Jun 30, 2026
e2205fa
LOGBROKER-10406 Move kafka lib to sdk (#44887)
kuzin57 Jun 30, 2026
6b8411e
Basic Strict Serializable support (#43962)
nikvas0 Jun 30, 2026
819bd77
fix dep leak (#44988)
Shfdis Jun 30, 2026
53deb86
Update import generation: 43
github-actions[bot] Jun 30, 2026
097d827
fix cmake
Jun 30, 2026
8b3783f
fix kafka cmake
Jun 30, 2026
e0439be
finalize sdk fixes
Jun 30, 2026
1b798b4
New version entry in changelog
Jun 30, 2026
be99f28
fix integration tests in ci
Jun 30, 2026
d137e16
Update CHANGELOG.md
Shfdis Jun 30, 2026
5efafc3
fix ydb local setup
Jun 30, 2026
ad57abb
Merge branch 'import-pr-43' of github.com:ydb-platform/ydb-cpp-sdk in…
Jun 30, 2026
41492f0
Fix IAM integration tests via dual YDB services in CI.
Jun 30, 2026
160b04c
strengthen coverage suite
Jul 1, 2026
8b1a60d
deadlock fix
Jul 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 0 additions & 47 deletions .dockerignore

This file was deleted.

2 changes: 1 addition & 1 deletion .github/import_generation.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
43
44
2 changes: 1 addition & 1 deletion .github/last_commit.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
b3b57fcb5915100b21bf9a507bf0a8c0627b7fee
fb25fb6453264260a02c6ec49492382fcaf801ce
47 changes: 47 additions & 0 deletions .github/scripts/run_iam_integration_tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env bash

set -euo pipefail

IAM_REGEX='^(DriverAuth|TMetadataFixture|TJwtIamFixture|TOAuthIamFixture|OAuth_WithFacility)\.'
IAM_CONTAINER_NAME="${IAM_CONTAINER_NAME:-ydb-iam}"
IAM_CTEST_JOBS="${IAM_CTEST_JOBS:-2}"
IAM_READY_ATTEMPTS="${IAM_READY_ATTEMPTS:-60}"
IAM_READY_SLEEP_SECONDS="${IAM_READY_SLEEP_SECONDS:-2}"
IAM_TOKEN="${IAM_TOKEN:-root@builtin}"

cleanup_iam() {
docker rm -f "${IAM_CONTAINER_NAME}" >/dev/null 2>&1 || true
}

wait_for_iam_ydb() {
for _ in $(seq 1 "${IAM_READY_ATTEMPTS}"); do
if docker exec -e "YDB_TOKEN=${IAM_TOKEN}" "${IAM_CONTAINER_NAME}" /ydb \
--endpoint grpc://localhost:2136 \
--database /local \
sql -s 'select 1' >/dev/null 2>&1; then
return 0
fi
sleep "${IAM_READY_SLEEP_SECONDS}"
done

echo "ydb-iam failed to become ready"
docker logs "${IAM_CONTAINER_NAME}" 2>&1 | tail -50 || true
return 1
}

trap cleanup_iam EXIT
cleanup_iam

docker run -d --name "${IAM_CONTAINER_NAME}" --hostname localhost \
-p 2235:2135 -p 2236:2136 -p 28765:8765 \
-v /tmp/ydb_iam_certs:/ydb_certs \
-e YDB_USE_IN_MEMORY_PDISKS=true \
-e YDB_TABLE_ENABLE_PREPARED_DDL=true \
-e YDB_ENFORCE_USER_TOKEN_REQUIREMENT=true \
-e YDB_DEFAULT_CLUSTERADMIN=root@builtin \
ghcr.io/ydb-platform/local-ydb:trunk

wait_for_iam_ydb

YDB_ENDPOINT=localhost:2236 YDB_DATABASE=/local \
ctest -j"${IAM_CTEST_JOBS}" --test-dir build -R "${IAM_REGEX}" --output-on-failure
10 changes: 9 additions & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,15 @@ jobs:
- name: Test
shell: bash
run: |
ctest -j1 --preset coverage-all --output-on-failure
set -euo pipefail

IAM_REGEX='^(DriverAuth|TMetadataFixture|TJwtIamFixture|TOAuthIamFixture|OAuth_WithFacility)\.'
FLAKY_REGEX='(ManyMessages|DiscoveryHang|DescribeHang)'
EXCLUDE_REGEX="${IAM_REGEX}|${FLAKY_REGEX}"

ctest -j1 --preset coverage-all -E "${EXCLUDE_REGEX}" --output-on-failure

IAM_CTEST_JOBS=1 ./.github/scripts/run_iam_integration_tests.sh

- name: Generate coverage report
uses: ./.github/actions/gcovr
Expand Down
13 changes: 11 additions & 2 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,16 @@ jobs:
- name: Test
shell: bash
run: |
YDB_VERSION=${{ matrix.ydb-version }} ctest -j2 --preset integration
IAM_REGEX='^(DriverAuth|TMetadataFixture|TJwtIamFixture|TOAuthIamFixture|OAuth_WithFacility)\.'

YDB_VERSION=${{ matrix.ydb-version }} ctest -j2 --preset integration \
-E "${IAM_REGEX}" --output-on-failure

case '${{ matrix.ydb-version }}' in
25.1|trunk)
./.github/scripts/run_iam_integration_tests.sh
;;
esac

test-install:
name: "Test CMake Install"
Expand Down Expand Up @@ -267,4 +276,4 @@ jobs:
- name: Smoke-test generated .deb packages
shell: bash
run: |
./scripts/test_deb_packages.sh build-deb
./scripts/test_deb_packages.sh build-deb
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## v3.20.0

* Added automatic retries for unary methods of table and query clients(ExecuteQuery, ExecuteScript, BulkUpsert, ReadRows).

* Implemented native ranges(TRowRange) and iterators over both streaming query results and TResultSet.

## v3.19.0

* Added metric buffer for batched metric writes to reduce OpenTelemetry hot-path overhead.
Expand Down
3 changes: 3 additions & 0 deletions Testing/Temporary/LastTest.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Start testing: Jul 01 00:28 MSK
----------------------------------------------------------
End testing: Jul 01 00:28 MSK
66 changes: 21 additions & 45 deletions examples/basic_example/basic_example.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#include "basic_example.h"

#include <ydb-cpp-sdk/client/retry/retry.h>

#include <ydb-cpp-sdk/client/result/rows.h>
#include <util/string/cast.h>

#include <format>

using namespace NYdb;
using namespace NYdb::NQuery;
using namespace NYdb::NStatusHelpers;
using NYdb::NRetry::TRetryOperationSettings;

template <class T>
std::string OptionalToString(const std::optional<T>& opt) {
Expand Down Expand Up @@ -338,14 +338,18 @@ void MultiStep(TQueryClient client) {
return result2;
})); // The end of the retried lambda

TResultSetParser parser(*resultSet);
std::cout << "> MultiStep:" << std::endl;
while (parser.TryNextRow()) {
auto airDate = TInstant::Days(*parser.ColumnParser("air_date").GetOptionalUint64());

std::cout << "Episode " << OptionalToString(parser.ColumnParser("episode_id").GetOptionalUint64())
<< ", Season: " << OptionalToString(parser.ColumnParser("season_id").GetOptionalUint64())
<< ", Title: " << OptionalToString(parser.ColumnParser("title").GetOptionalUtf8())
TRowRange range(std::move(*resultSet));
for (auto [episodeId, seasonId, title, airDateDays] : range.Get<
std::optional<uint64_t>,
std::optional<uint64_t>,
std::optional<std::string>,
std::optional<uint64_t>>({"episode_id", "season_id", "title", "air_date"})) {
auto airDate = TInstant::Days(*airDateDays);

std::cout << "Episode " << OptionalToString(episodeId)
<< ", Season: " << OptionalToString(seasonId)
<< ", Title: " << OptionalToString(title)
<< ", Air date: " << airDate.FormatLocalTime("%a %b %d, %Y")
<< std::endl;
}
Expand Down Expand Up @@ -395,7 +399,7 @@ void ExplicitTcl(TQueryClient client) {
void StreamQuerySelect(TQueryClient client) {
std::cout << "> StreamQuery:" << std::endl;

ThrowOnError(client.RetryQuerySync([](TQueryClient client) -> TStatus {
ThrowOnError(client.RetryQuerySync([](TSession session) -> TStatus {
auto query = R"(
DECLARE $series AS List<UInt64>;

Expand All @@ -419,44 +423,16 @@ void StreamQuerySelect(TQueryClient client) {
.Build()
.Build();

// Executes stream query
auto resultStreamQuery = client.StreamExecuteQuery(query, TTxControl::NoTx(), parameters).GetValueSync();

if (!resultStreamQuery.IsSuccess()) {
return resultStreamQuery;
}

// Iterates over results
bool eos = false;

while (!eos) {
auto streamPart = resultStreamQuery.ReadNext().ExtractValueSync();

if (!streamPart.IsSuccess()) {
eos = true;
if (!streamPart.EOS()) {
return streamPart;
}
continue;
}

// It is possible to duplicate lines in the output stream due to an external retryer.
if (streamPart.HasResultSet()) {
auto rs = streamPart.ExtractResultSet();
TResultSetParser parser(rs);
while (parser.TryNextRow()) {
std::cout << "Season"
<< ", SeriesId: " << OptionalToString(parser.ColumnParser("series_id").GetOptionalUint64())
<< ", SeasonId: " << OptionalToString(parser.ColumnParser("season_id").GetOptionalUint64())
<< ", Title: " << OptionalToString(parser.ColumnParser("title").GetOptionalUtf8())
<< ", Air date: " << parser.ColumnParser("first_aired").GetOptionalDate()->FormatLocalTime("%Y-%m-%d")
<< std::endl;
}
}
for (auto& parser : TRowRange(
session.StreamExecuteQuery(query, TTxControl::NoTx(), parameters).ExtractValueSync())) {
std::cout << "Season" << ", SeriesId: " << OptionalToString(parser.ColumnParser("series_id").GetOptionalUint64())
<< ", SeasonId: " << OptionalToString(parser.ColumnParser("season_id").GetOptionalUint64())
<< ", Title: " << OptionalToString(parser.ColumnParser("title").GetOptionalUtf8())
<< ", Air date: " << parser.ColumnParser("first_aired").GetOptionalDate()->FormatLocalTime("%Y-%m-%d")
<< std::endl;
}
return TStatus(EStatus::SUCCESS, NYdb::NIssue::TIssues());
}));

}


Expand Down
58 changes: 41 additions & 17 deletions include/ydb-cpp-sdk/client/iam/common/generic_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@ class TGrpcIamCredentialsProvider : public ICredentialsProvider {
}
};
auto facility = weakFacility.lock();
auto self = weakSelf.lock();

try {
if (facility) {
Expand All @@ -178,7 +177,7 @@ class TGrpcIamCredentialsProvider : public ICredentialsProvider {
} catch (...) {
}

if (self) {
if (auto self = weakSelf.lock()) {
std::lock_guard guard(self->Lock_);
self->ResetContextImpl();
}
Expand All @@ -189,9 +188,13 @@ class TGrpcIamCredentialsProvider : public ICredentialsProvider {
try {
RequestFiller_(req);
} catch (...) {
const auto now = SysClock::now();
std::lock_guard guard(Lock_);
LastRequestError_ = TStringBuilder() << "Request failed: " << CurrentExceptionMessage();
LastRequestError_ = TStringBuilder()
<< "Last request error was at " << FormatSysTimeUtcIsoMicros(now)
<< ". Failed to prepare IAM request: " << CurrentExceptionMessage();
ResetContextImpl();
RescheduleOnFailure();
return;
}

Expand Down Expand Up @@ -247,11 +250,23 @@ class TGrpcIamCredentialsProvider : public ICredentialsProvider {
if (Context_.has_value() || SysClock::now() < NextTicketUpdate_) {
return true;
}
FillContext(guard);
try {
FillContext(guard);
} catch (...) {
const auto now = SysClock::now();
LastRequestError_ = TStringBuilder()
<< "Last request error was at " << FormatSysTimeUtcIsoMicros(now)
<< ". Failed to prepare IAM request context: " << CurrentExceptionMessage();
ResetContextImpl();
}
if (NeedStop_) {
ResetContextImpl();
return false;
}
if (!Context_.has_value()) {
RescheduleOnFailure();
return true;
}
}
UpdateTicket();
return true;
Expand All @@ -267,31 +282,40 @@ class TGrpcIamCredentialsProvider : public ICredentialsProvider {
<< " Message: \"" << status.error_message()
<< "\" iam-endpoint: \"" << IamEndpoint_.Endpoint << "\"";

const auto now = SysClock::now();
const auto retryDelay = std::min(BackoffTimeout_, BACKOFF_MAX);
NextTicketUpdate_ = SafeAddSystemTime(now, ToBoundedSysDuration(retryDelay));
BackoffTimeout_ = std::min(BackoffTimeout_ * 2, BACKOFF_MAX);
RescheduleOnFailure();
} else {
LastRequestError_ = "";
Ticket_ = result.iam_token();
BackoffTimeout_ = BACKOFF_START;

const auto now = SysClock::now();
const SysTimePoint refreshAt = SafeAddSystemTime(now, ToBoundedSysDuration(IamEndpoint_.RefreshPeriod));
const SysTimePoint expiresAt = SysClock::from_time_t(result.expires_at().seconds());
const SysDuration requestMargin = ToBoundedSysDuration(IamEndpoint_.RequestTimeout);

SysTimePoint nextUpdate = std::min(refreshAt, expiresAt);
nextUpdate = SafeAddSystemTime(nextUpdate, -requestMargin);
nextUpdate = std::max(nextUpdate, SafeAddSystemTime(now, ToBoundedSysDuration(MINIMUM_REFRESH_INTERVAL)));
NextTicketUpdate_ = nextUpdate;
RescheduleOnSuccess(expiresAt);

TokenReady_.notify_all();
}

ResetContextImpl();
}

void RescheduleOnFailure() { // call with Lock_
const auto now = SysClock::now();
const auto retryDelay = std::min(BackoffTimeout_, BACKOFF_MAX);
NextTicketUpdate_ = SafeAddSystemTime(now, ToBoundedSysDuration(retryDelay));
BackoffTimeout_ = std::min(BackoffTimeout_ * 2, BACKOFF_MAX);
}

void RescheduleOnSuccess(const SysTimePoint expiresAt) { // call with Lock_
BackoffTimeout_ = BACKOFF_START;

const auto now = SysClock::now();
const SysTimePoint refreshAt = SafeAddSystemTime(now, ToBoundedSysDuration(IamEndpoint_.RefreshPeriod));
const SysDuration requestMargin = ToBoundedSysDuration(IamEndpoint_.RequestTimeout);

SysTimePoint nextUpdate = std::min(refreshAt, expiresAt);
nextUpdate = SafeAddSystemTime(nextUpdate, -requestMargin);
nextUpdate = std::max(nextUpdate, SafeAddSystemTime(now, ToBoundedSysDuration(MINIMUM_REFRESH_INTERVAL)));
NextTicketUpdate_ = nextUpdate;
}

private:
std::shared_ptr<grpc::Channel> Channel_;
std::shared_ptr<typename TService::Stub> Stub_;
Expand Down
Loading
Loading