Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support up to max unsigned integer in Bitfield offset (#2964) #3099

Merged
merged 2 commits into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 21 additions & 24 deletions src/main/java/io/lettuce/core/BitFieldArgs.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private Builder() {
* Create a new {@code GET} subcommand.
*
* @param bitFieldType the bit field type, must not be {@code null}.
* @param offset bitfield offset
* @param offset bitfield offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
* @return a new {@code GET} subcommand for the given {@code bitFieldType} and {@code offset}.
*/
public static BitFieldArgs get(BitFieldType bitFieldType, int offset) {
Expand All @@ -93,7 +93,7 @@ public static BitFieldArgs get(BitFieldType bitFieldType, Offset offset) {
* Create a new {@code SET} subcommand.
*
* @param bitFieldType the bit field type, must not be {@code null}.
* @param offset bitfield offset
* @param offset bitfield offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
* @param value the value
* @return a new {@code SET} subcommand for the given {@code bitFieldType}, {@code offset} and {@code value}.
*/
Expand All @@ -118,7 +118,7 @@ public static BitFieldArgs set(BitFieldType bitFieldType, Offset offset, long va
* Create a new {@code INCRBY} subcommand.
*
* @param bitFieldType the bit field type, must not be {@code null}.
* @param offset bitfield offset
* @param offset bitfield offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
* @param value the value
* @return a new {@code INCRBY} subcommand for the given {@code bitFieldType}, {@code offset} and {@code value} .
*/
Expand Down Expand Up @@ -177,7 +177,7 @@ public static BitFieldType unsigned(int bits) {
/**
* Creates a new {@link Offset} for the given {@code offset}.
*
* @param offset zero-based offset.
* @param offset zero-based offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
* @return the {@link Offset}.
* @since 4.3
*/
Expand Down Expand Up @@ -233,7 +233,7 @@ public BitFieldArgs get(BitFieldType bitFieldType) {
* Adds a new {@code GET} subcommand.
*
* @param bitFieldType the bit field type, must not be {@code null}.
* @param offset bitfield offset
* @param offset bitfield offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
* @return a new {@code GET} subcommand for the given {@code bitFieldType} and {@code offset}.
*/
public BitFieldArgs get(BitFieldType bitFieldType, int offset) {
Expand All @@ -258,7 +258,7 @@ public BitFieldArgs get(BitFieldType bitFieldType, Offset offset) {
/**
* Adds a new {@code GET} subcommand using the field type of the previous command.
*
* @param offset bitfield offset
* @param offset bitfield offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
* @return a new {@code GET} subcommand for the given {@code bitFieldType} and {@code offset}.
* @throws IllegalStateException if no previous field type was found
*/
Expand Down Expand Up @@ -291,7 +291,7 @@ public BitFieldArgs set(BitFieldType bitFieldType, long value) {
/**
* Adds a new {@code SET} subcommand using the field type of the previous command.
*
* @param offset bitfield offset
* @param offset bitfield offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
* @param value the value
* @return a new {@code SET} subcommand for the given {@code bitFieldType}, {@code offset} and {@code value}.
* @throws IllegalStateException if no previous field type was found
Expand All @@ -304,7 +304,7 @@ public BitFieldArgs set(int offset, long value) {
* Adds a new {@code SET} subcommand.
*
* @param bitFieldType the bit field type, must not be {@code null}.
* @param offset bitfield offset
* @param offset bitfield offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
* @param value the value
* @return a new {@code SET} subcommand for the given {@code bitFieldType}, {@code offset} and {@code value}.
*/
Expand Down Expand Up @@ -353,7 +353,7 @@ public BitFieldArgs incrBy(BitFieldType bitFieldType, long value) {
/**
* Adds a new {@code INCRBY} subcommand using the field type of the previous command.
*
* @param offset bitfield offset
* @param offset bitfield offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
* @param value the value
* @return a new {@code INCRBY} subcommand for the given {@code bitFieldType}, {@code offset} and {@code value}.
* @throws IllegalStateException if no previous field type was found
Expand All @@ -366,7 +366,7 @@ public BitFieldArgs incrBy(int offset, long value) {
* Adds a new {@code INCRBY} subcommand.
*
* @param bitFieldType the bit field type, must not be {@code null}.
* @param offset bitfield offset
* @param offset bitfield offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
* @param value the value
* @return a new {@code INCRBY} subcommand for the given {@code bitFieldType}, {@code offset} and {@code value}.
*/
Expand Down Expand Up @@ -432,14 +432,13 @@ private static class Set extends SubCommand {

private final boolean bitOffset;

private final long offset;
private final int offset;

private final long value;

private Set(BitFieldType bitFieldType, boolean bitOffset, int offset, long value) {

LettuceAssert.notNull(bitFieldType, "BitFieldType must not be null");
LettuceAssert.isTrue(offset > -1, "Offset must be greater or equal to 0");

this.bitFieldType = bitFieldType;
this.bitOffset = bitOffset;
Expand All @@ -453,9 +452,9 @@ <K, V> void build(CommandArgs<K, V> args) {
args.add(CommandType.SET).add(bitFieldType.asString());

if (bitOffset) {
args.add("#" + offset);
args.add("#" + Integer.toUnsignedString(offset));
} else {
args.add(offset);
args.add(Integer.toUnsignedString(offset));
}

args.add(value);
Expand All @@ -477,7 +476,6 @@ private static class Get extends SubCommand {
private Get(BitFieldType bitFieldType, boolean bitOffset, int offset) {

LettuceAssert.notNull(bitFieldType, "BitFieldType must not be null");
LettuceAssert.isTrue(offset > -1, "Offset must be greater or equal to 0");

this.bitFieldType = bitFieldType;
this.bitOffset = bitOffset;
Expand All @@ -490,9 +488,9 @@ <K, V> void build(CommandArgs<K, V> args) {
args.add(CommandType.GET).add(bitFieldType.asString());

if (bitOffset) {
args.add("#" + offset);
args.add("#" + Integer.toUnsignedString(offset));
} else {
args.add(offset);
args.add(Integer.toUnsignedString(offset));
}
}

Expand All @@ -507,14 +505,13 @@ private static class IncrBy extends SubCommand {

private final boolean bitOffset;

private final long offset;
private final int offset;

private final long value;

private IncrBy(BitFieldType bitFieldType, boolean offsetWidthMultiplier, int offset, long value) {

LettuceAssert.notNull(bitFieldType, "BitFieldType must not be null");
LettuceAssert.isTrue(offset > -1, "Offset must be greater or equal to 0");

this.bitFieldType = bitFieldType;
this.bitOffset = offsetWidthMultiplier;
Expand All @@ -528,9 +525,9 @@ <K, V> void build(CommandArgs<K, V> args) {
args.add(CommandType.INCRBY).add(bitFieldType.asString());

if (bitOffset) {
args.add("#" + offset);
args.add("#" + Integer.toUnsignedString(offset));
} else {
args.add(offset);
args.add(Integer.toUnsignedString(offset));
}

args.add(value);
Expand Down Expand Up @@ -646,8 +643,8 @@ public String toString() {
}

/**
* Represents a bit field offset. See also <a href="https://redis.io/commands/bitfield#bits-and-positional-offsets">Bits and
* positional offsets</a>
* Represents a bit field offset. Offset supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}. See also
* <a href="https://redis.io/commands/bitfield#bits-and-positional-offsets">Bits and positional offsets</a>
*
* @since 4.3
*/
Expand Down Expand Up @@ -681,7 +678,7 @@ public int getOffset() {

@Override
public String toString() {
return (multiplyByTypeWidth ? "#" : "") + offset;
return (multiplyByTypeWidth ? "#" : "") + Integer.toUnsignedString(offset);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ void bitfieldArgsTest() {

assertThat(offset(5).toString()).isEqualTo("5");
assertThat(typeWidthBasedOffset(5).toString()).isEqualTo("#5");

assertThat(offset(-1).toString()).isEqualTo(Integer.toUnsignedString(-1));
assertThat(typeWidthBasedOffset(-1).toString()).isEqualTo("#" + Integer.toUnsignedString(-1));
}

@Test
Expand All @@ -147,6 +150,18 @@ void bitfieldGetWithOffset() {
assertThat(bitstring.get(key)).isEqualTo("10000000");
}

@Test
@EnabledOnCommand("BITFIELD")
void bitfieldGetWithUnsignedOffset() {

long unsignedIntMax = (1L << 32) - 1;
BitFieldArgs bitFieldArgs = BitFieldArgs.Builder.set(signed(8), 0, 1).get(signed(1), (int) unsignedIntMax);

List<Long> values = redis.bitfield(key, bitFieldArgs);

assertThat(values).containsExactly(0L, 0L);
}

@Test
@EnabledOnCommand("BITFIELD")
void bitfieldSet() {
Expand All @@ -171,6 +186,16 @@ void bitfieldWithOffsetSet() {
assertThat(bitstring.get(key)).isEqualTo("1000000000000010");
}

@Test
@EnabledOnCommand("BITFIELD")
void bitfieldWithUnsignedOffsetSet() {

long unsignedIntMax = (1L << 32) - 1;
redis.bitfield(key, BitFieldArgs.Builder.set(signed(1), offset((int) unsignedIntMax), 1));
assertThat(bitstring.getbit(key, unsignedIntMax)).isEqualTo(1);
assertThat(bitstring.bitcount(key)).isEqualTo(1);
}

@Test
@EnabledOnCommand("BITFIELD")
void bitfieldIncrBy() {
Expand All @@ -195,6 +220,16 @@ void bitfieldWithOffsetIncrBy() {
assertThat(bitstring.get(key)).isEqualTo("0000000000000010");
}

@Test
@EnabledOnCommand("BITFIELD")
void bitfieldWithUnsignedOffsetIncryBy() {

long unsignedIntMax = (1L << 32) - 1;
redis.bitfield(key, BitFieldArgs.Builder.incrBy(signed(1), offset((int) unsignedIntMax), 1));
assertThat(bitstring.getbit(key, unsignedIntMax)).isEqualTo(1);
assertThat(bitstring.bitcount(key)).isEqualTo(1);
}

@Test
@EnabledOnCommand("BITFIELD")
void bitfieldOverflow() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ void bitfieldGetWithOffset() {
assertThat(bitstring.get(key)).isEqualTo("10000000");
}

@Test
void bitfieldGetWithUnsignedOffset() {

long unsignedIntMax = (1L << 32) - 1;
BitFieldArgs bitFieldArgs = BitFieldArgs.Builder.set(signed(8), 0, 1).get(signed(1), (int) unsignedIntMax);

StepVerifier.create(reactive.bitfield(key, bitFieldArgs)).expectNext(Value.just(0L), Value.just(0L)).verifyComplete();
}

@Test
void bitfieldSet() {

Expand Down
Loading