Skip to content

Commit 6366f78

Browse files
autocomplete changes
1 parent 77c6779 commit 6366f78

File tree

5 files changed

+375
-103
lines changed

5 files changed

+375
-103
lines changed

ydb/core/viewer/json_autocomplete.h

Lines changed: 131 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,27 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
2222
TJsonSettings JsonSettings;
2323
ui32 Timeout = 0;
2424

25+
TAutoPtr<TEvViewer::TEvViewerResponse> ProxyResult;
2526
TAutoPtr<NConsole::TEvConsole::TEvListTenantsResponse> ConsoleResult;
2627
TAutoPtr<TEvTxProxySchemeCache::TEvNavigateKeySetResult> CacheResult;
2728

28-
struct SchemaWordData {
29+
struct TSchemaWordData {
2930
TString Name;
30-
TString Type;
31+
NKikimrViewer::EAutocompleteType Type;
3132
TString Table;
32-
SchemaWordData() {}
33-
SchemaWordData(const TString& name, const TString& type, const TString& table = "")
33+
TSchemaWordData() {}
34+
TSchemaWordData(const TString& name, const NKikimrViewer::EAutocompleteType type, const TString& table = "")
3435
: Name(name)
3536
, Type(type)
3637
, Table(table)
3738
{}
3839
};
39-
THashMap<TString, SchemaWordData> Dictionary;
40+
THashMap<TString, TSchemaWordData> Dictionary;
4041
TString Database;
42+
TVector<TString> Tables;
4143
TVector<TString> Paths;
4244
TString Prefix;
43-
TString PrefixPath;
45+
TString SearchWord;
4446
ui32 Limit = 10;
4547
NKikimrViewer::TQueryAutocomplete Result;
4648

@@ -63,6 +65,7 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
6365
TStringBuf content = Event->Get()->Request.GetPostContent();
6466
ParsePostContent(content);
6567
}
68+
PrepareParameters();
6669
}
6770

6871
// proxied request
@@ -72,43 +75,49 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
7275
auto& request = ViewerRequest->Get()->Record.GetAutocompleteRequest();
7376

7477
Database = request.GetDatabase();
75-
for (auto& path: request.GetTables()) {
76-
Paths.emplace_back(path);
78+
for (auto& table: request.GetTables()) {
79+
Tables.emplace_back(table);
7780
}
7881
Prefix = request.GetPrefix();
7982

8083
Timeout = ViewerRequest->Get()->Record.GetTimeout();
8184
Direct = true;
85+
PrepareParameters();
8286
}
8387

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;
88+
void PrepareParameters() {
89+
if (Database) {
90+
TString prefixUpToLastSlash = "";
9991
auto splitPos = Prefix.find_last_of('/');
10092
if (splitPos != std::string::npos) {
101-
path += "/" + Prefix.substr(0, splitPos);
102-
Prefix = Prefix.substr(splitPos + 1);
93+
prefixUpToLastSlash += Prefix.substr(0, splitPos);
94+
SearchWord = Prefix.substr(splitPos + 1);
95+
} else {
96+
SearchWord = Prefix;
97+
}
98+
99+
if (Tables.size() == 0) {
100+
Paths.emplace_back(Database);
101+
} else {
102+
for (TString& table: Tables) {
103+
TString path = table;
104+
if (!table.StartsWith(Database)) {
105+
path = Database + "/" + path;
106+
}
107+
path += "/" + prefixUpToLastSlash;
108+
Paths.emplace_back(path);
109+
}
103110
}
111+
} else {
112+
SearchWord = Prefix;
104113
}
105114
}
106115

