@Test public void throwsIfBoundUnexpectedlyChangedUnderUs() { PaxosTimestampBoundStore additionalStore = createPaxosTimestampBoundStore(1); additionalStore.storeUpperLimit(TIMESTAMP_1); assertThatThrownBy(() -> store.storeUpperLimit(TIMESTAMP_2)) .isInstanceOf(NotCurrentLeaderException.class); }
@Override public synchronized void storeUpperLimit(long limit) throws MultipleRunningTimestampServiceError { long newSeq = PaxosAcceptor.NO_LOG_ENTRY + 1; if (agreedState != null) { Preconditions.checkArgument(limit >= agreedState.getBound(), "Tried to store an upper limit %s less than the current limit %s", limit, agreedState.getBound()); newSeq = agreedState.getSeqId() + 1; } while (true) { try { proposer.propose(newSeq, PtBytes.toBytes(limit)); PaxosValue value = knowledge.getLearnedValue(newSeq) .orElseThrow(() -> new SafeIllegalStateException("Timestamp bound store: Paxos proposal" + " returned without learning a value. This is unexpected and would suggest a bug in" + " AtlasDB code. Please contact support.")); checkAgreedBoundIsOurs(limit, newSeq, value); long newLimit = PtBytes.toLong(value.getData()); agreedState = ImmutableSequenceAndBound.of(newSeq, newLimit); if (newLimit < limit) { log.warn("It appears we updated the timestamp limit to {}, which was less than our target {}." + " This suggests we have another timestamp service running; possibly because we" + " lost and regained leadership. For safety, we are now stopping this service.", SafeArg.of("newLimit", newLimit), SafeArg.of("target", limit)); throw new NotCurrentLeaderException(String.format( "We updated the timestamp limit to %s, which was less than our target %s.", newLimit, limit)); } return; } catch (PaxosRoundFailureException e) { waitForRandomBackoff(e, this::wait); } } }
PaxosTimestampBoundStore implements TimestampBoundStore { @Override public synchronized void storeUpperLimit(long limit) throws MultipleRunningTimestampServiceError { long newSeq = PaxosAcceptor.NO_LOG_ENTRY + 1; if (agreedState != null) { Preconditions.checkArgument(limit >= agreedState.getBound(), "Tried to store an upper limit %s less than the current limit %s", limit, agreedState.getBound()); newSeq = agreedState.getSeqId() + 1; } while (true) { try { proposer.propose(newSeq, PtBytes.toBytes(limit)); PaxosValue value = knowledge.getLearnedValue(newSeq) .orElseThrow(() -> new SafeIllegalStateException("Timestamp bound store: Paxos proposal" + " returned without learning a value. This is unexpected and would suggest a bug in" + " AtlasDB code. Please contact support.")); checkAgreedBoundIsOurs(limit, newSeq, value); long newLimit = PtBytes.toLong(value.getData()); agreedState = ImmutableSequenceAndBound.of(newSeq, newLimit); if (newLimit < limit) { log.warn("It appears we updated the timestamp limit to {}, which was less than our target {}." + " This suggests we have another timestamp service running; possibly because we" + " lost and regained leadership. For safety, we are now stopping this service.", SafeArg.of("newLimit", newLimit), SafeArg.of("target", limit)); throw new NotCurrentLeaderException(String.format( "We updated the timestamp limit to %s, which was less than our target %s.", newLimit, limit)); } return; } catch (PaxosRoundFailureException e) { waitForRandomBackoff(e, this::wait); } } } }
PaxosTimestampBoundStore implements TimestampBoundStore { @Override public synchronized void storeUpperLimit(long limit) throws MultipleRunningTimestampServiceError { long newSeq = PaxosAcceptor.NO_LOG_ENTRY + 1; if (agreedState != null) { Preconditions.checkArgument(limit >= agreedState.getBound(), "Tried to store an upper limit %s less than the current limit %s", limit, agreedState.getBound()); newSeq = agreedState.getSeqId() + 1; } while (true) { try { proposer.propose(newSeq, PtBytes.toBytes(limit)); PaxosValue value = knowledge.getLearnedValue(newSeq) .orElseThrow(() -> new SafeIllegalStateException("Timestamp bound store: Paxos proposal" + " returned without learning a value. This is unexpected and would suggest a bug in" + " AtlasDB code. Please contact support.")); checkAgreedBoundIsOurs(limit, newSeq, value); long newLimit = PtBytes.toLong(value.getData()); agreedState = ImmutableSequenceAndBound.of(newSeq, newLimit); if (newLimit < limit) { log.warn("It appears we updated the timestamp limit to {}, which was less than our target {}." + " This suggests we have another timestamp service running; possibly because we" + " lost and regained leadership. For safety, we are now stopping this service.", SafeArg.of("newLimit", newLimit), SafeArg.of("target", limit)); throw new NotCurrentLeaderException(String.format( "We updated the timestamp limit to %s, which was less than our target %s.", newLimit, limit)); } return; } catch (PaxosRoundFailureException e) { waitForRandomBackoff(e, this::wait); } } } PaxosTimestampBoundStore(
            PaxosProposer proposer,
            PaxosLearner knowledge,
            PaxosAcceptorNetworkClient acceptorNetworkClient,
            PaxosLearnerNetworkClient learnerClient,
            long maximumWaitBeforeProposalMs); }
