Skip to content

Commit 90f8c91

Browse files
Merge 77408b4 into ee48ce2
2 parents ee48ce2 + 77408b4 commit 90f8c91

File tree

4 files changed

+363
-91
lines changed

4 files changed

+363
-91
lines changed

ydb/core/viewer/json_autocomplete.h

Lines changed: 122 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <ydb/core/base/tablet.h>
55
#include <ydb/core/base/tablet_pipe.h>
66
#include <ydb/library/services/services.pb.h>
7+
#include <ydb/core/viewer/protos/viewer.pb.h>
78
#include <ydb/core/viewer/json/json.h>
89
#include "viewer.h"
910
#include "query_autocomplete_helper.h"
@@ -13,6 +14,7 @@ namespace NViewer {
1314

1415
using namespace NActors;
1516
using TNavigate = NSchemeCache::TSchemeCacheNavigate;
17+
using TEntity = NKikimrViewer::TQueryAutocomplete_TResult_TEntity;
1618

1719
class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
1820
using TBase = TViewerPipeClient<TJsonAutocomplete>;
@@ -22,25 +24,27 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
2224
TJsonSettings JsonSettings;
2325
ui32 Timeout = 0;
2426

27+
TAutoPtr<TEvViewer::TEvViewerResponse> ProxyResult;
2528
TAutoPtr<NConsole::TEvConsole::TEvListTenantsResponse> ConsoleResult;
2629
TAutoPtr<TEvTxProxySchemeCache::TEvNavigateKeySetResult> CacheResult;
2730

28-
struct SchemaWordData {
31+
struct TSchemaWordData {
2932
TString Name;
30-
TString Type;
33+
TEntity::EType Type;
3134
TString Table;
32-
SchemaWordData() {}
33-
SchemaWordData(const TString& name, const TString& type, const TString& table = "")
35+
TSchemaWordData() {}
36+
TSchemaWordData(const TString& name, const TEntity::EType type, const TString& table = "")
3437
: Name(name)
3538
, Type(type)
3639
, Table(table)
3740
{}
3841
};
39-
THashMap<TString, SchemaWordData> Dictionary;
42+
THashMap<TString, TSchemaWordData> Dictionary;
4043
TString Database;
44+
TVector<TString> Tables;
4145
TVector<TString> Paths;
4246
TString Prefix;
43-
TString PrefixPath;
47+
TString SearchWord;
4448
ui32 Limit = 10;
4549
NKikimrViewer::TQueryAutocomplete Result;
4650

@@ -63,6 +67,7 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
6367
TStringBuf content = Event->Get()->Request.GetPostContent();
6468
ParsePostContent(content);
6569
}
70+
PrepareParameters();
6671
}
6772

6873
// proxied request
@@ -72,43 +77,49 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
7277
auto& request = ViewerRequest->Get()->Record.GetAutocompleteRequest();
7378

7479
Database = request.GetDatabase();
75-
for (auto& path: request.GetTables()) {
76-
Paths.emplace_back(path);
80+
for (auto& table: request.GetTables()) {
81+
Tables.emplace_back(table);
7782
}
7883
Prefix = request.GetPrefix();
7984

8085
Timeout = ViewerRequest->Get()->Record.GetTimeout();
8186
Direct = true;
87+
PrepareParameters();
8288
}
8389

