Commit da928f4f authored by amir.yosef's avatar amir.yosef

Update validation technique

parent c6c0e76b
<component name="ArtifactManager">
<artifact type="jar" name="Redis:jar">
<output-path>$PROJECT_DIR$/out/artifacts/Redis_jar</output-path>
<root id="archive" name="Redis.jar">
<element id="module-output" name="Redis" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-all-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-codec-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-buffer-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-common-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-handler-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-resolver-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-codec-dns-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-codec-xml-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-transport-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-codec-http-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-codec-mqtt-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-codec-smtp-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-codec-http2-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-codec-redis-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-codec-socks-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-codec-stomp-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-resolver-dns-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-codec-haproxy-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-handler-proxy-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-transport-udt-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-codec-memcache-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-transport-rxtx-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-transport-sctp-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-handler-ssl-ocsp-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-transport-classes-epoll-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-transport-classes-kqueue-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-resolver-dns-classes-macos-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-transport-native-unix-common-4.1.112.Final.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-transport-native-kqueue-4.1.112.Final-osx-x86_64.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-transport-native-epoll-4.1.112.Final-linux-x86_64.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-resolver-dns-native-macos-4.1.112.Final-osx-x86_64.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-transport-native-epoll-4.1.112.Final-linux-riscv64.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-transport-native-kqueue-4.1.112.Final-osx-aarch_64.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-transport-native-epoll-4.1.112.Final-linux-aarch_64.jar" path-in-jar="/" />
<element id="extracted-dir" path="$PROJECT_DIR$/../Socket/lib/netty-resolver-dns-native-macos-4.1.112.Final-osx-aarch_64.jar" path-in-jar="/" />
</root>
</artifact>
</component>
\ No newline at end of file
package command; package command;
import model.Command;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class CommandValidator { public final class CommandValidator {
private CommandValidator() { private static final CommandValidator INSTANCE = new CommandValidator();
}
private static final class InstanceHolder { private CommandValidator() {
private static final CommandValidator instance = new CommandValidator();
} }
public static CommandValidator getInstance() { public static CommandValidator getInstance() {
return InstanceHolder.instance; return INSTANCE;
} }
public boolean validateSetCommand(List<String> args) { public boolean validateSetCommand(List<String> args) {
if (args == null || args.isEmpty()) { if (args == null || args.size() < 2) {
return false; return false;
} }
if (args.size() < 2) { int size = args.size();
return false; if (size == 2) {
return true;
} }
if (args.size() > 2) { boolean hasPx = false;
Map<String, String> commandsMap = IntStream.iterate(2, i -> i < args.size(), i -> i + 2) String pxValue = null;
.boxed()
.collect(Collectors.toMap(i -> args.get(i).toLowerCase(), i -> args.get(i + 1), (a, b) -> b)); for (int i = 2; i < size - 1; i += 2) {
String key = args.get(i).toLowerCase();
String expiration = commandsMap.get(Command.PX.getValue().toLowerCase()); if ("px".equals(key)) {
if (expiration != null) { hasPx = true;
try { pxValue = args.get(i + 1);
Long.parseLong(expiration); break;
} catch (NumberFormatException e) {
return false;
}
} }
} }
if (hasPx) {
return isValidLong(pxValue);
} else {
return size % 2 == 0 || isValidLong(args.get(size - 1));
}
}
private boolean isValidLong(String value) {
if (value == null || value.isEmpty()) {
return false;
}
int len = value.length();
if (len > 19) {
return false;
}
for (int i = 0; i < len; i++) {
char c = value.charAt(i);
if (i == 0 && c == '-') {
if (len == 1) return false;
continue;
}
if (c < '0' || c > '9') {
return false;
}
}
return true; return true;
} }
...@@ -51,8 +67,12 @@ public class CommandValidator { ...@@ -51,8 +67,12 @@ public class CommandValidator {
return args != null && args.size() == 1; return args != null && args.size() == 1;
} }
public boolean validateInfoCommand(List<String> args) { public boolean validateInfoCommand(List<String> args) {
return args != null && args.size() == 1 && "replication".equalsIgnoreCase(args.getFirst()); return args != null && args.size() == 1 &&
"replication".equalsIgnoreCase(args.getFirst());
}
public boolean validateEchoCommand(List<String> args) {
return !args.isEmpty() && args.getFirst() != null;
} }
} }
\ No newline at end of file
...@@ -6,6 +6,7 @@ import java.util.List; ...@@ -6,6 +6,7 @@ import java.util.List;
public class EchoCommand implements CommandExecutable<byte[]> { public class EchoCommand implements CommandExecutable<byte[]> {
private final List<String> args; private final List<String> args;
private final CommandValidator validator = CommandValidator.getInstance();
public EchoCommand(List<String> args) { public EchoCommand(List<String> args) {
this.args = args; this.args = args;
...@@ -13,7 +14,7 @@ public class EchoCommand implements CommandExecutable<byte[]> { ...@@ -13,7 +14,7 @@ public class EchoCommand implements CommandExecutable<byte[]> {
@Override @Override
public byte[] execute() { public byte[] execute() {
if (!args.isEmpty() && args.getFirst() != null) { if (validator.validateEchoCommand(args)) {
return (Response.getResponse(args.getFirst())); return (Response.getResponse(args.getFirst()));
} else { } else {
return "".getBytes(); return "".getBytes();
......
package command; package command;
import model.Command;
import storage.Storage; import storage.Storage;
import util.Response; import util.Response;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class SetCommand implements CommandExecutable<byte[]> { public class SetCommand implements CommandExecutable<byte[]> {
private static final byte[] OK_RESPONSE = "+OK\r\n".getBytes();
private static final byte[] ERROR_RESPONSE = Response.getResponse("wrong args");
private final Storage storage = Storage.getInstance(); private final Storage storage = Storage.getInstance();
private final List<String> args; private final List<String> args;
private final CommandValidator validator = CommandValidator.getInstance(); private final CommandValidator validator = CommandValidator.getInstance();
...@@ -21,21 +20,33 @@ public class SetCommand implements CommandExecutable<byte[]> { ...@@ -21,21 +20,33 @@ public class SetCommand implements CommandExecutable<byte[]> {
@Override @Override
public byte[] execute() { public byte[] execute() {
if (!validator.validateSetCommand(args)) { if (!validator.validateSetCommand(args)) {
return Response.getResponse("wrong args"); return ERROR_RESPONSE;
} }
String key = args.get(0).toLowerCase();
Map<String, String> commandsMap = IntStream.iterate(2, i -> i < args.size(), i -> i + 2)
.boxed()
.collect(Collectors.toMap(i -> args.get(i).toLowerCase(), i -> args.get(i + 1), (a, b) -> b));
String value = args.get(1); String value = args.get(1);
String expiration = commandsMap.get(Command.PX.getValue().toLowerCase());
if (expiration != null) { int size = args.size();
Long expirationTime = Long.parseLong(expiration); if (size > 2) {
storage.save(args.getFirst().toLowerCase(), value, expirationTime); String lastArg = args.get(size - 1);
try {
if (size % 2 == 0) {
if ("px".equalsIgnoreCase(args.get(size - 2))) {
long expirationTime = Long.parseLong(lastArg);
storage.save(key, value, expirationTime);
} else {
storage.save(key, value);
}
} else {
long expirationTime = Long.parseLong(lastArg);
storage.save(key, value, expirationTime);
}
} catch (NumberFormatException e) {
return ERROR_RESPONSE;
}
} else { } else {
storage.save(args.getFirst().toLowerCase(), value); storage.save(key, value);
} }
return ("+OK\r\n".getBytes());
return OK_RESPONSE;
} }
} }
\ No newline at end of file
package command.replica; package command.replica;
import command.CommandExecutable; import command.CommandExecutable;
import model.Command;
import storage.Storage; import storage.Storage;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class ReplicaSetCommand implements CommandExecutable<Void> { public class ReplicaSetCommand implements CommandExecutable<Void> {
private final Storage storage = Storage.getInstance(); private final Storage storage = Storage.getInstance();
...@@ -22,22 +18,27 @@ public class ReplicaSetCommand implements CommandExecutable<Void> { ...@@ -22,22 +18,27 @@ public class ReplicaSetCommand implements CommandExecutable<Void> {
@Override @Override
public Void execute() { public Void execute() {
Map<String, String> commandsMap = IntStream.iterate(2, i -> i < args.size(), i -> i + 2).boxed() String key = args.get(0).toLowerCase();
.collect(Collectors.toMap(i -> args.get(i).toLowerCase(), i -> args.get(i + 1), (a, b) -> b));
String value = args.get(1); String value = args.get(1);
String expiration = commandsMap.get(Command.PX.getValue().toLowerCase()); String expiration = null;
for (int i = 2; i < args.size() - 1; i += 2) {
if ("px".equalsIgnoreCase(args.get(i))) {
expiration = args.get(i + 1);
break;
}
}
if (expiration != null) { if (expiration != null) {
try { try {
Long expirationTime = Long.parseLong(expiration); long expirationTime = Long.parseLong(expiration);
storage.save(args.getFirst().toLowerCase(), value, expirationTime); storage.save(key, value, expirationTime);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
logger.log(Level.SEVERE, "NumberFormatException", e); logger.log(Level.SEVERE, "NumberFormatException", e);
} }
} else { } else {
storage.save(args.getFirst().toLowerCase(), value); storage.save(key, value);
} }
return null; return null;
} }
} }
\ No newline at end of file
...@@ -11,7 +11,6 @@ public enum Command { ...@@ -11,7 +11,6 @@ public enum Command {
PING("PING"), PING("PING"),
PONG("PONG"), PONG("PONG"),
PSYNC("PSYNC"), PSYNC("PSYNC"),
PX("PX"),
REPLCONF("REPLCONF"), REPLCONF("REPLCONF"),
REPLICATION("REPLICATION"), REPLICATION("REPLICATION"),
SET("SET"), SET("SET"),
......
...@@ -5,7 +5,7 @@ import java.util.concurrent.ConcurrentHashMap; ...@@ -5,7 +5,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger; import java.util.logging.Logger;
public class Storage { public class Storage {
private final int capacity = 10000; private final int capacity = 1000000;
private static final Logger logger = Logger.getLogger(Storage.class.getName()); private static final Logger logger = Logger.getLogger(Storage.class.getName());
private final CachePolicy<String, String> storage; private final CachePolicy<String, String> storage;
private final Map<String, Long> timeToExpiration = new ConcurrentHashMap<>(capacity); private final Map<String, Long> timeToExpiration = new ConcurrentHashMap<>(capacity);
...@@ -19,7 +19,7 @@ public class Storage { ...@@ -19,7 +19,7 @@ public class Storage {
} }
private static final class StorageHolder { private static final class StorageHolder {
private static final Storage instance = new Storage(8000); private static final Storage instance = new Storage(800000);
} }
public static Storage getInstance() { public static Storage getInstance() {
......
...@@ -14,7 +14,7 @@ public class StorageManager { ...@@ -14,7 +14,7 @@ public class StorageManager {
public StorageManager() { public StorageManager() {
this.storage = Storage.getInstance(); this.storage = Storage.getInstance();
this.scheduler = Executors.newSingleThreadScheduledExecutor(); this.scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(this::performMaintenance, 2, 2, TimeUnit.MINUTES); scheduler.scheduleAtFixedRate(this::performMaintenance, 30, 30, TimeUnit.SECONDS);
} }
private void performMaintenance() { private void performMaintenance() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment