12
12
package org .opensearch .timeseries .indices ;
13
13
14
14
import static org .opensearch .core .xcontent .XContentParserUtils .ensureExpectedToken ;
15
+ import static org .opensearch .forecast .constant .ForecastCommonName .CUSTOM_RESULT_INDEX_PREFIX ;
15
16
import static org .opensearch .timeseries .util .RestHandlerUtils .createXContentParserFromRegistry ;
16
17
17
18
import java .io .IOException ;
51
52
import org .opensearch .action .search .SearchRequest ;
52
53
import org .opensearch .action .support .GroupedActionListener ;
53
54
import org .opensearch .action .support .IndicesOptions ;
55
+ import org .opensearch .ad .constant .ADCommonName ;
54
56
import org .opensearch .client .AdminClient ;
55
57
import org .opensearch .client .Client ;
56
58
import org .opensearch .cluster .LocalNodeClusterManagerListener ;
66
68
import org .opensearch .core .action .ActionListener ;
67
69
import org .opensearch .core .common .Strings ;
68
70
import org .opensearch .core .common .bytes .BytesArray ;
71
+ import org .opensearch .core .common .unit .ByteSizeUnit ;
72
+ import org .opensearch .core .common .unit .ByteSizeValue ;
69
73
import org .opensearch .core .xcontent .NamedXContentRegistry ;
70
74
import org .opensearch .core .xcontent .XContentParser ;
71
75
import org .opensearch .core .xcontent .XContentParser .Token ;
@@ -298,7 +302,8 @@ protected void deleteOldHistoryIndices(String indexPattern, TimeValue historyRet
298
302
long latest = Long .MIN_VALUE ;
299
303
for (IndexMetadata indexMetaData : clusterStateResponse .getState ().metadata ().indices ().values ()) {
300
304
long creationTime = indexMetaData .getCreationDate ();
301
- if ((Instant .now ().toEpochMilli () - creationTime ) > historyRetentionPeriod .millis ()) {
305
+ long indexAgeMillis = Instant .now ().toEpochMilli () - creationTime ;
306
+ if (indexAgeMillis > historyRetentionPeriod .millis ()) {
302
307
String indexName = indexMetaData .getIndex ().getName ();
303
308
candidates .add (indexName );
304
309
if (latest < creationTime ) {
@@ -1077,7 +1082,7 @@ public void onClusterManager() {
1077
1082
1078
1083
// schedule the next rollover for approx MAX_AGE later
1079
1084
scheduledRollover = threadPool
1080
- .scheduleWithFixedDelay (() -> rolloverAndDeleteHistoryIndex (), historyRolloverPeriod , executorName ());
1085
+ .scheduleWithFixedDelay (() -> rolloverAndDeleteHistoryIndex (), TimeValue . timeValueMinutes ( 1 ) , executorName ());
1081
1086
} catch (Exception e ) {
1082
1087
// This should be run on cluster startup
1083
1088
logger .error ("Error rollover result indices. " + "Can't rollover result until clusterManager node is restarted." , e );
@@ -1100,6 +1105,7 @@ protected void rescheduleRollover() {
1100
1105
if (scheduledRollover != null ) {
1101
1106
scheduledRollover .cancel ();
1102
1107
}
1108
+
1103
1109
scheduledRollover = threadPool
1104
1110
.scheduleWithFixedDelay (() -> rolloverAndDeleteHistoryIndex (), historyRolloverPeriod , executorName ());
1105
1111
}
@@ -1234,35 +1240,109 @@ protected void rolloverAndDeleteHistoryIndex(
1234
1240
String rolloverIndexPattern ,
1235
1241
IndexType resultIndex
1236
1242
) {
1237
- if (!doesDefaultResultIndexExist ()) {
1238
- return ;
1243
+ // build rollover request for default result index
1244
+ RolloverRequest defaultResultIndexRolloverRequest = buildRolloverRequest (resultIndexAlias , rolloverIndexPattern );
1245
+ defaultResultIndexRolloverRequest .addMaxIndexDocsCondition (historyMaxDocs * getNumberOfPrimaryShards ());
1246
+
1247
+ // get config files that have custom result index alias to perform rollover on
1248
+ getConfigsWithCustomResultIndexAlias (ActionListener .wrap (candidateResultAliases -> {
1249
+ if (candidateResultAliases == null || candidateResultAliases .isEmpty ()) {
1250
+ // no custom result index alias found
1251
+ if (!doesDefaultResultIndexExist ()) {
1252
+ // no default result index found either
1253
+ return ;
1254
+ }
1255
+ // perform rollover and delete on default result index
1256
+ proceedWithDefaultRolloverAndDelete (
1257
+ resultIndexAlias ,
1258
+ defaultResultIndexRolloverRequest ,
1259
+ allResultIndicesPattern ,
1260
+ resultIndex
1261
+ );
1262
+ logger .info ("Candidate custom result indices are empty." );
1263
+ return ;
1264
+ }
1265
+
1266
+ // perform rollover and delete on found custom result index alias
1267
+ candidateResultAliases .forEach (config -> handleCustomResultIndex (config , resultIndex ));
1268
+
1269
+ }, e -> {
1270
+ logger .error ("Failed to get configs with custom result index alias." , e );
1271
+ // perform rollover and delete on default result index if getting error on getting custom result index alias
1272
+ proceedWithDefaultRolloverAndDelete (resultIndexAlias , defaultResultIndexRolloverRequest , allResultIndicesPattern , resultIndex );
1273
+ }));
1274
+ }
1275
+
1276
+ private void handleCustomResultIndex (Config config , IndexType resultIndex ) {
1277
+ RolloverRequest rolloverRequest = buildRolloverRequest (
1278
+ config .getCustomResultIndexOrAlias (),
1279
+ getCustomResultIndexPattern (config .getCustomResultIndexOrAlias ())
1280
+ );
1281
+
1282
+ // add rollover conditions if found in config
1283
+ if (config .getCustomResultIndexMinAge () != null ) {
1284
+ rolloverRequest .addMaxIndexAgeCondition (TimeValue .timeValueDays (config .getCustomResultIndexMinAge ()));
1285
+ }
1286
+ if (config .getCustomResultIndexMinSize () != null ) {
1287
+ rolloverRequest .addMaxIndexSizeCondition (new ByteSizeValue (config .getCustomResultIndexMinSize (), ByteSizeUnit .MB ));
1239
1288
}
1240
1289
1241
- // We have to pass null for newIndexName in order to get Elastic to increment the index count.
1242
- RolloverRequest rollOverRequest = new RolloverRequest (resultIndexAlias , null );
1290
+ // perform rollover and delete on custom result index alias
1291
+ proceedWithRolloverAndDelete (
1292
+ config .getCustomResultIndexOrAlias (),
1293
+ rolloverRequest ,
1294
+ getAllCustomResultIndexPattern (config .getCustomResultIndexOrAlias ()),
1295
+ resultIndex ,
1296
+ config .getCustomResultIndexTTL ()
1297
+ );
1298
+ }
1243
1299
1300
+ private void proceedWithDefaultRolloverAndDelete (
1301
+ String resultIndexAlias ,
1302
+ RolloverRequest rolloverRequest ,
1303
+ String allResultIndicesPattern ,
1304
+ IndexType resultIndex
1305
+ ) {
1306
+ proceedWithRolloverAndDelete (resultIndexAlias , rolloverRequest , allResultIndicesPattern , resultIndex , null );
1307
+ }
1308
+
1309
+ private RolloverRequest buildRolloverRequest (String resultIndexAlias , String rolloverIndexPattern ) {
1310
+ RolloverRequest rollOverRequest = new RolloverRequest (resultIndexAlias , null );
1244
1311
CreateIndexRequest createRequest = rollOverRequest .getCreateIndexRequest ();
1245
1312
1246
1313
createRequest .index (rolloverIndexPattern ).mapping (resultMapping , XContentType .JSON );
1247
-
1248
1314
choosePrimaryShards (createRequest , true );
1249
1315
1250
- rollOverRequest .addMaxIndexDocsCondition (historyMaxDocs * getNumberOfPrimaryShards ());
1316
+ return rollOverRequest ;
1317
+ }
1318
+
1319
+ private void proceedWithRolloverAndDelete (
1320
+ String resultIndexAlias ,
1321
+ RolloverRequest rollOverRequest ,
1322
+ String allResultIndicesPattern ,
1323
+ IndexType resultIndex ,
1324
+ Integer customResultIndexTtl
1325
+ ) {
1251
1326
adminClient .indices ().rolloverIndex (rollOverRequest , ActionListener .wrap (response -> {
1252
1327
if (!response .isRolledOver ()) {
1253
1328
logger .warn ("{} not rolled over. Conditions were: {}" , resultIndexAlias , response .getConditionStatus ());
1254
1329
} else {
1255
- IndexState indexStatetate = indexStates .computeIfAbsent (resultIndex , k -> new IndexState (k .getMapping ()));
1256
- indexStatetate .mappingUpToDate = true ;
1330
+ IndexState indexState = indexStates .computeIfAbsent (resultIndex , k -> new IndexState (k .getMapping ()));
1331
+ indexState .mappingUpToDate = true ;
1257
1332
logger .info ("{} rolled over. Conditions were: {}" , resultIndexAlias , response .getConditionStatus ());
1258
- deleteOldHistoryIndices (allResultIndicesPattern , historyRetentionPeriod );
1333
+ if (resultIndexAlias .startsWith (ADCommonName .CUSTOM_RESULT_INDEX_PREFIX )
1334
+ || resultIndexAlias .startsWith (CUSTOM_RESULT_INDEX_PREFIX )) {
1335
+ // handle custom result index deletion
1336
+ if (customResultIndexTtl != null ) {
1337
+ deleteOldHistoryIndices (allResultIndicesPattern , TimeValue .timeValueHours (customResultIndexTtl * 24 ));
1338
+
1339
+ }
1340
+ } else {
1341
+ // handle default result index deletion
1342
+ deleteOldHistoryIndices (allResultIndicesPattern , historyRetentionPeriod );
1343
+ }
1259
1344
}
1260
- }, exception -> {
1261
- // e.g., we may roll over too often. Since the index pattern is opensearch-ad-plugin-result-d-history-{now/d}-000001,
1262
- // we cannot roll over twice in the same day as the index with the same name exists. We will get
1263
- // resource_already_exists_exception.
1264
- logger .error ("Fail to roll over result index" , exception );
1265
- }));
1345
+ }, exception -> { logger .error ("Fail to roll over result index" , exception ); }));
1266
1346
}
1267
1347
1268
1348
protected void initResultIndexDirectly (
0 commit comments