This is an automated email from the ASF dual-hosted git repository.
sabbey37 pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/develop by this push:
new bcdf3ca GEODE-8582: Redis SCAN returns internal server error (#5603)
bcdf3ca is described below
commit bcdf3ca64d8aca83cdd48629d8a35be6352d2861
Author: Sarah <[email protected]>
AuthorDate: Thu Oct 8 09:35:05 2020 -0400
GEODE-8582: Redis SCAN returns internal server error (#5603)
Co-authored-by: Darrel Schneider <[email protected]>
---
.../ScanNativeRedisAcceptanceTest.java} | 5 +-
.../pubsub/PubSubNativeRedisAcceptanceTest.java | 2 +
.../executor/key/AbstractScanIntegrationTest.java | 112 +++++++++++++++++++++
.../executor/key/ScanIntegrationTest.java} | 11 +-
.../redis/internal/executor/key/ScanExecutor.java | 37 +++----
5 files changed, 142 insertions(+), 25 deletions(-)
diff --git
a/geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/pubsub/PubSubNativeRedisAcceptanceTest.java
b/geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/key/ScanNativeRedisAcceptanceTest.java
similarity index 87%
copy from
geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/pubsub/PubSubNativeRedisAcceptanceTest.java
copy to
geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/key/ScanNativeRedisAcceptanceTest.java
index ce7778f..237d691 100644
---
a/geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/pubsub/PubSubNativeRedisAcceptanceTest.java
+++
b/geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/key/ScanNativeRedisAcceptanceTest.java
@@ -13,13 +13,14 @@
* the License.
*/
-package org.apache.geode.redis.internal.executor.pubsub;
+package org.apache.geode.redis.internal.executor.key;
import org.junit.ClassRule;
import org.apache.geode.NativeRedisTestRule;
-public class PubSubNativeRedisAcceptanceTest extends
AbstractPubSubIntegrationTest {
+public class ScanNativeRedisAcceptanceTest extends AbstractScanIntegrationTest
{
+
@ClassRule
public static NativeRedisTestRule redis = new NativeRedisTestRule();
diff --git
a/geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/pubsub/PubSubNativeRedisAcceptanceTest.java
b/geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/pubsub/PubSubNativeRedisAcceptanceTest.java
index ce7778f..772ebb1 100644
---
a/geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/pubsub/PubSubNativeRedisAcceptanceTest.java
+++
b/geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/pubsub/PubSubNativeRedisAcceptanceTest.java
@@ -16,9 +16,11 @@
package org.apache.geode.redis.internal.executor.pubsub;
import org.junit.ClassRule;
+import org.junit.Ignore;
import org.apache.geode.NativeRedisTestRule;
+@Ignore("GEODE-8577")
public class PubSubNativeRedisAcceptanceTest extends
AbstractPubSubIntegrationTest {
@ClassRule
public static NativeRedisTestRule redis = new NativeRedisTestRule();
diff --git
a/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/executor/key/AbstractScanIntegrationTest.java
b/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/executor/key/AbstractScanIntegrationTest.java
new file mode 100644
index 0000000..7ab33ba
--- /dev/null
+++
b/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/executor/key/AbstractScanIntegrationTest.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
contributor license
+ * agreements. See the NOTICE file distributed with this work for additional
information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache
License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express
+ * or implied. See the License for the specific language governing permissions
and limitations under
+ * the License.
+ */
+
+package org.apache.geode.redis.internal.executor.key;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.ScanParams;
+import redis.clients.jedis.ScanResult;
+
+import org.apache.geode.test.awaitility.GeodeAwaitility;
+import org.apache.geode.test.dunit.rules.RedisPortSupplier;
+
+public abstract class AbstractScanIntegrationTest implements RedisPortSupplier
{
+
+ private Jedis jedis;
+ private static final int REDIS_CLIENT_TIMEOUT =
+ Math.toIntExact(GeodeAwaitility.getTimeout().toMillis());
+
+ @Before
+ public void setUp() {
+ jedis = new Jedis("localhost", getPort(), REDIS_CLIENT_TIMEOUT);
+ }
+
+ @After
+ public void tearDown() {
+ jedis.flushAll();
+ jedis.close();
+ }
+
+ @Test
+ public void givenOneKey_scanReturnsKey() {
+ jedis.set("a", "1");
+ ScanResult<String> result = jedis.scan("0");
+
+ assertThat(result.isCompleteIteration()).isTrue();
+ assertThat(result.getResult()).containsExactly("a");
+ }
+
+ @Test
+ public void givenEmptyDatabase_scanReturnsEmptyResult() {
+ ScanResult<String> result = jedis.scan("0");
+
+ assertThat(result.isCompleteIteration()).isTrue();
+ assertThat(result.getResult()).isEmpty();
+ }
+
+ @Test
+ public void givenMultipleKeys_scanReturnsAllKeys() {
+ jedis.set("a", "1");
+ jedis.sadd("b", "green", "orange");
+ jedis.hset("c", "potato", "sweet");
+ ScanResult<String> result = jedis.scan("0");
+
+ assertThat(result.isCompleteIteration()).isTrue();
+ assertThat(result.getResult()).containsExactlyInAnyOrder("a", "b", "c");
+ }
+
+ @Test
+ public void givenMultipleKeysWithCount_scanReturnsAllKeysWithoutDuplicates()
{
+ jedis.set("a", "1");
+ jedis.sadd("b", "green", "orange");
+ jedis.hset("c", "potato", "sweet");
+ ScanParams scanParams = new ScanParams();
+ scanParams.count(1);
+
+ ScanResult<String> result = jedis.scan("0", scanParams);
+ List<String> allKeysFromScan = new ArrayList<>();
+ allKeysFromScan.addAll(result.getResult());
+
+ while (!result.isCompleteIteration()) {
+ result = jedis.scan(result.getCursor(), scanParams);
+ allKeysFromScan.addAll(result.getResult());
+ }
+
+ assertThat(result.isCompleteIteration()).isTrue();
+ assertThat(allKeysFromScan).containsExactlyInAnyOrder("a", "b", "c");
+ }
+
+ @Test
+ public void
givenMultipleKeysWithMatch_scanReturnsAllMatchingKeysWithoutDuplicates() {
+ jedis.set("a", "1");
+ jedis.sadd("b", "green", "orange");
+ jedis.hset("c", "potato", "sweet");
+ ScanParams scanParams = new ScanParams();
+ scanParams.match("a*");
+
+ ScanResult<String> result = jedis.scan("0", scanParams);
+
+ assertThat(result.isCompleteIteration()).isTrue();
+ assertThat(result.getResult()).containsExactly("a");
+ }
+}
diff --git
a/geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/pubsub/PubSubNativeRedisAcceptanceTest.java
b/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/executor/key/ScanIntegrationTest.java
similarity index 75%
copy from
geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/pubsub/PubSubNativeRedisAcceptanceTest.java
copy to
geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/executor/key/ScanIntegrationTest.java
index ce7778f..bfc9e54 100644
---
a/geode-redis/src/acceptanceTest/java/org/apache/geode/redis/internal/executor/pubsub/PubSubNativeRedisAcceptanceTest.java
+++
b/geode-redis/src/integrationTest/java/org/apache/geode/redis/internal/executor/key/ScanIntegrationTest.java
@@ -13,19 +13,20 @@
* the License.
*/
-package org.apache.geode.redis.internal.executor.pubsub;
+package org.apache.geode.redis.internal.executor.key;
import org.junit.ClassRule;
-import org.apache.geode.NativeRedisTestRule;
+import org.apache.geode.redis.GeodeRedisServerRule;
+
+public class ScanIntegrationTest extends AbstractScanIntegrationTest {
-public class PubSubNativeRedisAcceptanceTest extends
AbstractPubSubIntegrationTest {
@ClassRule
- public static NativeRedisTestRule redis = new NativeRedisTestRule();
+ public static GeodeRedisServerRule server = new GeodeRedisServerRule();
@Override
public int getPort() {
- return redis.getPort();
+ return server.getPort();
}
}
diff --git
a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/key/ScanExecutor.java
b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/key/ScanExecutor.java
index aaf68be..ee2715e 100755
---
a/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/key/ScanExecutor.java
+++
b/geode-redis/src/main/java/org/apache/geode/redis/internal/executor/key/ScanExecutor.java
@@ -24,6 +24,7 @@ import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.apache.geode.redis.internal.RedisConstants.ArityDef;
+import org.apache.geode.redis.internal.data.ByteArrayWrapper;
import org.apache.geode.redis.internal.executor.RedisResponse;
import org.apache.geode.redis.internal.netty.Coder;
import org.apache.geode.redis.internal.netty.Command;
@@ -32,8 +33,7 @@ import
org.apache.geode.redis.internal.netty.ExecutionHandlerContext;
public class ScanExecutor extends AbstractScanExecutor {
@Override
- public RedisResponse executeCommand(Command command,
- ExecutionHandlerContext context) {
+ public RedisResponse executeCommand(Command command, ExecutionHandlerContext
context) {
List<byte[]> commandElems = command.getProcessedCommand();
if (commandElems.size() < 2) {
@@ -93,36 +93,37 @@ public class ScanExecutor extends AbstractScanExecutor {
return RedisResponse.error(ERROR_ILLEGAL_GLOB);
}
- @SuppressWarnings("unchecked")
- List<String> returnList = (List<String>)
getIteration(getDataRegion(context).keySet(),
- matchPattern, count, cursor);
+ List<String> returnList = getIteration(getDataRegion(context).keySet(),
matchPattern, count,
+ cursor);
return RedisResponse.scan(returnList);
}
- @SuppressWarnings("unchecked")
- private List<?> getIteration(Collection<?> list, Pattern matchPattern, int
count, int cursor) {
- List<String> returnList = new ArrayList<String>();
+ private List<String> getIteration(Collection<ByteArrayWrapper> list, Pattern
matchPattern,
+ int count, int cursor) {
+ List<String> returnList = new ArrayList<>();
int size = list.size();
int beforeCursor = 0;
int numElements = 0;
int i = -1;
- for (String key : (Collection<String>) list) {
+ for (ByteArrayWrapper key : list) {
i++;
if (beforeCursor < cursor) {
beforeCursor++;
continue;
- } else if (numElements < count) {
- if (matchPattern != null) {
- if (matchPattern.matcher(key).matches()) {
- returnList.add(key);
- numElements++;
- }
- } else {
- returnList.add(key);
+ }
+
+ String keyString = key.toString();
+ if (matchPattern != null) {
+ if (matchPattern.matcher(keyString).matches()) {
+ returnList.add(keyString);
numElements++;
}
} else {
+ returnList.add(keyString);
+ numElements++;
+ }
+ if (numElements == count) {
break;
}
}
@@ -130,7 +131,7 @@ public class ScanExecutor extends AbstractScanExecutor {
if (i >= size - 1) {
returnList.add(0, String.valueOf(0));
} else {
- returnList.add(0, String.valueOf(i));
+ returnList.add(0, String.valueOf(i + 1));
}
return returnList;
}