keith-turner commented on code in PR #4494: URL: https://github.com/apache/accumulo/pull/4494#discussion_r1595645395
########## core/src/main/java/org/apache/accumulo/core/util/time/SteadyTime.java: ########## @@ -0,0 +1,80 @@ +/* + * 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 + * + * https://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.accumulo.core.util.time; + +import java.time.Duration; +import java.util.Objects; + +import com.google.common.base.Preconditions; + +/** + * SteadyTime represents an approximation of the total duration of time this cluster has had a + * Manager. Because this represents an elapsed time it is guaranteed to not be negative. Review Comment: ```suggestion * Manager. Because this represents an elapsed time it is guaranteed to not be negative. SteadyTime * is not expected to represent real world date times, its main use is for computing deltas similar System.nanoTime but across JVM processes. ``` ########## core/src/main/java/org/apache/accumulo/core/util/time/SteadyTime.java: ########## @@ -0,0 +1,80 @@ +/* + * 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 + * + * https://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.accumulo.core.util.time; + +import java.time.Duration; +import java.util.Objects; + +import com.google.common.base.Preconditions; + +/** + * SteadyTime represents an approximation of the total duration of time this cluster has had a + * Manager. Because this represents an elapsed time it is guaranteed to not be negative. + */ +public class SteadyTime implements Comparable<SteadyTime> { + + private final Duration time; + + private SteadyTime(Duration time) { + Preconditions.checkArgument(!time.isNegative(), "SteadyTime should not be negative."); + this.time = time; + } + + public long getMillis() { + return time.toMillis(); + } + + public long getNanos() { + return time.toNanos(); + } + + public Duration getDuration() { + return time; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SteadyTime that = (SteadyTime) o; + return Objects.equals(time, that.time); + } + + @Override + public int hashCode() { + return Objects.hashCode(time); + } + + @Override + public int compareTo(SteadyTime other) { + return time.compareTo(other.time); + } + + public static SteadyTime from(long timeNs) { Review Comment: Times w/ units decrease the chance of writing time related bugs. ```suggestion public static SteadyTime from(long time, TimeUnit unit) { ``` ########## server/manager/src/test/java/org/apache/accumulo/manager/ManagerTimeTest.java: ########## @@ -0,0 +1,128 @@ +/* + * 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 + * + * https://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.accumulo.manager; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; + +import org.apache.accumulo.core.util.time.SteadyTime; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +public class ManagerTimeTest { + + @Test + public void testSteadyTime() { + long time = 20_000; + var steadyTime = SteadyTime.from(time); + + // make sure calling serialize on instance matches static helper + byte[] serialized = ManagerTime.serialize(steadyTime); + assertArrayEquals(serialized, ManagerTime.serialize(steadyTime)); + + // Verify deserialization matches original object + var deserialized = ManagerTime.deserialize(serialized); + assertEquals(steadyTime, deserialized); + assertEquals(0, steadyTime.compareTo(deserialized)); + } + + @ParameterizedTest + // Test with both a 0 and positive previous value. This simulates the value + // read out of zookeeper for the time and should never be negative as it is + // based on elapsed time from previous manager runs + @ValueSource(longs = {0, 50_000}) + public void testSteadyTimeFromSkew(long previousTime) throws InterruptedException { + List<Long> times = List.of(-100_000L, -100L, 0L, 20_000L, System.nanoTime()); + + for (Long time : times) { + // ManagerTime builds the skew amount by subtracting the current nanotime + // from the previous persisted time in ZK. The skew can be negative or positive because + // it will depend on if the current nanotime is negative or positive as + // nanotime is allowed to be negative + var skewAmount = ManagerTime.updateSkew(SteadyTime.from(previousTime), time); + + // Build a SteadyTime using the skewAmount + // SteadyTime should never be negative + var original = ManagerTime.fromSkew(time, skewAmount); + + // Simulate a future time and create another SteadyTime from the skew which should + // now be after the original + time = time + 10000; + var futureSkew = ManagerTime.fromSkew(time, skewAmount); + + // future should be after the original + assertTrue(futureSkew.compareTo(original) > 0); + } + } + + @ParameterizedTest + // Test with both a 0 and positive previous value. This simulates the value + // read out of zookeeper for the time and should never be negative as it is + // based on elapsed time from previous manager runs + @ValueSource(longs = {0, 50_000}) + public void testSteadyTimeFromSkewCurrent(long previousTime) throws InterruptedException { + // Also test fromSkew(skewAmount) method which only uses System.nanoTime() + var skewAmount = ManagerTime.updateSkew(SteadyTime.from(previousTime)); + + // Build a SteadyTime using the skewAmount and current time + var original = ManagerTime.fromSkew(skewAmount); Review Comment: Do you know if manager time should ever expect a negative skew? I have not looked into this, just wondering if you know based on looking at the code. If not sure I can look into it and see if preconditions and test for negative skew durations would be useful. ########## server/manager/src/main/java/org/apache/accumulo/manager/TabletGroupWatcher.java: ########## @@ -1386,7 +1386,7 @@ private void handleDeadTablets(TabletLists tLists, WalStateManager wals) deadTablets.subList(0, maxServersToShow)); Manager.log.debug("logs for dead servers: {}", deadLogs); if (canSuspendTablets()) { - store.suspend(deadTablets, deadLogs, manager.getSteadyTime()); + store.suspend(deadTablets, deadLogs, manager.getSteadyTime().getMillis()); Review Comment: It would be nice to push this new type down to Ample. Could do that by modifying `Ample.TabletMutator.putSuspension()` and `SuspendingTServer.suspensionTime` to use the new type. Could be a follow on issue, not sure what the fan out for that change is. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
