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

Initial commit

parents
### IntelliJ IDEA ###
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store
\ No newline at end of file
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
<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
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_STRING" value="--add-modules jdk.incubator.vector" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GoogleJavaFormatSettings">
<option name="enabled" value="false" />
</component>
</project>
\ No newline at end of file
<component name="libraryTable">
<library name="lib">
<CLASSES>
<root url="file://$PROJECT_DIR$/../Socket/lib" />
</CLASSES>
<JAVADOC />
<SOURCES />
<jarDirectory url="file://$PROJECT_DIR$/../Socket/lib" recursive="false" />
</library>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JsBuildToolPackageJson" sorting="DEFINITION_ORDER" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21 (5)" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/Redis.iml" filepath="$PROJECT_DIR$/Redis.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/key_value-server" vcs="Git" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="lib" level="project" />
</component>
</module>
\ No newline at end of file
key_value-server @ 212688a2
Subproject commit 212688a2e86cce11dbb31cfa0390c8a489418476
import server.Server;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
try {
Server.getInstance().start();
} catch (IOException e) {
System.err.println("Server failed to start: " + e.getMessage());
}
}
}
\ No newline at end of file
package client;
import parser.CommandParser;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
public abstract class Client {
protected final CommandParser commandParser;
protected final Socket socket;
protected BufferedReader reader;
protected Client(Socket socket) {
this.socket = socket;
this.commandParser = new CommandParser();
}
protected Client(BufferedReader reader, Socket socket) {
this.reader = reader;
this.commandParser = new CommandParser();
this.socket = socket;
}
public void run() {
try (OutputStream outputStream = socket.getOutputStream()) {
if (reader == null) {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
handleClient(reader, outputStream);
} catch (IOException e) {
System.out.println("IOException while handling client: " + e.getMessage());
}
}
protected abstract void handleClient(BufferedReader bufferedReader, OutputStream outputStream) throws IOException;
}
package client.primary;
import client.Client;
import handlers.ClientCommandHandler;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.List;
public class PrimaryClient extends Client {
public PrimaryClient(Socket socket) {
super(socket);
}
@Override
protected void handleClient(BufferedReader bufferedReader, OutputStream outputStream) throws IOException {
String line;
while ((line = bufferedReader.readLine()) != null) {
if (line.isEmpty()) continue;
List<String> parsedCommands = commandParser.parseCommand(bufferedReader, line);
ClientCommandHandler commandHandler = new ClientCommandHandler(parsedCommands, outputStream);
commandHandler.execute();
}
}
}
package command;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
public interface CommandHandler {
void execute(List<String> command, OutputStream os) throws IOException;
}
package command;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
public class CommandInvoker {
public static void invoke(CommandHandler command, List<String> CommandAndArgs, OutputStream os) throws IOException {
command.execute(CommandAndArgs, os);
}
}
package command;
import util.Response;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
public class EchoCommand implements CommandHandler {
@Override
public void execute(List<String> command, OutputStream os) {
try {
os.write(Response.getResponse(command.get(1)));
os.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
package command;
import storage.Storage;
import util.Response;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
public class GetCommand implements CommandHandler {
private final Storage storage = Storage.getInstance();
@Override
public void execute(List<String> commands, OutputStream os) {
try {
String response = storage.get(commands.get(1).toLowerCase());
if (response == null || response.isEmpty() || response.isBlank()) {
os.write("$-1\r\n".getBytes());
os.flush();
return;
}
os.write(Response.getResponse(response));
os.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
package command;
import model.Command;
import server.Configuration;
import util.Response;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class InfoCommand implements CommandHandler {
private final Configuration configuration = Configuration.getInstance();
@Override
public void execute(List<String> commands, OutputStream os) {
System.out.println(configuration.getInfo());
String command = commands.getFirst();
if (command.equalsIgnoreCase(Command.REPLICATION.getValue())) {
Map<String, String> info = configuration.getInfo();
String response = info.entrySet()
.stream()
.map(data -> data.getKey() + ":" + data.getValue())
.collect(Collectors.joining());
try {
os.write(Response.getResponse(response));
os.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
\ No newline at end of file
package command;
import model.Command;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
public class PingCommand implements CommandHandler {
@Override
public void execute(List<String> command, OutputStream os) {
System.out.printf("Processing PING command %s%n", command);
try {
os.write(("+" + Command.PONG.getValue() + "\r\n").getBytes());
os.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
\ No newline at end of file
package command;
import model.Command;
import storage.Storage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SetCommand implements CommandHandler {
private final Storage redisStorage = Storage.getInstance();
@Override
public void execute(List<String> commands, OutputStream os) {
Map<String, String> commandsMap = new HashMap<>();
//
// for (int i = 2; i < commands.size(); i += 2) {
// commandsMap.put(commands.get(i).toLowerCase(), commands.get(i + 1));
// }
String value = commands.get(2);
String expiration = commandsMap.get(Command.PX.getValue().toLowerCase());
if (expiration != null) {
try {
Long expirationTime = Long.parseLong(expiration);
redisStorage.save(commands.getFirst().toLowerCase(), value, expirationTime);
} catch (NumberFormatException e) {
System.out.println("NumberFormatException: " + e.getMessage());
}
} else {
redisStorage.save(commands.get(1).toLowerCase(), value);
}
try {
os.write("+OK\r\n".getBytes());
os.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
package command;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
public class UnknownCommand implements CommandHandler {
@Override
public void execute(List<String> command, OutputStream os) {
System.out.printf("Received unknown command %s%n", command);
try {
os.write(("-" + "Unknown Command" + "\r\n").getBytes());
os.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
package command.replica.handshake;
import model.Command;
import parser.CommandParser;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
public class PingCommand extends Sender {
public PingCommand(CommandParser commandParser) {
super(commandParser);
}
@Override
public void send(BufferedReader bufferedReader, OutputStream outputStream) throws IOException {
byte[] bytes = commandParser.getResponseFromCommandArray(List.of(Command.PING.getValue().toLowerCase())).getBytes();
outputStream.write(bytes);
outputStream.flush();
}
}
package command.replica.handshake;
import model.Command;
import parser.CommandParser;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
public class ReplConfCommand extends Sender {
private final String port;
public ReplConfCommand(String port, CommandParser commandParser) {
super(commandParser);
this.port = port;
}
@Override
public void send(BufferedReader bufferedReader, OutputStream outputStream) throws IOException {
String replconfResp = "";
replconfResp = getReplconfResp(bufferedReader, outputStream);
if (!replconfResp.isEmpty()) {
replconfResp = sendReplConfCapa(bufferedReader, outputStream);
}
if (!replconfResp.isEmpty()) {
outputStream.write(commandParser.getResponseFromCommandArray(List.of(Command.PSYNC.getValue(), "?", "-1")).getBytes());
}
}
private String sendReplConfCapa(BufferedReader bufferedReader, OutputStream outputStream) throws IOException {
outputStream.write(commandParser.getResponseFromCommandArray(List.of(
Command.REPLCONF.getValue(),
"capa",
"npsync2")
).getBytes()
);
outputStream.flush();
return bufferedReader.readLine();
}
private String getReplconfResp(BufferedReader bufferedReader, OutputStream outputStream) throws IOException {
outputStream.write(commandParser.getResponseFromCommandArray(List.of(
Command.REPLCONF.getValue(),
"listening-port",
String.valueOf(port))
).getBytes()
);
outputStream.flush();
return bufferedReader.readLine();
}
}
package command.replica.handshake;
import parser.CommandParser;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStream;
public abstract class Sender {
protected final CommandParser commandParser;
protected Sender(CommandParser commandParser) {
this.commandParser = commandParser;
}
public abstract void send(BufferedReader bufferedReader, OutputStream outputStream) throws IOException;
}
package factory;
import command.*;
import model.Command;
public class CommandFactory implements Factory {
private final Command command;
public CommandFactory(Command command) {
this.command = command;
}
public CommandHandler getInstance() {
return switch (command) {
case PING -> new PingCommand();
case ECHO -> new EchoCommand();
case SET -> new SetCommand();
case GET -> new GetCommand();
case INFO -> new InfoCommand();
// case REPLCONF -> new ReplConfCommand(replicaReceiver);
// case PSYNC -> new FullResyncCommandProcessor(replicaSender);
// case WAIT -> new WaitCommandProcessor(replicaSender, replicaReceiver);
// case CONFIG -> new ConfigCommandProcessor();
// case KEYS -> new KeysCommandProcessor();
// case TYPE -> new TypeCommandProcessor();
// case XADD -> new XaddCommandProcessor();
// case XRANGE -> new XrangeCommandProcessor();
// case XREAD -> new XreadCommandProcessor();
// case INCR -> new IncrCommandProcessor();
// case MULTI -> new MultiCommandProcessor(transactionMultiCommandService);
// case EXEC -> new ExecCommandProcessor(transactionMultiCommandService);
// case DISCARD -> new DiscardCommandProcessor(transactionMultiCommandService);
default -> new UnknownCommand();
};
}
}
package factory;
import command.CommandHandler;
public interface Factory {
CommandHandler getInstance();
}
package handlers;
import command.CommandHandler;
import command.CommandInvoker;
import factory.CommandFactory;
import model.Command;
import parser.CommandParser;
import util.CommandUtil;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;
public class ClientCommandHandler {
private final List<String> commands;
private final OutputStream os;
public ClientCommandHandler(List<String> commands, OutputStream outputStream) {
this.commands = commands;
this.os = outputStream;
CommandParser commandParser = new CommandParser();
}
public boolean execute() {
Command command = CommandUtil.getCommand(commands.getFirst().split(" ")[0]);
CommandHandler commandProcessor = new CommandFactory(command).getInstance();
List<String> commandAndArgs = Arrays.stream(commands.getFirst().split(" ")).toList();
try {
CommandInvoker.invoke(commandProcessor, commandAndArgs, os);
} catch (IOException e) {
throw new RuntimeException(e);
}
return false;
}
}
package model;
public enum Command {
ACK("ACK"),
CONFIG("CONFIG"),
ECHO("ECHO"),
FULLRESYNC("FULLRESYNC"),
GET("GET"),
INCR("INCR"),
INFO("INFO"),
KEYS("KEYS"),
PING("PING"),
PONG("PONG"),
PSYNC("PSYNC"),
PX("PX"),
REPLCONF("REPLCONF"),
REPLICATION("REPLICATION"),
SET("SET"),
TYPE("TYPE"),
WAIT("WAIT"),
XADD("XADD"),
XRANGE("XRANGE"),
XREAD("XREAD"), MULTI("MULTI"), EXEC("EXEC"), DISCARD("DISCARD");
private final String value;
Command(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
package parser;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class CommandParser {
public List<String> parseCommand(BufferedReader bufferedReader, String line) {
try {
ArrayList<String> commands = new ArrayList<>();
if (line.startsWith("*")) {
String substring = line.substring(1);
for (int i = 0; i < Integer.parseInt(substring); i++) {
bufferedReader.readLine();
String nextCommand = bufferedReader.readLine();
commands.add(nextCommand);
}
} else commands.add(line);
//System.out.println("Parsing commands: " + commands);
return commands;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public String getResponseFromCommandArray(List<String> command) {
StringBuilder sb = new StringBuilder();
sb.append("*").append(command.size()).append("\r\n");
for (String s : command) {
sb.append("$").append(s.length()).append("\r\n").append(s).append("\r\n");
}
return sb.toString();
}
}
package server;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class Configuration {
private final Map<String, String> info = new ConcurrentHashMap<>();
private Configuration() {
info.put("role", "master");
}
private static final class ConfigurationHolder {
private static final Configuration configuration = new Configuration();
}
public static Configuration getInstance() {
return ConfigurationHolder.configuration;
}
public String getRole() {
return ConfigurationHolder.configuration.info.get("role");
}
public String[] findRole(Map<String, String> parameters) {
String[] masterPortAndHost = new String[]{};
String role = "master";
if (parameters.containsKey("--replicaof")) {
masterPortAndHost = parameters.get("--replicaof").split(" ");
role = "slave";
} else {
info.put("master_repl_offset", "0");
info.put("master_replid", "8371b4fb1155b71f4a04d3e1bc3e18c4a990aeeb");
}
info.put("role", role);
return masterPortAndHost;
}
public Map<String, String> getInfo() {
return this.info;
}
}
package server;
import client.Client;
import client.primary.PrimaryClient;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Server {
private static final int PORT = 16379;
private final ExecutorService executor;
private static Server instance;
private Server() {
this.executor = Executors.newVirtualThreadPerTaskExecutor();
}
public static synchronized Server getInstance() throws IOException {
if (instance == null) {
instance = new Server();
}
return instance;
}
public void start() {
try (ServerSocket serverSocket = new ServerSocket(PORT)) {
System.out.println("Server started on port " + PORT);
while (true) {
serverSocket.setReuseAddress(true);
Socket clientSocket = serverSocket.accept();
System.out.println("New client connected: " + clientSocket.getRemoteSocketAddress());
handleClient(clientSocket);
}
} catch (IOException e) {
e.getStackTrace();
System.out.println("Server failed to handle: " + e.getMessage());
}
}
private void handleClient(Socket clientSocket) {
executor.submit(() -> {
Client task = new PrimaryClient(clientSocket);
task.run();
});
}
}
package storage;
public record RdbFile(String path, String fileName) {
}
package storage;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.lang.System.out;
public class RdbFileInfo {
private static RdbFileInfo instance;
private RdbFile rdbFile;
private RdbFileInfo() {
}
public static synchronized RdbFileInfo getInstance() {
if (instance == null) {
instance = new RdbFileInfo();
}
return instance;
}
public byte[] getContent() {
byte[] decode;
try (Stream<String> stringStream = Files.lines(Path.of(rdbFile.path() + "/" + rdbFile.fileName()))) {
String rdbFile = stringStream.collect(Collectors.joining());
decode = Base64.getDecoder().decode(rdbFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
return decode;
}
public String getFileName() {
return rdbFile.fileName();
}
public String getPath() {
return rdbFile.path();
}
public void setFile(Map<String, String> parameters) {
String path = "C:\\Users\\Amir\\Desktop\\Redis\\tmp";
String fileName = "rdb.rdb";
out.println(parameters);
if (parameters.containsKey("--dir")) {
path = parameters.get("--dir");
}
if (parameters.containsKey("--dbfilename")) {
fileName = parameters.get("--dbfilename");
}
if (path.isEmpty() || fileName.isEmpty()) {
return;
}
this.rdbFile = new RdbFile(path, fileName);
out.println(fileName);
String pathname = rdbFile.path() + "/" + rdbFile.fileName();
File file1 = new File(pathname);
if (!file1.exists()) {
boolean mkdir = file1.getParentFile().mkdirs();
out.println(mkdir);
try (FileWriter writer = new FileWriter(file1)) {
writer.write("UkVESVMwMDEx+glyZWRpcy12ZXIFNy4yLjD6CnJlZGlzLWJpdHPAQPoFY3RpbWXCbQi8ZfoIdXNlZC1tZW3CsMQQAPoIYW9mLWJhc2XAAP/wbjv+wP9aog==");
writer.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
package storage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import static java.lang.System.out;
public class RdbFileReader {
private final RdbFileInfo rdbFileInfo;
private final Map<String, Long> keysExpiration;
public RdbFileReader() {
rdbFileInfo = RdbFileInfo.getInstance();
keysExpiration = new HashMap<>();
}
private static String getKey(InputStream fis, int b) throws IOException {
String key;
int strLength = lengthEncoding(fis, b);
b = fis.read();
out.println("strLength == " + strLength);
if (strLength == 0) {
strLength = b;
}
byte[] bytes = fis.readNBytes(strLength);
key = new String(bytes);
return key;
}
private static String getValue(InputStream fis) throws IOException {
int strLength;
int b;
b = fis.read();
strLength = lengthEncoding(fis, b);
if (strLength == 0) {
strLength = b;
}
byte[] bytesValue = fis.readNBytes(strLength);
String value = new String(bytesValue);
out.println(value);
return value;
}
private static int lengthEncoding(InputStream is, int b) throws IOException {
int length = 100;
int first2bits = b & 11000000;
out.println("first2bits = " + first2bits);
if (first2bits == 0) {
out.println("00");
length = 0;
} else if (first2bits == 128) {
out.println("01");
length = 2;
} else if (first2bits == 256) {
out.println("10");
ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
buffer.put(is.readNBytes(4));
buffer.rewind();
length = 1 + buffer.getInt();
} else if (first2bits == 256 + 128) {
out.println("11");
length = 1;
}
return length;
}
public Map<String, String> readFile() {
String key = "";
Long expiration = null;
Map<String, String> storage = new HashMap<>();
try (
InputStream fis =
new FileInputStream(new File(rdbFileInfo.getPath(), rdbFileInfo.getFileName()))) {
byte[] redis = new byte[5];
byte[] version = new byte[4];
fis.read(redis);
fis.read(version);
out.println("Magic String = " +
new String(redis, StandardCharsets.UTF_8));
out.println("Version = " +
new String(version, StandardCharsets.UTF_8));
int b;
header:
while ((b = fis.read()) != -1) {
switch (b) {
case 0xFF:
out.println("EOF");
break;
case 0xFE:
out.println("SELECTDB");
break;
case 0xFD:
out.println("EXPIRETIME");
break;
case 0xFC:
out.println("EXPIRETIMEMS");
break;
case 0xFB:
out.println("RESIZEDB");
b = fis.read();
fis.readNBytes(lengthEncoding(fis, b));
fis.readNBytes(lengthEncoding(fis, b));
break header;
case 0xFA:
out.println("AUX");
break;
}
}
out.println("header done");
b = fis.read();
while ((b = fis.read()) != -1) {
out.println("value-type = " + b);
out.println("value-type = " + b);
if (b == 0xFC) {
expiration = getExpiration(fis);
out.println("expiration = " + expiration);
b = fis.read();
}
out.println(" b = " + Integer.toBinaryString(b));
if (!Integer.toBinaryString(b).equals("0")) {
break;
}
out.println("reading keys");
key = getKey(fis, b);
out.println(key);
String value = getValue(fis);
storage.put(key, value);
if (expiration != null && expiration != 0) {
keysExpiration.put(key, expiration);
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
out.flush();
return storage;
}
private Long getExpiration(InputStream fis) {
try {
byte[] bytes = fis.readNBytes(8);
ByteBuffer wrap = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
return wrap.getLong();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public Map<String, Long> getKeysExpiration() {
return keysExpiration;
}
}
package storage;
import jdk.incubator.vector.ByteVector;
import jdk.incubator.vector.VectorMask;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorSpecies;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class Storage {
private final Map<String, String> storage = new ConcurrentHashMap<>(10000);
private final Map<String, Long> timeToExpiration = new ConcurrentHashMap<>(10000);
private final Map<String, Long> currentTimeForKey = new ConcurrentHashMap<>(10000);
private static final VectorSpecies<Byte> SPECIES = ByteVector.SPECIES_128;
private Storage() {
// RdbFileReader reader = new RdbFileReader();
//Map<String, String> stringStringMap = reader.readFile();
// storage.putAll(stringStringMap);
//Map<String, Long> keysExpiration = reader.getKeysExpiration();
// timeToExpiration.putAll(keysExpiration);
}
private static final class StorageHolder {
private static final Storage storage = new Storage();
}
public static Storage getInstance() {
return StorageHolder.storage;
}
public void save(String key, String value) {
storage.put(key, value);
}
public void save(String key, String value, Long time) {
System.out.println("SAVE Storage: " + key);
currentTimeForKey.put(key, System.currentTimeMillis());
timeToExpiration.put(key, time);
save(key, value);
}
public String get(String key) {
System.out.println("GET Storage: " + key);
if (isExpired(key)) {
System.out.println("Key expired: " + key);
return "";
}
return storage.get(key);
}
private boolean isExpired(String key) {
long currentTime = System.currentTimeMillis();
if (timeToExpiration.containsKey(key)) {
long expirationTime = timeToExpiration.get(key);
if (currentTimeForKey.containsKey(key)) {
long currExpiration = currentTimeForKey.get(key);
long timeDiff = currentTime - currExpiration;
return vectorizedComparison(timeDiff, expirationTime);
} else {
return vectorizedComparison(currentTime, expirationTime);
}
}
return false;
}
private boolean vectorizedComparison(long timeDiff, long expirationTime) {
// Convert timeDiff and expirationTime to byte arrays for SIMD processing
byte[] timeDiffBytes = longToBytes(timeDiff);
byte[] expirationTimeBytes = longToBytes(expirationTime);
ByteVector timeDiffVector = ByteVector.fromArray(SPECIES, timeDiffBytes, 0);
ByteVector expirationTimeVector = ByteVector.fromArray(SPECIES, expirationTimeBytes, 0);
VectorMask<Byte> mask = timeDiffVector.compare(VectorOperators.GT, expirationTimeVector);
return mask.anyTrue();
}
private byte[] longToBytes(long value) {
byte[] bytes = new byte[8];
for (int i = 7; i >= 0; i--) {
bytes[i] = (byte) (value & 0xFF);
value >>= 8;
}
return bytes;
}
}
package util;
import model.Command;
public class CommandUtil {
public static Command getCommand(String command) {
if (command.toLowerCase().contains(Command.ECHO.getValue().toLowerCase())) {
return Command.ECHO;
} else if (command.toLowerCase().contains(Command.PING.getValue().toLowerCase())) {
return Command.PING;
} else if (command.toLowerCase().contains(Command.SET.getValue().toLowerCase())) {
return Command.SET;
} else if (command.toLowerCase().contains(Command.GET.getValue().toLowerCase())) {
return Command.GET;
} else if (command.toLowerCase().contains(Command.INFO.getValue().toLowerCase())) {
return Command.INFO;
} else if (command.toLowerCase().contains(Command.REPLCONF.getValue().toLowerCase()) || command.equalsIgnoreCase(Command.REPLCONF.getValue())) {
return Command.REPLCONF;
} else if (command.toLowerCase().contains(Command.FULLRESYNC.getValue().toLowerCase()) || command.equalsIgnoreCase(Command.FULLRESYNC.getValue())) {
return Command.FULLRESYNC;
} else if (command.toLowerCase().contains(Command.PSYNC.getValue()) || command.equalsIgnoreCase(Command.PSYNC.getValue())) {
return Command.PSYNC;
} else if (command.toLowerCase().contains(Command.WAIT.getValue()) || command.equalsIgnoreCase(Command.WAIT.getValue())) {
return Command.WAIT;
} else if (command.toLowerCase().contains(Command.CONFIG.getValue()) || command.equalsIgnoreCase(Command.CONFIG.getValue())) {
return Command.CONFIG;
} else if (command.toLowerCase().contains(Command.KEYS.getValue()) || command.equalsIgnoreCase(Command.KEYS.getValue())) {
return Command.KEYS;
} else if (command.toLowerCase().contains(Command.TYPE.getValue()) || command.equalsIgnoreCase(Command.TYPE.getValue())) {
return Command.TYPE;
} else if (command.toLowerCase().contains(Command.XADD.getValue()) || command.equalsIgnoreCase(Command.XADD.getValue())) {
return Command.XADD;
} else if (command.toLowerCase().contains(Command.XRANGE.getValue()) || command.equalsIgnoreCase(Command.XRANGE.getValue())) {
return Command.XRANGE;
} else if (command.toLowerCase().contains(Command.XREAD.getValue()) || command.equalsIgnoreCase(Command.XREAD.getValue())) {
return Command.XREAD;
} else if (command.toLowerCase().contains(Command.INCR.getValue()) || command.equalsIgnoreCase(Command.INCR.getValue())) {
return Command.INCR;
} else if (command.toLowerCase().contains(Command.MULTI.getValue()) || command.equalsIgnoreCase(Command.MULTI.getValue())) {
return Command.MULTI;
} else if (command.toLowerCase().contains(Command.EXEC.getValue()) || command.equalsIgnoreCase(Command.EXEC.getValue())) {
return Command.EXEC;
} else if (command.toLowerCase().contains(Command.DISCARD.getValue()) || command.equalsIgnoreCase(Command.DISCARD.getValue())) {
return Command.DISCARD;
} else return null;
}
}
package util;
public class Response {
public static byte[] getResponse(String response) {
return ("$" + response.length() + "\r\n" + response + "\r\n").getBytes();
}
}
UkVESVMwMDEx+glyZWRpcy12ZXIFNy4yLjD6CnJlZGlzLWJpdHPAQPoFY3RpbWXCbQi8ZfoIdXNlZC1tZW3CsMQQAPoIYW9mLWJhc2XAAP/wbjv+wP9aog==
\ No newline at end of file
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