11
11
#include < ydb/public/sdk/cpp/client/ydb_types/operation/operation.h>
12
12
13
13
#include < ydb/core/kqp/counters/kqp_counters.h>
14
+ #include < ydb/core/base/counters.h>
15
+ #include < library/cpp/threading/local_executor/local_executor.h>
14
16
15
17
#include < fmt/format.h>
16
18
@@ -54,7 +56,7 @@ Y_UNIT_TEST_SUITE(KqpQueryService) {
54
56
WaitForZeroSessions (counters);
55
57
}
56
58
57
- Y_UNIT_TEST (QueryOnClosedSession ) {
59
+ void DoClosedSessionRemovedWhileActiveTest ( bool withQuery ) {
58
60
auto kikimr = DefaultKikimrRunner ();
59
61
auto clientConfig = NGRpcProxy::TGRpcClientConfig (kikimr.GetEndpoint ());
60
62
NKqp::TKqpCounters counters (kikimr.GetTestServer ().GetRuntime ()->GetAppData ().Counters );
@@ -75,21 +77,134 @@ Y_UNIT_TEST_SUITE(KqpQueryService) {
75
77
76
78
UNIT_ASSERT (allDoneOk);
77
79
78
- auto execResult = session.ExecuteQuery (" SELECT 1;" ,
79
- NYdb::NQuery::TTxControl::BeginTx ().CommitTx ()).ExtractValueSync ();
80
+ if (withQuery) {
81
+ auto execResult = session.ExecuteQuery (" SELECT 1;" ,
82
+ NYdb::NQuery::TTxControl::BeginTx ().CommitTx ()).ExtractValueSync ();
80
83
81
- UNIT_ASSERT_VALUES_EQUAL (execResult.GetStatus (), EStatus::BAD_SESSION);
84
+ UNIT_ASSERT_VALUES_EQUAL (execResult.GetStatus (), EStatus::BAD_SESSION);
85
+ }
82
86
}
83
87
// closed session must be removed from session pool
84
88
{
85
89
auto result = db.GetSession ().GetValueSync ();
86
90
UNIT_ASSERT_VALUES_EQUAL_C (result.GetStatus (), EStatus::SUCCESS, result.GetIssues ().ToString ());
87
91
UNIT_ASSERT (result.GetSession ().GetId () != id);
88
92
}
93
+ UNIT_ASSERT_VALUES_EQUAL (db.GetActiveSessionCount (), 0 );
89
94
}
90
95
WaitForZeroSessions (counters);
91
96
}
92
97
98
+ Y_UNIT_TEST (ClosedSessionRemovedWhileActiveWithQuery) {
99
+ // - Session is active (user gfot it)
100
+ // - server close it
101
+ // - user executes query (got BAD SESSION)
102
+ // - session should be removed from pool
103
+ DoClosedSessionRemovedWhileActiveTest (true );
104
+ }
105
+
106
+ /* Not implemented in the sdk
107
+ Y_UNIT_TEST(ClosedSessionRemovedWhileActiveWithoutQuery) {
108
+ // - Session is active (user gfot it)
109
+ // - server close it
110
+ // - user do not executes any query
111
+ // - session should be removed from pool
112
+ DoClosedSessionRemovedWhileActiveTest(false);
113
+ }
114
+ */
115
+ // Copy paste from table service but with some modifications for query service
116
+ // Checks read iterators/session/sdk counters have expected values
117
+ Y_UNIT_TEST (CloseSessionsWithLoad) {
118
+ auto kikimr = std::make_shared<TKikimrRunner>();
119
+ kikimr->GetTestServer ().GetRuntime ()->SetLogPriority (NKikimrServices::KQP_EXECUTER, NLog::PRI_DEBUG);
120
+ kikimr->GetTestServer ().GetRuntime ()->SetLogPriority (NKikimrServices::KQP_SESSION, NLog::PRI_DEBUG);
121
+ kikimr->GetTestServer ().GetRuntime ()->SetLogPriority (NKikimrServices::KQP_COMPILE_ACTOR, NLog::PRI_DEBUG);
122
+ kikimr->GetTestServer ().GetRuntime ()->SetLogPriority (NKikimrServices::KQP_COMPILE_SERVICE, NLog::PRI_DEBUG);
123
+
124
+ NYdb::NQuery::TQueryClient db = kikimr->GetQueryClient ();
125
+
126
+ const ui32 SessionsCount = 50 ;
127
+ const TDuration WaitDuration = TDuration::Seconds (1 );
128
+
129
+ TVector<NYdb::NQuery::TQueryClient::TSession> sessions;
130
+ for (ui32 i = 0 ; i < SessionsCount; ++i) {
131
+ auto sessionResult = db.GetSession ().GetValueSync ();
132
+ UNIT_ASSERT_C (sessionResult.IsSuccess (), sessionResult.GetIssues ().ToString ());
133
+
134
+ sessions.push_back (sessionResult.GetSession ());
135
+ }
136
+
137
+ NPar::LocalExecutor ().RunAdditionalThreads (SessionsCount + 1 );
138
+ NPar::LocalExecutor ().ExecRange ([&kikimr, sessions, WaitDuration](int id) mutable {
139
+ if (id == (i32 )sessions.size ()) {
140
+ Sleep (WaitDuration);
141
+ Cerr << " start sessions close....." << Endl;
142
+ auto clientConfig = NGRpcProxy::TGRpcClientConfig (kikimr->GetEndpoint ());
143
+ for (ui32 i = 0 ; i < sessions.size (); ++i) {
144
+ bool allDoneOk = true ;
145
+ NTestHelpers::CheckDelete (clientConfig, sessions[i].GetId (), Ydb::StatusIds::SUCCESS, allDoneOk);
146
+ UNIT_ASSERT (allDoneOk);
147
+ }
148
+
149
+ Cerr << " finished sessions close....." << Endl;
150
+ auto counters = GetServiceCounters (kikimr->GetTestServer ().GetRuntime ()->GetAppData (0 ).Counters , " ydb" );
151
+
152
+ ui64 pendingCompilations = 0 ;
153
+ do {
154
+ Sleep (WaitDuration);
155
+ pendingCompilations = counters->GetNamedCounter (" name" , " table.query.compilation.active_count" , false )->Val ();
156
+ Cerr << " still compiling... " << pendingCompilations << Endl;
157
+ } while (pendingCompilations != 0 );
158
+
159
+ ui64 pendingSessions = 0 ;
160
+ do {
161
+ Sleep (WaitDuration);
162
+ pendingSessions = counters->GetNamedCounter (" name" , " table.session.active_count" , false )->Val ();
163
+ Cerr << " still active sessions ... " << pendingSessions << Endl;
164
+ } while (pendingSessions != 0 );
165
+
166
+ return ;
167
+ }
168
+
169
+ auto session = sessions[id];
170
+ TMaybe<TTransaction> tx;
171
+
172
+ while (true ) {
173
+ if (tx) {
174
+ auto result = tx->Commit ().GetValueSync ();
175
+ if (!result.IsSuccess ()) {
176
+ return ;
177
+ }
178
+
179
+ tx = {};
180
+ continue ;
181
+ }
182
+
183
+ auto query = Sprintf (R"(
184
+ SELECT Key, Text, Data FROM `/Root/EightShard` WHERE Key=%1$d + 0;
185
+ SELECT Key, Data, Text FROM `/Root/EightShard` WHERE Key=%1$d + 1;
186
+ SELECT Text, Key, Data FROM `/Root/EightShard` WHERE Key=%1$d + 2;
187
+ SELECT Text, Data, Key FROM `/Root/EightShard` WHERE Key=%1$d + 3;
188
+ SELECT Data, Key, Text FROM `/Root/EightShard` WHERE Key=%1$d + 4;
189
+ SELECT Data, Text, Key FROM `/Root/EightShard` WHERE Key=%1$d + 5;
190
+
191
+ UPSERT INTO `/Root/EightShard` (Key, Text) VALUES
192
+ (%2$dul, "New");
193
+ )" , RandomNumber<ui32>(), RandomNumber<ui32>());
194
+
195
+ auto result = session.ExecuteQuery (query, TTxControl::BeginTx ()).GetValueSync ();
196
+ if (!result.IsSuccess ()) {
197
+ UNIT_ASSERT_VALUES_EQUAL (result.GetStatus (), EStatus::BAD_SESSION);
198
+ Cerr << " received non-success status for session " << id << Endl;
199
+ return ;
200
+ }
201
+
202
+ tx = result.GetTransaction ();
203
+ }
204
+ }, 0 , SessionsCount + 1 , NPar::TLocalExecutor::WAIT_COMPLETE | NPar::TLocalExecutor::MED_PRIORITY);
205
+ WaitForZeroReadIterators (kikimr->GetTestServer (), " /Root/EightShard" );
206
+ }
207
+
93
208
Y_UNIT_TEST (PeriodicTaskInSessionPool) {
94
209
auto kikimr = DefaultKikimrRunner ();
95
210
auto clientConfig = NGRpcProxy::TGRpcClientConfig (kikimr.GetEndpoint ());
@@ -169,6 +284,104 @@ Y_UNIT_TEST_SUITE(KqpQueryService) {
169
284
WaitForZeroSessions (counters);
170
285
}
171
286
287
+ // Check closed session removed while its in the session pool
288
+ Y_UNIT_TEST (ClosedSessionRemovedFromPool) {
289
+ auto kikimr = DefaultKikimrRunner ();
290
+ auto clientConfig = NGRpcProxy::TGRpcClientConfig (kikimr.GetEndpoint ());
291
+ NKqp::TKqpCounters counters (kikimr.GetTestServer ().GetRuntime ()->GetAppData ().Counters );
292
+
293
+ {
294
+ auto db = kikimr.GetQueryClient ();
295
+
296
+ TString id;
297
+ {
298
+ auto result = db.GetSession ().GetValueSync ();
299
+ UNIT_ASSERT_VALUES_EQUAL_C (result.GetStatus (), EStatus::SUCCESS, result.GetIssues ().ToString ());
300
+ UNIT_ASSERT (result.GetSession ().GetId ());
301
+ auto session = result.GetSession ();
302
+ id = session.GetId ();
303
+ }
304
+
305
+ bool allDoneOk = true ;
306
+ NTestHelpers::CheckDelete (clientConfig, id, Ydb::StatusIds::SUCCESS, allDoneOk);
307
+
308
+ Sleep (TDuration::Seconds (5 ));
309
+
310
+ UNIT_ASSERT (allDoneOk);
311
+ {
312
+ auto result = db.GetSession ().GetValueSync ();
313
+ UNIT_ASSERT_VALUES_EQUAL_C (result.GetStatus (), EStatus::SUCCESS, result.GetIssues ().ToString ());
314
+ auto newSession = result.GetSession ();
315
+ UNIT_ASSERT_C (newSession.GetId () != id, " closed id: " << id << " new id: " << newSession.GetId ());
316
+
317
+ auto execResult = newSession.ExecuteQuery (" SELECT 1;" ,
318
+ NYdb::NQuery::TTxControl::BeginTx ().CommitTx ()).ExtractValueSync ();
319
+
320
+ UNIT_ASSERT_VALUES_EQUAL (execResult.GetStatus (), EStatus::SUCCESS);
321
+ }
322
+ }
323
+ WaitForZeroSessions (counters);
324
+ }
325
+
326
+ // Attempt to trigger simultanous server side close and return session
327
+ // From sdk perspective check no dataraces
328
+ Y_UNIT_TEST (ReturnAndCloseSameTime) {
329
+ auto kikimr = DefaultKikimrRunner ();
330
+ auto clientConfig = NGRpcProxy::TGRpcClientConfig (kikimr.GetEndpoint ());
331
+ NKqp::TKqpCounters counters (kikimr.GetTestServer ().GetRuntime ()->GetAppData ().Counters );
332
+
333
+ size_t iterations = 999 ;
334
+ auto db = kikimr.GetQueryClient ();
335
+
336
+ NPar::LocalExecutor ().RunAdditionalThreads (2 );
337
+ while (iterations--) {
338
+ auto lim = iterations % 33 ;
339
+ TVector<NYdb::NQuery::TQueryClient::TSession> sessions;
340
+ TVector<TString> sids;
341
+ sessions.reserve (lim);
342
+ sids.reserve (lim);
343
+ for (size_t i = 0 ; i < lim; ++i) {
344
+ auto sessionResult = db.GetSession ().GetValueSync ();
345
+ UNIT_ASSERT_C (sessionResult.IsSuccess (), sessionResult.GetIssues ().ToString ());
346
+
347
+ sessions.push_back (sessionResult.GetSession ());
348
+ sids.push_back (sessions.back ().GetId ());
349
+ }
350
+
351
+ if (iterations & 1 ) {
352
+ auto rng = std::default_random_engine {};
353
+ std::ranges::shuffle (sids, rng);
354
+ }
355
+
356
+ NPar::LocalExecutor ().ExecRange ([sessions{std::move (sessions)}, sids{std::move (sids)}, clientConfig](int id) mutable {
357
+ if (id == 0 ) {
358
+ for (size_t i = 0 ; i < sessions.size (); i++) {
359
+ auto s = std::move (sessions[i]);
360
+ auto execResult = s.ExecuteQuery (" SELECT 1;" ,
361
+ NYdb::NQuery::TTxControl::BeginTx ().CommitTx ()).ExtractValueSync ();
362
+ switch (execResult.GetStatus ()) {
363
+ case EStatus::SUCCESS:
364
+ case EStatus::BAD_SESSION:
365
+ break ;
366
+ default :
367
+ UNIT_ASSERT_C (false , " unexpected status: " << execResult.GetStatus ());
368
+ }
369
+ }
370
+ } else if (id == 1 ) {
371
+ for (size_t i = 0 ; i < sids.size (); i++) {
372
+ bool allDoneOk = true ;
373
+ NTestHelpers::CheckDelete (clientConfig, sids[i], Ydb::StatusIds::SUCCESS, allDoneOk);
374
+ UNIT_ASSERT (allDoneOk);
375
+ }
376
+ } else {
377
+ Y_ABORT_UNLESS (false , " unexpected thread cxount" );
378
+ }
379
+ }, 0 , 2 , NPar::TLocalExecutor::WAIT_COMPLETE | NPar::TLocalExecutor::MED_PRIORITY);
380
+ }
381
+
382
+ WaitForZeroSessions (counters);
383
+ }
384
+
172
385
Y_UNIT_TEST (StreamExecuteQueryPure) {
173
386
auto kikimr = DefaultKikimrRunner ();
174
387
auto db = kikimr.GetQueryClient ();
0 commit comments