Repository: incubator-ratis Updated Branches: refs/heads/master b7b7e7e0e -> 5ae2490de
RATIS-387. An interactive shell for the logservice Includes instructions on how to start a local quorum and connect the shell to it Project: http://git-wip-us.apache.org/repos/asf/incubator-ratis/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ratis/commit/5ae2490d Tree: http://git-wip-us.apache.org/repos/asf/incubator-ratis/tree/5ae2490d Diff: http://git-wip-us.apache.org/repos/asf/incubator-ratis/diff/5ae2490d Branch: refs/heads/master Commit: 5ae2490deee1cb30347d2c2ec492010a4567a181 Parents: b7b7e7e Author: Josh Elser <[email protected]> Authored: Tue Dec 4 22:32:20 2018 -0500 Committer: Josh Elser <[email protected]> Committed: Mon Dec 31 16:42:13 2018 -0500 ---------------------------------------------------------------------- pom.xml | 5 + ratis-logservice/README.md | 51 +++++++ ratis-logservice/pom.xml | 14 +- .../ratis/logservice/server/ServerOpts.java | 2 +- .../apache/ratis/logservice/shell/Command.java | 15 +++ .../ratis/logservice/shell/CommandFactory.java | 50 +++++++ .../ratis/logservice/shell/LogServiceShell.java | 133 +++++++++++++++++++ .../logservice/shell/LogServiceShellOpts.java | 8 ++ .../shell/commands/CreateLogCommand.java | 30 +++++ .../shell/commands/DeleteLogCommand.java | 32 +++++ .../logservice/shell/commands/ExitCommand.java | 20 +++ .../logservice/shell/commands/HelpCommand.java | 23 ++++ .../shell/commands/ListLogsCommand.java | 42 ++++++ .../shell/commands/PutToLogCommand.java | 36 +++++ .../shell/commands/ReadLogCommand.java | 53 ++++++++ 15 files changed, 508 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ratis/blob/5ae2490d/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 9d8a427..4d4282d 100644 --- a/pom.xml +++ b/pom.xml @@ -355,6 +355,11 @@ <artifactId>mockito-all</artifactId> <version>1.8.5</version> </dependency> + <dependency> + <groupId>org.jline</groupId> + <artifactId>jline</artifactId> + <version>3.9.0</version> + </dependency> </dependencies> </dependencyManagement> http://git-wip-us.apache.org/repos/asf/incubator-ratis/blob/5ae2490d/ratis-logservice/README.md ---------------------------------------------------------------------- diff --git a/ratis-logservice/README.md b/ratis-logservice/README.md new file mode 100644 index 0000000..1827594 --- /dev/null +++ b/ratis-logservice/README.md @@ -0,0 +1,51 @@ +# Ratis LogService + + +## Example shell + +Build: +```bash +$ mvn install +``` + +Change to logservice dectory: +```bash +$ cd ratis-log-service +``` + +Launch Metadata daemons: +```bash +$ mvn exec:java -Dexec.mainClass=org.apache.ratis.logservice.server.MetadataServer -Dexec.args="-p 9991 -d $HOME/logservice1 -h localhost -q localhost:9991,localhost:9992,localhost:9993" +``` +```bash +$ mvn exec:java -Dexec.mainClass=org.apache.ratis.logservice.server.MetadataServer -Dexec.args="-p 9992 -d $HOME/logservice2 -h localhost -q localhost:9991,localhost:9992,localhost:9993" +``` +```bash +$ mvn exec:java -Dexec.mainClass=org.apache.ratis.logservice.server.MetadataServer -Dexec.args="-p 9993 -d $HOME/logservice3 -h localhost -q localhost:9991,localhost:9992,localhost:9993" +``` + +Above, we have started three daemons that will form a quorum to act as the "LogService Metadata". They will track what +logs exist and the RAFT qs which service those logs. + +Launch Worker daemons: +```bash +$ mvn exec:java -Dexec.mainClass=org.apache.ratis.logservice.server.LogServer -Dexec.args="-p 9951 -d $HOME/worker1 -h localhost -q localhost:9991,localhost:9992,localhost:9993" +``` +```bash +$ mvn exec:java -Dexec.mainClass=org.apache.ratis.logservice.server.LogServer -Dexec.args="-p 9952 -d $HOME/worker2 -h localhost -q localhost:9991,localhost:9992,localhost:9993" +``` +```bash +$ mvn exec:java -Dexec.mainClass=org.apache.ratis.logservice.server.LogServer -Dexec.args="-p 9953 -d $HOME/worker3 -h localhost -q localhost:9991,localhost:9992,localhost:9993" +``` + +Now, we have started three daemons which can service a single LogStream. They will rep to the Metadata q, +and the Metadata quorum will choose three of them to form a RAFT quorum to "host" a single Log. + +Note: the `q` option here references to the Metadata quorum, not the worker quorum as is the case for the Metadata daemons. + +Launch client: +```bash +$ mvn exec:java -Dexec.mainClass=org.apache.ratis.logservice.shell.LogServiceShell -Dexec.args="-q localhost:9990,localhost:9991,localhost:9992" +``` + +This command will launch an interactive shell that you can use to interact with the system. http://git-wip-us.apache.org/repos/asf/incubator-ratis/blob/5ae2490d/ratis-logservice/pom.xml ---------------------------------------------------------------------- diff --git a/ratis-logservice/pom.xml b/ratis-logservice/pom.xml index 6c49231..a06218b 100644 --- a/ratis-logservice/pom.xml +++ b/ratis-logservice/pom.xml @@ -178,6 +178,15 @@ <artifactId>ratis-netty</artifactId> <groupId>org.apache.ratis</groupId> </dependency> + <!-- CLI dependencies --> + <dependency> + <groupId>com.beust</groupId> + <artifactId>jcommander</artifactId> + </dependency> + <dependency> + <groupId>org.jline</groupId> + <artifactId>jline</artifactId> + </dependency> <!-- Third-party dependencies --> <dependency> <groupId>org.slf4j</groupId> @@ -241,10 +250,5 @@ <artifactId>mockito-all</artifactId> <scope>test</scope> </dependency> - <dependency> - <groupId>com.beust</groupId> - <artifactId>jcommander</artifactId> - <version>1.72</version> - </dependency> </dependencies> </project> http://git-wip-us.apache.org/repos/asf/incubator-ratis/blob/5ae2490d/ratis-logservice/src/main/java/org/apache/ratis/logservice/server/ServerOpts.java ---------------------------------------------------------------------- diff --git a/ratis-logservice/src/main/java/org/apache/ratis/logservice/server/ServerOpts.java b/ratis-logservice/src/main/java/org/apache/ratis/logservice/server/ServerOpts.java index 18e4ba6..7ca9f90 100644 --- a/ratis-logservice/src/main/java/org/apache/ratis/logservice/server/ServerOpts.java +++ b/ratis-logservice/src/main/java/org/apache/ratis/logservice/server/ServerOpts.java @@ -38,7 +38,7 @@ public class ServerOpts { } @Parameter(names = {"-h", "--hostname"}, description = "Hostname") - private String host; + private String host = "localhost"; @Parameter(names = {"-p", "--port"}, description = "Port number") private int port = -1; http://git-wip-us.apache.org/repos/asf/incubator-ratis/blob/5ae2490d/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/Command.java ---------------------------------------------------------------------- diff --git a/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/Command.java b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/Command.java new file mode 100644 index 0000000..4d68792 --- /dev/null +++ b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/Command.java @@ -0,0 +1,15 @@ +package org.apache.ratis.logservice.shell; + +import org.apache.ratis.logservice.client.LogServiceClient; +import org.jline.reader.LineReader; +import org.jline.terminal.Terminal; + +/** + * Represents a single command in the shell. Each command must be stateless. + */ +public interface Command { + + String getHelpMessage(); + + void run(Terminal terminal, LineReader lineReader, LogServiceClient client, String[] args); +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-ratis/blob/5ae2490d/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/CommandFactory.java ---------------------------------------------------------------------- diff --git a/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/CommandFactory.java b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/CommandFactory.java new file mode 100644 index 0000000..161cf18 --- /dev/null +++ b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/CommandFactory.java @@ -0,0 +1,50 @@ +package org.apache.ratis.logservice.shell; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import org.apache.ratis.logservice.shell.commands.CreateLogCommand; +import org.apache.ratis.logservice.shell.commands.DeleteLogCommand; +import org.apache.ratis.logservice.shell.commands.ExitCommand; +import org.apache.ratis.logservice.shell.commands.HelpCommand; +import org.apache.ratis.logservice.shell.commands.ListLogsCommand; +import org.apache.ratis.logservice.shell.commands.PutToLogCommand; +import org.apache.ratis.logservice.shell.commands.ReadLogCommand; + +public class CommandFactory { + private static final Map<String,Command> KNOWN_COMMANDS = cacheCommands(); + + private static Map<String,Command> cacheCommands() { + Map<String,Command> commands = new HashMap<>(); + ExitCommand exitCommand = new ExitCommand(); + + // Ensure all keys are lowercase -- see the same logic in #create(String). + commands.put("create", new CreateLogCommand()); + commands.put("put", new PutToLogCommand()); + commands.put("read", new ReadLogCommand()); + commands.put("delete", new DeleteLogCommand()); + commands.put("exit", exitCommand); + commands.put("quit", exitCommand); + commands.put("help", new HelpCommand()); + commands.put("list", new ListLogsCommand()); + + return Collections.unmodifiableMap(commands); + } + + public static Map<String,Command> getCommands() { + return KNOWN_COMMANDS; + } + + private CommandFactory() {} + + /** + * Returns an instance of the command to run given the name, else null. + * Be aware that Command instances are singletons and do not retain state. + */ + public static Command create(String commandName) { + // Normalize the command name to lowercase + return KNOWN_COMMANDS.get(Objects.requireNonNull(commandName).toLowerCase()); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-ratis/blob/5ae2490d/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/LogServiceShell.java ---------------------------------------------------------------------- diff --git a/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/LogServiceShell.java b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/LogServiceShell.java new file mode 100644 index 0000000..bb669b7 --- /dev/null +++ b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/LogServiceShell.java @@ -0,0 +1,133 @@ +package org.apache.ratis.logservice.shell; + +import java.io.IOException; +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.Map.Entry; +import java.util.Objects; + +import org.apache.ratis.logservice.client.LogServiceClient; +import org.apache.ratis.logservice.shell.commands.ExitCommand; +import org.jline.reader.EndOfFileException; +import org.jline.reader.History; +import org.jline.reader.LineReader; +import org.jline.reader.LineReaderBuilder; +import org.jline.reader.UserInterruptException; +import org.jline.reader.impl.DefaultHighlighter; +import org.jline.reader.impl.history.DefaultHistory; +import org.jline.terminal.Terminal; +import org.jline.terminal.TerminalBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.beust.jcommander.JCommander; + +/** + * An interactive shell that can interact with a LogService instance. + */ +public class LogServiceShell { + private static Logger LOG = LoggerFactory.getLogger(LogServiceShell.class); + + private static final String PROMPT = "logservice> "; + + private final Terminal terminal; + private final LineReader lineReader; + private final LogServiceClient client; + + public LogServiceShell(Terminal terminal, LineReader reader, LogServiceClient client) { + this.terminal = Objects.requireNonNull(terminal); + this.lineReader = Objects.requireNonNull(reader); + this.client = Objects.requireNonNull(client); + } + + public void run() { + while (true) { + // Read and sanitize the input + String line; + try { + line = lineReader.readLine(PROMPT); + } catch (UserInterruptException e) { + continue; + } catch (EndOfFileException e) { + break; + } + if (line == null) { + continue; + } + line = line.trim(); + + // Construct the Command and args to pass to that command + Entry<Command,String[]> pair = parseCommand(line); + if (pair == null) { + continue; + } + Command command = pair.getKey(); + String[] commandArgs = pair.getValue(); + + // Our "exit" or "quit" + if (command instanceof ExitCommand) { + break; + } + + // Run the command + command.run(terminal, lineReader, client, commandArgs); + + // Flush a newline to the screen. + terminal.writer().flush(); + } + terminal.writer().println("Bye!"); + terminal.writer().flush(); + } + + Entry<Command,String[]> parseCommand(String line) { + String[] words = line.split("\\s+"); + if (words.length == 0) { + return null; + } + + String commandWord = words[0]; + Command command = CommandFactory.create(commandWord); + // If we have no command to run, return null. + if (command == null) { + return null; + } + + // Pull off the "command" name + String[] args = Arrays.copyOfRange(words, 1, words.length); + + return new AbstractMap.SimpleEntry<>(command, args); + } + + public static void main(String[] args) throws Exception { + final Terminal terminal = TerminalBuilder.builder() + .system(true) + .build(); + + History defaultHistory = new DefaultHistory(); + // Register a shutdown-hook per JLine documentation to save history + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { + defaultHistory.save(); + } catch (IOException e) { + LOG.debug("Failed to save terminal history", e); + } + })); + + final LineReader lineReader = LineReaderBuilder.builder() + .terminal(terminal) + .highlighter(new DefaultHighlighter()) + .history(defaultHistory) + .build(); + + LogServiceShellOpts opts = new LogServiceShellOpts(); + JCommander.newBuilder() + .addObject(opts) + .build() + .parse(args); + + try (LogServiceClient logServiceClient = new LogServiceClient(opts.metaQuorum)) { + LogServiceShell client = new LogServiceShell(terminal, lineReader, logServiceClient); + client.run(); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-ratis/blob/5ae2490d/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/LogServiceShellOpts.java ---------------------------------------------------------------------- diff --git a/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/LogServiceShellOpts.java b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/LogServiceShellOpts.java new file mode 100644 index 0000000..22742c5 --- /dev/null +++ b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/LogServiceShellOpts.java @@ -0,0 +1,8 @@ +package org.apache.ratis.logservice.shell; + +import com.beust.jcommander.Parameter; + +public class LogServiceShellOpts { + @Parameter(names = {"--meta-quorum", "-q"}) + public String metaQuorum; +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-ratis/blob/5ae2490d/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/CreateLogCommand.java ---------------------------------------------------------------------- diff --git a/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/CreateLogCommand.java b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/CreateLogCommand.java new file mode 100644 index 0000000..dc42e81 --- /dev/null +++ b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/CreateLogCommand.java @@ -0,0 +1,30 @@ +package org.apache.ratis.logservice.shell.commands; + +import org.apache.ratis.logservice.api.LogName; +import org.apache.ratis.logservice.api.LogStream; +import org.apache.ratis.logservice.client.LogServiceClient; +import org.apache.ratis.logservice.shell.Command; +import org.jline.reader.LineReader; +import org.jline.terminal.Terminal; + +public class CreateLogCommand implements Command { + + @Override public String getHelpMessage() { + return "`create` - Creates a new log with the given name"; + } + + @Override + public void run(Terminal terminal, LineReader lineReader, LogServiceClient client, String[] args) { + if (args.length != 1) { + terminal.writer().println("ERROR - Usage: create <name>"); + return; + } + String logName = args[0]; + try (LogStream stream = client.createLog(LogName.of(logName))) { + terminal.writer().println("Created log '" + logName + "'"); + } catch (Exception e) { + terminal.writer().println("Error creating log '" + logName + "'"); + e.printStackTrace(terminal.writer()); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-ratis/blob/5ae2490d/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/DeleteLogCommand.java ---------------------------------------------------------------------- diff --git a/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/DeleteLogCommand.java b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/DeleteLogCommand.java new file mode 100644 index 0000000..d589f8e --- /dev/null +++ b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/DeleteLogCommand.java @@ -0,0 +1,32 @@ +package org.apache.ratis.logservice.shell.commands; + +import java.io.IOException; + +import org.apache.ratis.logservice.api.LogName; +import org.apache.ratis.logservice.client.LogServiceClient; +import org.apache.ratis.logservice.shell.Command; +import org.jline.reader.LineReader; +import org.jline.terminal.Terminal; + +public class DeleteLogCommand implements Command { + + @Override public String getHelpMessage() { + return "`delete` - deletes the log with the given name."; + } + + @Override + public void run(Terminal terminal, LineReader lineReader, LogServiceClient client, String[] args) { + if (args.length != 1) { + terminal.writer().println("ERROR - Usage: delete <name>"); + return; + } + String logName = args[0]; + try { + client.deleteLog(LogName.of(logName)); + terminal.writer().println("Deleted log '" + logName + "'"); + } catch (IOException e) { + terminal.writer().println("Error deleting log '" + logName + "'"); + e.printStackTrace(terminal.writer()); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ratis/blob/5ae2490d/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/ExitCommand.java ---------------------------------------------------------------------- diff --git a/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/ExitCommand.java b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/ExitCommand.java new file mode 100644 index 0000000..e5c25d7 --- /dev/null +++ b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/ExitCommand.java @@ -0,0 +1,20 @@ +package org.apache.ratis.logservice.shell.commands; + +import org.apache.ratis.logservice.client.LogServiceClient; +import org.apache.ratis.logservice.shell.Command; +import org.jline.reader.LineReader; +import org.jline.terminal.Terminal; + +public class ExitCommand implements Command { + + @Override public String getHelpMessage() { + return "`exit` -- Exits this shell."; + } + + @Override + public void run(Terminal terminal, LineReader lineReader, LogServiceClient client, String[] args) { + throw new IllegalStateException("This command should be be invoked"); + } + +} + http://git-wip-us.apache.org/repos/asf/incubator-ratis/blob/5ae2490d/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/HelpCommand.java ---------------------------------------------------------------------- diff --git a/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/HelpCommand.java b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/HelpCommand.java new file mode 100644 index 0000000..ccb121f --- /dev/null +++ b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/HelpCommand.java @@ -0,0 +1,23 @@ +package org.apache.ratis.logservice.shell.commands; + +import org.apache.ratis.logservice.client.LogServiceClient; +import org.apache.ratis.logservice.shell.Command; +import org.apache.ratis.logservice.shell.CommandFactory; +import org.jline.reader.LineReader; +import org.jline.terminal.Terminal; + +public class HelpCommand implements Command { + + @Override public String getHelpMessage() { + return "`help` - Prints this help message"; + } + + @Override + public void run(Terminal terminal, LineReader lineReader, LogServiceClient client, String[] args) { + CommandFactory.getCommands() + .values() + .stream() + .forEach((c) -> terminal.writer().println(c.getHelpMessage())); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-ratis/blob/5ae2490d/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/ListLogsCommand.java ---------------------------------------------------------------------- diff --git a/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/ListLogsCommand.java b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/ListLogsCommand.java new file mode 100644 index 0000000..5896c09 --- /dev/null +++ b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/ListLogsCommand.java @@ -0,0 +1,42 @@ +package org.apache.ratis.logservice.shell.commands; + +import java.io.IOException; +import java.util.List; + +import org.apache.ratis.logservice.api.LogInfo; +import org.apache.ratis.logservice.client.LogServiceClient; +import org.apache.ratis.logservice.shell.Command; +import org.jline.reader.LineReader; +import org.jline.terminal.Terminal; + +public class ListLogsCommand implements Command { + + @Override + public String getHelpMessage() { + return "`list` - List the available logs"; + } + + @Override + public void run(Terminal terminal, LineReader lineReader, LogServiceClient client, String[] args) { + if (args.length != 0) { + terminal.writer().println("ERROR - Usage: list"); + return; + } + + try { + List<LogInfo> logs = client.listLogs(); + StringBuilder sb = new StringBuilder(); + for (LogInfo log : logs) { + if (sb.length() > 0) { + sb.append("\n"); + } + sb.append(log.getLogName().getName()); + } + terminal.writer().println(sb.toString()); + } catch (IOException e) { + terminal.writer().println("Failed to list available logs"); + e.printStackTrace(terminal.writer()); + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-ratis/blob/5ae2490d/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/PutToLogCommand.java ---------------------------------------------------------------------- diff --git a/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/PutToLogCommand.java b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/PutToLogCommand.java new file mode 100644 index 0000000..048d6be --- /dev/null +++ b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/PutToLogCommand.java @@ -0,0 +1,36 @@ +package org.apache.ratis.logservice.shell.commands; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +import org.apache.ratis.logservice.api.LogName; +import org.apache.ratis.logservice.api.LogStream; +import org.apache.ratis.logservice.api.LogWriter; +import org.apache.ratis.logservice.client.LogServiceClient; +import org.apache.ratis.logservice.shell.Command; +import org.jline.reader.LineReader; +import org.jline.terminal.Terminal; + +public class PutToLogCommand implements Command { + + @Override public String getHelpMessage() { + return "`put` - Appends a value to a log"; + } + + @Override + public void run(Terminal terminal, LineReader lineReader, LogServiceClient client, String[] args) { + if (args.length != 2) { + terminal.writer().println("ERROR - Usage: put <name> <value>"); + return; + } + String name = args[0]; + String value = args[1]; + try (LogStream stream = client.getLog(LogName.of(name)); + LogWriter writer = stream.createWriter()) { + writer.write(ByteBuffer.wrap(value.getBytes(StandardCharsets.UTF_8))); + } catch (Exception e) { + terminal.writer().println("Error writing to log"); + e.printStackTrace(terminal.writer()); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ratis/blob/5ae2490d/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/ReadLogCommand.java ---------------------------------------------------------------------- diff --git a/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/ReadLogCommand.java b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/ReadLogCommand.java new file mode 100644 index 0000000..c7f0d24 --- /dev/null +++ b/ratis-logservice/src/main/java/org/apache/ratis/logservice/shell/commands/ReadLogCommand.java @@ -0,0 +1,53 @@ +package org.apache.ratis.logservice.shell.commands; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import org.apache.ratis.logservice.api.LogName; +import org.apache.ratis.logservice.api.LogReader; +import org.apache.ratis.logservice.api.LogStream; +import org.apache.ratis.logservice.client.LogServiceClient; +import org.apache.ratis.logservice.shell.Command; +import org.jline.reader.LineReader; +import org.jline.terminal.Terminal; + +public class ReadLogCommand implements Command { + + @Override public String getHelpMessage() { + return "`read` - Reads all values from the given log"; + } + + @Override + public void run(Terminal terminal, LineReader lineReader, LogServiceClient client, String[] args) { + if (args.length != 1) { + terminal.writer().println("ERROR - Usage: read <name>"); + return; + } + String logName = args[0]; + try (LogStream stream = client.getLog(LogName.of(logName)); + LogReader reader = stream.createReader()) { + long firstId = stream.getStartRecordId(); + long lastId = stream.getLastRecordId(); + StringBuilder sb = new StringBuilder(); + int i = 0; + List<ByteBuffer> records = reader.readBulk((int) (lastId - firstId)); + for (ByteBuffer record : records) { + if (sb.length() > 0) { + sb.append(", "); + } + sb.append(i).append(":"); + if (record != null) { + String strData = new String(record.array(), record.arrayOffset(), record.remaining(), StandardCharsets.UTF_8); + sb.append(strData); + } + } + sb.insert(0, "["); + sb.append("]"); + terminal.writer().println(sb.toString()); + } catch (Exception e) { + terminal.writer().println("Failed to read from log"); + e.printStackTrace(terminal.writer()); + } + } +}
