diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java index 4cb3c678c075..1ae3842e1f67 100644 --- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java @@ -269,6 +269,7 @@ public static boolean isReadOnly( case CancelSnapshotDiff: case ListSnapshotDiffJobs: case TransferLeadership: + case SetSafeMode: return true; case CreateVolume: case SetVolumeProperty: diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java index f02af22e21c2..da9e45ebc3fb 100644 --- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.UUID; +import org.apache.hadoop.fs.SafeModeAction; import org.apache.hadoop.hdds.scm.container.common.helpers.ExcludeList; import org.apache.hadoop.ozone.OzoneAcl; import org.apache.hadoop.ozone.om.IOmMetadataReader; @@ -1054,4 +1055,18 @@ void setTimes(OmKeyArgs keyArgs, long mtime, long atime) throws IOException; UUID refetchSecretKey() throws IOException; + /** + * Enter, leave, or get safe mode. + * + * @param action One of {@link SafeModeAction} LEAVE, ENTER, GET, + * FORCE_EXIT. + * @param isChecked If true check only for Active metadata node / + * NameNode's status, else check first metadata node / + * NameNode's status. + * @throws IOException if set safe mode fails to proceed. + * @return true if the action is successfully accepted, otherwise false + * means rejected. + */ + boolean setSafeMode(SafeModeAction action, boolean isChecked) + throws IOException; } diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java index c009028c46b2..2c0aef893b14 100644 --- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java @@ -26,6 +26,7 @@ import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; +import org.apache.hadoop.fs.SafeModeAction; import org.apache.hadoop.hdds.annotation.InterfaceAudience; import org.apache.hadoop.hdds.client.ECReplicationConfig; import org.apache.hadoop.hdds.client.ReplicationConfig; @@ -169,6 +170,7 @@ import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RenewDelegationTokenResponseProto; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RevokeS3SecretRequest; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.S3Secret; +import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SafeMode; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ServiceListRequest; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ServiceListResponse; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetAclRequest; @@ -176,6 +178,8 @@ import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetBucketPropertyRequest; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetS3SecretRequest; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetS3SecretResponse; +import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetSafeModeRequest; +import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetSafeModeResponse; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetTimesRequest; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetVolumePropertyRequest; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.TenantAssignAdminRequest; @@ -2331,6 +2335,38 @@ public void setTimes(OmKeyArgs args, long mtime, long atime) handleError(submitRequest(omRequest)); } + @Override + public boolean setSafeMode(SafeModeAction action, boolean isChecked) + throws IOException { + SetSafeModeRequest setSafeModeRequest = + SetSafeModeRequest.newBuilder() + .setSafeMode(toProtoBuf(action)) + .build(); + + OMRequest omRequest = createOMRequest(Type.SetSafeMode) + .setSetSafeModeRequest(setSafeModeRequest).build(); + + SetSafeModeResponse setSafeModeResponse = + handleError(submitRequest(omRequest)).getSetSafeModeResponse(); + return setSafeModeResponse.getResponse(); + } + + private SafeMode toProtoBuf(SafeModeAction action) { + switch (action) { + case ENTER: + return SafeMode.ENTER; + case LEAVE: + return SafeMode.LEAVE; + case FORCE_EXIT: + return SafeMode.FORCE_EXIT; + case GET: + return SafeMode.GET; + default: + throw new IllegalArgumentException("Unsupported safe mode action " + + action); + } + } + @VisibleForTesting public OmTransport getTransport() { return transport; diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestLeaseRecovery.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestLeaseRecovery.java index a67db81ad867..fba842799c60 100644 --- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestLeaseRecovery.java +++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestLeaseRecovery.java @@ -48,6 +48,7 @@ import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_RATIS_ENABLE_KEY; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; @@ -120,6 +121,7 @@ public void testRecovery() throws Exception { ThreadLocalRandom.current().nextBytes(data); stream.write(data); stream.hsync(); + assertFalse(fs.isFileClosed(file)); int count = 0; while (count++ < 15 && !fs.recoverLease(file)) { @@ -127,6 +129,7 @@ public void testRecovery() throws Exception { } // The lease should have been recovered. assertTrue("File should be closed", fs.recoverLease(file)); + assertTrue(fs.isFileClosed(file)); // open it again, make sure the data is correct byte[] readData = new byte[1 << 20]; try (FSDataInputStream fdis = fs.open(file)) { diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFileSystemWithFSO.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFileSystemWithFSO.java index 8ed595187b16..ed148bc45fcf 100644 --- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFileSystemWithFSO.java +++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFileSystemWithFSO.java @@ -20,12 +20,14 @@ import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileStatus; +import org.apache.hadoop.fs.LeaseRecoverable; import org.apache.hadoop.fs.LocatedFileStatus; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.RemoteIterator; import org.apache.hadoop.fs.contract.ContractTestUtils; import org.apache.hadoop.ozone.OzoneConsts; import org.apache.hadoop.ozone.om.OMMetadataManager; +import org.apache.hadoop.ozone.om.exceptions.OMException; import org.apache.hadoop.ozone.om.helpers.BucketLayout; import org.apache.hadoop.ozone.om.helpers.OmBucketInfo; import org.apache.hadoop.ozone.om.helpers.OmDirectoryInfo; @@ -48,7 +50,9 @@ import java.util.Collection; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -568,6 +572,29 @@ public void testCreateFile() throws Exception { }, 1000, 120000); } + /** + * Verify recoverLease() and isFileClosed() APIs. + * @throws Exception + */ + @Test + public void testLeaseRecoverable() throws Exception { + // Create a file + Path parent = new Path("/d1/d2/"); + Path source = new Path(parent, "file1"); + + LeaseRecoverable fs = (LeaseRecoverable)getFs(); + FSDataOutputStream stream = getFs().create(source); + // file not visible yet + assertThrows(OMException.class, () -> fs.isFileClosed(source)); + stream.write(1); + stream.hsync(); + // file is visible and open + assertFalse(fs.isFileClosed(source)); + assertTrue(fs.recoverLease(source)); + // file is closed after lease recovery + assertTrue(fs.isFileClosed(source)); + } + private void verifyOMFileInfoFormat(OmKeyInfo omKeyInfo, String fileName, long parentID) { Assert.assertEquals("Wrong keyName", fileName, omKeyInfo.getKeyName()); diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestRootedOzoneFileSystem.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestRootedOzoneFileSystem.java index 6f2be4b099a9..40b5433d116d 100644 --- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestRootedOzoneFileSystem.java +++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestRootedOzoneFileSystem.java @@ -30,6 +30,8 @@ import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.PathIsNotEmptyDirectoryException; import org.apache.hadoop.fs.RemoteIterator; +import org.apache.hadoop.fs.SafeMode; +import org.apache.hadoop.fs.SafeModeAction; import org.apache.hadoop.fs.StreamCapabilities; import org.apache.hadoop.fs.Trash; import org.apache.hadoop.fs.TrashPolicy; @@ -2545,4 +2547,19 @@ public void testSetTimes() throws Exception { // verify that mtime is NOT updated as expected. Assert.assertEquals(mtime, fileStatus.getModificationTime()); } + + @Test + public void testSafeMode() throws Exception { + SafeMode safeModeFS = (SafeMode) fs; + // safe mode is off + assertFalse(safeModeFS.setSafeMode(SafeModeAction.GET)); + // shutdown datanodes and restart SCM + cluster.shutdownHddsDatanodes(); + cluster.restartStorageContainerManager(false); + // SCM should be in safe mode + assertTrue(safeModeFS.setSafeMode(SafeModeAction.GET)); + // force exit safe mode and verify that it's out of safe mode. + safeModeFS.setSafeMode(SafeModeAction.FORCE_EXIT); + assertFalse(safeModeFS.setSafeMode(SafeModeAction.GET)); + } } diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestRootedOzoneFileSystemWithFSO.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestRootedOzoneFileSystemWithFSO.java index 1b78da7ce076..8a7c3c453b8a 100644 --- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestRootedOzoneFileSystemWithFSO.java +++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestRootedOzoneFileSystemWithFSO.java @@ -19,8 +19,11 @@ import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileStatus; +import org.apache.hadoop.fs.LeaseRecoverable; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.contract.ContractTestUtils; +import org.apache.hadoop.ozone.om.exceptions.OMException; + import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Ignore; @@ -36,6 +39,8 @@ import java.util.concurrent.TimeoutException; import static org.apache.hadoop.ozone.OzoneConsts.OZONE_URI_DELIMITER; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; /** @@ -128,13 +133,13 @@ public void testRenameDestinationParentDoesntExist() throws Exception { + root + "/b/c"); // rename should fail and return false - Assert.assertFalse(getFs().rename(dir2SourcePath, destinPath)); + assertFalse(getFs().rename(dir2SourcePath, destinPath)); // (b) parent of dst is a file. /root_dir/file1/c Path filePath = new Path(getBucketPath() + root + "/file1"); ContractTestUtils.touch(getFs(), filePath); Path newDestinPath = new Path(filePath, "c"); // rename should fail and return false - Assert.assertFalse(getFs().rename(dir2SourcePath, newDestinPath)); + assertFalse(getFs().rename(dir2SourcePath, newDestinPath)); } @Test @@ -188,7 +193,7 @@ public void testRenameDirToItsOwnSubDir() throws Exception { LOG.info("Created dir1 {}", subDir1); LOG.info("Rename op-> source:{} to destin:{}", sourceRoot, subDir1); // rename should fail and return false - Assert.assertFalse(getFs().rename(sourceRoot, subDir1)); + assertFalse(getFs().rename(sourceRoot, subDir1)); } finally { getFs().delete(sourceRoot, true); } @@ -265,4 +270,20 @@ public void testListStatusFSO() throws Exception { Assert.assertEquals(valueGreaterBatchSize, fileStatuses.length); } + @Test + public void testLeaseRecoverable() throws Exception { + // Create a file + final String dir = "dir1"; + final String key = dir + "/key1"; + final Path source = new Path(getBucketPath(), key); + + LeaseRecoverable fs = (LeaseRecoverable)getFs(); + FSDataOutputStream stream = getFs().create(source); + assertThrows(OMException.class, () -> fs.isFileClosed(source)); + stream.write(1); + stream.hsync(); + assertFalse(fs.isFileClosed(source)); + assertTrue(fs.recoverLease(source)); + assertTrue(fs.isFileClosed(source)); + } } diff --git a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto index a64283fb1c5f..f38873a9e009 100644 --- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto +++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto @@ -139,6 +139,14 @@ enum Type { RefetchSecretKey = 121; ListSnapshotDiffJobs = 122; CancelSnapshotDiff = 123; + SetSafeMode = 124; +} + +enum SafeMode { + ENTER = 1; + LEAVE = 2; + FORCE_EXIT = 3; + GET = 4; } message OMRequest { @@ -259,9 +267,9 @@ message OMRequest { optional RecoverLeaseRequest RecoverLeaseRequest = 119; optional SetTimesRequest SetTimesRequest = 120; optional RefetchSecretKeyRequest RefetchSecretKeyRequest = 121; - optional ListSnapshotDiffJobRequest ListSnapshotDiffJobRequest = 122; optional CancelSnapshotDiffRequest CancelSnapshotDiffRequest = 123; + optional SetSafeModeRequest SetSafeModeRequest = 124; } message OMResponse { @@ -374,9 +382,9 @@ message OMResponse { optional RecoverLeaseResponse RecoverLeaseResponse = 119; optional SetTimesResponse SetTimesResponse = 120; optional RefetchSecretKeyResponse RefetchSecretKeyResponse = 121; - optional ListSnapshotDiffJobResponse ListSnapshotDiffJobResponse = 122; optional CancelSnapshotDiffResponse cancelSnapshotDiffResponse = 123; + optional SetSafeModeResponse SetSafeModeResponse = 124; } enum Status { @@ -1954,6 +1962,14 @@ message SetTimesRequest { message SetTimesResponse { } +message SetSafeModeRequest { + required SafeMode safeMode = 1; +} + +message SetSafeModeResponse { + optional bool response = 1; +} + /** The OM service that takes care of Ozone namespace. */ diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java index 95eb39caae03..ccbd673414fe 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java @@ -59,6 +59,7 @@ import org.apache.hadoop.fs.CommonConfigurationKeysPublic; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.FileUtil; +import org.apache.hadoop.fs.SafeModeAction; import org.apache.hadoop.hdds.HddsConfigKeys; import org.apache.hadoop.hdds.HddsUtils; import org.apache.hadoop.hdds.annotation.InterfaceAudience; @@ -288,6 +289,7 @@ import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_SERVER_DEFAULT_REPLICATION_TYPE_KEY; import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.DETECTED_LOOP_IN_BUCKET_LINKS; import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.FEATURE_NOT_ENABLED; +import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INTERNAL_ERROR; import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INVALID_AUTH_METHOD; import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INVALID_REQUEST; import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.PERMISSION_DENIED; @@ -4469,6 +4471,25 @@ public void setTimes(OmKeyArgs keyArgs, long mtime, long atime) throws IOException { } + @Override + public boolean setSafeMode(SafeModeAction action, boolean isChecked) + throws IOException { + switch (action) { + case ENTER: + throw new OMException("Enter safe mode is unsupported", + INTERNAL_ERROR); + case FORCE_EXIT: + return getScmClient().getContainerClient().forceExitSafeMode(); + case GET: + return getScmClient().getContainerClient().inSafeMode(); + //case LEAVE: + // TODO: support LEAVE in the future. + default: + throw new OMException("Unsupported safe mode action " + action, + INTERNAL_ERROR); + } + } + /** * Write down Layout version of a finalized feature to DB on finalization. * @param lvm OMLayoutVersionManager diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java index 7ccdc4fd59ab..e6023d23a17e 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java @@ -30,6 +30,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; +import org.apache.hadoop.fs.SafeModeAction; import org.apache.hadoop.hdds.client.ECReplicationConfig; import org.apache.hadoop.hdds.protocol.proto.HddsProtos; import org.apache.hadoop.hdds.protocol.proto.HddsProtos.TransferLeadershipRequestProto; @@ -115,6 +116,8 @@ import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.RepeatedKeyInfo; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ServiceListRequest; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ServiceListResponse; +import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetSafeModeRequest; +import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetSafeModeResponse; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetS3VolumeContextResponse; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Status; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SnapshotDiffRequest; @@ -333,6 +336,10 @@ public OMResponse handleReadRequest(OMRequest request) { case RefetchSecretKey: responseBuilder.setRefetchSecretKeyResponse(refetchSecretKey()); break; + case SetSafeMode: + SetSafeModeResponse setSafeModeResponse = + setSafeMode(request.getSetSafeModeRequest()); + responseBuilder.setSetSafeModeResponse(setSafeModeResponse); default: responseBuilder.setSuccess(false); responseBuilder.setMessage("Unrecognized Command Type: " + cmdType); @@ -1356,4 +1363,30 @@ private TransferLeadershipResponseProto transferLeadership( impl.transferLeadership(newLeaderId); return TransferLeadershipResponseProto.getDefaultInstance(); } + + private SetSafeModeResponse setSafeMode( + SetSafeModeRequest req) throws IOException { + OzoneManagerProtocolProtos.SafeMode safeMode = req.getSafeMode(); + boolean response = impl.setSafeMode(toSafeModeAction(safeMode), false); + return SetSafeModeResponse.newBuilder() + .setResponse(response) + .build(); + } + + private SafeModeAction toSafeModeAction( + OzoneManagerProtocolProtos.SafeMode safeMode) { + switch (safeMode) { + case ENTER: + return SafeModeAction.ENTER; + case LEAVE: + return SafeModeAction.LEAVE; + case FORCE_EXIT: + return SafeModeAction.FORCE_EXIT; + case GET: + return SafeModeAction.GET; + default: + throw new IllegalArgumentException("Unexpected safe mode action " + + safeMode); + } + } } diff --git a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/LeaseRecoverable.java b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/LeaseRecoverable.java new file mode 100644 index 000000000000..03d93bef562a --- /dev/null +++ b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/LeaseRecoverable.java @@ -0,0 +1,52 @@ +/* + * 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.hadoop.fs; + +import java.io.IOException; + +/** + * FIXME: Hack: This is copied from Hadoop 3.3.6. Remove this interface once + * we drop Hadoop 3.1, 3.2 support. + * Whether the given Path of the FileSystem has the capability to perform lease + * recovery. + */ +public interface LeaseRecoverable { + + /** + * Start the lease recovery of a file. + * + * @param file path to a file. + * @return true if the file is already closed, and it does not require lease + * recovery. + * @throws IOException if an error occurs during lease recovery. + * @throws UnsupportedOperationException if lease recovery is not supported + * by this filesystem. + */ + boolean recoverLease(Path file) throws IOException; + + /** + * Get the close status of a file. + * @param file The string representation of the path to the file + * @return return true if file is closed + * @throws IOException If an I/O error occurred + * @throws UnsupportedOperationException if isFileClosed is not supported by + * this filesystem. + */ + boolean isFileClosed(Path file) throws IOException; +} diff --git a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/SafeMode.java b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/SafeMode.java new file mode 100644 index 000000000000..e9fb827ded89 --- /dev/null +++ b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/SafeMode.java @@ -0,0 +1,57 @@ +/* + * 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.hadoop.fs; + +import java.io.IOException; + +/** + * FIXME: Hack: This is copied from Hadoop 3.3.6. Remove this interface once + * we drop Hadoop 3.1, 3.2 support. + * Whether the given filesystem is in any status of safe mode. + */ +public interface SafeMode { + + /** + * Enter, leave, or get safe mode. + * + * @param action One of {@link SafeModeAction} LEAVE, ENTER, GET, FORCE_EXIT. + * @throws IOException if set safe mode fails to proceed. + * @return true if the action is successfully accepted, otherwise false means + * rejected. + */ + default boolean setSafeMode(SafeModeAction action) throws IOException { + return setSafeMode(action, false); + } + + /** + * Enter, leave, or get safe mode. + * + * @param action One of {@link SafeModeAction} LEAVE, ENTER, GET, + * FORCE_EXIT. + * @param isChecked If true check only for Active metadata node / NameNode's + * status, + * else check first metadata node / NameNode's status. + * @throws IOException if set safe mode fails to proceed. + * @return true if the action is successfully accepted, otherwise false means + * rejected. + */ + boolean setSafeMode(SafeModeAction action, boolean isChecked) + throws IOException; + +} diff --git a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/SafeModeAction.java b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/SafeModeAction.java new file mode 100644 index 000000000000..20e7cb9f198e --- /dev/null +++ b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/SafeModeAction.java @@ -0,0 +1,44 @@ +/* + * 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.hadoop.fs; + +/** + * FIXME: Hack: This is copied from Hadoop 3.3.6. Remove this interface once + * we drop Hadoop 3.1, 3.2 support. + * An identical copy from org.apache.hadoop.hdfs.protocol.HdfsConstants + * .SafeModeAction, that helps + * the other file system implementation to define {@link SafeMode}. + */ +public enum SafeModeAction { + /** + * Starting entering into safe mode. + */ + ENTER, + /** + * Gracefully exit from safe mode. + */ + LEAVE, + /** + * Force Exit from safe mode. + */ + FORCE_EXIT, + /** + * Get the status of the safe mode. + */ + GET; +} diff --git a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicOzoneClientAdapterImpl.java b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicOzoneClientAdapterImpl.java index 6090722306a0..443ba17d5968 100644 --- a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicOzoneClientAdapterImpl.java +++ b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicOzoneClientAdapterImpl.java @@ -36,6 +36,7 @@ import org.apache.hadoop.fs.FileChecksum; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.PathIsNotEmptyDirectoryException; +import org.apache.hadoop.fs.SafeModeAction; import org.apache.hadoop.hdds.annotation.InterfaceAudience; import org.apache.hadoop.hdds.client.ReplicationConfig; import org.apache.hadoop.hdds.client.ReplicationFactor; @@ -716,9 +717,40 @@ private SnapshotDiffReportOzone getSnapshotDiffReportOnceComplete( return snapshotDiffResponse.getSnapshotDiffReport(); } + @Override + public boolean recoverLease(final String pathStr) throws IOException { + incrementCounter(Statistic.INVOCATION_RECOVER_LEASE, 1); + + return ozoneClient.getProxy().getOzoneManagerClient().recoverLease( + volume.getName(), bucket.getName(), pathStr); + } + @Override public void setTimes(String key, long mtime, long atime) throws IOException { incrementCounter(Statistic.INVOCATION_SET_TIMES, 1); bucket.setTimes(key, mtime, atime); } + + @Override + public boolean isFileClosed(String pathStr) throws IOException { + incrementCounter(Statistic.INVOCATION_IS_FILE_CLOSED, 1); + OFSPath ofsPath = new OFSPath(pathStr, config); + if (!ofsPath.isKey()) { + throw new IOException("not a file"); + } + OzoneFileStatus status = bucket.getFileStatus(pathStr); + if (!status.isFile()) { + throw new IOException("not a file"); + } + return !status.getKeyInfo().isHsync(); + } + + @Override + public boolean setSafeMode(SafeModeAction action, boolean isChecked) + throws IOException { + incrementCounter(Statistic.INVOCATION_SET_SAFE_MODE, 1); + + return ozoneClient.getProxy().getOzoneManagerClient().setSafeMode( + action, isChecked); + } } diff --git a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicOzoneFileSystem.java b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicOzoneFileSystem.java index 9b654062dace..f095d4271330 100644 --- a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicOzoneFileSystem.java +++ b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicOzoneFileSystem.java @@ -35,6 +35,7 @@ import org.apache.hadoop.fs.PathFilter; import org.apache.hadoop.fs.PathIsNotEmptyDirectoryException; import org.apache.hadoop.fs.RemoteIterator; +import org.apache.hadoop.fs.SafeModeAction; import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.hdds.annotation.InterfaceAudience; import org.apache.hadoop.hdds.annotation.InterfaceStability; @@ -1266,4 +1267,16 @@ private FileStatus convertFileStatus( } return new LocatedFileStatus(fileStatus, blockLocations); } + + protected boolean setSafeModeUtil(SafeModeAction action, + boolean isChecked) + throws IOException { + if (action == SafeModeAction.GET) { + statistics.incrementReadOps(1); + } else { + statistics.incrementWriteOps(1); + } + LOG.trace("setSafeMode() action:{}", action); + return getAdapter().setSafeMode(action, isChecked); + } } diff --git a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneClientAdapterImpl.java b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneClientAdapterImpl.java index 3bdde5333d09..6c6be7368014 100644 --- a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneClientAdapterImpl.java +++ b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneClientAdapterImpl.java @@ -41,6 +41,7 @@ import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.PathIsNotEmptyDirectoryException; +import org.apache.hadoop.fs.SafeModeAction; import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.hdds.annotation.InterfaceAudience; import org.apache.hadoop.hdds.client.ReplicationConfig; @@ -1370,8 +1371,31 @@ private SnapshotDiffReportOzone getSnapshotDiffReportOnceComplete( return snapshotDiffResponse.getSnapshotDiffReport(); } - public boolean recoverLease(final Path f) throws IOException { - OFSPath ofsPath = new OFSPath(f, config); + @Override + public boolean isFileClosed(String pathStr) throws IOException { + incrementCounter(Statistic.INVOCATION_IS_FILE_CLOSED, 1); + OFSPath ofsPath = new OFSPath(pathStr, config); + String key = ofsPath.getKeyName(); + if (ofsPath.isRoot() || ofsPath.isVolume()) { + throw new IOException("not a file"); + } else { + OzoneBucket bucket = getBucket(ofsPath, false); + if (ofsPath.isSnapshotPath()) { + throw new IOException("file is in a snapshot."); + } else { + OzoneFileStatus status = bucket.getFileStatus(key); + if (!status.isFile()) { + throw new IOException("not a file"); + } + return !status.getKeyInfo().isHsync(); + } + } + } + + @Override + public boolean recoverLease(final String pathStr) throws IOException { + incrementCounter(Statistic.INVOCATION_RECOVER_LEASE, 1); + OFSPath ofsPath = new OFSPath(pathStr, config); OzoneVolume volume = objectStore.getVolume(ofsPath.getVolumeName()); OzoneBucket bucket = getBucket(ofsPath, false); @@ -1379,6 +1403,7 @@ public boolean recoverLease(final Path f) throws IOException { volume.getName(), bucket.getName(), ofsPath.getKeyName()); } + @Override public void setTimes(String key, long mtime, long atime) throws IOException { incrementCounter(Statistic.INVOCATION_SET_TIMES, 1); OFSPath ofsPath = new OFSPath(key, config); @@ -1386,4 +1411,13 @@ public void setTimes(String key, long mtime, long atime) throws IOException { OzoneBucket bucket = getBucket(ofsPath, false); bucket.setTimes(ofsPath.getKeyName(), mtime, atime); } + + @Override + public boolean setSafeMode(SafeModeAction action, boolean isChecked) + throws IOException { + incrementCounter(Statistic.INVOCATION_SET_SAFE_MODE, 1); + + return ozoneClient.getProxy().getOzoneManagerClient().setSafeMode( + action, isChecked); + } } diff --git a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneFileSystem.java b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneFileSystem.java index 2639a8f05de1..e560b476638a 100644 --- a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneFileSystem.java +++ b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneFileSystem.java @@ -33,6 +33,7 @@ import org.apache.hadoop.fs.PathFilter; import org.apache.hadoop.fs.PathIsNotEmptyDirectoryException; import org.apache.hadoop.fs.RemoteIterator; +import org.apache.hadoop.fs.SafeModeAction; import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.fs.ContentSummary; import org.apache.hadoop.hdds.annotation.InterfaceAudience; @@ -1543,18 +1544,6 @@ public SnapshotDiffReport getSnapshotDiffReport(final Path snapshotDir, return adapter.getSnapshotDiffReport(snapshotDir, fromSnapshot, toSnapshot); } - - /** - * Start the lease recovery of a file. - * - * @param f a file - * @return true if the file is already closed - * @throws IOException if an error occurs - */ - public boolean recoverLease(final Path f) throws IOException { - return adapterImpl.recoverLease(f); - } - @Override public void setTimes(Path f, long mtime, long atime) throws IOException { incrementCounter(Statistic.INVOCATION_SET_TIMES, 1); @@ -1569,4 +1558,15 @@ public void setTimes(Path f, long mtime, long atime) throws IOException { adapter.setTimes(key, mtime, atime); } + protected boolean setSafeModeUtil(SafeModeAction action, + boolean isChecked) + throws IOException { + if (action == SafeModeAction.GET) { + statistics.incrementReadOps(1); + } else { + statistics.incrementWriteOps(1); + } + LOG.trace("setSafeMode() action:{}", action); + return getAdapter().setSafeMode(action, isChecked); + } } diff --git a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/OzoneClientAdapter.java b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/OzoneClientAdapter.java index 80cc50b9b9e7..c48f1a6366fe 100644 --- a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/OzoneClientAdapter.java +++ b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/OzoneClientAdapter.java @@ -26,6 +26,7 @@ import org.apache.hadoop.crypto.key.KeyProvider; import org.apache.hadoop.fs.FileChecksum; import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.SafeModeAction; import org.apache.hadoop.hdfs.protocol.SnapshotDiffReport; import org.apache.hadoop.ozone.security.OzoneTokenIdentifier; import org.apache.hadoop.security.token.Token; @@ -94,5 +95,12 @@ SnapshotDiffReport getSnapshotDiffReport(Path snapshotDir, String fromSnapshot, String toSnapshot) throws IOException, InterruptedException; + boolean recoverLease(String pathStr) throws IOException; + void setTimes(String key, long mtime, long atime) throws IOException; + + boolean isFileClosed(String pathStr) throws IOException; + + boolean setSafeMode(SafeModeAction action, boolean isChecked) + throws IOException; } diff --git a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/OzoneClientUtils.java b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/OzoneClientUtils.java index 2c6ce21aa0d6..cb628111767f 100644 --- a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/OzoneClientUtils.java +++ b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/OzoneClientUtils.java @@ -267,5 +267,4 @@ public static int limitValue(int confValue, String confName, int maxLimit) { } return limitVal; } - } diff --git a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/Statistic.java b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/Statistic.java index 09b9cdd777a2..aae71e9c4cde 100644 --- a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/Statistic.java +++ b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/Statistic.java @@ -74,7 +74,13 @@ public enum Statistic { INVOCATION_RENAME(CommonStatisticNames.OP_RENAME, "Calls of rename()"), INVOCATION_SET_TIMES(CommonStatisticNames.OP_SET_TIMES, - "Calls of setTimes()"); + "Calls of setTimes()"), + INVOCATION_IS_FILE_CLOSED("op_is_file_closed", + "Calls of isFileClosed()"), + INVOCATION_RECOVER_LEASE("op_recover_lease", + "Calls of recoverLease()"), + INVOCATION_SET_SAFE_MODE("op_set_safe_mode", + "Calls of setSafeMode()"); private static final Map SYMBOL_MAP = new HashMap<>(Statistic.values().length); diff --git a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/package-info.java b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/package-info.java new file mode 100644 index 000000000000..7c6d4c2c5007 --- /dev/null +++ b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/package-info.java @@ -0,0 +1,30 @@ +/* + * 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. + * + */ + +/** + * Interface definitions borrowed from Hadoop 3.3.6. + * FIXME: Hack: This is copied from Hadoop 3.3.6. Remove this interface once + * we drop Hadoop 3.1, 3.2 support. + */ +@InterfaceAudience.Private +@InterfaceStability.Evolving +package org.apache.hadoop.fs; + +import org.apache.hadoop.hdds.annotation.InterfaceAudience; +import org.apache.hadoop.hdds.annotation.InterfaceStability; diff --git a/hadoop-ozone/ozonefs-hadoop3/src/main/java/org/apache/hadoop/fs/ozone/OzoneFileSystem.java b/hadoop-ozone/ozonefs-hadoop3/src/main/java/org/apache/hadoop/fs/ozone/OzoneFileSystem.java index 8fa46d7a5378..203e7ed373eb 100644 --- a/hadoop-ozone/ozonefs-hadoop3/src/main/java/org/apache/hadoop/fs/ozone/OzoneFileSystem.java +++ b/hadoop-ozone/ozonefs-hadoop3/src/main/java/org/apache/hadoop/fs/ozone/OzoneFileSystem.java @@ -25,7 +25,10 @@ import org.apache.hadoop.crypto.key.KeyProvider; import org.apache.hadoop.crypto.key.KeyProviderTokenIssuer; import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.LeaseRecoverable; import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.SafeMode; +import org.apache.hadoop.fs.SafeModeAction; import org.apache.hadoop.fs.StorageStatistics; import org.apache.hadoop.hdds.annotation.InterfaceAudience; import org.apache.hadoop.hdds.annotation.InterfaceStability; @@ -43,7 +46,7 @@ @InterfaceAudience.Private @InterfaceStability.Evolving public class OzoneFileSystem extends BasicOzoneFileSystem - implements KeyProviderTokenIssuer { + implements KeyProviderTokenIssuer, LeaseRecoverable, SafeMode { private OzoneFSStorageStatistics storageStatistics; @@ -120,4 +123,26 @@ public boolean hasPathCapability(final Path path, final String capability) } return super.hasPathCapability(p, capability); } + + @Override + public boolean recoverLease(Path f) throws IOException { + LOG.trace("recoverLease() path:{}", f); + Path qualifiedPath = makeQualified(f); + String key = pathToKey(qualifiedPath); + return getAdapter().recoverLease(key); + } + + @Override + public boolean isFileClosed(Path f) throws IOException { + LOG.trace("isFileClosed() path:{}", f); + Path qualifiedPath = makeQualified(f); + String key = pathToKey(qualifiedPath); + return getAdapter().isFileClosed(key); + } + + @Override + public boolean setSafeMode(SafeModeAction action, boolean isChecked) + throws IOException { + return setSafeModeUtil(action, isChecked); + } } diff --git a/hadoop-ozone/ozonefs-hadoop3/src/main/java/org/apache/hadoop/fs/ozone/RootedOzoneFileSystem.java b/hadoop-ozone/ozonefs-hadoop3/src/main/java/org/apache/hadoop/fs/ozone/RootedOzoneFileSystem.java index 8243e04f9c19..9b1596c05b9e 100644 --- a/hadoop-ozone/ozonefs-hadoop3/src/main/java/org/apache/hadoop/fs/ozone/RootedOzoneFileSystem.java +++ b/hadoop-ozone/ozonefs-hadoop3/src/main/java/org/apache/hadoop/fs/ozone/RootedOzoneFileSystem.java @@ -18,7 +18,10 @@ package org.apache.hadoop.fs.ozone; +import org.apache.hadoop.fs.LeaseRecoverable; import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.SafeMode; +import org.apache.hadoop.fs.SafeModeAction; import org.apache.hadoop.hdds.annotation.InterfaceAudience; import org.apache.hadoop.hdds.annotation.InterfaceStability; import org.apache.hadoop.hdds.conf.ConfigurationSource; @@ -43,7 +46,7 @@ @InterfaceAudience.Private @InterfaceStability.Evolving public class RootedOzoneFileSystem extends BasicRootedOzoneFileSystem - implements KeyProviderTokenIssuer { + implements KeyProviderTokenIssuer, LeaseRecoverable, SafeMode { private OzoneFSStorageStatistics storageStatistics; @@ -118,4 +121,37 @@ public boolean hasPathCapability(final Path path, final String capability) } return super.hasPathCapability(p, capability); } + + /** + * Start the lease recovery of a file. + * + * @param f a file + * @return true if the file is already closed + * @throws IOException if an error occurs + */ + @Override + public boolean recoverLease(final Path f) throws IOException { + incrementCounter(Statistic.INVOCATION_RECOVER_LEASE, 1); + statistics.incrementWriteOps(1); + LOG.trace("recoverLease() path:{}", f); + Path qualifiedPath = makeQualified(f); + String key = pathToKey(qualifiedPath); + return getAdapter().recoverLease(key); + } + + @Override + public boolean isFileClosed(Path f) throws IOException { + incrementCounter(Statistic.INVOCATION_IS_FILE_CLOSED, 1); + statistics.incrementReadOps(1); + LOG.trace("isFileClosed() path:{}", f); + Path qualifiedPath = makeQualified(f); + String key = pathToKey(qualifiedPath); + return getAdapter().isFileClosed(key); + } + + @Override + public boolean setSafeMode(SafeModeAction action, boolean isChecked) + throws IOException { + return setSafeModeUtil(action, isChecked); + } } diff --git a/hadoop-ozone/ozonefs/src/main/java/org/apache/hadoop/fs/ozone/OzoneFileSystem.java b/hadoop-ozone/ozonefs/src/main/java/org/apache/hadoop/fs/ozone/OzoneFileSystem.java index 8fa46d7a5378..71f01e441427 100644 --- a/hadoop-ozone/ozonefs/src/main/java/org/apache/hadoop/fs/ozone/OzoneFileSystem.java +++ b/hadoop-ozone/ozonefs/src/main/java/org/apache/hadoop/fs/ozone/OzoneFileSystem.java @@ -25,7 +25,10 @@ import org.apache.hadoop.crypto.key.KeyProvider; import org.apache.hadoop.crypto.key.KeyProviderTokenIssuer; import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.LeaseRecoverable; import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.SafeMode; +import org.apache.hadoop.fs.SafeModeAction; import org.apache.hadoop.fs.StorageStatistics; import org.apache.hadoop.hdds.annotation.InterfaceAudience; import org.apache.hadoop.hdds.annotation.InterfaceStability; @@ -43,7 +46,7 @@ @InterfaceAudience.Private @InterfaceStability.Evolving public class OzoneFileSystem extends BasicOzoneFileSystem - implements KeyProviderTokenIssuer { + implements KeyProviderTokenIssuer, LeaseRecoverable, SafeMode { private OzoneFSStorageStatistics storageStatistics; @@ -120,4 +123,26 @@ public boolean hasPathCapability(final Path path, final String capability) } return super.hasPathCapability(p, capability); } + + @Override + public boolean recoverLease(Path f) throws IOException { + LOG.trace("isFileClosed() path:{}", f); + Path qualifiedPath = makeQualified(f); + String key = pathToKey(qualifiedPath); + return getAdapter().recoverLease(key); + } + + @Override + public boolean isFileClosed(Path f) throws IOException { + LOG.trace("isFileClosed() path:{}", f); + Path qualifiedPath = makeQualified(f); + String key = pathToKey(qualifiedPath); + return getAdapter().isFileClosed(key); + } + + @Override + public boolean setSafeMode(SafeModeAction action, boolean isChecked) + throws IOException { + return setSafeModeUtil(action, isChecked); + } } diff --git a/hadoop-ozone/ozonefs/src/main/java/org/apache/hadoop/fs/ozone/RootedOzoneFileSystem.java b/hadoop-ozone/ozonefs/src/main/java/org/apache/hadoop/fs/ozone/RootedOzoneFileSystem.java index 8808e28e8861..7561e20a875d 100644 --- a/hadoop-ozone/ozonefs/src/main/java/org/apache/hadoop/fs/ozone/RootedOzoneFileSystem.java +++ b/hadoop-ozone/ozonefs/src/main/java/org/apache/hadoop/fs/ozone/RootedOzoneFileSystem.java @@ -18,7 +18,10 @@ package org.apache.hadoop.fs.ozone; +import org.apache.hadoop.fs.LeaseRecoverable; import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.SafeMode; +import org.apache.hadoop.fs.SafeModeAction; import org.apache.hadoop.hdds.annotation.InterfaceAudience; import org.apache.hadoop.hdds.annotation.InterfaceStability; import org.apache.hadoop.hdds.conf.ConfigurationSource; @@ -43,7 +46,7 @@ @InterfaceAudience.Private @InterfaceStability.Evolving public class RootedOzoneFileSystem extends BasicRootedOzoneFileSystem - implements KeyProviderTokenIssuer { + implements KeyProviderTokenIssuer, LeaseRecoverable, SafeMode { private OzoneFSStorageStatistics storageStatistics; @@ -118,4 +121,28 @@ public boolean hasPathCapability(final Path path, final String capability) } return super.hasPathCapability(p, capability); } + + @Override + public boolean recoverLease(final Path f) throws IOException { + statistics.incrementWriteOps(1); + LOG.trace("recoverLease() path:{}", f); + Path qualifiedPath = makeQualified(f); + String key = pathToKey(qualifiedPath); + return getAdapter().recoverLease(key); + } + + @Override + public boolean isFileClosed(Path f) throws IOException { + statistics.incrementWriteOps(1); + LOG.trace("isFileClosed() path:{}", f); + Path qualifiedPath = makeQualified(f); + String key = pathToKey(qualifiedPath); + return getAdapter().isFileClosed(key); + } + + @Override + public boolean setSafeMode(SafeModeAction action, boolean isChecked) + throws IOException { + return setSafeModeUtil(action, isChecked); + } }