This is an automated email from the ASF dual-hosted git repository. sk0x50 pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push: new b5b3e71 IGNITE-16654 Added an ability to compare entry values in meta storage conditional updates. Fixes #706 b5b3e71 is described below commit b5b3e711134a787a69fc89223f663ab2676e11b0 Author: Mirza Aliev <alievmi...@gmail.com> AuthorDate: Thu Mar 10 17:58:25 2022 +0300 IGNITE-16654 Added an ability to compare entry values in meta storage conditional updates. Fixes #706 Signed-off-by: Slava Koptilin <slava.kopti...@gmail.com> --- .../client/ItMetaStorageServiceTest.java | 38 +++-- .../internal/metastorage/client/Conditions.java | 18 +-- .../ignite/internal/metastorage/client/If.java | 4 +- .../metastorage/client/SimpleCondition.java | 166 +++++++++++++++------ .../internal/metastorage/common/ConditionType.java | 36 +++-- .../ignite/internal/metastorage/server/If.java | 2 +- .../metastorage/server/ValueCondition.java | 42 +++++- .../server/raft/MetaStorageListener.java | 8 + .../metastorage/server/RevisionConditionTest.java | 4 +- .../metastorage/server/ValueConditionTest.java | 74 +++++++++ 10 files changed, 305 insertions(+), 87 deletions(-) diff --git a/modules/metastorage-client/src/integrationTest/java/org/apache/ignite/internal/metastorage/client/ItMetaStorageServiceTest.java b/modules/metastorage-client/src/integrationTest/java/org/apache/ignite/internal/metastorage/client/ItMetaStorageServiceTest.java index c54f084..e73a8be 100644 --- a/modules/metastorage-client/src/integrationTest/java/org/apache/ignite/internal/metastorage/client/ItMetaStorageServiceTest.java +++ b/modules/metastorage-client/src/integrationTest/java/org/apache/ignite/internal/metastorage/client/ItMetaStorageServiceTest.java @@ -18,6 +18,7 @@ package org.apache.ignite.internal.metastorage.client; import static java.util.stream.Collectors.toList; +import static org.apache.ignite.internal.metastorage.client.CompoundCondition.and; import static org.apache.ignite.internal.metastorage.client.CompoundCondition.or; import static org.apache.ignite.internal.metastorage.client.Conditions.revision; import static org.apache.ignite.internal.metastorage.client.Conditions.value; @@ -48,6 +49,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -63,6 +65,7 @@ import java.util.stream.Collectors; import org.apache.ignite.internal.metastorage.common.OperationType; import org.apache.ignite.internal.metastorage.server.AbstractCompoundCondition; import org.apache.ignite.internal.metastorage.server.AbstractSimpleCondition; +import org.apache.ignite.internal.metastorage.server.AndCondition; import org.apache.ignite.internal.metastorage.server.EntryEvent; import org.apache.ignite.internal.metastorage.server.KeyValueStorage; import org.apache.ignite.internal.metastorage.server.OrCondition; @@ -777,22 +780,27 @@ public class ItMetaStorageServiceTest { /* if (key1.value == val1 || key2.value != val2) - if (key3.revision == 3): + if (key3.revision == 3 || key2.value > val1 || key1.value >= val2): put(key1, rval1) return true else - put(key1, rval1) - remove(key2, rval2) - return false + if (key2.value < val1 && key1.value <= val2): + put(key1, rval1) + remove(key2, rval2) + return false + else + return true else put(key2, rval2) return false */ var iif = If.iif(or(value(key1).eq(val1), value(key2).ne(val2)), - iif(revision(key3).eq(3), + iif(or(revision(key3).eq(3), or(value(key2).gt(val1), value(key1).ge(val2))), ops(put(key1, rval1)).yield(true), - ops(put(key1, rval1), remove(key2)).yield(false)), + iif(and(value(key2).lt(val1), value(key1).le(val2)), + ops(put(key1, rval1), remove(key2)).yield(false), + ops().yield(true))), ops(put(key2, rval2)).yield(false)); var ifCaptor = ArgumentCaptor.forClass(org.apache.ignite.internal.metastorage.server.If.class); @@ -808,19 +816,29 @@ public class ItMetaStorageServiceTest { assertThat(resultIf.cond(), cond(new OrCondition(new ValueCondition(Type.EQUAL, key1.bytes(), val1), new ValueCondition(Type.NOT_EQUAL, key2.bytes(), val2)))); - assertThat(resultIf.andThen().iif().cond(), cond(new RevisionCondition(RevisionCondition.Type.EQUAL, key3.bytes(), 3))); + assertThat(resultIf.andThen().iif().cond(), + cond(new OrCondition(new RevisionCondition(RevisionCondition.Type.EQUAL, key3.bytes(), 3), + new OrCondition(new ValueCondition(ValueCondition.Type.GREATER, key2.bytes(), val1), new ValueCondition( + Type.GREATER_OR_EQUAL, key1.bytes(), val2))))); + + assertThat(resultIf.andThen().iif().orElse().iif().cond(), + cond(new AndCondition(new ValueCondition(ValueCondition.Type.LESS, key2.bytes(), val1), new ValueCondition( + Type.LESS_OR_EQUAL, key1.bytes(), val2)))); assertThat(resultIf.andThen().iif().andThen().update(), upd(new Update( - Arrays.asList(new org.apache.ignite.internal.metastorage.server.Operation(OperationType.PUT, key1.bytes(), rval1)), + List.of(new org.apache.ignite.internal.metastorage.server.Operation(OperationType.PUT, key1.bytes(), rval1)), new StatementResult(true)))); - assertThat(resultIf.andThen().iif().orElse().update(), upd(new Update( + assertThat(resultIf.andThen().iif().orElse().iif().andThen().update(), upd(new Update( Arrays.asList(new org.apache.ignite.internal.metastorage.server.Operation(OperationType.PUT, key1.bytes(), rval1), new org.apache.ignite.internal.metastorage.server.Operation(OperationType.REMOVE, key2.bytes(), null)), new StatementResult(false)))); + assertThat(resultIf.andThen().iif().orElse().iif().orElse().update(), + upd(new Update(Collections.emptyList(), new StatementResult(true)))); + assertThat(resultIf.orElse().update(), upd(new Update( - Arrays.asList(new org.apache.ignite.internal.metastorage.server.Operation(OperationType.PUT, key2.bytes(), rval2)), + List.of(new org.apache.ignite.internal.metastorage.server.Operation(OperationType.PUT, key2.bytes(), rval2)), new StatementResult(false)))); } diff --git a/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/Conditions.java b/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/Conditions.java index 8713fe0..8e65790 100644 --- a/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/Conditions.java +++ b/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/Conditions.java @@ -21,8 +21,8 @@ import org.apache.ignite.lang.ByteArray; import org.jetbrains.annotations.NotNull; /** - * This class contains fabric methods which produce conditions needed for conditional multi update functionality provided by meta storage - * service. + * This class contains fabric methods which produce conditions needed for a conditional multi update functionality provided by the meta + * storage service. * * @see SimpleCondition */ @@ -41,7 +41,7 @@ public final class Conditions { /** * Creates condition on entry value. * - * @param key Identifies an entry which condition will be applied to. Can't be {@code null}. + * @param key Identifies an entry, which condition will be applied to. Can't be {@code null}. * @return Condition on entry value. * @see SimpleCondition.ValueCondition */ @@ -50,9 +50,9 @@ public final class Conditions { } /** - * Creates condition on entry existence. + * Creates condition on an entry existence. * - * @param key Identifies an entry which condition will be applied to. Can't be {@code null}. + * @param key Identifies an entry, which condition will be applied to. Can't be {@code null}. * @return Condition on entry existence. */ public static SimpleCondition exists(@NotNull ByteArray key) { @@ -60,9 +60,9 @@ public final class Conditions { } /** - * Creates condition on entry not existence. + * Creates a condition on an entry not existence. * - * @param key Identifies an entry which condition will be applied to. Can't be {@code null}. + * @param key Identifies an entry, which condition will be applied to. Can't be {@code null}. * @return Condition on entry not existence. */ public static SimpleCondition notExists(@NotNull ByteArray key) { @@ -70,9 +70,9 @@ public final class Conditions { } /** - * Creates condition on an entry's value which checks whether value is tombstone or not. + * Creates a condition on an entry's value, which checks whether a value is tombstone or not. * - * @param key Identifies an entry which condition will be applied to. Can't be {@code null}. + * @param key Identifies an entry, which condition will be applied to. Can't be {@code null}. * @return Condition on entry's value is tombstone. */ public static SimpleCondition tombstone(@NotNull ByteArray key) { diff --git a/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/If.java b/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/If.java index d613e99..ad3ae0d 100644 --- a/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/If.java +++ b/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/If.java @@ -18,12 +18,12 @@ package org.apache.ignite.internal.metastorage.client; /** - * Root building block for the compound metas torage invoke command. + * Root building block for the compound meta storage invoke command. * Contains of boolean condition and 2 branches of execution, like usual programming language's if. * Every branch can be either new {@link If} statement (non-terminal) or result terminal statement {@link Update}. * * <p>The easiest way to construct the needed {@link If} conditional statement is the builtin shortcut methods. - * For example to create the statement, which implement the following pseudo code: + * For example to create the statement, which implement the following pseudocode: * <pre> * {@code * {@link CompoundCondition} diff --git a/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/SimpleCondition.java b/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/SimpleCondition.java index 559dd34..6382a0d 100644 --- a/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/SimpleCondition.java +++ b/modules/metastorage-client/src/main/java/org/apache/ignite/internal/metastorage/client/SimpleCondition.java @@ -21,7 +21,7 @@ import java.util.Collection; import org.apache.ignite.internal.metastorage.common.ConditionType; /** - * Represents a condition for meta storage conditional update. + * Represents a condition for a meta storage conditional update. * * @see MetaStorageService#invoke(Condition, Operation, Operation) * @see MetaStorageService#invoke(Condition, Collection, Collection) @@ -31,7 +31,7 @@ public final class SimpleCondition implements Condition { private final InnerCondition cond; /** - * Constructs a condition which wraps the actual condition implementation. + * Constructs a condition, which wraps the actual condition implementation. * * @param cond The actual condition implementation. */ @@ -48,8 +48,8 @@ public final class SimpleCondition implements Condition { } /** - * Represents condition on entry revision. Only one type of condition could be applied to the one instance of condition. Subsequent - * invocations of any method which produces condition will throw {@link IllegalStateException}. + * Represents a condition on an entry revision. Only one type of condition could be applied to the one instance of a condition. + * Subsequent invocations of any method, which produces a condition will throw {@link IllegalStateException}. */ public static final class RevisionCondition extends AbstractCondition { /** The revision as the condition argument. */ @@ -58,7 +58,7 @@ public final class SimpleCondition implements Condition { /** * Constructs a condition by a revision for an entry identified by the given key. * - * @param key Identifies an entry which condition will be applied to. + * @param key Identifies an entry, which condition will be applied to. */ RevisionCondition(byte[] key) { super(key); @@ -69,12 +69,12 @@ public final class SimpleCondition implements Condition { } /** - * Produces the condition of type {@link ConditionType#REV_EQUAL}. This condition tests the given revision on equality with target - * entry revision. + * Produces the condition of type {@link ConditionType#REV_EQUAL}. This condition tests the given revision on equality + * with the target entry revision. * * @param rev The revision. * @return The condition of type {@link ConditionType#REV_EQUAL}. - * @throws IllegalStateException In case when the condition is already defined. + * @throws IllegalStateException In the case when the condition is already defined. */ public SimpleCondition eq(long rev) { validate(type()); @@ -88,11 +88,11 @@ public final class SimpleCondition implements Condition { /** * Produces the condition of type {@link ConditionType#REV_NOT_EQUAL}. This condition tests the given revision on inequality with - * target entry revision. + * the target entry revision. * * @param rev The revision. * @return The condition of type {@link ConditionType#REV_NOT_EQUAL}. - * @throws IllegalStateException In case when the condition is already defined. + * @throws IllegalStateException In the case when the condition is already defined. */ public SimpleCondition ne(long rev) { validate(type()); @@ -106,11 +106,11 @@ public final class SimpleCondition implements Condition { /** * Produces the condition of type {@link ConditionType#REV_GREATER}. This condition tests that the target entry revision is greater - * than given revision. + * than the given revision. * * @param rev The revision. * @return The condition of type {@link ConditionType#REV_GREATER}. - * @throws IllegalStateException In case when the condition is already defined. + * @throws IllegalStateException In the case when the condition is already defined. */ public SimpleCondition gt(long rev) { validate(type()); @@ -124,11 +124,11 @@ public final class SimpleCondition implements Condition { /** * Produces the condition of type {@link ConditionType#REV_GREATER_OR_EQUAL}. This condition tests that the target entry revision is - * greater than or equal to given revision. + * greater than or equals to the given revision. * * @param rev The revision. * @return The condition of type {@link ConditionType#REV_GREATER_OR_EQUAL}. - * @throws IllegalStateException In case when the condition is already defined. + * @throws IllegalStateException In the case when the condition is already defined. */ public SimpleCondition ge(long rev) { validate(type()); @@ -141,29 +141,30 @@ public final class SimpleCondition implements Condition { } /** - * Produces the condition of type {@link ConditionType#REV_LESS}. This condition tests that target entry revision is less than the - * given revision. + * Produces the condition of type {@link ConditionType#REV_LESS}. This condition tests that the target entry revision is less + * than the given revision. * * @param rev The revision. * @return The condition of type {@link ConditionType#REV_LESS}. - * @throws IllegalStateException In case when the condition is already defined. + * @throws IllegalStateException In the case when the condition is already defined. */ public SimpleCondition lt(long rev) { validate(type()); type(ConditionType.REV_LESS); + this.rev = rev; return new SimpleCondition(this); } /** - * Produces the condition of type {@link ConditionType#REV_LESS_OR_EQUAL}. This condition tests that target entry revision is less - * than or equal to the given revision. + * Produces the condition of type {@link ConditionType#REV_LESS_OR_EQUAL}. This condition tests that the target entry revision + * is less than or equals to the given revision. * * @param rev The revision. * @return The condition of type {@link ConditionType#REV_LESS_OR_EQUAL}. - * @throws IllegalStateException In case when the condition is already defined. + * @throws IllegalStateException In the case when the condition is already defined. */ public SimpleCondition le(long rev) { validate(type()); @@ -177,8 +178,8 @@ public final class SimpleCondition implements Condition { } /** - * Represents condition on entry value. Only one type of condition could be applied to the one instance of condition. Subsequent - * invocations of any method which produces condition will throw {@link IllegalStateException}. + * Represents a condition on an entry value. Only the one type of condition could be applied to the one instance of a condition. + * Subsequent invocations of any method, which produces a condition will throw {@link IllegalStateException}. */ public static final class ValueCondition extends AbstractCondition { /** The value as the condition argument. */ @@ -187,7 +188,7 @@ public final class SimpleCondition implements Condition { /** * Constructs a condition by a value for an entry identified by the given key. * - * @param key Identifies an entry which condition will be applied to. + * @param key Identifies an entry, which condition will be applied to. */ ValueCondition(byte[] key) { super(key); @@ -198,12 +199,12 @@ public final class SimpleCondition implements Condition { } /** - * Produces the condition of type {@link ConditionType#VAL_EQUAL}. This condition tests the given value on equality with target + * Produces the condition of type {@link ConditionType#VAL_EQUAL}. This condition tests the given value on equality with the target * entry value. * * @param val The value. * @return The condition of type {@link ConditionType#VAL_EQUAL}. - * @throws IllegalStateException In case when the condition is already defined. + * @throws IllegalStateException In the case when the condition is already defined. */ public SimpleCondition eq(byte[] val) { validate(type()); @@ -217,11 +218,11 @@ public final class SimpleCondition implements Condition { /** * Produces the condition of type {@link ConditionType#VAL_NOT_EQUAL}. This condition tests the given value on inequality with - * target entry value. + * the target entry value. * * @param val The value. * @return The condition of type {@link ConditionType#VAL_NOT_EQUAL}. - * @throws IllegalStateException In case when the condition is already defined. + * @throws IllegalStateException In the case when the condition is already defined. */ public SimpleCondition ne(byte[] val) { validate(type()); @@ -232,17 +233,90 @@ public final class SimpleCondition implements Condition { return new SimpleCondition(this); } + + + /** + * Produces the condition of type {@link ConditionType#VAL_GREATER}. This condition tests that the target entry value is greater + * than the given value in the lexicographical order. + * + * @param val The value. + * @return The condition of type {@link ConditionType#VAL_GREATER}. + * @throws IllegalStateException In the case when the condition is already defined. + */ + public SimpleCondition gt(byte[] val) { + validate(type()); + + type(ConditionType.VAL_GREATER); + + this.val = val; + + return new SimpleCondition(this); + } + + /** + * Produces the condition of type {@link ConditionType#VAL_GREATER_OR_EQUAL}. This condition tests that the target entry value is + * greater than or equals to the given value in the lexicographical order. + * + * @param val The value. + * @return The condition of type {@link ConditionType#VAL_GREATER_OR_EQUAL}. + * @throws IllegalStateException In the case when the condition is already defined. + */ + public SimpleCondition ge(byte[] val) { + validate(type()); + + type(ConditionType.VAL_GREATER_OR_EQUAL); + + this.val = val; + + return new SimpleCondition(this); + } + + /** + * Produces the condition of type {@link ConditionType#VAL_LESS}. This condition tests that the target entry value is less than the + * given value in the lexicographical order. + * + * @param val The value. + * @return The condition of type {@link ConditionType#VAL_LESS}. + * @throws IllegalStateException In the case when the condition is already defined. + */ + public SimpleCondition lt(byte[] val) { + validate(type()); + + type(ConditionType.VAL_LESS); + + this.val = val; + + return new SimpleCondition(this); + } + + /** + * Produces the condition of type {@link ConditionType#VAL_LESS_OR_EQUAL}. This condition tests that the target entry value is less + * than or equals to the given value in the lexicographical order. + * + * @param val The value. + * @return The condition of type {@link ConditionType#VAL_LESS_OR_EQUAL}. + * @throws IllegalStateException In the case when the condition is already defined. + */ + public SimpleCondition le(byte[] val) { + validate(type()); + + type(ConditionType.VAL_LESS_OR_EQUAL); + + this.val = val; + + return new SimpleCondition(this); + } } /** - * Represents condition on an entry existence. Only one type of condition could be applied to the one instance of condition. Subsequent - * invocations of any method which produces condition will throw {@link IllegalStateException}. + * Represents a condition on an entry existence. Only the one type of a condition could be applied to the one instance of a condition. + * Subsequent invocations of any method, which produces a condition will throw {@link IllegalStateException}. */ public static final class ExistenceCondition extends AbstractCondition { /** * Constructs a condition on existence an entry identified by the given key. * - * @param key Identifies an entry which condition will be applied to. + * @param key Identifies an entry, which condition will be applied to. */ ExistenceCondition(byte[] key) { super(key); @@ -253,7 +327,7 @@ public final class SimpleCondition implements Condition { * given key. * * @return The condition of type {@link ConditionType#KEY_EXISTS}. - * @throws IllegalStateException In case when the condition is already defined. + * @throws IllegalStateException In the case when the condition is already defined. */ public SimpleCondition exists() { validate(type()); @@ -268,7 +342,7 @@ public final class SimpleCondition implements Condition { * identified by the given key. * * @return The condition of type {@link ConditionType#KEY_NOT_EXISTS}. - * @throws IllegalStateException In case when the condition is already defined. + * @throws IllegalStateException In the case when the condition is already defined. */ public SimpleCondition notExists() { validate(type()); @@ -280,15 +354,15 @@ public final class SimpleCondition implements Condition { } /** - * Represents condition on an entry's value which checks whether value is tombstone or not. Only one type of condition could be applied - * to the one instance of condition. Subsequent invocations of any method which produces condition will throw {@link - * IllegalStateException}. + * Represents a condition on an entry's value, which checks whether a value is tombstone or not. Only the one type of condition + * could be applied to the one instance of a condition. Subsequent invocations of any method which produces a condition + * will throw {@link IllegalStateException}. */ public static final class TombstoneCondition extends AbstractCondition { /** * Constructs a condition on an entry, identified by the given key, is tombstone. * - * @param key Identifies an entry which condition will be applied to. + * @param key Identifies an entry, which condition will be applied to. */ TombstoneCondition(byte[] key) { super(key); @@ -299,7 +373,7 @@ public final class SimpleCondition implements Condition { * given key, is tombstone. * * @return The condition of type {@link ConditionType#TOMBSTONE}. - * @throws IllegalStateException In case when the condition is already defined. + * @throws IllegalStateException In the case when the condition is already defined. */ public SimpleCondition tombstone() { validate(type()); @@ -311,9 +385,9 @@ public final class SimpleCondition implements Condition { } /** - * Checks that condition is not defined yet. If the condition is already defined then exception will be thrown. + * Checks that condition is not defined yet. If the condition is already defined then the {@link IllegalStateException} will be thrown. * - * @throws IllegalStateException In case when the condition is already defined. + * @throws IllegalStateException In the case when the condition is already defined. */ private static void validate(Enum<?> type) { if (type != null) { @@ -322,13 +396,13 @@ public final class SimpleCondition implements Condition { } /** - * Defines condition interface. + * Defines a condition interface. */ public interface InnerCondition { /** - * Returns key which identifies an entry which condition will be applied to. + * Returns a key, which identifies an entry, which condition will be applied to. * - * @return Key which identifies an entry which condition will be applied to. + * @return Key, which identifies an entry, which condition will be applied to. */ byte[] key(); @@ -336,7 +410,7 @@ public final class SimpleCondition implements Condition { } /** - * Defines an abstract condition with the key which identifies an entry which condition will be applied to. + * Defines an abstract condition with the key, which identifies an entry, which condition will be applied to. */ private abstract static class AbstractCondition implements InnerCondition { /** Entry key. */ @@ -350,16 +424,16 @@ public final class SimpleCondition implements Condition { /** * Constructs a condition with the given entry key. * - * @param key Key which identifies an entry which condition will be applied to. + * @param key Key, which identifies an entry, which condition will be applied to. */ private AbstractCondition(byte[] key) { this.key = key; } /** - * Returns the key which identifies an entry which condition will be applied to. + * Returns the key, which identifies an entry, which condition will be applied to. * - * @return Key which identifies an entry which condition will be applied to. + * @return Key, which identifies an entry, which condition will be applied to. */ @Override public byte[] key() { diff --git a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/ConditionType.java b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/ConditionType.java index 28d1770..08ae8bf 100644 --- a/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/ConditionType.java +++ b/modules/metastorage-common/src/main/java/org/apache/ignite/internal/metastorage/common/ConditionType.java @@ -18,39 +18,51 @@ package org.apache.ignite.internal.metastorage.common; /** - * Defines possible condition types which can be applied to the revision. + * Defines possible condition types, which can be applied to a revision. */ public enum ConditionType { - /** Equality condition type for revision. */ + /** Equality condition type for a revision. */ REV_EQUAL, - /** Inequality condition type for revision. */ + /** Inequality condition type for a revision. */ REV_NOT_EQUAL, - /** Greater than condition type for revision. */ + /** Greater than condition type for a revision. */ REV_GREATER, - /** Less than condition type for revision. */ + /** Less than condition type for a revision. */ REV_LESS, - /** Less than or equal to condition type for revision. */ + /** Less than or equal to condition type for a revision. */ REV_LESS_OR_EQUAL, - /** Greater than or equal to condition type for revision. */ + /** Greater than or equal to condition type for a revision. */ REV_GREATER_OR_EQUAL, - /** Equality condition type for value. */ + /** Equality condition type for a value. */ VAL_EQUAL, - /** Inequality condition type for value. */ + /** Inequality condition type for a value. */ VAL_NOT_EQUAL, - /** Existence condition type for key. */ + /** Greater than condition type for a value. */ + VAL_GREATER, + + /** Less than condition type for a value. */ + VAL_LESS, + + /** Less than or equal to condition type for a value. */ + VAL_LESS_OR_EQUAL, + + /** Greater than or equal to condition type for a value. */ + VAL_GREATER_OR_EQUAL, + + /** Existence condition type for a key. */ KEY_EXISTS, - /** Non-existence condition type for key. */ + /** Non-existence condition type for a key. */ KEY_NOT_EXISTS, - /** Tombstone condition type for key. */ + /** Tombstone condition type for a key. */ TOMBSTONE } diff --git a/modules/metastorage-server/src/main/java/org/apache/ignite/internal/metastorage/server/If.java b/modules/metastorage-server/src/main/java/org/apache/ignite/internal/metastorage/server/If.java index 5477d59..f5b3152 100644 --- a/modules/metastorage-server/src/main/java/org/apache/ignite/internal/metastorage/server/If.java +++ b/modules/metastorage-server/src/main/java/org/apache/ignite/internal/metastorage/server/If.java @@ -20,7 +20,7 @@ package org.apache.ignite.internal.metastorage.server; /** * Root building block for the compound meta storage invoke command. * Contains of boolean condition and 2 branches of execution, like usual programming language's if. - * Every branch can be either new {@link If} statement (non-terminal) or result terminal statement {@link Update}. + * Every branch can be either a new {@link If} statement (non-terminal) or a result terminal statement {@link Update}. */ public class If { /** Boolean condition. */ diff --git a/modules/metastorage-server/src/main/java/org/apache/ignite/internal/metastorage/server/ValueCondition.java b/modules/metastorage-server/src/main/java/org/apache/ignite/internal/metastorage/server/ValueCondition.java index 605d5be..cc3594b 100644 --- a/modules/metastorage-server/src/main/java/org/apache/ignite/internal/metastorage/server/ValueCondition.java +++ b/modules/metastorage-server/src/main/java/org/apache/ignite/internal/metastorage/server/ValueCondition.java @@ -21,14 +21,14 @@ import java.util.Arrays; import org.jetbrains.annotations.NotNull; /** - * Defines condition on entry value. + * Defines condition on entry value. Values are compared in the lexicographical order. */ public class ValueCondition extends AbstractSimpleCondition { /** Condition type. */ @NotNull private final Type type; - /** Value which will be tested against an entry value. */ + /** Value, which will be tested against an entry value. */ @NotNull private final byte[] val; @@ -36,8 +36,8 @@ public class ValueCondition extends AbstractSimpleCondition { * Constructs value condition with the given type, key and value. * * @param type Condition type. Can't be {@code null}. - * @param key Key identifies an entry which condition will be applied to. Can't be {@code null}. - * @param val Value which will be tested against an entry value. Can't be {@code null}. + * @param key Key identifies an entry, which condition will be applied to. Can't be {@code null}. + * @param val Value, which will be tested against an entry value. Can't be {@code null}. */ public ValueCondition(@NotNull Type type, @NotNull byte[] key, @NotNull byte[] val) { super(key); @@ -55,7 +55,7 @@ public class ValueCondition extends AbstractSimpleCondition { } /** - * Defines possible condition types which can be applied to the value. + * Defines possible condition types, which can be applied to the value. Values are compared in the lexicographical order. */ public enum Type { /** Equality condition type. */ @@ -72,6 +72,38 @@ public class ValueCondition extends AbstractSimpleCondition { public boolean test(long res) { return res != 0; } + }, + + /** Greater than condition type. */ + GREATER { + @Override + public boolean test(long res) { + return res > 0; + } + }, + + /** Less than condition type. */ + LESS { + @Override + public boolean test(long res) { + return res < 0; + } + }, + + /** Less than or equal to condition type. */ + LESS_OR_EQUAL { + @Override + public boolean test(long res) { + return res <= 0; + } + }, + + /** Greater than or equal to condition type. */ + GREATER_OR_EQUAL { + @Override + public boolean test(long res) { + return res >= 0; + } }; /** diff --git a/modules/metastorage-server/src/main/java/org/apache/ignite/internal/metastorage/server/raft/MetaStorageListener.java b/modules/metastorage-server/src/main/java/org/apache/ignite/internal/metastorage/server/raft/MetaStorageListener.java index 17d9658..8bb6460 100644 --- a/modules/metastorage-server/src/main/java/org/apache/ignite/internal/metastorage/server/raft/MetaStorageListener.java +++ b/modules/metastorage-server/src/main/java/org/apache/ignite/internal/metastorage/server/raft/MetaStorageListener.java @@ -450,6 +450,14 @@ public class MetaStorageListener implements RaftGroupListener { return new ValueCondition(ValueCondition.Type.EQUAL, key, inf.value()); } else if (type == ConditionType.VAL_NOT_EQUAL) { return new ValueCondition(ValueCondition.Type.NOT_EQUAL, key, inf.value()); + } else if (type == ConditionType.VAL_GREATER) { + return new ValueCondition(ValueCondition.Type.GREATER, key, inf.value()); + } else if (type == ConditionType.VAL_GREATER_OR_EQUAL) { + return new ValueCondition(ValueCondition.Type.GREATER_OR_EQUAL, key, inf.value()); + } else if (type == ConditionType.VAL_LESS) { + return new ValueCondition(ValueCondition.Type.LESS, key, inf.value()); + } else if (type == ConditionType.VAL_LESS_OR_EQUAL) { + return new ValueCondition(ValueCondition.Type.LESS_OR_EQUAL, key, inf.value()); } else if (type == ConditionType.REV_EQUAL) { return new RevisionCondition(RevisionCondition.Type.EQUAL, key, inf.revision()); } else if (type == ConditionType.REV_NOT_EQUAL) { diff --git a/modules/metastorage-server/src/test/java/org/apache/ignite/internal/metastorage/server/RevisionConditionTest.java b/modules/metastorage-server/src/test/java/org/apache/ignite/internal/metastorage/server/RevisionConditionTest.java index 29f14c5..93cf451 100644 --- a/modules/metastorage-server/src/test/java/org/apache/ignite/internal/metastorage/server/RevisionConditionTest.java +++ b/modules/metastorage-server/src/test/java/org/apache/ignite/internal/metastorage/server/RevisionConditionTest.java @@ -73,7 +73,7 @@ public class RevisionConditionTest { } /** - * Tests that revision is greater than or equal to another one . + * Tests that revision is greater than or equal to another one. */ @Test public void ge() { @@ -98,7 +98,7 @@ public class RevisionConditionTest { } /** - * Tests that revision is less than or equal to another one . + * Tests that revision is less than or equal to another one. */ @Test public void le() { diff --git a/modules/metastorage-server/src/test/java/org/apache/ignite/internal/metastorage/server/ValueConditionTest.java b/modules/metastorage-server/src/test/java/org/apache/ignite/internal/metastorage/server/ValueConditionTest.java index f515cf9..0d592b5 100644 --- a/modules/metastorage-server/src/test/java/org/apache/ignite/internal/metastorage/server/ValueConditionTest.java +++ b/modules/metastorage-server/src/test/java/org/apache/ignite/internal/metastorage/server/ValueConditionTest.java @@ -18,7 +18,12 @@ package org.apache.ignite.internal.metastorage.server; import static org.apache.ignite.internal.metastorage.server.ValueCondition.Type.EQUAL; +import static org.apache.ignite.internal.metastorage.server.ValueCondition.Type.GREATER; +import static org.apache.ignite.internal.metastorage.server.ValueCondition.Type.GREATER_OR_EQUAL; +import static org.apache.ignite.internal.metastorage.server.ValueCondition.Type.LESS; +import static org.apache.ignite.internal.metastorage.server.ValueCondition.Type.LESS_OR_EQUAL; import static org.apache.ignite.internal.metastorage.server.ValueCondition.Type.NOT_EQUAL; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; @@ -38,6 +43,9 @@ public class ValueConditionTest { /** Other entry value. */ private static final byte[] VAL_2 = new byte[]{22}; + /** Yet another entry value. */ + private static final byte[] VAL_3 = new byte[]{33}; + /** * Tests values equality. */ @@ -46,6 +54,8 @@ public class ValueConditionTest { Condition cond = new ValueCondition(EQUAL, KEY, VAL_1); assertTrue(cond.test(new Entry(KEY, VAL_1, 1, 1))); + + assertFalse(cond.test(new Entry(KEY, VAL_2, 1, 1))); } /** @@ -56,5 +66,69 @@ public class ValueConditionTest { Condition cond = new ValueCondition(NOT_EQUAL, KEY, VAL_1); assertTrue(cond.test(new Entry(KEY, VAL_2, 1, 1))); + + assertFalse(cond.test(new Entry(KEY, VAL_1, 1, 1))); + } + + /** + * Tests that value is greater than another one. + */ + @Test + public void gt() { + Condition cond = new ValueCondition(GREATER, KEY, VAL_1); + + // byte[]{22} > byte[]{11}. + assertTrue(cond.test(new Entry(KEY, VAL_2, 1, 1))); + + // byte[]{11} > byte[]{11}. + assertFalse(cond.test(new Entry(KEY, VAL_1, 1, 1))); + } + + /** + * Tests that value is greater than or equal to another one. + */ + @Test + public void ge() { + Condition cond = new ValueCondition(GREATER_OR_EQUAL, KEY, VAL_2); + + // byte[]{33} >= byte[]{22}. + assertTrue(cond.test(new Entry(KEY, VAL_3, 1, 1))); + + // byte[]{22} >= byte[]{22}. + assertTrue(cond.test(new Entry(KEY, VAL_2, 1, 1))); + + // byte[]{11} >= byte[]{22}. + assertFalse(cond.test(new Entry(KEY, VAL_1, 1, 1))); + } + + /** + * Tests that value is less than another one. + */ + @Test + public void lt() { + Condition cond = new ValueCondition(LESS, KEY, VAL_2); + + // byte[]{11} < byte[]{22} + assertTrue(cond.test(new Entry(KEY, VAL_1, 1, 1))); + + // byte[]{22} < byte[]{22} + assertFalse(cond.test(new Entry(KEY, VAL_2, 1, 1))); + } + + /** + * Tests that value is less than or equal to another one. + */ + @Test + public void le() { + Condition cond = new ValueCondition(LESS_OR_EQUAL, KEY, VAL_2); + + // byte[]{11} <= byte[]{22} + assertTrue(cond.test(new Entry(KEY, VAL_1, 1, 1))); + + // byte[]{22} <= byte[]{22} + assertTrue(cond.test(new Entry(KEY, VAL_2, 1, 1))); + + // byte[]{33} <= byte[]{22} + assertFalse(cond.test(new Entry(KEY, VAL_3, 1, 1))); } }