Skip to content

Commit

Permalink
Add support for CLIENT TRACKINGINFO (redis#2862)
Browse files Browse the repository at this point in the history
* Initial commit

* Added the CLIENT TRACKINGINFO command

* Implement the final version of the command, add parser utility

* Add some more unit tests. Polishing.

* Implemented dynamic parsing of the result returned from CLIENT TRACKINGINFO

* Fixed conflixt issues

* Addressed Ali's comment on calling the .getDynamicMap only once

* Circle back to using domain objects

* Missed several crucial files

* Remove part of the license that is not needed
  • Loading branch information
tishun authored Aug 8, 2024
1 parent 53ba22b commit 103636c
Show file tree
Hide file tree
Showing 23 changed files with 964 additions and 24 deletions.
5 changes: 5 additions & 0 deletions src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,11 @@ public RedisFuture<String> clientTracking(TrackingArgs args) {
return dispatch(commandBuilder.clientTracking(args));
}

@Override
public RedisFuture<TrackingInfo> clientTrackinginfo() {
return dispatch(commandBuilder.clientTrackinginfo());
}

@Override
public RedisFuture<Long> clientUnblock(long id, UnblockType type) {
return dispatch(commandBuilder.clientUnblock(id, type));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,11 @@ public Mono<String> clientTracking(TrackingArgs args) {
return createMono(() -> commandBuilder.clientTracking(args));
}

@Override
public Mono<TrackingInfo> clientTrackinginfo() {
return createMono(commandBuilder::clientTrackinginfo);
}

@Override
public Mono<Long> clientUnblock(long id, UnblockType type) {
return createMono(() -> commandBuilder.clientUnblock(id, type));
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/io/lettuce/core/RedisCommandBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,12 @@ Command<K, V, String> clientTracking(TrackingArgs trackingArgs) {
return createCommand(CLIENT, new StatusOutput<>(codec), args);
}

Command<K, V, TrackingInfo> clientTrackinginfo() {
CommandArgs<K, V> args = new CommandArgs<>(codec).add(TRACKINGINFO);

return new Command<>(CLIENT, new ComplexOutput<>(codec, TrackingInfoParser.INSTANCE), args);
}

Command<K, V, Long> clientUnblock(long id, UnblockType type) {
LettuceAssert.notNull(type, "UnblockType " + MUST_NOT_BE_NULL);

Expand Down
165 changes: 165 additions & 0 deletions src/main/java/io/lettuce/core/TrackingInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/*
* Copyright 2024, Redis Ltd. and Contributors
* All rights reserved.
*
* Licensed under the MIT License.
*/

package io.lettuce.core;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.List;

/**
* Contains the output of a <a href="https://redis.io/docs/latest/commands/client-trackinginfo/">CLIENT TRACKINGINFO</a>
* command.
*
* @author Tihomir Mateev
* @since 6.5
*/
public class TrackingInfo {

private final Set<TrackingFlag> flags = new HashSet<>();

private final long redirect;

private final List<String> prefixes = new ArrayList<>();

/**
* Constructor
*
* @param flags a {@link Set} of {@link TrackingFlag}s that the command returned
* @param redirect the client ID used for notification redirection, -1 when none
* @param prefixes a {@link List} of key prefixes for which notifications are sent to the client
*
* @see TrackingFlag
*/
public TrackingInfo(Set<TrackingFlag> flags, long redirect, List<String> prefixes) {
this.flags.addAll(flags);
this.redirect = redirect;
this.prefixes.addAll(prefixes);
}

/**
* @return set of all the {@link TrackingFlag}s currently enabled on the client connection
*/
public Set<TrackingFlag> getFlags() {
return Collections.unmodifiableSet(flags);
}

/**
* @return the client ID used for notification redirection, -1 when none
*/
public long getRedirect() {
return redirect;
}

/**
* @return a {@link List} of key prefixes for which notifications are sent to the client
*/
public List<String> getPrefixes() {
return Collections.unmodifiableList(prefixes);
}

@Override
public String toString() {
return "TrackingInfo{" + "flags=" + flags + ", redirect=" + redirect + ", prefixes=" + prefixes + '}';
}

@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
TrackingInfo that = (TrackingInfo) o;
return redirect == that.redirect && Objects.equals(flags, that.flags) && Objects.equals(prefixes, that.prefixes);
}

@Override
public int hashCode() {
return Objects.hash(flags, redirect, prefixes);
}

/**
* CLIENT TRACKINGINFO flags
*
* @see <a href="https://redis.io/docs/latest/commands/client-trackinginfo/">CLIENT TRACKINGINFO</a>
*/
public enum TrackingFlag {

/**
* The connection isn't using server assisted client side caching.
*/
OFF,
/**
* Server assisted client side caching is enabled for the connection.
*/
ON,
/**
* The client uses broadcasting mode.
*/
BCAST,
/**
* The client does not cache keys by default.
*/
OPTIN,
/**
* The client caches keys by default.
*/
OPTOUT,
/**
* The next command will cache keys (exists only together with optin).
*/
CACHING_YES,
/**
* The next command won't cache keys (exists only together with optout).
*/
CACHING_NO,
/**
* The client isn't notified about keys modified by itself.
*/
NOLOOP,
/**
* The client ID used for redirection isn't valid anymore.
*/
BROKEN_REDIRECT;

/**
* Convert a given {@link String} flag to the corresponding {@link TrackingFlag}
*
* @param flag a {@link String} representation of the flag
* @return the resulting {@link TrackingFlag} or {@link IllegalArgumentException} if unrecognized
*/
public static TrackingFlag from(String flag) {
switch (flag.toLowerCase()) {
case "off":
return OFF;
case "on":
return ON;
case "bcast":
return BCAST;
case "optin":
return OPTIN;
case "optout":
return OPTOUT;
case "caching-yes":
return CACHING_YES;
case "caching-no":
return CACHING_NO;
case "noloop":
return NOLOOP;
case "broken_redirect":
return BROKEN_REDIRECT;
default:
throw new RuntimeException("Unsupported flag: " + flag);
}
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import io.lettuce.core.ShutdownArgs;
import io.lettuce.core.TrackingArgs;
import io.lettuce.core.UnblockType;
import io.lettuce.core.TrackingInfo;
import io.lettuce.core.protocol.CommandType;

/**
Expand Down Expand Up @@ -177,6 +178,14 @@ public interface RedisServerAsyncCommands<K, V> {
*/
RedisFuture<String> clientTracking(TrackingArgs args);

/**
* Returns information about the current client connection's use of the server assisted client side caching feature.
*
* @return {@link TrackingInfo}, for more information check the documentation
* @since 6.5
*/
RedisFuture<TrackingInfo> clientTrackinginfo();

/**
* Unblock the specified blocked client.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import io.lettuce.core.ShutdownArgs;
import io.lettuce.core.TrackingArgs;
import io.lettuce.core.UnblockType;
import io.lettuce.core.TrackingInfo;
import io.lettuce.core.protocol.CommandType;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
Expand Down Expand Up @@ -177,6 +178,14 @@ public interface RedisServerReactiveCommands<K, V> {
*/
Mono<String> clientTracking(TrackingArgs args);

/**
* Returns information about the current client connection's use of the server assisted client side caching feature.
*
* @return {@link TrackingInfo}, for more information check the documentation
* @since 6.5
*/
Mono<TrackingInfo> clientTrackinginfo();

/**
* Unblock the specified blocked client.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import io.lettuce.core.KillArgs;
import io.lettuce.core.ShutdownArgs;
import io.lettuce.core.TrackingArgs;
import io.lettuce.core.TrackingInfo;
import io.lettuce.core.UnblockType;
import io.lettuce.core.protocol.CommandType;

Expand Down Expand Up @@ -176,6 +177,14 @@ public interface RedisServerCommands<K, V> {
*/
String clientTracking(TrackingArgs args);

/**
* Returns information about the current client connection's use of the server assisted client side caching feature.
*
* @return {@link TrackingInfo}, for more information check the documentation
* @since 6.5
*/
TrackingInfo clientTrackinginfo();

/**
* Unblock the specified blocked client.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@
*/
package io.lettuce.core.cluster.api.async;

import java.util.Date;
import java.util.List;
import java.util.Map;

import java.util.List;
import java.util.Date;
import io.lettuce.core.ClientListArgs;
import io.lettuce.core.FlushMode;
import io.lettuce.core.KillArgs;
import io.lettuce.core.TrackingArgs;
import io.lettuce.core.UnblockType;
import io.lettuce.core.TrackingInfo;
import io.lettuce.core.protocol.CommandType;

/**
Expand Down Expand Up @@ -175,6 +175,14 @@ public interface NodeSelectionServerAsyncCommands<K, V> {
*/
AsyncExecutions<String> clientTracking(TrackingArgs args);

/**
* Returns information about the current client connection's use of the server assisted client side caching feature.
*
* @return {@link TrackingInfo}, for more information check the documentation
* @since 6.5
*/
AsyncExecutions<TrackingInfo> clientTrackinginfo();

/**
* Unblock the specified blocked client.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import io.lettuce.core.KillArgs;
import io.lettuce.core.TrackingArgs;
import io.lettuce.core.UnblockType;
import io.lettuce.core.TrackingInfo;
import io.lettuce.core.protocol.CommandType;

/**
Expand Down Expand Up @@ -163,7 +164,7 @@ public interface NodeSelectionServerCommands<K, V> {
* @return simple-string-reply {@code OK} if the connection name was successfully set.
* @since 6.3
*/
Executions<String> clientSetinfo(String key, V value);
Executions<String> clientSetinfo(String key, String value);

/**
* Enables the tracking feature of the Redis server, that is used for server assisted client side caching. Tracking messages
Expand All @@ -175,6 +176,14 @@ public interface NodeSelectionServerCommands<K, V> {
*/
Executions<String> clientTracking(TrackingArgs args);

/**
* Returns information about the current client connection's use of the server assisted client side caching feature.
*
* @return {@link TrackingInfo}, for more information check the documentation
* @since 6.5
*/
Executions<TrackingInfo> clientTrackinginfo();

/**
* Unblock the specified blocked client.
*
Expand Down
Loading

0 comments on commit 103636c

Please sign in to comment.