Skip to content

Commit

Permalink
Add support up to max unsigned integer in Bitfield offset (#2964) (#3099
Browse files Browse the repository at this point in the history
)

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

* Add test for reactive command
  • Loading branch information
psw0946 authored Dec 27, 2024
1 parent f48b43d commit b925816
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 24 deletions.
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

0 comments on commit b925816

Please sign in to comment.