PaxosTimestampBoundStore implements TimestampBoundStore { @Override public synchronized void storeUpperLimit(long limit) throws MultipleRunningTimestampServiceError { long newSeq = PaxosAcceptor.NO_LOG_ENTRY + 1; if (agreedState != null) { Preconditions.checkArgument(limit >= agreedState.getBound(), "Tried to store an upper limit %s less than the current limit %s", limit, agreedState.getBound()); newSeq = agreedState.getSeqId() + 1; } while (true) { try { proposer.propose(newSeq, PtBytes.toBytes(limit)); PaxosValue value = knowledge.getLearnedValue(newSeq) .orElseThrow(() -> new SafeIllegalStateException("Timestamp bound store: Paxos proposal" + " returned without learning a value. This is unexpected and would suggest a bug in" + " AtlasDB code. Please contact support.")); checkAgreedBoundIsOurs(limit, newSeq, value); long newLimit = PtBytes.toLong(value.getData()); agreedState = ImmutableSequenceAndBound.of(newSeq, newLimit); if (newLimit < limit) { log.warn("It appears we updated the timestamp limit to {}, which was less than our target {}." + " This suggests we have another timestamp service running; possibly because we" + " lost and regained leadership. For safety, we are now stopping this service.", SafeArg.of("newLimit", newLimit), SafeArg.of("target", limit)); throw new NotCurrentLeaderException(String.format( "We updated the timestamp limit to %s, which was less than our target %s.", newLimit, limit)); } return; } catch (PaxosRoundFailureException e) { waitForRandomBackoff(e, this::wait); } } } PaxosTimestampBoundStore(
            PaxosProposer proposer,
            PaxosLearner knowledge,
            PaxosAcceptorNetworkClient acceptorNetworkClient,
            PaxosLearnerNetworkClient learnerClient,
            long maximumWaitBeforeProposalMs); @Override synchronized long getUpperLimit(); @Override synchronized void storeUpperLimit(long limit); }
PaxosTimestampBoundStore implements TimestampBoundStore { @Override public synchronized void storeUpperLimit(long limit) throws MultipleRunningTimestampServiceError { long newSeq = PaxosAcceptor.NO_LOG_ENTRY + 1; if (agreedState != null) { Preconditions.checkArgument(limit >= agreedState.getBound(), "Tried to store an upper limit %s less than the current limit %s", limit, agreedState.getBound()); newSeq = agreedState.getSeqId() + 1; } while (true) { try { proposer.propose(newSeq, PtBytes.toBytes(limit)); PaxosValue value = knowledge.getLearnedValue(newSeq) .orElseThrow(() -> new SafeIllegalStateException("Timestamp bound store: Paxos proposal" + " returned without learning a value. This is unexpected and would suggest a bug in" + " AtlasDB code. Please contact support.")); checkAgreedBoundIsOurs(limit, newSeq, value); long newLimit = PtBytes.toLong(value.getData()); agreedState = ImmutableSequenceAndBound.of(newSeq, newLimit); if (newLimit < limit) { log.warn("It appears we updated the timestamp limit to {}, which was less than our target {}." + " This suggests we have another timestamp service running; possibly because we" + " lost and regained leadership. For safety, we are now stopping this service.", SafeArg.of("newLimit", newLimit), SafeArg.of("target", limit)); throw new NotCurrentLeaderException(String.format( "We updated the timestamp limit to %s, which was less than our target %s.", newLimit, limit)); } return; } catch (PaxosRoundFailureException e) { waitForRandomBackoff(e, this::wait); } } } PaxosTimestampBoundStore(
            PaxosProposer proposer,
            PaxosLearner knowledge,
            PaxosAcceptorNetworkClient acceptorNetworkClient,
            PaxosLearnerNetworkClient learnerClient,
            long maximumWaitBeforeProposalMs); @Override synchronized long getUpperLimit(); @Override synchronized void storeUpperLimit(long limit);  }