84-
void PreparePaths() {
85-
if (Paths.size() == 0) {
86-
Paths.emplace_back("");
87-
}
88-
TString prefixPath = "";
89-
auto splitPos = Prefix.find_last_of('/');
90-
if (splitPos != std::string::npos) {
91-
prefixPath += "/" + Prefix.substr(0, splitPos);
92-
Prefix = Prefix.substr(splitPos + 1);
93-
}
94-
for (TString& path: Paths) {
95-
if (!path.StartsWith(Database)) {
96-
path = Database + "/" + path;
97-
}
98-
path += prefixPath;
90+
void PrepareParameters() {
91+
if (Database) {
92+
TString prefixUpToLastSlash = "";
9993
auto splitPos = Prefix.find_last_of('/');
10094
if (splitPos != std::string::npos) {
101-
path += "/" + Prefix.substr(0, splitPos);
102-
Prefix = Prefix.substr(splitPos + 1);
95+
prefixUpToLastSlash += Prefix.substr(0, splitPos);
96+
SearchWord = Prefix.substr(splitPos + 1);
97+
} else {
98+
SearchWord = Prefix;
10399
}
100+
101+
if (Tables.size() == 0) {
102+
Paths.emplace_back(Database);
103+
} else {
104+
for (TString& table: Tables) {
105+
TString path = table;
106+
if (!table.StartsWith(Database)) {
107+
path = Database + "/" + path;
108+
}
109+
path += "/" + prefixUpToLastSlash;
110+
Paths.emplace_back(path);
111+
}
112+
}
113+
} else {
114+
SearchWord = Prefix;
104115
}
105116
}
106117

107118
void ParseCgiParameters(const TCgiParameters& params) {
108119
JsonSettings.EnumAsNumbers = !FromStringWithDefault<bool>(params.Get("enums"), true);
109120
JsonSettings.UI64AsString = !FromStringWithDefault<bool>(params.Get("ui64"), false);
110121
Database = params.Get("database");
111-
StringSplitter(params.Get("table")).Split(',').SkipEmpty().Collect(&Paths);
122+
StringSplitter(params.Get("table")).Split(',').SkipEmpty().Collect(&Tables);
112123
Prefix = params.Get("prefix");
113124
Limit = FromStringWithDefault<ui32>(params.Get("limit"), Limit);
114125
Direct = FromStringWithDefault<bool>(params.Get("direct"), Direct);
@@ -121,8 +132,10 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
121132
bool success = NJson::ReadJsonTree(content, &JsonConfig, &requestData);
122133
if (success) {
123134
Database = Database.empty() ? requestData["database"].GetStringSafe({}) : Database;
124-
for (auto& table: requestData["tables"].GetArraySafe()) {
125-
Paths.emplace_back(table.GetStringSafe());
135+
if (requestData["table"].IsArray()) {
136+
for (auto& table: requestData["table"].GetArraySafe()) {
137+
Tables.emplace_back(table.GetStringSafe());
138+
}
126139
}
127140
Prefix = Prefix.empty() ? requestData["prefix"].GetStringSafe({}) : Prefix;
128141
}
@@ -157,38 +170,41 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
157170

158171
void Bootstrap() {
159172
if (ViewerRequest) {
160-
// proxied request
161-
PreparePaths();
173+
// handle proxied request
162174
SendSchemeCacheRequest();
163175
} else if (!Database) {
164-
// autocomplete databases via console request
176+
// autocomplete database list via console request
165177
RequestConsoleListTenants();
166178
} else {
167179
if (!Direct) {
168-
// autocomplete with proxy
169-
RequestStateStorageEndpointsLookup(Database); // to find some dynamic node and redirect there
180+
// proxy request to a dynamic node of the specified database
181+
RequestStateStorageEndpointsLookup(Database);
170182
}
171183
if (Requests == 0) {
172-
// autocomplete without proxy
173-
PreparePaths();
184+
// perform autocomplete without proxying
174185
SendSchemeCacheRequest();
175186
}
176187
}
177188

178-
179189
Become(&TThis::StateRequestedDescribe, TDuration::MilliSeconds(Timeout), new TEvents::TEvWakeup());
180190
}
181191

182192
void Connected(TEvInterconnect::TEvNodeConnected::TPtr &) {}
183193

184194
void Undelivered(TEvents::TEvUndelivered::TPtr &ev) {
185-
if (ev->Get()->SourceType == NViewer::TEvViewer::EvViewerRequest) {
186-
SendSchemeCacheRequest();
195+
if (!Direct && ev->Get()->SourceType == NViewer::TEvViewer::EvViewerRequest) {
196+
Direct = true;
197+
SendSchemeCacheRequest(); // fallback
198+
RequestDone();
187199
}
188200
}
189201

190202
void Disconnected(TEvInterconnect::TEvNodeDisconnected::TPtr &) {
191-
SendSchemeCacheRequest();
203+
if (!Direct) {
204+
Direct = true;
205+
SendSchemeCacheRequest(); // fallback
206+
RequestDone();
207+
}
192208
}
193209

194210
void Handle(TEvStateStorage::TEvBoardInfo::TPtr& ev) {
@@ -203,6 +219,7 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
203219
} else {
204220
SendDynamicNodeAutocompleteRequest();
205221
}
222+
RequestDone();
206223
}
207224

208225
void SendSchemeCacheRequest() {
@@ -253,90 +270,106 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
253270
}
254271
}
255272

256-
TString ConvertType(TNavigate::EKind navigate) {
273+
TEntity::EType ConvertType(TNavigate::EKind navigate) {
257274
switch (navigate) {
258275
case TNavigate::KindSubdomain:
259-
return "subdomain";
276+
return TEntity::Subdomain;
260277
case TNavigate::KindPath:
261-
return "directory";
278+
return TEntity::Directory;
262279
case TNavigate::KindExtSubdomain:
263-
return "database";
280+
return TEntity::Database;
264281
case TNavigate::KindTable:
265-
return "table";
282+
return TEntity::Table;
266283
case TNavigate::KindOlapStore:
267-
return "columnStore";
284+
return TEntity::ColumnStore;
268285
case TNavigate::KindColumnTable:
269-
return "columnTable";
286+
return TEntity::ColumnTable;
270287
case TNavigate::KindRtmr:
271-
return "rtmrVolume";
288+
return TEntity::RtmrVolume;
272289
case TNavigate::KindKesus:
273-
return "kesus";
290+
return TEntity::Kesus;
274291
case TNavigate::KindSolomon:
275-
return "solomonVolume";
292+
return TEntity::SolomonVolume;
276293
case TNavigate::KindTopic:
277-
return "persQueueGroup";
294+
return TEntity::PersQueueGroup;
278295
case TNavigate::KindCdcStream:
279-
return "cdcStream";
296+
return TEntity::CdcStream;
280297
case TNavigate::KindSequence:
281-
return "sequence";
298+
return TEntity::Sequence;
282299
case TNavigate::KindReplication:
283-
return "replication";
300+
return TEntity::Replication;
284301
case TNavigate::KindBlobDepot:
285-
return "blobDepot";
302+
return TEntity::BlobDepot;
286303
case TNavigate::KindExternalTable:
287-
return "externalTable";
304+
return TEntity::ExternalTable;
288305
case TNavigate::KindExternalDataSource:
289-
return "externalDataSource";
306+
return TEntity::ExternalDataSource;
290307
case TNavigate::KindBlockStoreVolume:
291-
return "blockStoreVolume";
308+
return TEntity::BlockStoreVolume;
292309
case TNavigate::KindFileStore:
293-
return "fileStore";
310+
return TEntity::FileStore;
294311
case TNavigate::KindView:
295-
return "view";
312+
return TEntity::View;
296313
default:
297-
return "directory";
314+
return TEntity::Directory;
315+
}
316+
}
317+
318+
void ParseProxyResult() {
319+
if (ProxyResult == nullptr) {
320+
Result.add_error("Failed to collect information from ProxyResult");
321+
return;
322+
}
323+
if (ProxyResult->Record.HasAutocompleteResponse()) {
324+
Result = ProxyResult->Record.GetAutocompleteResponse();
325+
} else {
326+
Result.add_error("Proxying return empty response");
298327
}
328+
299329
}
300330

301331
void ParseConsoleResult() {
302332
if (ConsoleResult == nullptr) {
303-
Result.add_error("Failed to collect information");
333+
Result.add_error("Failed to collect information from ConsoleResult");
304334
return;
305335
}
306336

307337
Ydb::Cms::ListDatabasesResult listTenantsResult;
308338
ConsoleResult->Record.GetResponse().operation().result().UnpackTo(&listTenantsResult);
309339
for (const TString& path : listTenantsResult.paths()) {
310-
Dictionary[path] = SchemaWordData(path, "database");
340+
Dictionary[path] = TSchemaWordData(path, TEntity::Database);
311341
}
312-
RequestDone();
313342
}
314343

315344
void ParseCacheResult() {
316345
if (CacheResult == nullptr) {
317-
Result.add_error("Failed to collect information");
346+
Result.add_error("Failed to collect information from CacheResult");
318347
return;
319348
}
320349
NSchemeCache::TSchemeCacheNavigate *navigate = CacheResult->Request.Get();
321350
if (navigate->ErrorCount > 0) {
322-
Result.add_error("Inner errors while collected information");
351+
for (auto& entry: CacheResult->Request.Get()->ResultSet) {
352+
if (entry.Status != TSchemeCacheNavigate::EStatus::Ok) {
353+
Result.add_error(TStringBuilder() << "Error receiving Navigate response: `" << CanonizePath(entry.Path) << "` has <" << ToString(entry.Status) << "> status");
354+
}
355+
}
323356
return;
324357
}
325358
for (auto& entry: CacheResult->Request.Get()->ResultSet) {
326359
TString path = CanonizePath(entry.Path);
327360
if (entry.ListNodeEntry) {
328361
for (const auto& child : entry.ListNodeEntry->Children) {
329-
Dictionary[child.Name] = SchemaWordData(child.Name, ConvertType(child.Kind), path);
362+
Dictionary[child.Name] = TSchemaWordData(child.Name, ConvertType(child.Kind), path);
330363
}
331364
};
332365
for (const auto& [id, column] : entry.Columns) {
333-
Dictionary[column.Name] = SchemaWordData(column.Name, path, "column");
366+
Dictionary[column.Name] = TSchemaWordData(column.Name, TEntity::Column, path);
334367
}
335368
for (const auto& index : entry.Indexes) {
336-
Dictionary[index.GetName()] = SchemaWordData(index.GetName(), path, "index");
369+
Dictionary[index.GetName()] = TSchemaWordData(index.GetName(), TEntity::Index, path);
337370
}
338371
for (const auto& cdcStream : entry.CdcStreams) {
339-
Dictionary[cdcStream.GetName()] = SchemaWordData(cdcStream.GetName(), path, "cdcstream");
372+
Dictionary[cdcStream.GetName()] = TSchemaWordData(cdcStream.GetName(), TEntity::CdcStream, path);
340373
}
341374
}
342375
}
@@ -364,23 +397,27 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
364397
}
365398

366399
void ReplyAndPassAway() {
367-
if (!Database) {
368-
ParseConsoleResult();
369-
} else {
400+
if (ProxyResult) {
401+
ParseProxyResult();
402+
} else if (Database) {
370403
ParseCacheResult();
404+
} else {
405+
ParseConsoleResult();
371406
}
372407

373-
Result.set_success(Result.error_size() == 0);
374-
if (Result.error_size() == 0) {
375-
auto fuzzy = FuzzySearcher<SchemaWordData>(Dictionary);
376-
auto autocomplete = fuzzy.Search(Prefix, Limit);
377-
Result.MutableResult()->SetTotal(autocomplete.size());
378-
for (SchemaWordData& wordData: autocomplete) {
379-
auto entity = Result.MutableResult()->AddEntities();
380-
entity->SetName(wordData.Name);
381-
entity->SetType(wordData.Type);
382-
if (wordData.Table) {
383-
entity->SetParent(wordData.Table);
408+
if (!ProxyResult) {
409+
Result.set_success(Result.error_size() == 0);
410+
if (Result.error_size() == 0) {
411+
auto fuzzy = FuzzySearcher<TSchemaWordData>(Dictionary);
412+
auto autocomplete = fuzzy.Search(SearchWord, Limit);
413+
Result.MutableResult()->SetTotal(autocomplete.size());
414+
for (TSchemaWordData& wordData: autocomplete) {
415+
auto entity = Result.MutableResult()->AddEntities();
416+
entity->SetName(wordData.Name);
417+
entity->SetType(wordData.Type);
418+
if (wordData.Table) {
419+
entity->SetParent(wordData.Table);
420+
}
384421
}
385422
}
386423
}
@@ -390,10 +427,8 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
390427
}
391428

392429
void Handle(TEvViewer::TEvViewerResponse::TPtr& ev) {
393-
if (ev.Get()->Get()->Record.HasAutocompleteResponse()) {
394-
Result = ev.Get()->Get()->Record.GetAutocompleteResponse();
395-
}
396-
SendAutocompleteResponse();
430+
ProxyResult = ev.Release()->Release();
431+
RequestDone();
397432
}
398433

399434
void HandleTimeout() {

0 commit comments

Comments
 (0)