This is an automated email from the ASF dual-hosted git repository.
sijie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git
The following commit(s) were added to refs/heads/master by this push:
new 9524a9f Migrate command `readjournal`
9524a9f is described below
commit 9524a9f4a82dd990aa437a2931bf2e5541ea0a37
Author: Yong Zhang <[email protected]>
AuthorDate: Fri Mar 29 12:44:24 2019 +0800
Migrate command `readjournal`
Descriptions of the changes in this PR:
- Use `bkctl` execute `readjournal` command
### Motivation
- Migrate from bookieshelll
Reviewers: Jia Zhai <[email protected]>, Sijie Guo <[email protected]>
This closes #2000 from zymap/command-readjournal
---
.../java/org/apache/bookkeeper/bookie/Bookie.java | 4 +-
.../org/apache/bookkeeper/bookie/BookieShell.java | 196 ++-----------------
.../org/apache/bookkeeper/bookie/LedgerCache.java | 2 +-
.../tools/cli/commands/bookie/FormatUtil.java | 98 ++++++++++
.../cli/commands/bookie/ReadJournalCommand.java | 213 +++++++++++++++++++++
.../tools/cli/commands/BookieCommandGroup.java | 5 +-
.../commands/bookie/ReadJournalCommandTest.java | 128 +++++++++++++
7 files changed, 466 insertions(+), 180 deletions(-)
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java
index 44c9509..06ccd58 100644
--- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/Bookie.java
@@ -116,8 +116,8 @@ public class Bookie extends BookieCriticalThread {
final HandleFactory handles;
final boolean entryLogPerLedgerEnabled;
- static final long METAENTRY_ID_LEDGER_KEY = -0x1000;
- static final long METAENTRY_ID_FENCE_KEY = -0x2000;
+ public static final long METAENTRY_ID_LEDGER_KEY = -0x1000;
+ public static final long METAENTRY_ID_FENCE_KEY = -0x2000;
public static final long METAENTRY_ID_FORCE_LEDGER = -0x4000;
static final long METAENTRY_ID_LEDGER_EXPLICITLAC = -0x8000;
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieShell.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieShell.java
index fa52bc7..8c448a1 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieShell.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieShell.java
@@ -29,7 +29,6 @@ import com.google.common.collect.Lists;
import com.google.common.util.concurrent.UncheckedExecutionException;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
-import io.netty.buffer.Unpooled;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
@@ -38,7 +37,6 @@ import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.URI;
-import java.nio.ByteBuffer;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -51,7 +49,6 @@ import java.util.Base64;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
-import java.util.Formatter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -71,10 +68,10 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
+
import org.apache.bookkeeper.bookie.BookieException.CookieNotFoundException;
import org.apache.bookkeeper.bookie.BookieException.InvalidCookieException;
import org.apache.bookkeeper.bookie.EntryLogger.EntryLogScanner;
-import org.apache.bookkeeper.bookie.Journal.JournalScanner;
import org.apache.bookkeeper.bookie.storage.ldb.LocationsIndexRebuildOp;
import org.apache.bookkeeper.client.BKException;
import org.apache.bookkeeper.client.BKException.MetaStoreException;
@@ -107,10 +104,12 @@ import org.apache.bookkeeper.stats.NullStatsLogger;
import
org.apache.bookkeeper.tools.cli.commands.bookie.ConvertToDBStorageCommand;
import
org.apache.bookkeeper.tools.cli.commands.bookie.ConvertToInterleavedStorageCommand;
import org.apache.bookkeeper.tools.cli.commands.bookie.FormatCommand;
+import org.apache.bookkeeper.tools.cli.commands.bookie.FormatUtil;
import org.apache.bookkeeper.tools.cli.commands.bookie.InitCommand;
import org.apache.bookkeeper.tools.cli.commands.bookie.LastMarkCommand;
import org.apache.bookkeeper.tools.cli.commands.bookie.LedgerCommand;
import org.apache.bookkeeper.tools.cli.commands.bookie.ListFilesOnDiscCommand;
+import org.apache.bookkeeper.tools.cli.commands.bookie.ReadJournalCommand;
import org.apache.bookkeeper.tools.cli.commands.bookie.SanityTestCommand;
import org.apache.bookkeeper.tools.cli.commands.bookies.InfoCommand;
import org.apache.bookkeeper.tools.cli.commands.bookies.ListBookiesCommand;
@@ -122,7 +121,6 @@ import
org.apache.bookkeeper.tools.cli.commands.cookie.GetCookieCommand;
import org.apache.bookkeeper.tools.cli.commands.cookie.UpdateCookieCommand;
import org.apache.bookkeeper.tools.framework.CliFlags;
import org.apache.bookkeeper.util.BookKeeperConstants;
-import org.apache.bookkeeper.util.DiskChecker;
import org.apache.bookkeeper.util.EntryFormatter;
import org.apache.bookkeeper.util.IOUtils;
import org.apache.bookkeeper.util.LedgerIdFormatter;
@@ -1437,55 +1435,25 @@ public class BookieShell implements Tool {
return -1;
}
+ long journalId = -1L;
+ String filename = "";
+ try {
+ journalId = Long.parseLong(leftArgs[0]);
+ } catch (NumberFormatException nfe) {
+ filename = leftArgs[0];
+ }
+
boolean printMsg = false;
if (cmdLine.hasOption("m")) {
printMsg = true;
}
- Journal journal = null;
- if (getJournals().size() > 1) {
- if (!cmdLine.hasOption("dir")) {
- System.err.println("ERROR: invalid or missing journal
directory");
- printUsage();
- return -1;
- }
-
- File journalDirectory = new
File(cmdLine.getOptionValue("dir"));
- for (Journal j : getJournals()) {
- if (j.getJournalDirectory().equals(journalDirectory)) {
- journal = j;
- break;
- }
- }
-
- if (journal == null) {
- System.err.println("ERROR: journal directory not found");
- printUsage();
- return -1;
- }
- } else {
- journal = getJournals().get(0);
- }
-
- long journalId;
- try {
- journalId = Long.parseLong(leftArgs[0]);
- } catch (NumberFormatException nfe) {
- // not a journal id
- File f = new File(leftArgs[0]);
- String name = f.getName();
- if (!name.endsWith(".txn")) {
- // not a journal file
- System.err.println("ERROR: invalid journal file name " +
leftArgs[0]);
- printUsage();
- return -1;
- }
- String idString = name.split("\\.")[0];
- journalId = Long.parseLong(idString, 16);
- }
- // scan journal
- scanJournal(journal, journalId, printMsg);
- return 0;
+ ReadJournalCommand.ReadJournalFlags flags = new
ReadJournalCommand.ReadJournalFlags().msg(printMsg)
+
.fileName(filename).journalId(journalId)
+
.dir(cmdLine.getOptionValue("dir"));
+ ReadJournalCommand cmd = new ReadJournalCommand(ledgerIdFormatter,
entryFormatter);
+ boolean result = cmd.apply(bkConf, flags);
+ return result ? 0 : -1;
}
@Override
@@ -1626,7 +1594,6 @@ public class BookieShell implements Tool {
}
}
-
/**
* Command to print help message.
*/
@@ -1803,7 +1770,6 @@ public class BookieShell implements Tool {
}
}
-
/**
* Print which node has the auditor lock.
*/
@@ -2493,7 +2459,6 @@ public class BookieShell implements Tool {
void progress(long updated, long issued);
}
-
/**
* Convert bookie indexes from InterleavedStorage to DbLedgerStorage
format.
*/
@@ -2898,29 +2863,6 @@ public class BookieShell implements Tool {
entryLogger.scanEntryLog(logId, scanner);
}
- private synchronized List<Journal> getJournals() throws IOException {
- if (null == journals) {
- journals =
Lists.newArrayListWithCapacity(bkConf.getJournalDirs().length);
- int idx = 0;
- for (File journalDir : bkConf.getJournalDirs()) {
- journals.add(new Journal(idx++, new File(journalDir,
BookKeeperConstants.CURRENT_DIR), bkConf,
- new LedgerDirsManager(bkConf, bkConf.getLedgerDirs(),
- new DiskChecker(bkConf.getDiskUsageThreshold(),
bkConf.getDiskUsageWarnThreshold()))));
- }
- }
- return journals;
- }
-
- /**
- * Scan journal file.
- *
- * @param journalId Journal File Id
- * @param scanner Journal File Scanner
- */
- protected void scanJournal(Journal journal, long journalId, JournalScanner
scanner) throws IOException {
- journal.scanJournal(journalId, 0L, scanner);
- }
-
///
/// Bookie Shell Commands
///
@@ -2953,7 +2895,7 @@ public class BookieShell implements Tool {
@Override
public void process(long ledgerId, long startPos, ByteBuf entry) {
- formatEntry(startPos, entry, printMsg);
+ FormatUtil.formatEntry(startPos, entry, printMsg,
ledgerIdFormatter, entryFormatter);
}
});
}
@@ -2985,7 +2927,7 @@ public class BookieShell implements Tool {
if ((candidateLedgerId == entrysLedgerId) &&
(candidateLedgerId == ledgerId)
&& ((entrysEntryId == entryId) || (entryId == -1))) {
entryFound.setValue(true);
- formatEntry(startPos, entry, printMsg);
+ FormatUtil.formatEntry(startPos, entry, printMsg,
ledgerIdFormatter, entryFormatter);
}
}
});
@@ -3034,7 +2976,7 @@ public class BookieShell implements Tool {
*/
long entryEndPos = entryStartPos + entrySize + 4 - 1;
if (((rangeEndPos == -1) || (entryStartPos <=
rangeEndPos)) && (rangeStartPos <= entryEndPos)) {
- formatEntry(entryStartPos, entry, printMsg);
+ FormatUtil.formatEntry(entryStartPos, entry,
printMsg, ledgerIdFormatter, entryFormatter);
entryFound.setValue(true);
}
}
@@ -3050,40 +2992,6 @@ public class BookieShell implements Tool {
}
/**
- * Scan a journal file.
- *
- * @param journalId Journal File Id
- * @param printMsg Whether printing the entry data.
- */
- protected void scanJournal(Journal journal, long journalId, final boolean
printMsg) throws Exception {
- System.out.println("Scan journal " + journalId + " (" +
Long.toHexString(journalId) + ".txn)");
- scanJournal(journal, journalId, new JournalScanner() {
- boolean printJournalVersion = false;
-
- @Override
- public void process(int journalVersion, long offset, ByteBuffer
entry) throws IOException {
- if (!printJournalVersion) {
- System.out.println("Journal Version : " + journalVersion);
- printJournalVersion = true;
- }
- formatEntry(offset, Unpooled.wrappedBuffer(entry), printMsg);
- }
- });
- }
-
- /**
- * Print last log mark.
- */
- protected void printLastLogMark() throws IOException {
- for (Journal journal : getJournals()) {
- LogMark lastLogMark = journal.getLastLogMark().getCurMark();
- System.out.println("LastLogMark: Journal Id - " +
lastLogMark.getLogFileId() + "("
- + Long.toHexString(lastLogMark.getLogFileId()) + ".txn),
Pos - "
- + lastLogMark.getLogFileOffset());
- }
- }
-
- /**
* Format the entry into a readable format.
*
* @param entry
@@ -3102,70 +3010,6 @@ public class BookieShell implements Tool {
}
}
- /**
- * Format the message into a readable format.
- *
- * @param pos
- * File offset of the message stored in entry log file
- * @param recBuff
- * Entry Data
- * @param printMsg
- * Whether printing the message body
- */
- private void formatEntry(long pos, ByteBuf recBuff, boolean printMsg) {
- int entrySize = recBuff.readableBytes();
- long ledgerId = recBuff.readLong();
- long entryId = recBuff.readLong();
-
- System.out.println("--------- Lid=" +
ledgerIdFormatter.formatLedgerId(ledgerId) + ", Eid=" + entryId
- + ", ByteOffset=" + pos + ", EntrySize=" + entrySize + "
---------");
- if (entryId == Bookie.METAENTRY_ID_LEDGER_KEY) {
- int masterKeyLen = recBuff.readInt();
- byte[] masterKey = new byte[masterKeyLen];
- recBuff.readBytes(masterKey);
- System.out.println("Type: META");
- System.out.println("MasterKey: " + bytes2Hex(masterKey));
- System.out.println();
- return;
- }
- if (entryId == Bookie.METAENTRY_ID_FENCE_KEY) {
- System.out.println("Type: META");
- System.out.println("Fenced");
- System.out.println();
- return;
- }
- // process a data entry
- long lastAddConfirmed = recBuff.readLong();
- System.out.println("Type: DATA");
- System.out.println("LastConfirmed: " + lastAddConfirmed);
- if (!printMsg) {
- System.out.println();
- return;
- }
- // skip digest checking
- recBuff.skipBytes(8);
- System.out.println("Data:");
- System.out.println();
- try {
- byte[] ret = new byte[recBuff.readableBytes()];
- recBuff.readBytes(ret);
- entryFormatter.formatEntry(ret);
- } catch (Exception e) {
- System.out.println("N/A. Corrupted.");
- }
- System.out.println();
- }
-
- static String bytes2Hex(byte[] data) {
- StringBuilder sb = new StringBuilder(data.length * 2);
- Formatter formatter = new Formatter(sb);
- for (byte b : data) {
- formatter.format("%02x", b);
- }
- formatter.close();
- return sb.toString();
- }
-
private static int getOptionIntValue(CommandLine cmdLine, String option,
int defaultVal) {
if (cmdLine.hasOption(option)) {
String val = cmdLine.getOptionValue(option);
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCache.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCache.java
index 86984b7..993bd0c 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCache.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerCache.java
@@ -21,7 +21,7 @@
package org.apache.bookkeeper.bookie;
-import static org.apache.bookkeeper.bookie.BookieShell.bytes2Hex;
+import static
org.apache.bookkeeper.tools.cli.commands.bookie.FormatUtil.bytes2Hex;
import io.netty.buffer.ByteBuf;
import java.io.Closeable;
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/bookie/FormatUtil.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/bookie/FormatUtil.java
new file mode 100644
index 0000000..d786c7e
--- /dev/null
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/bookie/FormatUtil.java
@@ -0,0 +1,98 @@
+/*
+ * 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.bookkeeper.tools.cli.commands.bookie;
+
+import io.netty.buffer.ByteBuf;
+import java.util.Formatter;
+import org.apache.bookkeeper.bookie.Bookie;
+import org.apache.bookkeeper.util.EntryFormatter;
+import org.apache.bookkeeper.util.LedgerIdFormatter;
+
+/**
+ * .Provide to format message.
+ */
+public class FormatUtil {
+
+ /**
+ * Format the message into a readable format.
+ * @param pos
+ * File offset of the message stored in entry log file
+ * @param recBuff
+ * Entry Data
+ * @param printMsg
+ * Whether printing the message body
+ * @param ledgerIdFormatter
+ * @param entryFormatter
+ */
+ public static void formatEntry(long pos, ByteBuf recBuff, boolean
printMsg, LedgerIdFormatter ledgerIdFormatter,
+ EntryFormatter entryFormatter) {
+ int entrySize = recBuff.readableBytes();
+ long ledgerId = recBuff.readLong();
+ long entryId = recBuff.readLong();
+
+ System.out.println(
+ "--------- Lid=" + ledgerIdFormatter.formatLedgerId(ledgerId) + ",
Eid=" + entryId + ", ByteOffset=" + pos
+ + ", EntrySize=" + entrySize + " ---------");
+ if (entryId == Bookie.METAENTRY_ID_LEDGER_KEY) {
+ int masterKeyLen = recBuff.readInt();
+ byte[] masterKey = new byte[masterKeyLen];
+ recBuff.readBytes(masterKey);
+ System.out.println("Type: META");
+ System.out.println("MasterKey: " + bytes2Hex(masterKey));
+ System.out.println();
+ return;
+ }
+ if (entryId == Bookie.METAENTRY_ID_FENCE_KEY) {
+ System.out.println("Type: META");
+ System.out.println("Fenced");
+ System.out.println();
+ return;
+ }
+ // process a data entry
+ long lastAddConfirmed = recBuff.readLong();
+ System.out.println("Type: DATA");
+ System.out.println("LastConfirmed: " + lastAddConfirmed);
+ if (!printMsg) {
+ System.out.println();
+ return;
+ }
+ // skip digest checking
+ recBuff.skipBytes(8);
+ System.out.println("Data:");
+ System.out.println();
+ try {
+ byte[] ret = new byte[recBuff.readableBytes()];
+ recBuff.readBytes(ret);
+ entryFormatter.formatEntry(ret);
+ } catch (Exception e) {
+ System.out.println("N/A. Corrupted.");
+ }
+ System.out.println();
+ }
+
+ public static String bytes2Hex(byte[] data) {
+ StringBuilder sb = new StringBuilder(data.length * 2);
+ Formatter formatter = new Formatter(sb);
+ for (byte b : data) {
+ formatter.format("%02x", b);
+ }
+ formatter.close();
+ return sb.toString();
+ }
+}
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadJournalCommand.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadJournalCommand.java
new file mode 100644
index 0000000..6729257
--- /dev/null
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadJournalCommand.java
@@ -0,0 +1,213 @@
+/*
+ * 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.bookkeeper.tools.cli.commands.bookie;
+
+import com.beust.jcommander.Parameter;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.UncheckedExecutionException;
+import io.netty.buffer.Unpooled;
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import org.apache.bookkeeper.bookie.Journal;
+import org.apache.bookkeeper.bookie.LedgerDirsManager;
+import org.apache.bookkeeper.conf.ServerConfiguration;
+import org.apache.bookkeeper.tools.cli.helpers.BookieCommand;
+import org.apache.bookkeeper.tools.framework.CliFlags;
+import org.apache.bookkeeper.tools.framework.CliSpec;
+import org.apache.bookkeeper.util.BookKeeperConstants;
+import org.apache.bookkeeper.util.DiskChecker;
+import org.apache.bookkeeper.util.EntryFormatter;
+import org.apache.bookkeeper.util.LedgerIdFormatter;
+
+/**
+ * Command to scan a journal file and format the entries into readable format.
+ */
+public class ReadJournalCommand extends
BookieCommand<ReadJournalCommand.ReadJournalFlags> {
+
+ private static final String NAME = "readjournal";
+ private static final String DESC = "Scan a journal file and format the
entries into readable format.";
+ private static final long DEFAULT_JOURNALID = -1L;
+ private static final String DEFAULT = "";
+ private LedgerIdFormatter ledgerIdFormatter;
+ private EntryFormatter entryFormatter;
+
+ List<Journal> journals = null;
+
+ public ReadJournalCommand() {
+ this(new ReadJournalFlags());
+ }
+
+ public ReadJournalCommand(LedgerIdFormatter idFormatter, EntryFormatter
entryFormatter) {
+ this(new ReadJournalFlags());
+ this.ledgerIdFormatter = idFormatter;
+ this.entryFormatter = entryFormatter;
+ }
+
+ ReadJournalCommand(ReadJournalFlags flags) {
+
super(CliSpec.<ReadJournalFlags>newBuilder().withName(NAME).withDescription(DESC).withFlags(flags).build());
+ }
+
+ /**
+ * Flag for read journal command.
+ */
+ @Accessors(fluent = true)
+ @Setter
+ public static class ReadJournalFlags extends CliFlags {
+
+ @Parameter(names = {"-m", "--msg"}, description = "Print message body")
+ private boolean msg;
+
+ @Parameter(names = { "-d", "--dir" }, description = "Journal directory
(needed if more than one journal "
+ +
"configured)")
+ private String dir = DEFAULT;
+
+ @Parameter(names = {"-id", "--journalid"}, description = "Journal Id")
+ private long journalId = DEFAULT_JOURNALID;
+
+ @Parameter(names = {"-f", "--filename"}, description = "Journal file
name")
+ private String fileName = DEFAULT;
+
+ @Parameter(names = {"-l", "--ledgerIdFormatter"}, description = "Set
ledger id formatter")
+ private String ledgerIdFormatter = DEFAULT;
+
+ @Parameter(names = {"-e", "--entryformatter"}, description = "set
entry formatter")
+ private String entryFormatter = DEFAULT;
+
+ }
+
+ @Override
+ public boolean apply(ServerConfiguration conf, ReadJournalFlags cmdFlags) {
+ initTools(conf, cmdFlags);
+ if (!checkArgs(cmdFlags)) {
+ return false;
+ }
+ try {
+ return handler(conf, cmdFlags);
+ } catch (IOException e) {
+ throw new UncheckedExecutionException(e.getMessage(), e);
+ }
+ }
+
+ private void initTools(ServerConfiguration conf, ReadJournalFlags flags) {
+ if (!flags.ledgerIdFormatter.equals(DEFAULT)) {
+ ledgerIdFormatter =
LedgerIdFormatter.newLedgerIdFormatter(flags.ledgerIdFormatter, conf);
+ } else {
+ ledgerIdFormatter = LedgerIdFormatter.newLedgerIdFormatter(conf);
+ }
+
+ if (!flags.entryFormatter.equals(DEFAULT)) {
+ entryFormatter =
EntryFormatter.newEntryFormatter(flags.entryFormatter, conf);
+ } else {
+ entryFormatter = EntryFormatter.newEntryFormatter(conf);
+ }
+ }
+ private boolean handler(ServerConfiguration conf, ReadJournalFlags cmd)
throws IOException {
+ Journal journal = null;
+ if (getJournals(conf).size() > 1) {
+ if (cmd.dir.equals(DEFAULT)) {
+ System.err.println("ERROR: invalid or missing journal
directory");
+ usage();
+ return false;
+ }
+ File journalDirectory = new File(cmd.dir);
+ for (Journal j : getJournals(conf)) {
+ if (j.getJournalDirectory().equals(journalDirectory)) {
+ journal = j;
+ break;
+ }
+ }
+
+ if (journal == null) {
+ System.err.println("ERROR: journal directory not found");
+ usage();
+ return false;
+ }
+ } else {
+ journal = getJournals(conf).get(0);
+ }
+
+ long journalId = cmd.journalId;
+ if (cmd.journalId == DEFAULT_JOURNALID &&
!cmd.fileName.equals(DEFAULT)) {
+ File f = new File(cmd.fileName);
+ String name = f.getName();
+ if (!name.endsWith(".txn")) {
+ System.err.println("ERROR: invalid journal file name " +
cmd.fileName);
+ usage();
+ return false;
+ }
+ String idString = name.split("\\.")[0];
+ journalId = Long.parseLong(idString);
+ }
+ scanJournal(journal, journalId, cmd.msg);
+ return true;
+ }
+
+ private boolean checkArgs(ReadJournalFlags flags) {
+ if ((flags.fileName.equals(DEFAULT) && flags.journalId ==
DEFAULT_JOURNALID)) {
+ System.out.println("ERROR: You should figure jounalId or journal
filename");
+ return false;
+ }
+
+ return true;
+ }
+
+ private synchronized List<Journal> getJournals(ServerConfiguration conf) {
+ if (null == journals) {
+ journals =
Lists.newArrayListWithCapacity(conf.getJournalDirs().length);
+ int idx = 0;
+ for (File journalDir : conf.getJournalDirs()) {
+ journals.add(new Journal(idx++, new File(journalDir,
BookKeeperConstants.CURRENT_DIR), conf,
+ new LedgerDirsManager(conf, conf.getLedgerDirs(),
+ new DiskChecker(conf.getDiskUsageThreshold(),
conf.getDiskUsageWarnThreshold()))));
+ }
+ }
+ return journals;
+ }
+
+ /**
+ * Scan a journal file.
+ *
+ * @param journalId Journal File Id
+ * @param printMsg Whether printing the entry data.
+ */
+ private void scanJournal(Journal journal, long journalId, final boolean
printMsg) throws IOException {
+ System.out.println("Scan journal " + journalId + " (" +
Long.toHexString(journalId) + ".txn)");
+ scanJournal(journal, journalId, new Journal.JournalScanner() {
+ boolean printJournalVersion = false;
+
+ @Override
+ public void process(int journalVersion, long offset, ByteBuffer
entry) throws IOException {
+ if (!printJournalVersion) {
+ System.out.println("Journal Version : " + journalVersion);
+ printJournalVersion = true;
+ }
+ FormatUtil
+ .formatEntry(offset, Unpooled.wrappedBuffer(entry),
printMsg, ledgerIdFormatter, entryFormatter);
+ }
+ });
+ }
+
+ private void scanJournal(Journal journal, long journalId,
Journal.JournalScanner scanner) throws IOException {
+ journal.scanJournal(journalId, 0L, scanner);
+ }
+}
diff --git
a/tools/ledger/src/main/java/org/apache/bookkeeper/tools/cli/commands/BookieCommandGroup.java
b/tools/ledger/src/main/java/org/apache/bookkeeper/tools/cli/commands/BookieCommandGroup.java
index 9390d2e..c8c7817 100644
---
a/tools/ledger/src/main/java/org/apache/bookkeeper/tools/cli/commands/BookieCommandGroup.java
+++
b/tools/ledger/src/main/java/org/apache/bookkeeper/tools/cli/commands/BookieCommandGroup.java
@@ -28,6 +28,7 @@ import
org.apache.bookkeeper.tools.cli.commands.bookie.InitCommand;
import org.apache.bookkeeper.tools.cli.commands.bookie.LastMarkCommand;
import org.apache.bookkeeper.tools.cli.commands.bookie.LedgerCommand;
import org.apache.bookkeeper.tools.cli.commands.bookie.ListFilesOnDiscCommand;
+import org.apache.bookkeeper.tools.cli.commands.bookie.ReadJournalCommand;
import org.apache.bookkeeper.tools.cli.commands.bookie.SanityTestCommand;
import org.apache.bookkeeper.tools.common.BKFlags;
import org.apache.bookkeeper.tools.framework.CliCommandGroup;
@@ -53,7 +54,9 @@ public class BookieCommandGroup extends
CliCommandGroup<BKFlags> {
.addCommand(new LedgerCommand())
.addCommand(new ListFilesOnDiscCommand())
.addCommand(new ConvertToDBStorageCommand())
- .addCommand(new ConvertToInterleavedStorageCommand()).build();
+ .addCommand(new ConvertToInterleavedStorageCommand())
+ .addCommand(new ReadJournalCommand())
+ .build();
public BookieCommandGroup() {
super(spec);
diff --git
a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadJournalCommandTest.java
b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadJournalCommandTest.java
new file mode 100644
index 0000000..d78519a
--- /dev/null
+++
b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/bookie/ReadJournalCommandTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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.bookkeeper.tools.cli.commands.bookie;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.powermock.api.mockito.PowerMockito.mock;
+import static org.powermock.api.mockito.PowerMockito.verifyNew;
+import static org.powermock.api.mockito.PowerMockito.when;
+import static org.powermock.api.mockito.PowerMockito.whenNew;
+
+import java.io.File;
+import org.apache.bookkeeper.bookie.Journal;
+import org.apache.bookkeeper.bookie.LedgerDirsManager;
+import org.apache.bookkeeper.conf.ServerConfiguration;
+import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase;
+import org.apache.bookkeeper.util.DiskChecker;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+
+/**
+ * Unit test for read journal command.
+ */
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({ ReadJournalCommand.class, Journal.class,
LedgerDirsManager.class,
+ DiskChecker.class })
+public class ReadJournalCommandTest extends BookieCommandTestBase {
+
+ private Journal journal;
+
+ @Rule
+ private TemporaryFolder folder = new TemporaryFolder();
+
+ public ReadJournalCommandTest() {
+ super(3, 0);
+ }
+
+ @Override
+ public void setup() throws Exception {
+ super.setup();
+ whenNew(ServerConfiguration.class).withNoArguments().thenReturn(conf);
+
+ DiskChecker checker = mock(DiskChecker.class);
+
whenNew(DiskChecker.class).withArguments(eq(conf.getDiskUsageThreshold()),
eq(conf.getDiskUsageWarnThreshold()))
+ .thenReturn(checker);
+ LedgerDirsManager ledgerDirsManager = mock(LedgerDirsManager.class);
+ whenNew(LedgerDirsManager.class).withArguments(eq(conf),
eq(conf.getLedgerDirs()), eq(checker))
+ .thenReturn(ledgerDirsManager);
+ journal = mock(Journal.class);
+ whenNew(Journal.class).withArguments(anyInt(), any(File.class),
eq(conf), eq(ledgerDirsManager))
+ .thenReturn(journal);
+
when(journal.getJournalDirectory()).thenReturn(conf.getJournalDirs()[0]);
+ }
+
+ @Test
+ public void testWithJournalId() throws Exception {
+ conf.setJournalDirsName(new String[] {
folder.getRoot().getAbsolutePath() });
+ when(journal.getJournalDirectory()).thenReturn(new File(""));
+ testCommand("-id", "1");
+ verifyNew(Journal.class, times(1))
+ .withArguments(anyInt(), any(File.class), eq(conf),
any(LedgerDirsManager.class));
+ verifyNew(LedgerDirsManager.class, times(1))
+ .withArguments(eq(conf), eq(conf.getLedgerDirs()),
any(DiskChecker.class));
+ verifyNew(DiskChecker.class, times(1))
+ .withArguments(eq(conf.getDiskUsageThreshold()),
eq(conf.getDiskUsageWarnThreshold()));
+ }
+
+ @Test
+ public void testWithFilename() throws Exception {
+ conf.setJournalDirsName(new String[] {
folder.getRoot().getAbsolutePath() });
+ when(journal.getJournalDirectory()).thenReturn(new File(""));
+ File file = folder.newFile("1.txn");
+ testCommand("-f", file.getAbsolutePath(), "-m");
+ verifyNew(Journal.class, times(1))
+ .withArguments(anyInt(), any(File.class), eq(conf),
any(LedgerDirsManager.class));
+ verifyNew(LedgerDirsManager.class, times(1))
+ .withArguments(eq(conf), eq(conf.getLedgerDirs()),
any(DiskChecker.class));
+ verifyNew(DiskChecker.class, times(1))
+ .withArguments(eq(conf.getDiskUsageThreshold()),
eq(conf.getDiskUsageWarnThreshold()));
+ }
+
+ @Test
+ public void testWithMsg() throws Exception {
+ testCommand("-id", "1", "-d",
conf.getJournalDirs()[0].getAbsolutePath());
+ verifyNew(Journal.class, times(3))
+ .withArguments(anyInt(), any(File.class), eq(conf),
any(LedgerDirsManager.class));
+ verifyNew(LedgerDirsManager.class, times(3))
+ .withArguments(eq(conf), eq(conf.getLedgerDirs()),
any(DiskChecker.class));
+ verifyNew(DiskChecker.class, times(3))
+ .withArguments(eq(conf.getDiskUsageThreshold()),
eq(conf.getDiskUsageWarnThreshold()));
+ verify(journal, times(1)).getJournalDirectory();
+ }
+
+ public void testCommand(String... args) throws Exception {
+ ReadJournalCommand command = new ReadJournalCommand();
+ Assert.assertTrue(command.apply(bkFlags, args));
+ }
+
+ @Test
+ public void testWithoutArgs() {
+ ReadJournalCommand command = new ReadJournalCommand();
+ Assert.assertFalse(command.apply(bkFlags, new String[] { "" }));
+ }
+}