-
Notifications
You must be signed in to change notification settings - Fork 15
[Named min timestamp leases] Metric tracking fresh ts shortfall #7402
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ | |
|
||
package com.palantir.lock.client.timestampleases; | ||
|
||
import com.codahale.metrics.Counter; | ||
import com.github.rholder.retry.Attempt; | ||
import com.github.rholder.retry.RetryException; | ||
import com.github.rholder.retry.Retryer; | ||
|
@@ -39,6 +40,7 @@ | |
import com.palantir.lock.LimitingLongSupplier; | ||
import com.palantir.lock.client.LeasedLockToken; | ||
import com.palantir.lock.client.LockTokenUnlocker; | ||
import com.palantir.lock.client.TimestampLeaseMetrics; | ||
import com.palantir.lock.v2.TimestampLeaseResult; | ||
import com.palantir.lock.v2.TimestampLeaseResults; | ||
import com.palantir.logsafe.Preconditions; | ||
|
@@ -62,28 +64,38 @@ public final class TimestampLeaseAcquirerImpl implements TimestampLeaseAcquirer | |
private final NamespacedTimestampLeaseService delegate; | ||
private final Unlocker unlocker; | ||
private final Supplier<UUID> uuidSupplier; | ||
private final Counter notEnoughFreshTimestampsCounter; | ||
|
||
private final Retryer<Optional<TimestampLeaseResponses>> retryer = | ||
RetryerBuilder.<Optional<TimestampLeaseResponses>>newBuilder() | ||
.retryIfResult(Optional::isEmpty) | ||
.withStopStrategy(StopStrategies.stopAfterAttempt(3)) | ||
.build(); | ||
|
||
@VisibleForTesting | ||
TimestampLeaseAcquirerImpl( | ||
NamespacedTimestampLeaseService delegate, Unlocker unlocker, Supplier<UUID> uuidSupplier) { | ||
private TimestampLeaseAcquirerImpl( | ||
NamespacedTimestampLeaseService delegate, | ||
Unlocker unlocker, | ||
Supplier<UUID> uuidSupplier, | ||
Counter notEnoughFreshTimestampsCounter) { | ||
this.delegate = delegate; | ||
this.unlocker = unlocker; | ||
this.uuidSupplier = uuidSupplier; | ||
this.notEnoughFreshTimestampsCounter = notEnoughFreshTimestampsCounter; | ||
} | ||
|
||
private TimestampLeaseAcquirerImpl(NamespacedTimestampLeaseService delegate, Unlocker unlocker) { | ||
this(delegate, unlocker, UniqueIds::pseudoRandomUuidV4); | ||
@VisibleForTesting | ||
TimestampLeaseAcquirerImpl( | ||
NamespacedTimestampLeaseService delegate, Unlocker unlocker, Supplier<UUID> uuidSupplier) { | ||
this(delegate, unlocker, uuidSupplier, new Counter()); | ||
} | ||
|
||
public static TimestampLeaseAcquirer create( | ||
NamespacedTimestampLeaseService timestampLeaseService, LockTokenUnlocker unlocker) { | ||
return new TimestampLeaseAcquirerImpl(timestampLeaseService, identifier -> unlock(unlocker, identifier)); | ||
NamespacedTimestampLeaseService delegate, LockTokenUnlocker unlocker, TimestampLeaseMetrics metrics) { | ||
return new TimestampLeaseAcquirerImpl( | ||
delegate, | ||
identifier -> unlock(unlocker, identifier), | ||
UniqueIds::pseudoRandomUuidV4, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generally in the rest of the code we use |
||
metrics.notEnoughFreshTimestamps()); | ||
} | ||
|
||
@Override | ||
|
@@ -146,23 +158,27 @@ private Optional<TimestampLeaseResponses> acquireLeases(Map<TimestampLeaseName, | |
requestedFreshTimestamps.keySet().equals(responseMap.keySet()), | ||
"Response lease timestamps need to match request timestamp names exactly"); | ||
|
||
boolean wasFullyFulfilled = requestedFreshTimestamps.keySet().stream().allMatch(timestampName -> { | ||
int requestedTimestamps = requestedFreshTimestamps.get(timestampName); | ||
long returnedTimestamps = | ||
responseMap.get(timestampName).getFreshTimestamps().getCount(); | ||
return returnedTimestamps >= requestedTimestamps; | ||
}); | ||
long wereNotFullyFulfilled = requestedFreshTimestamps.keySet().stream() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: |
||
.filter(timestampName -> { | ||
int requestedTimestamps = requestedFreshTimestamps.get(timestampName); | ||
long returnedTimestamps = | ||
responseMap.get(timestampName).getFreshTimestamps().getCount(); | ||
return returnedTimestamps < requestedTimestamps; | ||
}) | ||
.count(); | ||
|
||
if (wereNotFullyFulfilled > 0) { | ||
notEnoughFreshTimestampsCounter.inc(wereNotFullyFulfilled); | ||
|
||
if (!wasFullyFulfilled) { | ||
unlock(response); | ||
log.info( | ||
"Timestamp lease request was not fully fulfilled. This should happen infrequently.", | ||
SafeArg.of("requests", requests), | ||
SafeArg.of("requests", request), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: makes sense, but change the arg name too. |
||
SafeArg.of("responses", response)); | ||
return Optional.empty(); | ||
} else { | ||
return Optional.of(response); | ||
} | ||
|
||
return Optional.of(response); | ||
} | ||
|
||
private void unlock(TimestampLeaseResponses responses) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,4 +30,10 @@ namespaces: | |
type: timer | ||
docs: observed call duration during leader election | ||
|
||
timestampLease: | ||
docs: Timestamp lease client side telemetry | ||
metrics: | ||
notEnoughFreshTimestamps: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pedantry: I'd probably have |
||
type: counter | ||
docs: Counts instances where TimeLock returns less than the requested number of timestamps in acquire timestamp lease calls | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: should have asked on earlier review, but what is the purpose of the UUID supplier? We know from the type that it is a UUID supplier 😅