@@ -51,6 +51,50 @@ class TSchemeGetter: public TActorBootstrapped<TSchemeGetter> {
5151 return errorType == S3Errors::RESOURCE_NOT_FOUND || errorType == S3Errors::NO_SUCH_KEY;
5252 }
5353
54+ static TString ChangefeedDescriptionKey (const TString& changefeedPrefix) {
55+ return TStringBuilder () << changefeedPrefix << " /changefeed_description.pb" ;
56+ }
57+
58+ static TString TopicDescriptionKey (const TString& changefeedPrefix) {
59+ return TStringBuilder () << changefeedPrefix << " /topic_description.pb" ;
60+ }
61+
62+ void ListObjects (const TString& prefix) {
63+ auto request = Model::ListObjectsRequest ()
64+ .WithPrefix (prefix);
65+
66+ Send (Client, new TEvExternalStorage::TEvListObjectsRequest (request));
67+ }
68+
69+ void HandleChangefeeds (TEvExternalStorage::TEvListObjectsResponse::TPtr& ev) {
70+ const auto & result = ev.Get ()->Get ()->Result ;
71+
72+ LOG_D (" HandleChangefeeds TEvExternalStorage::TEvListObjectResponse"
73+ << " : self# " << SelfId ()
74+ << " , result# " << result);
75+
76+ if (!CheckResult (result, " ListObject" )) {
77+ return ;
78+ }
79+
80+ const auto & objects = result.GetResult ().GetContents ();
81+ ChangefeedsKeys.reserve (objects.size ());
82+
83+ for (const auto & obj : objects) {
84+ const TFsPath& path = obj.GetKey ();
85+ if (path.GetName () == " changefeed_description.pb" ) {
86+ ChangefeedsKeys.push_back (path.Dirname ());
87+ }
88+ }
89+
90+ if (!ChangefeedsKeys.empty ()) {
91+ HeadObject (ChangefeedDescriptionKey (ChangefeedsKeys[0 ]));
92+ } else {
93+ Reply ();
94+ }
95+
96+ }
97+
5498 void HeadObject (const TString& key) {
5599 auto request = Model::HeadObjectRequest ()
56100 .WithKey (key);
@@ -128,6 +172,36 @@ class TSchemeGetter: public TActorBootstrapped<TSchemeGetter> {
128172 GetObject (ChecksumKey, std::make_pair (0 , contentLength - 1 ));
129173 }
130174
175+ void HandleChangefeed (TEvExternalStorage::TEvHeadObjectResponse::TPtr& ev) {
176+ const auto & result = ev->Get ()->Result ;
177+
178+ LOG_D (" HandleChangefeed TEvExternalStorage::TEvHeadObjectResponse"
179+ << " : self# " << SelfId ()
180+ << " , result# " << result);
181+
182+ if (!CheckResult (result, " HeadObject" )) {
183+ return ;
184+ }
185+
186+ const auto contentLength = result.GetResult ().GetContentLength ();
187+ GetObject (ChangefeedDescriptionKey (ChangefeedsKeys[IndexDownloadedChangefeed]), std::make_pair (0 , contentLength - 1 ));
188+ }
189+
190+ void HandleTopic (TEvExternalStorage::TEvHeadObjectResponse::TPtr& ev) {
191+ const auto & result = ev->Get ()->Result ;
192+
193+ LOG_D (" HandleTopic TEvExternalStorage::TEvHeadObjectResponse"
194+ << " : self# " << SelfId ()
195+ << " , result# " << result);
196+
197+ if (!CheckResult (result, " HeadObject" )) {
198+ return ;
199+ }
200+
201+ const auto contentLength = result.GetResult ().GetContentLength ();
202+ GetObject (TopicDescriptionKey (ChangefeedsKeys[IndexDownloadedChangefeed]), std::make_pair (0 , contentLength - 1 ));
203+ }
204+
131205 void GetObject (const TString& key, const std::pair<ui64, ui64>& range) {
132206 auto request = Model::GetObjectRequest ()
133207 .WithKey (key)
@@ -205,7 +279,7 @@ class TSchemeGetter: public TActorBootstrapped<TSchemeGetter> {
205279 if (NeedDownloadPermissions) {
206280 StartDownloadingPermissions ();
207281 } else {
208- Reply ();
282+ StartDownloadingChangefeeds ();
209283 }
210284 };
211285
@@ -242,7 +316,7 @@ class TSchemeGetter: public TActorBootstrapped<TSchemeGetter> {
242316 item.Permissions = std::move (permissions);
243317
244318 auto nextStep = [this ]() {
245- Reply ();
319+ StartDownloadingChangefeeds ();
246320 };
247321
248322 if (NeedValidateChecksums) {
@@ -274,6 +348,82 @@ class TSchemeGetter: public TActorBootstrapped<TSchemeGetter> {
274348 ChecksumValidatedCallback ();
275349 }
276350
351+ void HandleChangefeed (TEvExternalStorage::TEvGetObjectResponse::TPtr& ev) {
352+ const auto & msg = *ev->Get ();
353+ const auto & result = msg.Result ;
354+
355+ LOG_D (" HandleChangefeed TEvExternalStorage::TEvGetObjectResponse"
356+ << " : self# " << SelfId ()
357+ << " , result# " << result);
358+
359+ if (!CheckResult (result, " GetObject" )) {
360+ return ;
361+ }
362+
363+ Y_ABORT_UNLESS (ItemIdx < ImportInfo->Items .size ());
364+ auto & item = ImportInfo->Items .at (ItemIdx);
365+
366+ LOG_T (" Trying to parse changefeed"
367+ << " : self# " << SelfId ()
368+ << " , body# " << SubstGlobalCopy (msg.Body , " \n " , " \\ n" ));
369+
370+ Ydb::Table::ChangefeedDescription changefeed;
371+ if (!google::protobuf::TextFormat::ParseFromString (msg.Body , &changefeed)) {
372+ return Reply (false , " Cannot parse сhangefeed" );
373+ }
374+ item.Changefeeds [IndexDownloadedChangefeed].ChangefeedDescription = std::move (changefeed);
375+
376+ auto nextStep = [this ]() {
377+ HeadObject (TopicDescriptionKey (ChangefeedsKeys[IndexDownloadedChangefeed]));
378+ };
379+
380+ if (NeedValidateChecksums) {
381+ StartValidatingChecksum (ChangefeedDescriptionKey (ChangefeedsKeys[IndexDownloadedChangefeed]), msg.Body , nextStep);
382+ } else {
383+ nextStep ();
384+ }
385+ }
386+
387+ void HandleTopic (TEvExternalStorage::TEvGetObjectResponse::TPtr& ev) {
388+ const auto & msg = *ev->Get ();
389+ const auto & result = msg.Result ;
390+
391+ LOG_D (" HandleTopic TEvExternalStorage::TEvGetObjectResponse"
392+ << " : self# " << SelfId ()
393+ << " , result# " << result);
394+
395+ if (!CheckResult (result, " GetObject" )) {
396+ return ;
397+ }
398+
399+ Y_ABORT_UNLESS (ItemIdx < ImportInfo->Items .size ());
400+ auto & item = ImportInfo->Items .at (ItemIdx);
401+
402+ LOG_T (" Trying to parse topic"
403+ << " : self# " << SelfId ()
404+ << " , body# " << SubstGlobalCopy (msg.Body , " \n " , " \\ n" ));
405+
406+ Ydb::Topic::DescribeTopicResult topic;
407+ if (!google::protobuf::TextFormat::ParseFromString (msg.Body , &topic)) {
408+ return Reply (false , " Cannot parse topic" );
409+ }
410+ item.Changefeeds [IndexDownloadedChangefeed].Topic = std::move (topic);
411+
412+ auto nextStep = [this ]() {
413+ if (++IndexDownloadedChangefeed == ChangefeedsKeys.size ()) {
414+ Reply ();
415+ } else {
416+ HeadObject (ChangefeedDescriptionKey (ChangefeedsKeys[IndexDownloadedChangefeed]));
417+ }
418+ };
419+
420+ if (NeedValidateChecksums) {
421+ StartValidatingChecksum (TopicDescriptionKey (ChangefeedsKeys[IndexDownloadedChangefeed]), msg.Body , nextStep);
422+ } else {
423+ nextStep ();
424+ }
425+ }
426+
277427 template <typename TResult>
278428 bool CheckResult (const TResult& result, const TStringBuf marker) {
279429 if (result.IsSuccess ()) {
@@ -312,12 +462,20 @@ class TSchemeGetter: public TActorBootstrapped<TSchemeGetter> {
312462 TActor::PassAway ();
313463 }
314464
315- void Download ( const TString& key ) {
465+ void DownloadCommon ( ) {
316466 if (Client) {
317467 Send (Client, new TEvents::TEvPoisonPill ());
318468 }
319469 Client = RegisterWithSameMailbox (CreateS3Wrapper (ExternalStorageConfig->ConstructStorageOperator ()));
470+ }
471+
472+ void DownloadWithoutKey () {
473+ DownloadCommon ();
474+ ListObjects (ImportInfo->Settings .items (ItemIdx).source_prefix ());
475+ }
320476
477+ void Download (const TString& key) {
478+ DownloadCommon ();
321479 HeadObject (key);
322480 }
323481
@@ -337,6 +495,10 @@ class TSchemeGetter: public TActorBootstrapped<TSchemeGetter> {
337495 Download (ChecksumKey);
338496 }
339497
498+ void DownloadChangefeeds () {
499+ DownloadWithoutKey ();
500+ }
501+
340502 void ResetRetries () {
341503 Attempt = 0 ;
342504 }
@@ -353,6 +515,12 @@ class TSchemeGetter: public TActorBootstrapped<TSchemeGetter> {
353515 Become (&TThis::StateDownloadPermissions);
354516 }
355517
518+ void StartDownloadingChangefeeds () {
519+ ResetRetries ();
520+ DownloadChangefeeds ();
521+ Become (&TThis::StateDownloadChangefeeds);
522+ }
523+
356524 void StartValidatingChecksum (const TString& key, const TString& object, std::function<void ()> checksumValidatedCallback) {
357525 ChecksumKey = NBackup::ChecksumKey (key);
358526 Checksum = NBackup::ComputeChecksum (object);
@@ -413,6 +581,17 @@ class TSchemeGetter: public TActorBootstrapped<TSchemeGetter> {
413581 }
414582 }
415583
584+ STATEFN (StateDownloadChangefeeds) {
585+ switch (ev->GetTypeRewrite ()) {
586+ hFunc (TEvExternalStorage::TEvListObjectsResponse, HandleChangefeeds);
587+ hFunc (TEvExternalStorage::TEvHeadObjectResponse, HandleChangefeed);
588+ hFunc (TEvExternalStorage::TEvGetObjectResponse, HandleChangefeed);
589+
590+ sFunc (TEvents::TEvWakeup, DownloadChangefeeds);
591+ sFunc (TEvents::TEvPoisonPill, PassAway);
592+ }
593+ }
594+
416595 STATEFN (StateDownloadChecksum) {
417596 switch (ev->GetTypeRewrite ()) {
418597 hFunc (TEvExternalStorage::TEvHeadObjectResponse, HandleChecksum);
@@ -432,6 +611,8 @@ class TSchemeGetter: public TActorBootstrapped<TSchemeGetter> {
432611 const TString MetadataKey;
433612 TString SchemeKey;
434613 const TString PermissionsKey;
614+ TVector<TString> ChangefeedsKeys;
615+ ui64 IndexDownloadedChangefeed = 0 ;
435616
436617 const ui32 Retries;
437618 ui32 Attempt = 0 ;
0 commit comments