diff --git a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.HDFS-3077.txt b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.HDFS-3077.txt index 919510092ee..38ad79e6a8d 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.HDFS-3077.txt +++ b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.HDFS-3077.txt @@ -68,3 +68,5 @@ HDFS-3914. QJM: acceptRecovery should abort current segment (todd) HDFS-3915. QJM: Failover fails with auth error in secure cluster (todd) HDFS-3906. QJM: quorum timeout on failover with large log segment (todd) + +HDFS-3840. JournalNodes log JournalNotFormattedException backtrace error before being formatted (todd) diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/client/AsyncLogger.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/client/AsyncLogger.java index 19206e6dbcc..99b9d6b287d 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/client/AsyncLogger.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/client/AsyncLogger.java @@ -90,6 +90,11 @@ public ListenableFuture finalizeLogSegment( */ public ListenableFuture format(NamespaceInfo nsInfo); + /** + * @return whether or not the remote node has any valid data. + */ + public ListenableFuture isFormatted(); + /** * @return the state of the last epoch on the target node. */ diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/client/AsyncLoggerSet.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/client/AsyncLoggerSet.java index 8cd6304adde..40df91c00e5 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/client/AsyncLoggerSet.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/client/AsyncLoggerSet.java @@ -216,29 +216,7 @@ public QuorumCall getJournalState() { public QuorumCall isFormatted() { Map> calls = Maps.newHashMap(); for (AsyncLogger logger : loggers) { - final SettableFuture ret = SettableFuture.create(); - ListenableFuture jstate = - logger.getJournalState(); - Futures.addCallback(jstate, new FutureCallback() { - @Override - public void onFailure(Throwable t) { - if (t instanceof RemoteException) { - t = ((RemoteException)t).unwrapRemoteException(); - } - if (t instanceof JournalNotFormattedException) { - ret.set(false); - } else { - ret.setException(t); - } - } - - @Override - public void onSuccess(GetJournalStateResponseProto jstate) { - ret.set(true); - } - }); - - calls.put(logger, ret); + calls.put(logger, logger.isFormatted()); } return QuorumCall.create(calls); } diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/client/IPCLoggerChannel.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/client/IPCLoggerChannel.java index f627b8a2e9f..2186d86ba5b 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/client/IPCLoggerChannel.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/client/IPCLoggerChannel.java @@ -293,6 +293,16 @@ public void run() { } } + @Override + public ListenableFuture isFormatted() { + return executor.submit(new Callable() { + @Override + public Boolean call() throws IOException { + return getProxy().isFormatted(journalId); + } + }); + } + @Override public ListenableFuture getJournalState() { return executor.submit(new Callable() { diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/protocol/QJournalProtocol.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/protocol/QJournalProtocol.java index a6527f19a96..769d0848bd1 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/protocol/QJournalProtocol.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/protocol/QJournalProtocol.java @@ -47,6 +47,12 @@ public interface QJournalProtocol { public static final long versionID = 1L; + /** + * @return true if the given journal has been formatted and + * contains valid data. + */ + public boolean isFormatted(String journalId) throws IOException; + /** * Get the current state of the journal, including the most recent * epoch number and the HTTP port. diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/protocolPB/QJournalProtocolServerSideTranslatorPB.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/protocolPB/QJournalProtocolServerSideTranslatorPB.java index b689a3da17c..a232331b0b3 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/protocolPB/QJournalProtocolServerSideTranslatorPB.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/protocolPB/QJournalProtocolServerSideTranslatorPB.java @@ -32,6 +32,8 @@ import org.apache.hadoop.hdfs.qjournal.protocol.QJournalProtocolProtos.GetJournalStateResponseProto; import org.apache.hadoop.hdfs.qjournal.protocol.QJournalProtocolProtos.HeartbeatRequestProto; import org.apache.hadoop.hdfs.qjournal.protocol.QJournalProtocolProtos.HeartbeatResponseProto; +import org.apache.hadoop.hdfs.qjournal.protocol.QJournalProtocolProtos.IsFormattedRequestProto; +import org.apache.hadoop.hdfs.qjournal.protocol.QJournalProtocolProtos.IsFormattedResponseProto; import org.apache.hadoop.hdfs.qjournal.protocol.QJournalProtocolProtos.JournalIdProto; import org.apache.hadoop.hdfs.qjournal.protocol.QJournalProtocolProtos.JournalRequestProto; import org.apache.hadoop.hdfs.qjournal.protocol.QJournalProtocolProtos.JournalResponseProto; @@ -67,6 +69,22 @@ public QJournalProtocolServerSideTranslatorPB(QJournalProtocol impl) { this.impl = impl; } + + @Override + public IsFormattedResponseProto isFormatted(RpcController controller, + IsFormattedRequestProto request) throws ServiceException { + try { + boolean ret = impl.isFormatted( + convert(request.getJid())); + return IsFormattedResponseProto.newBuilder() + .setIsFormatted(ret) + .build(); + } catch (IOException ioe) { + throw new ServiceException(ioe); + } + } + + @Override public GetJournalStateResponseProto getJournalState(RpcController controller, GetJournalStateRequestProto request) throws ServiceException { diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/protocolPB/QJournalProtocolTranslatorPB.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/protocolPB/QJournalProtocolTranslatorPB.java index d5177e00bfc..290a62aa1d2 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/protocolPB/QJournalProtocolTranslatorPB.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/protocolPB/QJournalProtocolTranslatorPB.java @@ -33,6 +33,8 @@ import org.apache.hadoop.hdfs.qjournal.protocol.QJournalProtocolProtos.GetJournalStateRequestProto; import org.apache.hadoop.hdfs.qjournal.protocol.QJournalProtocolProtos.GetJournalStateResponseProto; import org.apache.hadoop.hdfs.qjournal.protocol.QJournalProtocolProtos.HeartbeatRequestProto; +import org.apache.hadoop.hdfs.qjournal.protocol.QJournalProtocolProtos.IsFormattedRequestProto; +import org.apache.hadoop.hdfs.qjournal.protocol.QJournalProtocolProtos.IsFormattedResponseProto; import org.apache.hadoop.hdfs.qjournal.protocol.QJournalProtocolProtos.JournalIdProto; import org.apache.hadoop.hdfs.qjournal.protocol.QJournalProtocolProtos.JournalRequestProto; import org.apache.hadoop.hdfs.qjournal.protocol.QJournalProtocolProtos.NewEpochRequestProto; @@ -78,6 +80,20 @@ public void close() { } + @Override + public boolean isFormatted(String journalId) throws IOException { + try { + IsFormattedRequestProto req = IsFormattedRequestProto.newBuilder() + .setJid(convertJournalId(journalId)) + .build(); + IsFormattedResponseProto resp = rpcProxy.isFormatted( + NULL_CONTROLLER, req); + return resp.getIsFormatted(); + } catch (ServiceException e) { + throw ProtobufHelper.getRemoteException(e); + } + } + @Override public GetJournalStateResponseProto getJournalState(String jid) throws IOException { diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/server/Journal.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/server/Journal.java index 6e75bbc22f2..dd11d3a323f 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/server/Journal.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/server/Journal.java @@ -402,10 +402,14 @@ private synchronized void checkWriteRequest(RequestInfo reqInfo) throws IOExcept } } + public synchronized boolean isFormatted() { + return storage.isFormatted(); + } + private void checkFormatted() throws JournalNotFormattedException { - if (!storage.isFormatted()) { - throw new JournalNotFormattedException("Journal " + storage + - " not formatted"); + if (!isFormatted()) { + throw new JournalNotFormattedException("Journal " + + storage.getSingularStorageDir() + " not formatted"); } } diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/server/JournalNodeRpcServer.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/server/JournalNodeRpcServer.java index 3ff9df83fe3..02d9df0c236 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/server/JournalNodeRpcServer.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/qjournal/server/JournalNodeRpcServer.java @@ -107,6 +107,11 @@ static InetSocketAddress getAddress(Configuration conf) { DFSConfigKeys.DFS_JOURNALNODE_RPC_ADDRESS_KEY); } + @Override + public boolean isFormatted(String journalId) throws IOException { + return jn.getOrCreateJournal(journalId).isFormatted(); + } + @Override public GetJournalStateResponseProto getJournalState(String journalId) throws IOException { diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/proto/QJournalProtocol.proto b/hadoop-hdfs-project/hadoop-hdfs/src/main/proto/QJournalProtocol.proto index 8a6bd0d5085..9c448ce3c8c 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/proto/QJournalProtocol.proto +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/proto/QJournalProtocol.proto @@ -116,6 +116,17 @@ message PurgeLogsRequestProto { message PurgeLogsResponseProto { } +/** + * isFormatted() + */ +message IsFormattedRequestProto { + required JournalIdProto jid = 1; +} + +message IsFormattedResponseProto { + required bool isFormatted = 1; +} + /** * getJournalState() */ @@ -210,6 +221,8 @@ message AcceptRecoveryResponseProto { * See the request and response for details of rpc call. */ service QJournalProtocolService { + rpc isFormatted(IsFormattedRequestProto) returns (IsFormattedResponseProto); + rpc getJournalState(GetJournalStateRequestProto) returns (GetJournalStateResponseProto); rpc newEpoch(NewEpochRequestProto) returns (NewEpochResponseProto); diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/qjournal/server/TestJournal.java b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/qjournal/server/TestJournal.java index 05cca1c0a25..aaf1f883cd9 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/qjournal/server/TestJournal.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/qjournal/server/TestJournal.java @@ -156,10 +156,13 @@ public void testFormatResetsCachedValues() throws Exception { assertEquals(12345L, journal.getLastPromisedEpoch()); assertEquals(12345L, journal.getLastWriterEpoch()); - + assertTrue(journal.isFormatted()); + journal.format(FAKE_NSINFO_2); + assertEquals(0, journal.getLastPromisedEpoch()); assertEquals(0, journal.getLastWriterEpoch()); + assertTrue(journal.isFormatted()); } /**