2424import org .elasticsearch .common .collect .ImmutableOpenMap ;
2525import org .elasticsearch .common .component .AbstractLifecycleComponent ;
2626import org .elasticsearch .common .io .stream .StreamInput ;
27+ import org .elasticsearch .common .metrics .CounterMetric ;
2728import org .elasticsearch .common .settings .Settings ;
2829import org .elasticsearch .common .unit .ByteSizeValue ;
30+ import org .elasticsearch .common .util .CombinedRateLimiter ;
2931import org .elasticsearch .index .Index ;
3032import org .elasticsearch .index .IndexSettings ;
3133import org .elasticsearch .index .engine .EngineException ;
4951import org .elasticsearch .snapshots .SnapshotState ;
5052import org .elasticsearch .xpack .ccr .Ccr ;
5153import org .elasticsearch .xpack .ccr .CcrLicenseChecker ;
54+ import org .elasticsearch .xpack .ccr .CcrSettings ;
5255import org .elasticsearch .xpack .ccr .action .CcrRequests ;
5356import org .elasticsearch .xpack .ccr .action .repositories .ClearCcrRestoreSessionAction ;
5457import org .elasticsearch .xpack .ccr .action .repositories .ClearCcrRestoreSessionRequest ;
6669import java .util .List ;
6770import java .util .Map ;
6871import java .util .Set ;
72+ import java .util .function .LongConsumer ;
6973
7074/**
7175 * This repository relies on a remote cluster for Ccr restores. It is read-only so it can only be used to
@@ -79,12 +83,17 @@ public class CcrRepository extends AbstractLifecycleComponent implements Reposit
7983 private static final SnapshotId SNAPSHOT_ID = new SnapshotId (LATEST , LATEST );
8084
8185 private final RepositoryMetaData metadata ;
86+ private final CcrSettings ccrSettings ;
8287 private final String remoteClusterAlias ;
8388 private final Client client ;
8489 private final CcrLicenseChecker ccrLicenseChecker ;
8590
86- public CcrRepository (RepositoryMetaData metadata , Client client , CcrLicenseChecker ccrLicenseChecker , Settings settings ) {
91+ private final CounterMetric throttledTime = new CounterMetric ();
92+
93+ public CcrRepository (RepositoryMetaData metadata , Client client , CcrLicenseChecker ccrLicenseChecker , Settings settings ,
94+ CcrSettings ccrSettings ) {
8795 this .metadata = metadata ;
96+ this .ccrSettings = ccrSettings ;
8897 assert metadata .name ().startsWith (NAME_PREFIX ) : "CcrRepository metadata.name() must start with: " + NAME_PREFIX ;
8998 this .remoteClusterAlias = Strings .split (metadata .name (), NAME_PREFIX )[1 ];
9099 this .ccrLicenseChecker = ccrLicenseChecker ;
@@ -206,7 +215,7 @@ public long getSnapshotThrottleTimeInNanos() {
206215
207216 @ Override
208217 public long getRestoreThrottleTimeInNanos () {
209- return 0 ;
218+ return throttledTime . count () ;
210219 }
211220
212221 @ Override
@@ -257,7 +266,7 @@ public void restoreShard(IndexShard indexShard, SnapshotId snapshotId, Version v
257266 // TODO: There should be some local timeout. And if the remote cluster returns an unknown session
258267 // response, we should be able to retry by creating a new session.
259268 String name = metadata .name ();
260- try (RestoreSession restoreSession = RestoreSession . openSession (name , remoteClient , leaderShardId , indexShard , recoveryState )) {
269+ try (RestoreSession restoreSession = openSession (name , remoteClient , leaderShardId , indexShard , recoveryState )) {
261270 restoreSession .restoreFiles ();
262271 } catch (Exception e ) {
263272 throw new IndexShardRestoreFailedException (indexShard .shardId (), "failed to restore snapshot [" + snapshotId + "]" , e );
@@ -285,6 +294,15 @@ private void maybeUpdateMappings(Client localClient, Client remoteClient, Index
285294 }
286295 }
287296
297+ private RestoreSession openSession (String repositoryName , Client remoteClient , ShardId leaderShardId , IndexShard indexShard ,
298+ RecoveryState recoveryState ) {
299+ String sessionUUID = UUIDs .randomBase64UUID ();
300+ PutCcrRestoreSessionAction .PutCcrRestoreSessionResponse response = remoteClient .execute (PutCcrRestoreSessionAction .INSTANCE ,
301+ new PutCcrRestoreSessionRequest (sessionUUID , leaderShardId )).actionGet ();
302+ return new RestoreSession (repositoryName , remoteClient , sessionUUID , response .getNode (), indexShard , recoveryState ,
303+ response .getStoreFileMetaData (), ccrSettings .getRateLimiter (), throttledTime ::inc );
304+ }
305+
288306 private static class RestoreSession extends FileRestoreContext implements Closeable {
289307
290308 private static final int BUFFER_SIZE = 1 << 16 ;
@@ -293,23 +311,19 @@ private static class RestoreSession extends FileRestoreContext implements Closea
293311 private final String sessionUUID ;
294312 private final DiscoveryNode node ;
295313 private final Store .MetadataSnapshot sourceMetaData ;
314+ private final CombinedRateLimiter rateLimiter ;
315+ private final LongConsumer throttleListener ;
296316
297317 RestoreSession (String repositoryName , Client remoteClient , String sessionUUID , DiscoveryNode node , IndexShard indexShard ,
298- RecoveryState recoveryState , Store .MetadataSnapshot sourceMetaData ) {
318+ RecoveryState recoveryState , Store .MetadataSnapshot sourceMetaData , CombinedRateLimiter rateLimiter ,
319+ LongConsumer throttleListener ) {
299320 super (repositoryName , indexShard , SNAPSHOT_ID , recoveryState , BUFFER_SIZE );
300321 this .remoteClient = remoteClient ;
301322 this .sessionUUID = sessionUUID ;
302323 this .node = node ;
303324 this .sourceMetaData = sourceMetaData ;
304- }
305-
306- static RestoreSession openSession (String repositoryName , Client remoteClient , ShardId leaderShardId , IndexShard indexShard ,
307- RecoveryState recoveryState ) {
308- String sessionUUID = UUIDs .randomBase64UUID ();
309- PutCcrRestoreSessionAction .PutCcrRestoreSessionResponse response = remoteClient .execute (PutCcrRestoreSessionAction .INSTANCE ,
310- new PutCcrRestoreSessionRequest (sessionUUID , leaderShardId )).actionGet ();
311- return new RestoreSession (repositoryName , remoteClient , sessionUUID , response .getNode (), indexShard , recoveryState ,
312- response .getStoreFileMetaData ());
325+ this .rateLimiter = rateLimiter ;
326+ this .throttleListener = throttleListener ;
313327 }
314328
315329 void restoreFiles () throws IOException {
@@ -324,7 +338,7 @@ void restoreFiles() throws IOException {
324338
325339 @ Override
326340 protected InputStream fileInputStream (BlobStoreIndexShardSnapshot .FileInfo fileInfo ) {
327- return new RestoreFileInputStream (remoteClient , sessionUUID , node , fileInfo .metadata ());
341+ return new RestoreFileInputStream (remoteClient , sessionUUID , node , fileInfo .metadata (), rateLimiter , throttleListener );
328342 }
329343
330344 @ Override
@@ -341,14 +355,19 @@ private static class RestoreFileInputStream extends InputStream {
341355 private final String sessionUUID ;
342356 private final DiscoveryNode node ;
343357 private final StoreFileMetaData fileToRecover ;
358+ private final CombinedRateLimiter rateLimiter ;
359+ private final LongConsumer throttleListener ;
344360
345361 private long pos = 0 ;
346362
347- private RestoreFileInputStream (Client remoteClient , String sessionUUID , DiscoveryNode node , StoreFileMetaData fileToRecover ) {
363+ private RestoreFileInputStream (Client remoteClient , String sessionUUID , DiscoveryNode node , StoreFileMetaData fileToRecover ,
364+ CombinedRateLimiter rateLimiter , LongConsumer throttleListener ) {
348365 this .remoteClient = remoteClient ;
349366 this .sessionUUID = sessionUUID ;
350367 this .node = node ;
351368 this .fileToRecover = fileToRecover ;
369+ this .rateLimiter = rateLimiter ;
370+ this .throttleListener = throttleListener ;
352371 }
353372
354373
@@ -365,6 +384,10 @@ public int read(byte[] bytes, int off, int len) throws IOException {
365384 }
366385
367386 int bytesRequested = (int ) Math .min (remainingBytes , len );
387+
388+ long nanosPaused = rateLimiter .maybePause (bytesRequested );
389+ throttleListener .accept (nanosPaused );
390+
368391 String fileName = fileToRecover .name ();
369392 GetCcrRestoreFileChunkRequest request = new GetCcrRestoreFileChunkRequest (node , sessionUUID , fileName , bytesRequested );
370393 GetCcrRestoreFileChunkAction .GetCcrRestoreFileChunkResponse response =
@@ -388,5 +411,6 @@ public int read(byte[] bytes, int off, int len) throws IOException {
388411
389412 return bytesReceived ;
390413 }
414+
391415 }
392416}
0 commit comments