8
8
9
9
package org .opensearch .index .remote ;
10
10
11
+ import org .apache .logging .log4j .Logger ;
12
+ import org .apache .logging .log4j .message .ParameterizedMessage ;
13
+ import org .opensearch .common .CheckedFunction ;
14
+ import org .opensearch .common .logging .Loggers ;
11
15
import org .opensearch .core .common .io .stream .StreamInput ;
12
16
import org .opensearch .core .common .io .stream .StreamOutput ;
13
17
import org .opensearch .core .common .io .stream .Writeable ;
18
22
import org .opensearch .index .store .DirectoryFileTransferTracker ;
19
23
20
24
import java .io .IOException ;
21
- import java .util .HashMap ;
25
+ import java .util .Collection ;
26
+ import java .util .Collections ;
22
27
import java .util .HashSet ;
23
28
import java .util .Map ;
24
29
import java .util .Set ;
25
30
import java .util .concurrent .atomic .AtomicLong ;
26
31
import java .util .concurrent .atomic .AtomicReference ;
27
32
import java .util .stream .Collectors ;
28
33
34
+ import static org .opensearch .index .shard .RemoteStoreRefreshListener .EXCLUDE_FILES ;
35
+
29
36
/**
30
37
* Keeps track of remote refresh which happens in {@link org.opensearch.index.shard.RemoteStoreRefreshListener}. This consist of multiple critical metrics.
31
38
*
32
39
* @opensearch.internal
33
40
*/
34
41
public class RemoteSegmentTransferTracker {
35
42
43
+ private final Logger logger ;
44
+
36
45
/**
37
46
* ShardId for which this instance tracks the remote segment upload metadata.
38
47
*/
@@ -124,14 +133,15 @@ public class RemoteSegmentTransferTracker {
124
133
private final Map <String , AtomicLong > rejectionCountMap = ConcurrentCollections .newConcurrentMap ();
125
134
126
135
/**
127
- * Map of name to size of the segment files created as part of the most recent refresh.
136
+ * Keeps track of segment files and their size in bytes which are part of the most recent refresh.
128
137
*/
129
- private volatile Map <String , Long > latestLocalFileNameLengthMap ;
138
+ private final Map <String , Long > latestLocalFileNameLengthMap = ConcurrentCollections . newConcurrentMap () ;
130
139
131
140
/**
132
- * Set of names of segment files that were uploaded as part of the most recent remote refresh.
141
+ * This contains the files from the last successful remote refresh and ongoing uploads. This gets reset to just the
142
+ * last successful remote refresh state on successful remote refresh.
133
143
*/
134
- private final Set <String > latestUploadedFiles = new HashSet <> ();
144
+ private final Set <String > latestUploadedFiles = ConcurrentCollections . newConcurrentSet ();
135
145
136
146
/**
137
147
* Keeps the bytes lag computed so that we do not compute it for every request.
@@ -182,6 +192,7 @@ public RemoteSegmentTransferTracker(
182
192
int uploadBytesPerSecMovingAverageWindowSize ,
183
193
int uploadTimeMsMovingAverageWindowSize
184
194
) {
195
+ logger = Loggers .getLogger (getClass (), shardId );
185
196
this .shardId = shardId ;
186
197
// Both the local refresh time and remote refresh time are set with current time to give consistent view of time lag when it arises.
187
198
long currentClockTimeMs = System .currentTimeMillis ();
@@ -193,8 +204,6 @@ public RemoteSegmentTransferTracker(
193
204
uploadBytesMovingAverageReference = new AtomicReference <>(new MovingAverage (uploadBytesMovingAverageWindowSize ));
194
205
uploadBytesPerSecMovingAverageReference = new AtomicReference <>(new MovingAverage (uploadBytesPerSecMovingAverageWindowSize ));
195
206
uploadTimeMsMovingAverageReference = new AtomicReference <>(new MovingAverage (uploadTimeMsMovingAverageWindowSize ));
196
-
197
- latestLocalFileNameLengthMap = new HashMap <>();
198
207
this .directoryFileTransferTracker = directoryFileTransferTracker ;
199
208
}
200
209
@@ -206,7 +215,8 @@ public long getLocalRefreshSeqNo() {
206
215
return localRefreshSeqNo ;
207
216
}
208
217
209
- public void updateLocalRefreshSeqNo (long localRefreshSeqNo ) {
218
+ // Visible for testing
219
+ void updateLocalRefreshSeqNo (long localRefreshSeqNo ) {
210
220
assert localRefreshSeqNo >= this .localRefreshSeqNo : "newLocalRefreshSeqNo="
211
221
+ localRefreshSeqNo
212
222
+ " < "
@@ -224,7 +234,17 @@ public long getLocalRefreshClockTimeMs() {
224
234
return localRefreshClockTimeMs ;
225
235
}
226
236
227
- public void updateLocalRefreshTimeMs (long localRefreshTimeMs ) {
237
+ /**
238
+ * Updates the last refresh time and refresh seq no which is seen by local store.
239
+ */
240
+ public void updateLocalRefreshTimeAndSeqNo () {
241
+ updateLocalRefreshClockTimeMs (System .currentTimeMillis ());
242
+ updateLocalRefreshTimeMs (System .nanoTime () / 1_000_000L );
243
+ updateLocalRefreshSeqNo (getLocalRefreshSeqNo () + 1 );
244
+ }
245
+
246
+ // Visible for testing
247
+ void updateLocalRefreshTimeMs (long localRefreshTimeMs ) {
228
248
assert localRefreshTimeMs >= this .localRefreshTimeMs : "newLocalRefreshTimeMs="
229
249
+ localRefreshTimeMs
230
250
+ " < "
@@ -234,7 +254,7 @@ public void updateLocalRefreshTimeMs(long localRefreshTimeMs) {
234
254
computeTimeMsLag ();
235
255
}
236
256
237
- public void updateLocalRefreshClockTimeMs (long localRefreshClockTimeMs ) {
257
+ private void updateLocalRefreshClockTimeMs (long localRefreshClockTimeMs ) {
238
258
this .localRefreshClockTimeMs = localRefreshClockTimeMs ;
239
259
}
240
260
@@ -369,12 +389,36 @@ long getRejectionCount(String rejectionReason) {
369
389
return rejectionCountMap .get (rejectionReason ).get ();
370
390
}
371
391
372
- Map <String , Long > getLatestLocalFileNameLengthMap () {
373
- return latestLocalFileNameLengthMap ;
392
+ public Map <String , Long > getLatestLocalFileNameLengthMap () {
393
+ return Collections . unmodifiableMap ( latestLocalFileNameLengthMap ) ;
374
394
}
375
395
376
- public void setLatestLocalFileNameLengthMap (Map <String , Long > latestLocalFileNameLengthMap ) {
377
- this .latestLocalFileNameLengthMap = latestLocalFileNameLengthMap ;
396
+ /**
397
+ * Updates the latestLocalFileNameLengthMap by adding file name and it's size to the map. The method is given a function as an argument which is used for determining the file size (length in bytes). This method is also provided the collection of segment files which are the latest refresh local segment files. This method also removes the stale segment files from the map that are not part of the input segment files.
398
+ *
399
+ * @param segmentFiles list of local refreshed segment files
400
+ * @param fileSizeFunction function is used to determine the file size in bytes
401
+ */
402
+ public void updateLatestLocalFileNameLengthMap (
403
+ Collection <String > segmentFiles ,
404
+ CheckedFunction <String , Long , IOException > fileSizeFunction
405
+ ) {
406
+ // Update the map
407
+ segmentFiles .stream ()
408
+ .filter (file -> EXCLUDE_FILES .contains (file ) == false )
409
+ .filter (file -> latestLocalFileNameLengthMap .containsKey (file ) == false || latestLocalFileNameLengthMap .get (file ) == 0 )
410
+ .forEach (file -> {
411
+ long fileSize = 0 ;
412
+ try {
413
+ fileSize = fileSizeFunction .apply (file );
414
+ } catch (IOException e ) {
415
+ logger .warn (new ParameterizedMessage ("Exception while reading the fileLength of file={}" , file ), e );
416
+ }
417
+ latestLocalFileNameLengthMap .put (file , fileSize );
418
+ });
419
+ Set <String > fileSet = new HashSet <>(segmentFiles );
420
+ // Remove keys from the fileSizeMap that do not exist in the latest segment files
421
+ latestLocalFileNameLengthMap .entrySet ().removeIf (entry -> fileSet .contains (entry .getKey ()) == false );
378
422
computeBytesLag ();
379
423
}
380
424
@@ -390,7 +434,7 @@ public void setLatestUploadedFiles(Set<String> files) {
390
434
}
391
435
392
436
private void computeBytesLag () {
393
- if (latestLocalFileNameLengthMap == null || latestLocalFileNameLengthMap .isEmpty ()) {
437
+ if (latestLocalFileNameLengthMap .isEmpty ()) {
394
438
return ;
395
439
}
396
440
Set <String > filesNotYetUploaded = latestLocalFileNameLengthMap .keySet ()
0 commit comments