yql_plan.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. #include "yql_plan.h"
  2. #include <yql/essentials/providers/common/provider/yql_provider_names.h>
  3. #include <util/generic/map.h>
  4. namespace NYql {
  5. namespace {
  6. struct TPinAttrs {
  7. TPinInfo Info;
  8. ui32 ProviderId = 0;
  9. ui32 PinId = 0;
  10. TPinAttrs(const TPinInfo& info)
  11. : Info(info)
  12. {}
  13. };
  14. struct TNodeInfo {
  15. ui64 NodeId;
  16. const TExprNode* const Node;
  17. IDataProvider* Provider;
  18. bool IsVisible;
  19. TExprNode::TListType Dependencies;
  20. TVector<TPinAttrs> Inputs;
  21. TVector<TPinAttrs> Outputs;
  22. ui32 InputsCount = 0;
  23. ui32 OutputsCount = 0;
  24. TNodeInfo(ui64 nodeId, const TExprNode* node)
  25. : NodeId(nodeId)
  26. , Node(node)
  27. , Provider(nullptr)
  28. , IsVisible(true)
  29. {}
  30. };
  31. struct TBasicNode {
  32. ui64 Id = 0;
  33. ui32 Level = 0;
  34. enum class EType : ui32 {
  35. Unknown,
  36. Operation,
  37. Input,
  38. Output
  39. };
  40. TString DisplayName;
  41. EType Type = EType::Unknown;
  42. };
  43. struct TPinKey {
  44. ui32 ProviderId;
  45. ui32 PinId;
  46. TBasicNode::EType Type;
  47. bool operator==(const TPinKey& other) const {
  48. return ProviderId == other.ProviderId && PinId == other.PinId && Type == other.Type;
  49. }
  50. size_t Hash() const {
  51. return CombineHashes(CombineHashes(IntHash(ProviderId), IntHash(PinId)), IntHash(ui32(Type)));
  52. }
  53. struct THash {
  54. size_t operator()(const TPinKey& x) const {
  55. return x.Hash();
  56. }
  57. };
  58. };
  59. struct TBasicLink {
  60. const ui64 Source;
  61. const ui64 Target;
  62. TBasicLink(ui64 source, ui64 target)
  63. : Source(source)
  64. , Target(target)
  65. {}
  66. };
  67. struct TLevelContext {
  68. TBasicNode* const Node;
  69. TVector<ui64> Inputs;
  70. TVector<ui64> Outputs;
  71. TLevelContext()
  72. : Node(nullptr)
  73. {}
  74. TLevelContext(TBasicNode* node)
  75. : Node(node)
  76. {}
  77. };
  78. struct TProviderInfo {
  79. ui32 Id;
  80. const TExprNode* Node;
  81. IDataProvider* Provider;
  82. TNodeMap<ui32> Pin;
  83. std::vector<const TExprNode*> PinOrder;
  84. TProviderInfo(ui32 id, const TExprNode* node, IDataProvider* provider)
  85. : Id(id)
  86. , Node(node)
  87. , Provider(provider)
  88. {}
  89. };
  90. using TProviderInfoMap = TMap<TString, TProviderInfo>;
  91. void WriteProviders(const TString& tag, const TProviderInfoMap& providers, NYson::TYsonWriter& writer) {
  92. writer.OnKeyedItem(tag);
  93. writer.OnBeginList();
  94. for (auto& p : providers) {
  95. writer.OnListItem();
  96. writer.OnBeginMap();
  97. writer.OnKeyedItem("Id");
  98. writer.OnUint64Scalar(p.second.Id);
  99. writer.OnKeyedItem("Name");
  100. writer.OnStringScalar(p.second.Node->Child(0)->Content());
  101. p.second.Provider->GetPlanFormatter().WriteDetails(*p.second.Node, writer);
  102. writer.OnKeyedItem("Pins");
  103. writer.OnBeginList();
  104. for (auto pin : p.second.PinOrder) {
  105. writer.OnListItem();
  106. writer.OnBeginMap();
  107. writer.OnKeyedItem("Id");
  108. const auto found = p.second.Pin.find(pin);
  109. YQL_ENSURE(found != p.second.Pin.cend());
  110. writer.OnUint64Scalar(found->second);
  111. p.second.Provider->GetPlanFormatter().WritePinDetails(*pin, writer);
  112. writer.OnEndMap();
  113. }
  114. writer.OnEndList();
  115. writer.OnEndMap();
  116. }
  117. writer.OnEndList();
  118. }
  119. ui32 FillLevels(THashMap<ui32, TLevelContext>& basicNodesMap, ui32 current, THashSet<ui32>& visited) {
  120. if (visited.contains(current)) {
  121. return 0;
  122. }
  123. auto findPtr = basicNodesMap.FindPtr(current);
  124. YQL_ENSURE(findPtr);
  125. auto& ctx = *findPtr;
  126. if (ctx.Node->Level) {
  127. return ctx.Node->Level;
  128. }
  129. visited.insert(current);
  130. ui32 maxLevel = 0;
  131. bool hasOutputs = false;
  132. for (auto& child : ctx.Inputs) {
  133. auto findPtr = basicNodesMap.FindPtr(child);
  134. YQL_ENSURE(findPtr);
  135. auto& childCtx = *findPtr;
  136. hasOutputs = hasOutputs || !childCtx.Outputs.empty();
  137. maxLevel = Max(maxLevel, FillLevels(basicNodesMap, child, visited));
  138. }
  139. ctx.Node->Level = maxLevel + (hasOutputs ? 2 : 1);
  140. for (auto& child : ctx.Outputs) {
  141. auto findPtr = basicNodesMap.FindPtr(child);
  142. YQL_ENSURE(findPtr);
  143. auto& childCtx = *findPtr;
  144. childCtx.Node->Level = ctx.Node->Level + 1;
  145. }
  146. visited.erase(current);
  147. return ctx.Node->Level;
  148. }
  149. }
  150. class TPlanBuilder : public IPlanBuilder {
  151. public:
  152. TPlanBuilder(TTypeAnnotationContext& types)
  153. : Types_(types)
  154. {}
  155. void WritePlan(NYson::TYsonWriter& writer, const TExprNode::TPtr& root, const TPlanSettings& settings) override {
  156. if (!root) {
  157. return;
  158. }
  159. TNodeMap<TNodeInfo> nodes;
  160. TExprNode::TListType order;
  161. TProviderInfoMap providers;
  162. writer.OnBeginMap();
  163. writer.OnKeyedItem("Detailed");
  164. writer.OnBeginMap();
  165. writer.OnKeyedItem("Operations");
  166. writer.OnBeginList();
  167. VisitNode(root, nodes, order);
  168. ui32 lastId = 0;
  169. TVector<TBasicNode> basicNodes;
  170. TVector<TBasicLink> basicLinks;
  171. TMap<TString, ui32> opStats;
  172. for (auto node : order) {
  173. auto& info = nodes.find(node.Get())->second;
  174. if (!info.IsVisible) {
  175. continue;
  176. }
  177. lastId = info.NodeId;
  178. writer.OnListItem();
  179. writer.OnBeginMap();
  180. writer.OnKeyedItem("Id");
  181. writer.OnUint64Scalar(info.NodeId);
  182. writer.OnKeyedItem("Name");
  183. writer.OnStringScalar(node->Content());
  184. opStats[TString(node->Content())] += 1;
  185. if (info.Provider) {
  186. TVector<TPinInfo> inputs;
  187. TVector<TPinInfo> outputs;
  188. info.InputsCount = info.Provider->GetPlanFormatter().GetInputs(*node, inputs, settings.WithLimits);
  189. info.OutputsCount = info.Provider->GetPlanFormatter().GetOutputs(*node, outputs, settings.WithLimits);
  190. if (info.InputsCount) {
  191. writer.OnKeyedItem("InputsCount");
  192. writer.OnUint64Scalar(info.InputsCount);
  193. }
  194. if (info.OutputsCount) {
  195. writer.OnKeyedItem("OutputsCount");
  196. writer.OnUint64Scalar(info.OutputsCount);
  197. }
  198. WritePins("Inputs", inputs, writer, info.Inputs, providers);
  199. WritePins("Outputs", outputs, writer, info.Outputs, providers);
  200. info.Provider->GetPlanFormatter().WritePlanDetails(*info.Node, writer, settings.WithLimits);
  201. }
  202. TSet<ui64> dependsOn;
  203. for (auto child : info.Dependencies) {
  204. GatherDependencies(*child, nodes, dependsOn);
  205. }
  206. if (!dependsOn.empty()) {
  207. writer.OnKeyedItem("DependsOn");
  208. writer.OnBeginList();
  209. for (auto childId : dependsOn) {
  210. writer.OnListItem();
  211. writer.OnUint64Scalar(childId);
  212. }
  213. writer.OnEndList();
  214. }
  215. writer.OnEndMap();
  216. }
  217. writer.OnEndList();
  218. writer.OnKeyedItem("OperationRoot");
  219. writer.OnUint64Scalar(lastId);
  220. WriteProviders("Providers", providers, writer);
  221. writer.OnKeyedItem("OperationStats");
  222. writer.OnBeginMap();
  223. for (auto& x : opStats) {
  224. writer.OnKeyedItem(x.first);
  225. writer.OnUint64Scalar(x.second);
  226. }
  227. writer.OnEndMap();
  228. writer.OnEndMap();
  229. BuildBasicGraph(nodes, order, lastId, basicNodes, basicLinks);
  230. writer.OnKeyedItem("Basic");
  231. writer.OnBeginMap();
  232. writer.OnKeyedItem("nodes");
  233. writer.OnBeginList();
  234. for (auto& basicNode : basicNodes) {
  235. writer.OnListItem();
  236. writer.OnBeginMap();
  237. writer.OnKeyedItem("id");
  238. writer.OnUint64Scalar(basicNode.Id);
  239. writer.OnKeyedItem("level");
  240. writer.OnUint64Scalar(basicNode.Level);
  241. writer.OnKeyedItem("name");
  242. writer.OnStringScalar(basicNode.DisplayName);
  243. writer.OnKeyedItem("type");
  244. switch (basicNode.Type) {
  245. case TBasicNode::EType::Operation:
  246. writer.OnStringScalar("op");
  247. break;
  248. case TBasicNode::EType::Input:
  249. writer.OnStringScalar("in");
  250. break;
  251. case TBasicNode::EType::Output:
  252. writer.OnStringScalar("out");
  253. break;
  254. default:
  255. YQL_ENSURE(false, "Unsupported node type");
  256. }
  257. writer.OnEndMap();
  258. }
  259. writer.OnEndList();
  260. writer.OnKeyedItem("links");
  261. writer.OnBeginList();
  262. for (auto& basicLink : basicLinks) {
  263. writer.OnListItem();
  264. writer.OnBeginMap();
  265. writer.OnKeyedItem("source");
  266. writer.OnUint64Scalar(basicLink.Source);
  267. writer.OnKeyedItem("target");
  268. writer.OnUint64Scalar(basicLink.Target);
  269. writer.OnEndMap();
  270. }
  271. writer.OnEndList();
  272. writer.OnEndMap();
  273. writer.OnEndMap();
  274. }
  275. void VisitCallable(const TExprNode::TPtr& node, TNodeMap<TNodeInfo>& nodes, TExprNode::TListType& order) {
  276. if (nodes.cend() != nodes.find(node.Get())) {
  277. return;
  278. }
  279. auto& translatedId = Types_.NodeToOperationId[node->UniqueId()];
  280. if (translatedId == 0) {
  281. translatedId = ++NextId_;
  282. }
  283. auto& info = nodes.emplace(node.Get(), TNodeInfo(translatedId, node.Get())).first->second;
  284. TExprNode::TListType& dependencies = info.Dependencies;
  285. if (node->Content() == CommitName) {
  286. dependencies.push_back(node->Child(0));
  287. auto dataSinkName = node->Child(1)->Child(0)->Content();
  288. auto datasink = Types_.DataSinkMap.FindPtr(dataSinkName);
  289. YQL_ENSURE(datasink);
  290. info.Provider = (*datasink).Get();
  291. info.IsVisible = dataSinkName != ResultProviderName;
  292. }
  293. else if (node->ChildrenSize() >= 2 && node->Child(1)->IsCallable("DataSource")) {
  294. auto dataSourceName = node->Child(1)->Child(0)->Content();
  295. auto datasource = Types_.DataSourceMap.FindPtr(dataSourceName);
  296. YQL_ENSURE(datasource);
  297. info.Provider = (*datasource).Get();
  298. info.IsVisible = (*datasource)->GetPlanFormatter().GetDependencies(*node, dependencies, true);
  299. }
  300. else if (node->ChildrenSize() >= 2 && node->Child(1)->IsCallable("DataSink")) {
  301. auto dataSinkName = node->Child(1)->Child(0)->Content();
  302. auto datasink = Types_.DataSinkMap.FindPtr(dataSinkName);
  303. YQL_ENSURE(datasink);
  304. info.Provider = (*datasink).Get();
  305. info.IsVisible = (*datasink)->GetPlanFormatter().GetDependencies(*node, dependencies, true);
  306. }
  307. else if (node->IsCallable("DqStage") ||
  308. node->IsCallable("DqPhyStage") ||
  309. node->IsCallable("DqQuery!") ||
  310. node->ChildrenSize() >= 1 && node->Child(0)->IsCallable("TDqOutput")) {
  311. auto provider = Types_.DataSinkMap.FindPtr(DqProviderName);
  312. YQL_ENSURE(provider);
  313. info.Provider = (*provider).Get();
  314. info.IsVisible = (*provider)->GetPlanFormatter().GetDependencies(*node, dependencies, true);
  315. } else {
  316. info.IsVisible = false;
  317. for (auto& child : node->Children()) {
  318. dependencies.push_back(child.Get());
  319. }
  320. }
  321. for (const auto& child : dependencies) {
  322. VisitNode(child, nodes, order);
  323. }
  324. order.push_back(node);
  325. }
  326. void VisitNode(const TExprNode::TPtr& node, TNodeMap<TNodeInfo>& nodes,
  327. TExprNode::TListType& order) {
  328. switch (node->Type()) {
  329. case TExprNode::Atom:
  330. case TExprNode::List:
  331. case TExprNode::World:
  332. case TExprNode::Lambda:
  333. case TExprNode::Argument:
  334. case TExprNode::Arguments:
  335. return;
  336. case TExprNode::Callable:
  337. VisitCallable(node, nodes, order);
  338. break;
  339. }
  340. }
  341. void GatherDependencies(const TExprNode& node,
  342. const TNodeMap<TNodeInfo>& nodes, TSet<ui64>& dependsOn) {
  343. const auto info = nodes.find(&node);
  344. if (nodes.cend() == info)
  345. return;
  346. if (info->second.IsVisible) {
  347. dependsOn.insert(info->second.NodeId);
  348. return;
  349. }
  350. for (auto child : info->second.Dependencies) {
  351. GatherDependencies(*child, nodes, dependsOn);
  352. }
  353. }
  354. void BuildBasicGraph(
  355. const TNodeMap<TNodeInfo>& nodes, const TExprNode::TListType& order,
  356. ui32 root, TVector<TBasicNode>& basicNodes, TVector<TBasicLink>& basicLinks) {
  357. THashMap<TPinKey, ui32, TPinKey::THash> allInputs;
  358. THashMap<TPinKey, ui32, TPinKey::THash> allOutputs;
  359. for (auto node : order) {
  360. const auto found = nodes.find(node.Get());
  361. YQL_ENSURE(found != nodes.cend());
  362. auto& info = found->second;
  363. if (!info.IsVisible) {
  364. continue;
  365. }
  366. if (info.Provider) {
  367. for (auto& input : info.Inputs) {
  368. if (input.Info.HideInBasicPlan) {
  369. continue;
  370. }
  371. auto inputKey = TPinKey{ input.ProviderId, input.PinId, TBasicNode::EType::Input };
  372. if (allInputs.contains(inputKey)) {
  373. continue;
  374. }
  375. auto& translatedId = PinMap_[inputKey];
  376. if (translatedId == 0) {
  377. translatedId = ++NextId_;
  378. }
  379. TBasicNode basicNode;
  380. basicNode.Level = 0;
  381. basicNode.Type = TBasicNode::EType::Input;
  382. basicNode.DisplayName = input.Info.DisplayName;
  383. basicNode.Id = translatedId;
  384. basicNodes.push_back(basicNode);
  385. allInputs[inputKey] = basicNode.Id;
  386. }
  387. for (auto& output : info.Outputs) {
  388. if (output.Info.HideInBasicPlan) {
  389. continue;
  390. }
  391. auto outputKey = TPinKey{ output.ProviderId, output.PinId, TBasicNode::EType::Output };
  392. if (allOutputs.contains(outputKey)) {
  393. continue;
  394. }
  395. auto& translatedId = PinMap_[outputKey];
  396. if (translatedId == 0) {
  397. translatedId = ++NextId_;
  398. }
  399. TBasicNode basicNode;
  400. basicNode.Level = 0;
  401. basicNode.Type = TBasicNode::EType::Output;
  402. basicNode.DisplayName = output.Info.DisplayName;
  403. basicNode.Id = translatedId;
  404. basicNodes.push_back(basicNode);
  405. allOutputs[outputKey] = basicNode.Id;
  406. }
  407. }
  408. }
  409. for (auto node : order) {
  410. auto& info = nodes.find(node.Get())->second;
  411. if (!info.IsVisible) {
  412. continue;
  413. }
  414. TBasicNode basicNode;
  415. basicNode.Level = 0;
  416. basicNode.Type = TBasicNode::EType::Operation;
  417. TStringBuilder builder;
  418. builder << info.Provider->GetPlanFormatter().GetOperationDisplayName(*node);
  419. if (info.InputsCount > 1) {
  420. builder << ", in " << info.InputsCount;
  421. }
  422. if (info.OutputsCount > 1) {
  423. builder << ", out " << info.OutputsCount;
  424. }
  425. basicNode.DisplayName = builder;
  426. basicNode.Id = info.NodeId;
  427. basicNodes.push_back(basicNode);
  428. for (auto& input : info.Inputs) {
  429. auto inputKey = TPinKey{ input.ProviderId, input.PinId, TBasicNode::EType::Input };
  430. auto foundInput = allInputs.FindPtr(inputKey);
  431. if (foundInput) {
  432. basicLinks.push_back(TBasicLink(*foundInput, info.NodeId));
  433. }
  434. }
  435. for (auto& output : info.Outputs) {
  436. auto outputKey = TPinKey{ output.ProviderId, output.PinId, TBasicNode::EType::Output };
  437. auto foundOutput = allOutputs.FindPtr(outputKey);
  438. if (foundOutput) {
  439. basicLinks.push_back(TBasicLink(info.NodeId, *foundOutput));
  440. }
  441. }
  442. TSet<ui64> dependsOn;
  443. for (auto child : info.Dependencies) {
  444. GatherDependencies(*child, nodes, dependsOn);
  445. }
  446. for (auto& prevOp : dependsOn) {
  447. basicLinks.push_back(TBasicLink(prevOp, info.NodeId));
  448. }
  449. }
  450. THashMap<ui32, TLevelContext> basicNodesMap;
  451. for (auto& node : basicNodes) {
  452. basicNodesMap.insert({ node.Id, TLevelContext(&node) });
  453. }
  454. for (auto& link : basicLinks) {
  455. basicNodesMap[link.Target].Inputs.push_back(link.Source);
  456. auto target = basicNodesMap.FindPtr(link.Target);
  457. YQL_ENSURE(target);
  458. if (target->Node->Type == TBasicNode::EType::Output) {
  459. basicNodesMap[link.Source].Outputs.push_back(link.Target);
  460. }
  461. }
  462. if (root) {
  463. THashSet<ui32> visited;
  464. FillLevels(basicNodesMap, root, visited);
  465. }
  466. }
  467. void UpdateProviders(TProviderInfoMap& providers, const TExprNode* node, IDataProvider* provider) {
  468. auto path = provider->GetPlanFormatter().GetProviderPath(*node);
  469. if (providers.FindPtr(path)) {
  470. return;
  471. }
  472. ui32 providerId = 0;
  473. if (auto p = ProviderIds_.FindPtr(path)) {
  474. providerId = *p;
  475. } else {
  476. providerId = static_cast<ui32>(ProviderIds_.size() + 1);
  477. ProviderIds_.insert({path, providerId});
  478. }
  479. providers.insert(std::make_pair(path, TProviderInfo(providerId, node, provider)));
  480. }
  481. void UpdateProviders(TProviderInfoMap& providers, const TVector<TPinInfo>& pins) {
  482. for (auto& pin : pins) {
  483. if (pin.DataSource) {
  484. auto providerName = pin.DataSource->Child(0)->Content();
  485. auto providerPtr = Types_.DataSourceMap.FindPtr(providerName);
  486. YQL_ENSURE(providerPtr);
  487. UpdateProviders(providers, pin.DataSource, providerPtr->Get());
  488. }
  489. if (pin.DataSink) {
  490. auto providerName = pin.DataSink->Child(0)->Content();
  491. auto providerPtr = Types_.DataSinkMap.FindPtr(providerName);
  492. YQL_ENSURE(providerPtr);
  493. UpdateProviders(providers, pin.DataSink, providerPtr->Get());
  494. }
  495. }
  496. }
  497. IDataProvider& GetProvider(const TPinInfo& pin, TTypeAnnotationContext& types) {
  498. if (pin.DataSource) {
  499. auto providerName = pin.DataSource->Child(0)->Content();
  500. auto providerPtr = types.DataSourceMap.FindPtr(providerName);
  501. YQL_ENSURE(providerPtr && *providerPtr);
  502. return **providerPtr;
  503. }
  504. if (pin.DataSink) {
  505. auto providerName = pin.DataSink->Child(0)->Content();
  506. auto providerPtr = types.DataSinkMap.FindPtr(providerName);
  507. YQL_ENSURE(providerPtr && *providerPtr);
  508. return **providerPtr;
  509. }
  510. YQL_ENSURE(false, "Expected either datasource or sink");
  511. }
  512. TProviderInfo& FindProvider(TProviderInfoMap& providers, const TPinInfo& pin) const {
  513. if (pin.DataSource) {
  514. auto providerName = pin.DataSource->Child(0)->Content();
  515. auto providerPtr = Types_.DataSourceMap.FindPtr(providerName);
  516. YQL_ENSURE(providerPtr && *providerPtr);
  517. auto infoPtr = providers.FindPtr((*providerPtr)->GetPlanFormatter().GetProviderPath(*pin.DataSource));
  518. YQL_ENSURE(infoPtr);
  519. return *infoPtr;
  520. }
  521. if (pin.DataSink) {
  522. auto providerName = pin.DataSink->Child(0)->Content();
  523. auto providerPtr = Types_.DataSinkMap.FindPtr(providerName);
  524. YQL_ENSURE(providerPtr && *providerPtr);
  525. auto infoPtr = providers.FindPtr((*providerPtr)->GetPlanFormatter().GetProviderPath(*pin.DataSink));
  526. YQL_ENSURE(infoPtr);
  527. return *infoPtr;
  528. }
  529. YQL_ENSURE(false, "Expected either datasource or sink");
  530. }
  531. void WritePins(const TString& tag, const TVector<TPinInfo>& pins, NYson::TYsonWriter& writer,
  532. TVector<TPinAttrs>& pinAttrs, TProviderInfoMap& providers) {
  533. if (!pins.empty()) {
  534. UpdateProviders(providers, pins);
  535. writer.OnKeyedItem(tag);
  536. writer.OnBeginList();
  537. for (auto pin : pins) {
  538. TPinAttrs attrs(pin);
  539. auto& info = FindProvider(providers, pin);
  540. attrs.ProviderId = info.Id;
  541. writer.OnListItem();
  542. writer.OnBeginList();
  543. writer.OnListItem();
  544. writer.OnUint64Scalar(info.Id);
  545. if (pin.Key) {
  546. auto p = info.Pin.insert(std::make_pair(pin.Key, static_cast<ui32>(info.Pin.size() + 1)));
  547. if (p.second) {
  548. info.PinOrder.push_back(pin.Key);
  549. }
  550. writer.OnListItem();
  551. writer.OnUint64Scalar(p.first->second);
  552. attrs.PinId = p.first->second;
  553. }
  554. writer.OnEndList();
  555. pinAttrs.push_back(attrs);
  556. }
  557. writer.OnEndList();
  558. }
  559. }
  560. void Clear() override {
  561. Types_.NodeToOperationId.clear();
  562. PinMap_.clear();
  563. ProviderIds_.clear();
  564. NextId_ = 0;
  565. }
  566. private:
  567. TTypeAnnotationContext& Types_;
  568. THashMap<TPinKey, ui32, TPinKey::THash> PinMap_;
  569. TMap<TString, ui32> ProviderIds_;
  570. ui32 NextId_ = 0;
  571. };
  572. TAutoPtr<IPlanBuilder> CreatePlanBuilder(TTypeAnnotationContext& types) {
  573. return new TPlanBuilder(types);
  574. }
  575. }