107116
void ParseCgiParameters(const TCgiParameters& params) {
108117
JsonSettings.EnumAsNumbers = !FromStringWithDefault<bool>(params.Get("enums"), true);
109118
JsonSettings.UI64AsString = !FromStringWithDefault<bool>(params.Get("ui64"), false);
110119
Database = params.Get("database");
111-
StringSplitter(params.Get("table")).Split(',').SkipEmpty().Collect(&Paths);
120+
StringSplitter(params.Get("table")).Split(',').SkipEmpty().Collect(&Tables);
112121
Prefix = params.Get("prefix");
113122
Limit = FromStringWithDefault<ui32>(params.Get("limit"), Limit);
114123
Direct = FromStringWithDefault<bool>(params.Get("direct"), Direct);
@@ -121,8 +130,10 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
121130
bool success = NJson::ReadJsonTree(content, &JsonConfig, &requestData);
122131
if (success) {
123132
Database = Database.empty() ? requestData["database"].GetStringSafe({}) : Database;
124-
for (auto& table: requestData["tables"].GetArraySafe()) {
125-
Paths.emplace_back(table.GetStringSafe());
133+
if (requestData["table"].IsArray()) {
134+
for (auto& table: requestData["table"].GetArraySafe()) {
135+
Tables.emplace_back(table.GetStringSafe());
136+
}
126137
}
127138
Prefix = Prefix.empty() ? requestData["prefix"].GetStringSafe({}) : Prefix;
128139
}
@@ -157,38 +168,41 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
157168

158169
void Bootstrap() {
159170
if (ViewerRequest) {
160-
// proxied request
161-
PreparePaths();
171+
// handle proxied request
162172
SendSchemeCacheRequest();
163173
} else if (!Database) {
164-
// autocomplete databases via console request
174+
// autocomplete database list via console request
165175
RequestConsoleListTenants();
166176
} else {
167177
if (!Direct) {
168-
// autocomplete with proxy
169-
RequestStateStorageEndpointsLookup(Database); // to find some dynamic node and redirect there
178+
// proxy request to a dynamic node of the specified database
179+
RequestStateStorageEndpointsLookup(Database);
170180
}
171181
if (Requests == 0) {
172-
// autocomplete without proxy
173-
PreparePaths();
182+
// perform autocomplete without proxying
174183
SendSchemeCacheRequest();
175184
}
176185
}
177186

178-
179187
Become(&TThis::StateRequestedDescribe, TDuration::MilliSeconds(Timeout), new TEvents::TEvWakeup());
180188
}
181189

182190
void Connected(TEvInterconnect::TEvNodeConnected::TPtr &) {}
183191

184192
void Undelivered(TEvents::TEvUndelivered::TPtr &ev) {
185-
if (ev->Get()->SourceType == NViewer::TEvViewer::EvViewerRequest) {
186-
SendSchemeCacheRequest();
193+
if (!Direct && ev->Get()->SourceType == NViewer::TEvViewer::EvViewerRequest) {
194+
Direct = true;
195+
SendSchemeCacheRequest(); // fallback
196+
RequestDone();
187197
}
188198
}
189199

190200
void Disconnected(TEvInterconnect::TEvNodeDisconnected::TPtr &) {
191-
SendSchemeCacheRequest();
201+
if (!Direct) {
202+
Direct = true;
203+
SendSchemeCacheRequest(); // fallback
204+
RequestDone();
205+
}
192206
}
193207

194208
void Handle(TEvStateStorage::TEvBoardInfo::TPtr& ev) {
@@ -203,6 +217,7 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
203217
} else {
204218
SendDynamicNodeAutocompleteRequest();
205219
}
220+
RequestDone();
206221
}
207222

208223
void SendSchemeCacheRequest() {
@@ -253,90 +268,106 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
253268
}
254269
}
255270

256-
TString ConvertType(TNavigate::EKind navigate) {
271+
void ParseProxyResult() {
272+
if (ProxyResult == nullptr) {
273+
Result.add_error("Failed to collect information from ProxyResult");
274+
return;
275+
}
276+
if (ProxyResult->Record.HasAutocompleteResponse()) {
277+
Result = ProxyResult->Record.GetAutocompleteResponse();
278+
} else {
279+
Result.add_error("Proxying return empty response");
280+
}
281+
282+
}
283+
284+
void ParseConsoleResult() {
285+
if (ConsoleResult == nullptr) {
286+
Result.add_error("Failed to collect information from ConsoleResult");
287+
return;
288+
}
289+
290+
Ydb::Cms::ListDatabasesResult listTenantsResult;
291+
ConsoleResult->Record.GetResponse().operation().result().UnpackTo(&listTenantsResult);
292+
for (const TString& path : listTenantsResult.paths()) {
293+
Dictionary[path] = TSchemaWordData(path, NKikimrViewer::ext_sub_domain);
294+
}
295+
}
296+
297+
NKikimrViewer::EAutocompleteType ConvertType(TNavigate::EKind navigate) {
257298
switch (navigate) {
258299
case TNavigate::KindSubdomain:
259-
return "subdomain";
300+
return NKikimrViewer::sub_domain;
260301
case TNavigate::KindPath:
261-
return "directory";
302+
return NKikimrViewer::dir;
262303
case TNavigate::KindExtSubdomain:
263-
return "database";
304+
return NKikimrViewer::ext_sub_domain;
264305
case TNavigate::KindTable:
265-
return "table";
306+
return NKikimrViewer::table;
266307
case TNavigate::KindOlapStore:
267-
return "columnStore";
308+
return NKikimrViewer::column_store;
268309
case TNavigate::KindColumnTable:
269-
return "columnTable";
310+
return NKikimrViewer::column_table;
270311
case TNavigate::KindRtmr:
271-
return "rtmrVolume";
312+
return NKikimrViewer::rtmr_volume;
272313
case TNavigate::KindKesus:
273-
return "kesus";
314+
return NKikimrViewer::kesus;
274315
case TNavigate::KindSolomon:
275-
return "solomonVolume";
316+
return NKikimrViewer::solomon_volume;
276317
case TNavigate::KindTopic:
277-
return "persQueueGroup";
318+
return NKikimrViewer::pers_queue_group;
278319
case TNavigate::KindCdcStream:
279-
return "cdcStream";
320+
return NKikimrViewer::cdc_stream;
280321
case TNavigate::KindSequence:
281-
return "sequence";
322+
return NKikimrViewer::sequence;
282323
case TNavigate::KindReplication:
283-
return "replication";
324+
return NKikimrViewer::replication;
284325
case TNavigate::KindBlobDepot:
285-
return "blobDepot";
326+
return NKikimrViewer::blob_depot;
286327
case TNavigate::KindExternalTable:
287-
return "externalTable";
328+
return NKikimrViewer::external_table;
288329
case TNavigate::KindExternalDataSource:
289-
return "externalDataSource";
330+
return NKikimrViewer::external_data_source;
290331
case TNavigate::KindBlockStoreVolume:
291-
return "blockStoreVolume";
332+
return NKikimrViewer::block_store_volume;
292333
case TNavigate::KindFileStore:
293-
return "fileStore";
334+
return NKikimrViewer::file_store;
294335
case TNavigate::KindView:
295-
return "view";
336+
return NKikimrViewer::view;
296337
default:
297-
return "directory";
298-
}
299-
}
300-
301-
void ParseConsoleResult() {
302-
if (ConsoleResult == nullptr) {
303-
Result.add_error("Failed to collect information");
304-
return;
305-
}
306-
307-
Ydb::Cms::ListDatabasesResult listTenantsResult;
308-
ConsoleResult->Record.GetResponse().operation().result().UnpackTo(&listTenantsResult);
309-
for (const TString& path : listTenantsResult.paths()) {
310-
Dictionary[path] = SchemaWordData(path, "database");
338+
return NKikimrViewer::dir;
311339
}
312-
RequestDone();
313340
}
314341

315342
void ParseCacheResult() {
316343
if (CacheResult == nullptr) {
317-
Result.add_error("Failed to collect information");
344+
Result.add_error("Failed to collect information from CacheResult");
318345
return;
319346
}
320347
NSchemeCache::TSchemeCacheNavigate *navigate = CacheResult->Request.Get();
321348
if (navigate->ErrorCount > 0) {
322-
Result.add_error("Inner errors while collected information");
349+
for (auto& entry: CacheResult->Request.Get()->ResultSet) {
350+
if (entry.Status != TSchemeCacheNavigate::EStatus::Ok) {
351+
Result.add_error(TStringBuilder() << "Error receiving Navigate response: `" << CanonizePath(entry.Path) << "` has <" << ToString(entry.Status) << "> status");
352+
}
353+
}
323354
return;
324355
}
325356
for (auto& entry: CacheResult->Request.Get()->ResultSet) {
326357
TString path = CanonizePath(entry.Path);
327358
if (entry.ListNodeEntry) {
328359
for (const auto& child : entry.ListNodeEntry->Children) {
329-
Dictionary[child.Name] = SchemaWordData(child.Name, ConvertType(child.Kind), path);
360+
Dictionary[child.Name] = TSchemaWordData(child.Name, ConvertType(child.Kind), path);
330361
}
331362
};
332363
for (const auto& [id, column] : entry.Columns) {
333-
Dictionary[column.Name] = SchemaWordData(column.Name, path, "column");
364+
Dictionary[column.Name] = TSchemaWordData(column.Name, NKikimrViewer::column, path);
334365
}
335366
for (const auto& index : entry.Indexes) {
336-
Dictionary[index.GetName()] = SchemaWordData(index.GetName(), path, "index");
367+
Dictionary[index.GetName()] = TSchemaWordData(index.GetName(), NKikimrViewer::index, path);
337368
}
338369
for (const auto& cdcStream : entry.CdcStreams) {
339-
Dictionary[cdcStream.GetName()] = SchemaWordData(cdcStream.GetName(), path, "cdcstream");
370+
Dictionary[cdcStream.GetName()] = TSchemaWordData(cdcStream.GetName(), NKikimrViewer::cdc_stream, path);
340371
}
341372
}
342373
}
@@ -364,23 +395,27 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
364395
}
365396

366397
void ReplyAndPassAway() {
367-
if (!Database) {
368-
ParseConsoleResult();
369-
} else {
398+
if (ProxyResult) {
399+
ParseProxyResult();
400+
} else if (Database) {
370401
ParseCacheResult();
402+
} else {
403+
ParseConsoleResult();
371404
}
372405

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);
406+
if (!ProxyResult) {
407+
Result.set_success(Result.error_size() == 0);
408+
if (Result.error_size() == 0) {
409+
auto fuzzy = FuzzySearcher<TSchemaWordData>(Dictionary);
410+
auto autocomplete = fuzzy.Search(SearchWord, Limit);
411+
Result.MutableResult()->SetTotal(autocomplete.size());
412+
for (TSchemaWordData& wordData: autocomplete) {
413+
auto entity = Result.MutableResult()->AddEntities();
414+
entity->SetName(wordData.Name);
415+
entity->SetType(wordData.Type);
416+
if (wordData.Table) {
417+
entity->SetParent(wordData.Table);
418+
}
384419
}
385420
}
386421
}
@@ -390,10 +425,8 @@ class TJsonAutocomplete : public TViewerPipeClient<TJsonAutocomplete> {
390425
}
391426

392427
void Handle(TEvViewer::TEvViewerResponse::TPtr& ev) {
393-
if (ev.Get()->Get()->Record.HasAutocompleteResponse()) {
394-
Result = ev.Get()->Get()->Record.GetAutocompleteResponse();
395-
}
396-
SendAutocompleteResponse();
428+
ProxyResult = ev.Release()->Release();
429+
RequestDone();
397430
}
398431

399432
void HandleTimeout() {

0 commit comments

Comments
 (0)