From 85059825cfcc368fa320726b61fd47ec30ef5ad8 Mon Sep 17 00:00:00 2001 From: aalouane <30903736+ergo14@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:27:53 +0100 Subject: [PATCH] [Named min timestamp leases] Client API (#7324) --- .../impl/InstrumentedTimelockService.java | 16 ++++++++++ .../ReviewedRestrictedApiUsage.java | 23 +++++++++++++ .../AcquireNamedMinTimestampLeaseResult.java | 32 +++++++++++++++++++ .../com/palantir/lock/v2/TimelockService.java | 26 +++++++++++++++ .../lock/client/ProfilingTimelockService.java | 17 ++++++++++ .../client/RemoteTimelockServiceAdapter.java | 17 ++++++++++ .../palantir/lock/client/TimeLockClient.java | 15 +++++++++ .../client/UnreliableTimeLockService.java | 15 +++++++++ .../lock/impl/LegacyTimelockService.java | 14 ++++++++ 9 files changed, 175 insertions(+) create mode 100644 lock-api-objects/src/main/java/com/palantir/lock/annotations/ReviewedRestrictedApiUsage.java create mode 100644 lock-api-objects/src/main/java/com/palantir/lock/v2/AcquireNamedMinTimestampLeaseResult.java diff --git a/atlasdb-impl-shared/src/main/java/com/palantir/atlasdb/transaction/impl/InstrumentedTimelockService.java b/atlasdb-impl-shared/src/main/java/com/palantir/atlasdb/transaction/impl/InstrumentedTimelockService.java index 352c7d0b1f7..b7742a716f8 100644 --- a/atlasdb-impl-shared/src/main/java/com/palantir/atlasdb/transaction/impl/InstrumentedTimelockService.java +++ b/atlasdb-impl-shared/src/main/java/com/palantir/atlasdb/transaction/impl/InstrumentedTimelockService.java @@ -18,6 +18,8 @@ import com.codahale.metrics.Meter; import com.palantir.atlasdb.AtlasDbMetricNames; import com.palantir.atlasdb.util.MetricsManager; +import com.palantir.lock.annotations.ReviewedRestrictedApiUsage; +import com.palantir.lock.v2.AcquireNamedMinTimestampLeaseResult; import com.palantir.lock.v2.ClientLockingOptions; import com.palantir.lock.v2.LockImmutableTimestampResponse; import com.palantir.lock.v2.LockRequest; @@ -131,6 +133,20 @@ public long currentTimeMillis() { return executeWithRecord(timelockService::currentTimeMillis); } + @ReviewedRestrictedApiUsage + @Override + public AcquireNamedMinTimestampLeaseResult acquireNamedMinTimestampLease( + String timestampName, int numFreshTimestamps) { + return executeWithRecord( + () -> timelockService.acquireNamedMinTimestampLease(timestampName, numFreshTimestamps)); + } + + @ReviewedRestrictedApiUsage + @Override + public long getMinLeasedTimestampForName(String timestampName) { + return executeWithRecord(() -> timelockService.getMinLeasedTimestampForName(timestampName)); + } + private T executeWithRecord(Supplier method) { try { T result = method.get(); diff --git a/lock-api-objects/src/main/java/com/palantir/lock/annotations/ReviewedRestrictedApiUsage.java b/lock-api-objects/src/main/java/com/palantir/lock/annotations/ReviewedRestrictedApiUsage.java new file mode 100644 index 00000000000..940c28ab389 --- /dev/null +++ b/lock-api-objects/src/main/java/com/palantir/lock/annotations/ReviewedRestrictedApiUsage.java @@ -0,0 +1,23 @@ +/* + * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved. + * + * Licensed 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 com.palantir.lock.annotations; + +/** + * Annotation to be used to indicate that usage of a restricted method is intentional and all the nuances about it + * are understood. + */ +public @interface ReviewedRestrictedApiUsage {} diff --git a/lock-api-objects/src/main/java/com/palantir/lock/v2/AcquireNamedMinTimestampLeaseResult.java b/lock-api-objects/src/main/java/com/palantir/lock/v2/AcquireNamedMinTimestampLeaseResult.java new file mode 100644 index 00000000000..dd36f489178 --- /dev/null +++ b/lock-api-objects/src/main/java/com/palantir/lock/v2/AcquireNamedMinTimestampLeaseResult.java @@ -0,0 +1,32 @@ +/* + * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved. + * + * Licensed 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 com.palantir.lock.v2; + +import java.util.List; +import org.immutables.value.Value; + +@Value.Immutable +public interface AcquireNamedMinTimestampLeaseResult { + @Value.Parameter + long minLeasedTimestamp(); + + @Value.Parameter + LockToken lock(); + + @Value.Parameter + List freshTimestamps(); +} diff --git a/lock-api-objects/src/main/java/com/palantir/lock/v2/TimelockService.java b/lock-api-objects/src/main/java/com/palantir/lock/v2/TimelockService.java index 84d9529103f..6046300f2a7 100644 --- a/lock-api-objects/src/main/java/com/palantir/lock/v2/TimelockService.java +++ b/lock-api-objects/src/main/java/com/palantir/lock/v2/TimelockService.java @@ -15,6 +15,8 @@ */ package com.palantir.lock.v2; +import com.google.errorprone.annotations.RestrictedApi; +import com.palantir.lock.annotations.ReviewedRestrictedApiUsage; import com.palantir.logsafe.Safe; import com.palantir.processors.AutoDelegate; import com.palantir.processors.DoNotDelegate; @@ -110,4 +112,28 @@ default List startIdentifiedAtlasDbTr void tryUnlock(Set tokens); long currentTimeMillis(); + + /** + * Acquires a lease on a named timestamp. The lease is taken out with a new fresh timestamp. + * The returned timestamps are fresh timestamps obtained strictly after the lease is taken out. + */ + @RestrictedApi( + explanation = + "This method is for internal Atlas and internal library use only. Clients MUST NOT use it unless" + + " given explicit approval. Mis-use can result in SEVERE DATA CORRUPTION and the API contract" + + " is subject to change at any time.", + allowlistAnnotations = ReviewedRestrictedApiUsage.class) + AcquireNamedMinTimestampLeaseResult acquireNamedMinTimestampLease(String timestampName, int numFreshTimestamps); + + /** + * Returns the smallest leased timestamp in the associated named collection at the time of the call. + * If there are no active leases, a fresh timestamp is obtained and returned. + */ + @RestrictedApi( + explanation = + "This method is for internal Atlas and internal library use only. Clients MUST NOT use it unless" + + " given explicit approval. Mis-use can result in SEVERE DATA CORRUPTION and the API contract" + + " is subject to change at any time.", + allowlistAnnotations = ReviewedRestrictedApiUsage.class) + long getMinLeasedTimestampForName(String timestampName); } diff --git a/lock-api/src/main/java/com/palantir/lock/client/ProfilingTimelockService.java b/lock-api/src/main/java/com/palantir/lock/client/ProfilingTimelockService.java index bfa07884c79..616e5e8979e 100644 --- a/lock-api/src/main/java/com/palantir/lock/client/ProfilingTimelockService.java +++ b/lock-api/src/main/java/com/palantir/lock/client/ProfilingTimelockService.java @@ -20,6 +20,8 @@ import com.google.common.base.Stopwatch; import com.google.common.util.concurrent.RateLimiter; import com.palantir.common.base.Throwables; +import com.palantir.lock.annotations.ReviewedRestrictedApiUsage; +import com.palantir.lock.v2.AcquireNamedMinTimestampLeaseResult; import com.palantir.lock.v2.ClientLockingOptions; import com.palantir.lock.v2.LockImmutableTimestampResponse; import com.palantir.lock.v2.LockRequest; @@ -169,6 +171,21 @@ public long currentTimeMillis() { return runTaskTimed("currentTimeMillis", delegate::currentTimeMillis); } + @ReviewedRestrictedApiUsage + @Override + public AcquireNamedMinTimestampLeaseResult acquireNamedMinTimestampLease( + String timestampName, int numFreshTimestamps) { + return runTaskTimed( + "acquireNamedMinTimestampLease", + () -> delegate.acquireNamedMinTimestampLease(timestampName, numFreshTimestamps)); + } + + @ReviewedRestrictedApiUsage + @Override + public long getMinLeasedTimestampForName(String timestampName) { + return runTaskTimed("getMinLeasedNamedTimestamp", () -> delegate.getMinLeasedTimestampForName(timestampName)); + } + private T runTaskTimed(String actionName, Supplier action) { Stopwatch stopwatch = stopwatchSupplier.get(); try { diff --git a/lock-api/src/main/java/com/palantir/lock/client/RemoteTimelockServiceAdapter.java b/lock-api/src/main/java/com/palantir/lock/client/RemoteTimelockServiceAdapter.java index 1db5f4894ae..91a1c21a671 100644 --- a/lock-api/src/main/java/com/palantir/lock/client/RemoteTimelockServiceAdapter.java +++ b/lock-api/src/main/java/com/palantir/lock/client/RemoteTimelockServiceAdapter.java @@ -20,6 +20,8 @@ import com.palantir.atlasdb.timelock.api.ConjureGetFreshTimestampsResponseV2; import com.palantir.atlasdb.timelock.api.ConjureTimestampRange; import com.palantir.atlasdb.timelock.api.Namespace; +import com.palantir.lock.annotations.ReviewedRestrictedApiUsage; +import com.palantir.lock.v2.AcquireNamedMinTimestampLeaseResult; import com.palantir.lock.v2.ClientLockingOptions; import com.palantir.lock.v2.LockImmutableTimestampResponse; import com.palantir.lock.v2.LockRequest; @@ -168,6 +170,21 @@ public long currentTimeMillis() { return rpcClient.currentTimeMillis(); } + @ReviewedRestrictedApiUsage + @Override + public AcquireNamedMinTimestampLeaseResult acquireNamedMinTimestampLease( + String timestampName, int numFreshTimestamps) { + // TODO(aalouane): implement! + throw new UnsupportedOperationException("Not implemented yet!"); + } + + @ReviewedRestrictedApiUsage + @Override + public long getMinLeasedTimestampForName(String timestampName) { + // TODO(aalouane): implement! + throw new UnsupportedOperationException("Not implemented yet!"); + } + @Override public void close() { transactionStarter.close(); diff --git a/lock-api/src/main/java/com/palantir/lock/client/TimeLockClient.java b/lock-api/src/main/java/com/palantir/lock/client/TimeLockClient.java index fd5b31c1b0e..4c0f2272e1e 100644 --- a/lock-api/src/main/java/com/palantir/lock/client/TimeLockClient.java +++ b/lock-api/src/main/java/com/palantir/lock/client/TimeLockClient.java @@ -21,6 +21,8 @@ import com.palantir.common.concurrent.NamedThreadFactory; import com.palantir.common.concurrent.PTExecutors; import com.palantir.leader.NotCurrentLeaderException; +import com.palantir.lock.annotations.ReviewedRestrictedApiUsage; +import com.palantir.lock.v2.AcquireNamedMinTimestampLeaseResult; import com.palantir.lock.v2.ClientLockingOptions; import com.palantir.lock.v2.LockImmutableTimestampResponse; import com.palantir.lock.v2.LockLeaseRefresher; @@ -180,6 +182,19 @@ public long currentTimeMillis() { return executeOnTimeLock(delegate::currentTimeMillis); } + @ReviewedRestrictedApiUsage + @Override + public AcquireNamedMinTimestampLeaseResult acquireNamedMinTimestampLease( + String timestampName, int numFreshTimestamps) { + return delegate.acquireNamedMinTimestampLease(timestampName, numFreshTimestamps); + } + + @ReviewedRestrictedApiUsage + @Override + public long getMinLeasedTimestampForName(String timestampName) { + return delegate.getMinLeasedTimestampForName(timestampName); + } + private static T executeOnTimeLock(Callable callable) { try { return callable.call(); diff --git a/lock-api/src/main/java/com/palantir/lock/client/UnreliableTimeLockService.java b/lock-api/src/main/java/com/palantir/lock/client/UnreliableTimeLockService.java index e45252af686..17852ad8e65 100644 --- a/lock-api/src/main/java/com/palantir/lock/client/UnreliableTimeLockService.java +++ b/lock-api/src/main/java/com/palantir/lock/client/UnreliableTimeLockService.java @@ -19,6 +19,8 @@ import com.google.common.collect.Sets; import com.palantir.atlasdb.buggify.api.BuggifyFactory; import com.palantir.atlasdb.buggify.impl.DefaultBuggifyFactory; +import com.palantir.lock.annotations.ReviewedRestrictedApiUsage; +import com.palantir.lock.v2.AcquireNamedMinTimestampLeaseResult; import com.palantir.lock.v2.ClientLockingOptions; import com.palantir.lock.v2.LockImmutableTimestampResponse; import com.palantir.lock.v2.LockRequest; @@ -155,6 +157,19 @@ public long currentTimeMillis() { return delegate.currentTimeMillis(); } + @ReviewedRestrictedApiUsage + @Override + public AcquireNamedMinTimestampLeaseResult acquireNamedMinTimestampLease( + String timestampName, int numFreshTimestamps) { + return delegate.acquireNamedMinTimestampLease(timestampName, numFreshTimestamps); + } + + @ReviewedRestrictedApiUsage + @Override + public long getMinLeasedTimestampForName(String timestampName) { + return delegate.getMinLeasedTimestampForName(timestampName); + } + private void maybeRandomlyIncreaseTimestamp() { buggify.maybe(INCREASE_TIMESTAMP_PROBABILITY).run(timestampManager::randomlyIncreaseTimestamp); } diff --git a/lock-impl/src/main/java/com/palantir/lock/impl/LegacyTimelockService.java b/lock-impl/src/main/java/com/palantir/lock/impl/LegacyTimelockService.java index 0ff9978a39a..855e04359c7 100644 --- a/lock-impl/src/main/java/com/palantir/lock/impl/LegacyTimelockService.java +++ b/lock-impl/src/main/java/com/palantir/lock/impl/LegacyTimelockService.java @@ -24,6 +24,7 @@ import com.palantir.lock.LockRefreshToken; import com.palantir.lock.LockService; import com.palantir.lock.SimpleTimeDuration; +import com.palantir.lock.v2.AcquireNamedMinTimestampLeaseResult; import com.palantir.lock.v2.ClientLockingOptions; import com.palantir.lock.v2.LockImmutableTimestampResponse; import com.palantir.lock.v2.LockRequest; @@ -181,6 +182,19 @@ public long currentTimeMillis() { return lockService.currentTimeMillis(); } + @Override + public AcquireNamedMinTimestampLeaseResult acquireNamedMinTimestampLease( + String timestampName, int numFreshTimestamps) { + // TODO(aalouane): implement! + throw new UnsupportedOperationException("Not implemented yet!"); + } + + @Override + public long getMinLeasedTimestampForName(String timestampName) { + // TODO(aalouane): implement! + throw new UnsupportedOperationException("Not implemented yet!"); + } + private long getImmutableTimestampInternal(long ts) { Long minLocked = lockService.getMinLockedInVersionId(immutableTsLockClient.getClientId()); return minLocked == null ? ts : minLocked;