This is an automated email from the ASF dual-hosted git repository. kharekartik pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/pinot.git
The following commit(s) were added to refs/heads/master by this push: new 692d78c112 Add TablePauseStatus to track the pause details (#13803) 692d78c112 is described below commit 692d78c1120c411feabfe378d276ee0adec1f68c Author: Shounak kulkarni <shounakmk...@gmail.com> AuthorDate: Wed Aug 21 10:36:43 2024 +0500 Add TablePauseStatus to track the pause details (#13803) * Add table pause status container to track the pause details * deprecate IS_TABLE_PAUSED * fix * Allow passing comment for resuming ingestion * Avoid the confusion on description field in APIs * refactor PauseStatus * refactors * revert to consumingSegments * fix naming --- .../{PauseStatus.java => PauseStatusDetails.java} | 29 ++++++-- .../api/resources/PinotRealtimeTableResource.java | 11 ++- .../controller/helix/ControllerRequestClient.java | 14 ++-- .../controller/helix/SegmentStatusChecker.java | 2 +- .../realtime/PinotLLCRealtimeSegmentManager.java | 82 ++++++++++++++++------ ...PartialUpsertTableRebalanceIntegrationTest.java | 6 +- .../apache/pinot/spi/config/table/PauseState.java | 75 ++++++++++++++++++++ 7 files changed, 178 insertions(+), 41 deletions(-) diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PauseStatus.java b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PauseStatusDetails.java similarity index 65% rename from pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PauseStatus.java rename to pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PauseStatusDetails.java index 9542e70eba..d531ed65e8 100644 --- a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PauseStatus.java +++ b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PauseStatusDetails.java @@ -22,21 +22,28 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.Set; +import org.apache.pinot.spi.config.table.PauseState; @JsonInclude(JsonInclude.Include.NON_NULL) -public class PauseStatus { +public class PauseStatusDetails { private boolean _pauseFlag; private Set<String> _consumingSegments; - private String _description; + private PauseState.ReasonCode _reasonCode; + private String _comment; + private String _timestamp; @JsonCreator - public PauseStatus(@JsonProperty("pauseFlag") boolean pauseFlag, + public PauseStatusDetails(@JsonProperty("pauseFlag") boolean pauseFlag, @JsonProperty("consumingSegments") Set<String> consumingSegments, - @JsonProperty("description") String description) { + @JsonProperty("reasonCode") PauseState.ReasonCode reasonCode, + @JsonProperty("comment") String comment, + @JsonProperty("timestamp") String timestamp) { _pauseFlag = pauseFlag; _consumingSegments = consumingSegments; - _description = description; + _reasonCode = reasonCode; + _comment = comment != null ? comment : pauseFlag ? "Table is paused." : "Table is unpaused."; + _timestamp = timestamp; } public boolean getPauseFlag() { @@ -47,7 +54,15 @@ public class PauseStatus { return _consumingSegments; } - public String getDescription() { - return _description; + public PauseState.ReasonCode getReasonCode() { + return _reasonCode; + } + + public String getComment() { + return _comment; + } + + public String getTimestamp() { + return _timestamp; } } diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotRealtimeTableResource.java b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotRealtimeTableResource.java index 44fc0433e5..2ab15427f7 100644 --- a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotRealtimeTableResource.java +++ b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotRealtimeTableResource.java @@ -57,6 +57,7 @@ import org.apache.pinot.controller.util.ConsumingSegmentInfoReader; import org.apache.pinot.core.auth.Actions; import org.apache.pinot.core.auth.Authorize; import org.apache.pinot.core.auth.TargetType; +import org.apache.pinot.spi.config.table.PauseState; import org.apache.pinot.spi.config.table.TableType; import org.apache.pinot.spi.utils.CommonConstants; import org.apache.pinot.spi.utils.JsonUtils; @@ -103,12 +104,14 @@ public class PinotRealtimeTableResource { @ApiOperation(value = "Pause consumption of a realtime table", notes = "Pause the consumption of a realtime table") public Response pauseConsumption( @ApiParam(value = "Name of the table", required = true) @PathParam("tableName") String tableName, + @ApiParam(value = "Comment on pausing the consumption") @QueryParam("comment") String comment, @Context HttpHeaders headers) { tableName = DatabaseUtils.translateTableName(tableName, headers); String tableNameWithType = TableNameBuilder.REALTIME.tableNameWithType(tableName); validateTable(tableNameWithType); try { - return Response.ok(_pinotLLCRealtimeSegmentManager.pauseConsumption(tableNameWithType)).build(); + return Response.ok(_pinotLLCRealtimeSegmentManager.pauseConsumption(tableNameWithType, + PauseState.ReasonCode.ADMINISTRATIVE, comment)).build(); } catch (Exception e) { throw new ControllerApplicationException(LOGGER, e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR, e); } @@ -125,6 +128,7 @@ public class PinotRealtimeTableResource { + "available offsets are picked to minimize the data loss.") public Response resumeConsumption( @ApiParam(value = "Name of the table", required = true) @PathParam("tableName") String tableName, + @ApiParam(value = "Comment on pausing the consumption") @QueryParam("comment") String comment, @ApiParam( value = "lastConsumed (safer) | smallest (repeat rows) | largest (miss rows)", allowableValues = "lastConsumed, smallest, largest", @@ -143,7 +147,8 @@ public class PinotRealtimeTableResource { + "'largest'.", consumeFrom), Response.Status.BAD_REQUEST); } try { - return Response.ok(_pinotLLCRealtimeSegmentManager.resumeConsumption(tableNameWithType, consumeFrom)).build(); + return Response.ok(_pinotLLCRealtimeSegmentManager.resumeConsumption(tableNameWithType, consumeFrom, + PauseState.ReasonCode.ADMINISTRATIVE, comment)).build(); } catch (Exception e) { throw new ControllerApplicationException(LOGGER, e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR, e); } @@ -246,7 +251,7 @@ public class PinotRealtimeTableResource { String tableNameWithType = TableNameBuilder.REALTIME.tableNameWithType(tableName); validateTable(tableNameWithType); try { - return Response.ok().entity(_pinotLLCRealtimeSegmentManager.getPauseStatus(tableNameWithType)).build(); + return Response.ok().entity(_pinotLLCRealtimeSegmentManager.getPauseStatusDetails(tableNameWithType)).build(); } catch (Exception e) { throw new ControllerApplicationException(LOGGER, e.getMessage(), Response.Status.INTERNAL_SERVER_ERROR, e); } diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/helix/ControllerRequestClient.java b/pinot-controller/src/main/java/org/apache/pinot/controller/helix/ControllerRequestClient.java index 39d553aa65..18676d581d 100644 --- a/pinot-controller/src/main/java/org/apache/pinot/controller/helix/ControllerRequestClient.java +++ b/pinot-controller/src/main/java/org/apache/pinot/controller/helix/ControllerRequestClient.java @@ -31,7 +31,7 @@ import javax.annotation.Nullable; import org.apache.pinot.common.exception.HttpErrorStatusException; import org.apache.pinot.common.utils.SimpleHttpResponse; import org.apache.pinot.common.utils.http.HttpClient; -import org.apache.pinot.controller.api.resources.PauseStatus; +import org.apache.pinot.controller.api.resources.PauseStatusDetails; import org.apache.pinot.spi.config.table.TableConfig; import org.apache.pinot.spi.config.table.TableType; import org.apache.pinot.spi.config.tenant.Tenant; @@ -253,36 +253,36 @@ public class ControllerRequestClient { } } - public PauseStatus pauseConsumption(String tableName) + public PauseStatusDetails pauseConsumption(String tableName) throws IOException { try { SimpleHttpResponse response = HttpClient.wrapAndThrowHttpException( _httpClient.sendJsonPostRequest(new URI(_controllerRequestURLBuilder.forPauseConsumption(tableName)), null, _headers)); - return JsonUtils.stringToObject(response.getResponse(), PauseStatus.class); + return JsonUtils.stringToObject(response.getResponse(), PauseStatusDetails.class); } catch (HttpErrorStatusException | URISyntaxException e) { throw new IOException(e); } } - public PauseStatus resumeConsumption(String tableName) + public PauseStatusDetails resumeConsumption(String tableName) throws IOException { try { SimpleHttpResponse response = HttpClient.wrapAndThrowHttpException( _httpClient.sendJsonPostRequest(new URI(_controllerRequestURLBuilder.forResumeConsumption(tableName)), null, _headers)); - return JsonUtils.stringToObject(response.getResponse(), PauseStatus.class); + return JsonUtils.stringToObject(response.getResponse(), PauseStatusDetails.class); } catch (HttpErrorStatusException | URISyntaxException e) { throw new IOException(e); } } - public PauseStatus getPauseStatus(String tableName) + public PauseStatusDetails getPauseStatusDetails(String tableName) throws IOException { try { SimpleHttpResponse response = HttpClient.wrapAndThrowHttpException( _httpClient.sendGetRequest(new URI(_controllerRequestURLBuilder.forPauseStatus(tableName)), _headers)); - return JsonUtils.stringToObject(response.getResponse(), PauseStatus.class); + return JsonUtils.stringToObject(response.getResponse(), PauseStatusDetails.class); } catch (HttpErrorStatusException | URISyntaxException e) { throw new IOException(e); } diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/helix/SegmentStatusChecker.java b/pinot-controller/src/main/java/org/apache/pinot/controller/helix/SegmentStatusChecker.java index ceb33402e8..a9a2484752 100644 --- a/pinot-controller/src/main/java/org/apache/pinot/controller/helix/SegmentStatusChecker.java +++ b/pinot-controller/src/main/java/org/apache/pinot/controller/helix/SegmentStatusChecker.java @@ -225,7 +225,7 @@ public class SegmentStatusChecker extends ControllerPeriodicTask<SegmentStatusCh return; } - if (Boolean.parseBoolean(idealState.getRecord().getSimpleField(PinotLLCRealtimeSegmentManager.IS_TABLE_PAUSED))) { + if (PinotLLCRealtimeSegmentManager.isTablePaused(idealState)) { context._pausedTables.add(tableNameWithType); } diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/realtime/PinotLLCRealtimeSegmentManager.java b/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/realtime/PinotLLCRealtimeSegmentManager.java index bb331f2bc4..85c5cad0de 100644 --- a/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/realtime/PinotLLCRealtimeSegmentManager.java +++ b/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/realtime/PinotLLCRealtimeSegmentManager.java @@ -18,10 +18,12 @@ */ package org.apache.pinot.controller.helix.core.realtime; +import com.fasterxml.jackson.core.JsonProcessingException; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import java.io.IOException; import java.net.URI; +import java.sql.Timestamp; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -67,7 +69,7 @@ import org.apache.pinot.common.utils.helix.HelixHelper; import org.apache.pinot.controller.ControllerConf; import org.apache.pinot.controller.api.events.MetadataEventNotifierFactory; import org.apache.pinot.controller.api.resources.Constants; -import org.apache.pinot.controller.api.resources.PauseStatus; +import org.apache.pinot.controller.api.resources.PauseStatusDetails; import org.apache.pinot.controller.helix.core.PinotHelixResourceManager; import org.apache.pinot.controller.helix.core.PinotTableIdealStateBuilder; import org.apache.pinot.controller.helix.core.assignment.segment.SegmentAssignment; @@ -87,6 +89,7 @@ import org.apache.pinot.segment.spi.index.metadata.SegmentMetadataImpl; import org.apache.pinot.segment.spi.partition.PartitionFunction; import org.apache.pinot.segment.spi.partition.metadata.ColumnPartitionMetadata; import org.apache.pinot.spi.config.table.ColumnPartitionConfig; +import org.apache.pinot.spi.config.table.PauseState; import org.apache.pinot.spi.config.table.SegmentPartitionConfig; import org.apache.pinot.spi.config.table.SegmentsValidationAndRetentionConfig; import org.apache.pinot.spi.config.table.TableConfig; @@ -107,6 +110,7 @@ import org.apache.pinot.spi.utils.CommonConstants; import org.apache.pinot.spi.utils.CommonConstants.Helix.StateModel.SegmentStateModel; import org.apache.pinot.spi.utils.CommonConstants.Segment.Realtime.Status; import org.apache.pinot.spi.utils.IngestionConfigUtils; +import org.apache.pinot.spi.utils.JsonUtils; import org.apache.pinot.spi.utils.StringUtil; import org.apache.pinot.spi.utils.builder.TableNameBuilder; import org.apache.pinot.spi.utils.retry.RetryPolicies; @@ -133,7 +137,10 @@ import org.slf4j.LoggerFactory; public class PinotLLCRealtimeSegmentManager { // simple field in Ideal State representing pause status for the table + // Deprecated in favour of PAUSE_STATE + @Deprecated public static final String IS_TABLE_PAUSED = "isTablePaused"; + public static final String PAUSE_STATE = "pauseState"; private static final Logger LOGGER = LoggerFactory.getLogger(PinotLLCRealtimeSegmentManager.class); private static final int STARTING_SEQUENCE_NUMBER = 0; // Initial sequence number for new table segments @@ -973,10 +980,29 @@ public class PinotLLCRealtimeSegmentManager { }, RetryPolicies.exponentialBackoffRetryPolicy(10, 1000L, 1.2f)); } - private boolean isTablePaused(IdealState idealState) { + public static boolean isTablePaused(IdealState idealState) { + PauseState pauseState = extractTablePauseState(idealState); + if (pauseState != null) { + return pauseState.isPaused(); + } + // backward compatibility + // TODO : remove this handling after next release. + // Expectation is that all table IS are migrated to the newer representation. return Boolean.parseBoolean(idealState.getRecord().getSimpleField(IS_TABLE_PAUSED)); } + private static PauseState extractTablePauseState(IdealState idealState) { + String pauseStateStr = idealState.getRecord().getSimpleField(PinotLLCRealtimeSegmentManager.PAUSE_STATE); + try { + if (pauseStateStr != null) { + return JsonUtils.stringToObject(pauseStateStr, PauseState.class); + } + } catch (JsonProcessingException e) { + LOGGER.warn("Unable to parse the pause state from ideal state : {}", pauseStateStr); + } + return null; + } + @VisibleForTesting void updateInstanceStatesForNewConsumingSegment(Map<String, Map<String, String>> instanceStatesMap, @Nullable String committingSegmentName, @Nullable String newSegmentName, SegmentAssignment segmentAssignment, @@ -1689,25 +1715,28 @@ public class PinotLLCRealtimeSegmentManager { /** * Pause consumption on a table by - * 1) setting "isTablePaused" in ideal states to true and + * 1) update PauseState in the table ideal state and * 2) sending force commit messages to servers */ - public PauseStatus pauseConsumption(String tableNameWithType) { - IdealState updatedIdealState = updatePauseStatusInIdealState(tableNameWithType, true); + public PauseStatusDetails pauseConsumption(String tableNameWithType, PauseState.ReasonCode reasonCode, + @Nullable String comment) { + IdealState updatedIdealState = updatePauseStateInIdealState(tableNameWithType, true, reasonCode, comment); Set<String> consumingSegments = findConsumingSegments(updatedIdealState); sendForceCommitMessageToServers(tableNameWithType, consumingSegments); - return new PauseStatus(true, consumingSegments, consumingSegments.isEmpty() ? null : "Pause flag is set." - + " Consuming segments are being committed." - + " Use /pauseStatus endpoint in a few moments to check if all consuming segments have been committed."); + return new PauseStatusDetails(true, consumingSegments, reasonCode, comment != null ? comment + : "Pause flag is set. Consuming segments are being committed." + + " Use /pauseStatus endpoint in a few moments to check if all consuming segments have been committed.", + new Timestamp(System.currentTimeMillis()).toString()); } /** * Resume consumption on a table by - * 1) setting "isTablePaused" in ideal states to false and + * 1) update PauseState by clearing all pause reasons in the table ideal state and * 2) triggering segment validation job to create new consuming segments in ideal states */ - public PauseStatus resumeConsumption(String tableNameWithType, @Nullable String offsetCriteria) { - IdealState updatedIdealState = updatePauseStatusInIdealState(tableNameWithType, false); + public PauseStatusDetails resumeConsumption(String tableNameWithType, @Nullable String offsetCriteria, + PauseState.ReasonCode reasonCode, @Nullable String comment) { + IdealState updatedIdealState = updatePauseStateInIdealState(tableNameWithType, false, reasonCode, comment); // trigger realtime segment validation job to resume consumption Map<String, String> taskProperties = new HashMap<>(); @@ -1718,17 +1747,24 @@ public class PinotLLCRealtimeSegmentManager { _helixResourceManager .invokeControllerPeriodicTask(tableNameWithType, Constants.REALTIME_SEGMENT_VALIDATION_MANAGER, taskProperties); - return new PauseStatus(false, findConsumingSegments(updatedIdealState), "Pause flag is cleared. " - + "Consuming segments are being created. Use /pauseStatus endpoint in a few moments to double check."); + return new PauseStatusDetails(false, findConsumingSegments(updatedIdealState), reasonCode, + comment != null ? comment : "Pause flag is cleared. Consuming segments are being created. Use /pauseStatus " + + "endpoint in a few moments to double check.", new Timestamp(System.currentTimeMillis()).toString()); } - private IdealState updatePauseStatusInIdealState(String tableNameWithType, boolean pause) { + private IdealState updatePauseStateInIdealState(String tableNameWithType, boolean pause, + PauseState.ReasonCode reasonCode, @Nullable String comment) { + PauseState pauseState = new PauseState(pause, reasonCode, comment, + new Timestamp(System.currentTimeMillis()).toString()); IdealState updatedIdealState = HelixHelper.updateIdealState(_helixManager, tableNameWithType, idealState -> { ZNRecord znRecord = idealState.getRecord(); + znRecord.setSimpleField(PAUSE_STATE, pauseState.toJsonString()); + // maintain for backward compatibility znRecord.setSimpleField(IS_TABLE_PAUSED, Boolean.valueOf(pause).toString()); return new IdealState(znRecord); - }, RetryPolicies.noDelayRetryPolicy(1)); - LOGGER.info("Set 'isTablePaused' to {} in the Ideal State for table {}.", pause, tableNameWithType); + }, RetryPolicies.noDelayRetryPolicy(3)); + LOGGER.info("Set 'pauseState' to {} in the Ideal State for table {}. " + + "Also set 'isTablePaused' to {} for backward compatibility.", pauseState, tableNameWithType, pause); return updatedIdealState; } @@ -1767,14 +1803,20 @@ public class PinotLLCRealtimeSegmentManager { /** * Return pause status: - * - the value of `isTablePaused` flag in ideal state + * - Information from the 'pauseState' in the table ideal state * - list of consuming segments */ - public PauseStatus getPauseStatus(String tableNameWithType) { + public PauseStatusDetails getPauseStatusDetails(String tableNameWithType) { IdealState idealState = getIdealState(tableNameWithType); - String isTablePausedStr = idealState.getRecord().getSimpleField(IS_TABLE_PAUSED); Set<String> consumingSegments = findConsumingSegments(idealState); - return new PauseStatus(Boolean.parseBoolean(isTablePausedStr), consumingSegments, null); + PauseState pauseState = extractTablePauseState(idealState); + if (pauseState != null) { + return new PauseStatusDetails(pauseState.isPaused(), consumingSegments, pauseState.getReasonCode(), + pauseState.getComment(), pauseState.getTimeInMillis()); + } + String isTablePausedStr = idealState.getRecord().getSimpleField(IS_TABLE_PAUSED); + return new PauseStatusDetails(Boolean.parseBoolean(isTablePausedStr), consumingSegments, + PauseState.ReasonCode.ADMINISTRATIVE, null, ""); } @VisibleForTesting diff --git a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/PartialUpsertTableRebalanceIntegrationTest.java b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/PartialUpsertTableRebalanceIntegrationTest.java index 6f3bd9659d..d62c8fee40 100644 --- a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/PartialUpsertTableRebalanceIntegrationTest.java +++ b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/PartialUpsertTableRebalanceIntegrationTest.java @@ -36,7 +36,7 @@ import org.apache.pinot.common.utils.LLCSegmentName; import org.apache.pinot.common.utils.SimpleHttpResponse; import org.apache.pinot.common.utils.helix.HelixHelper; import org.apache.pinot.common.utils.http.HttpClient; -import org.apache.pinot.controller.api.resources.PauseStatus; +import org.apache.pinot.controller.api.resources.PauseStatusDetails; import org.apache.pinot.controller.api.resources.ServerRebalanceJobStatusResponse; import org.apache.pinot.controller.api.resources.ServerReloadControllerJobStatusResponse; import org.apache.pinot.controller.helix.core.PinotHelixResourceManager; @@ -192,8 +192,8 @@ public class PartialUpsertTableRebalanceIntegrationTest extends BaseClusterInteg getControllerRequestClient().pauseConsumption(realtimeTableName); TestUtils.waitForCondition((aVoid) -> { try { - PauseStatus pauseStatus = getControllerRequestClient().getPauseStatus(realtimeTableName); - return pauseStatus.getConsumingSegments().isEmpty(); + PauseStatusDetails pauseStatusDetails = getControllerRequestClient().getPauseStatusDetails(realtimeTableName); + return pauseStatusDetails.getConsumingSegments().isEmpty(); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/pinot-spi/src/main/java/org/apache/pinot/spi/config/table/PauseState.java b/pinot-spi/src/main/java/org/apache/pinot/spi/config/table/PauseState.java new file mode 100644 index 0000000000..2a71d480fe --- /dev/null +++ b/pinot-spi/src/main/java/org/apache/pinot/spi/config/table/PauseState.java @@ -0,0 +1,75 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pinot.spi.config.table; + +import org.apache.pinot.spi.config.BaseJsonConfig; + + +public class PauseState extends BaseJsonConfig { + private boolean _paused; + private ReasonCode _reasonCode; + private String _comment; + private String _timestamp; + + public PauseState() { + } + + public PauseState(boolean paused, ReasonCode reasonCode, String comment, String timestamp) { + _paused = paused; + _reasonCode = reasonCode; + _comment = comment; + _timestamp = timestamp; + } + + public boolean isPaused() { + return _paused; + } + + public ReasonCode getReasonCode() { + return _reasonCode; + } + + public String getComment() { + return _comment; + } + + public String getTimeInMillis() { + return _timestamp; + } + + public void setPaused(boolean paused) { + _paused = paused; + } + + public void setReasonCode(ReasonCode reasonCode) { + _reasonCode = reasonCode; + } + + public void setComment(String comment) { + _comment = comment; + } + + public void setTimeInMillis(String timestamp) { + _timestamp = timestamp; + } + + public enum ReasonCode { + ADMINISTRATIVE + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org For additional commands, e-mail: commits-h...@pinot.apache.org