HDFS-12911. [SPS]: Modularize the SPS code and expose necessary interfaces for external/internal implementations. Contributed by Uma Maheswara Rao G
This commit is contained in:
parent
05d4daf6ba
commit
8d4f74e733
|
@ -93,8 +93,8 @@ import org.apache.hadoop.hdfs.server.namenode.NameNode;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.Namesystem;
|
import org.apache.hadoop.hdfs.server.namenode.Namesystem;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.ha.HAContext;
|
import org.apache.hadoop.hdfs.server.namenode.ha.HAContext;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.metrics.NameNodeMetrics;
|
import org.apache.hadoop.hdfs.server.namenode.metrics.NameNodeMetrics;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.sps.Context;
|
import org.apache.hadoop.hdfs.server.namenode.sps.SPSPathIds;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.sps.IntraSPSNameNodeContext;
|
import org.apache.hadoop.hdfs.server.namenode.sps.SPSService;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.sps.StoragePolicySatisfier;
|
import org.apache.hadoop.hdfs.server.namenode.sps.StoragePolicySatisfier;
|
||||||
import org.apache.hadoop.hdfs.server.protocol.BlockCommand;
|
import org.apache.hadoop.hdfs.server.protocol.BlockCommand;
|
||||||
import org.apache.hadoop.hdfs.server.protocol.BlockReportContext;
|
import org.apache.hadoop.hdfs.server.protocol.BlockReportContext;
|
||||||
|
@ -434,7 +434,8 @@ public class BlockManager implements BlockStatsMXBean {
|
||||||
private final StoragePolicySatisfier sps;
|
private final StoragePolicySatisfier sps;
|
||||||
private final boolean storagePolicyEnabled;
|
private final boolean storagePolicyEnabled;
|
||||||
private boolean spsEnabled;
|
private boolean spsEnabled;
|
||||||
private Context spsctxt = null;
|
private final SPSPathIds spsPaths;
|
||||||
|
|
||||||
/** Minimum live replicas needed for the datanode to be transitioned
|
/** Minimum live replicas needed for the datanode to be transitioned
|
||||||
* from ENTERING_MAINTENANCE to IN_MAINTENANCE.
|
* from ENTERING_MAINTENANCE to IN_MAINTENANCE.
|
||||||
*/
|
*/
|
||||||
|
@ -481,8 +482,8 @@ public class BlockManager implements BlockStatsMXBean {
|
||||||
conf.getBoolean(
|
conf.getBoolean(
|
||||||
DFSConfigKeys.DFS_STORAGE_POLICY_SATISFIER_ENABLED_KEY,
|
DFSConfigKeys.DFS_STORAGE_POLICY_SATISFIER_ENABLED_KEY,
|
||||||
DFSConfigKeys.DFS_STORAGE_POLICY_SATISFIER_ENABLED_DEFAULT);
|
DFSConfigKeys.DFS_STORAGE_POLICY_SATISFIER_ENABLED_DEFAULT);
|
||||||
spsctxt = new IntraSPSNameNodeContext(namesystem, this, conf);
|
sps = new StoragePolicySatisfier(conf);
|
||||||
sps = new StoragePolicySatisfier(spsctxt);
|
spsPaths = new SPSPathIds();
|
||||||
blockTokenSecretManager = createBlockTokenSecretManager(conf);
|
blockTokenSecretManager = createBlockTokenSecretManager(conf);
|
||||||
|
|
||||||
providedStorageMap = new ProvidedStorageMap(namesystem, this, conf);
|
providedStorageMap = new ProvidedStorageMap(namesystem, this, conf);
|
||||||
|
@ -5041,8 +5042,7 @@ public class BlockManager implements BlockStatsMXBean {
|
||||||
LOG.info("Storage policy satisfier is already running.");
|
LOG.info("Storage policy satisfier is already running.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO: FSDirectory will get removed via HDFS-12911 modularization work
|
sps.start(false);
|
||||||
sps.start(false, namesystem.getFSDirectory());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5078,8 +5078,7 @@ public class BlockManager implements BlockStatsMXBean {
|
||||||
LOG.info("Storage policy satisfier is already running.");
|
LOG.info("Storage policy satisfier is already running.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO: FSDirectory will get removed via HDFS-12911 modularization work
|
sps.start(true);
|
||||||
sps.start(true, namesystem.getFSDirectory());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5119,4 +5118,48 @@ public class BlockManager implements BlockStatsMXBean {
|
||||||
String path) throws IOException {
|
String path) throws IOException {
|
||||||
return sps.checkStoragePolicySatisfyPathStatus(path);
|
return sps.checkStoragePolicySatisfyPathStatus(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return SPS service instance.
|
||||||
|
*/
|
||||||
|
public SPSService getSPSService() {
|
||||||
|
return this.sps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the next SPS path id, on which path users has invoked to satisfy
|
||||||
|
* storages.
|
||||||
|
*/
|
||||||
|
public Long getNextSPSPathId() {
|
||||||
|
return spsPaths.pollNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the SPS path id from the list of sps paths.
|
||||||
|
*/
|
||||||
|
public void removeSPSPathId(long trackId) {
|
||||||
|
spsPaths.remove(trackId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up all sps path ids.
|
||||||
|
*/
|
||||||
|
public void removeAllSPSPathIds() {
|
||||||
|
spsPaths.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the sps path to SPSPathIds list.
|
||||||
|
*/
|
||||||
|
public void addSPSPathId(long id) {
|
||||||
|
spsPaths.add(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if sps enabled.
|
||||||
|
*/
|
||||||
|
public boolean isSPSEnabled() {
|
||||||
|
return spsEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@ import org.apache.hadoop.fs.permission.FsAction;
|
||||||
import org.apache.hadoop.hdfs.XAttrHelper;
|
import org.apache.hadoop.hdfs.XAttrHelper;
|
||||||
import org.apache.hadoop.hdfs.server.blockmanagement.BlockManager;
|
import org.apache.hadoop.hdfs.server.blockmanagement.BlockManager;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSDirectory.DirOp;
|
import org.apache.hadoop.hdfs.server.namenode.FSDirectory.DirOp;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.snapshot.Snapshot;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
@ -87,21 +86,14 @@ final class FSDirSatisfyStoragePolicyOp {
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean unprotectedSatisfyStoragePolicy(INode inode, FSDirectory fsd) {
|
static boolean unprotectedSatisfyStoragePolicy(INode inode, FSDirectory fsd) {
|
||||||
if (inode.isFile() && inode.asFile().numBlocks() != 0) {
|
if (inode.isFile() && inode.asFile().numBlocks() == 0) {
|
||||||
// Adding directly in the storageMovementNeeded queue, So it can
|
return false;
|
||||||
// get more priority compare to directory.
|
} else {
|
||||||
fsd.getBlockManager().getStoragePolicySatisfier()
|
|
||||||
.satisfyStoragePolicy(inode.getId());
|
|
||||||
return true;
|
|
||||||
} else if (inode.isDirectory()
|
|
||||||
&& inode.asDirectory().getChildrenNum(Snapshot.CURRENT_STATE_ID) > 0) {
|
|
||||||
// Adding directory in the pending queue, so FileInodeIdCollector process
|
// Adding directory in the pending queue, so FileInodeIdCollector process
|
||||||
// directory child in batch and recursively
|
// directory child in batch and recursively
|
||||||
fsd.getBlockManager().getStoragePolicySatisfier()
|
fsd.getBlockManager().addSPSPathId(inode.getId());
|
||||||
.addInodeToPendingDirQueue(inode.getId());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean inodeHasSatisfyXAttr(INode inode) {
|
private static boolean inodeHasSatisfyXAttr(INode inode) {
|
||||||
|
|
|
@ -1401,14 +1401,16 @@ public class FSDirectory implements Closeable {
|
||||||
if (!inode.isSymlink()) {
|
if (!inode.isSymlink()) {
|
||||||
final XAttrFeature xaf = inode.getXAttrFeature();
|
final XAttrFeature xaf = inode.getXAttrFeature();
|
||||||
addEncryptionZone((INodeWithAdditionalFields) inode, xaf);
|
addEncryptionZone((INodeWithAdditionalFields) inode, xaf);
|
||||||
addStoragePolicySatisfier((INodeWithAdditionalFields) inode, xaf);
|
if (namesystem.getBlockManager().isSPSEnabled()) {
|
||||||
|
addStoragePolicySatisfier((INodeWithAdditionalFields) inode, xaf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addStoragePolicySatisfier(INodeWithAdditionalFields inode,
|
private void addStoragePolicySatisfier(INodeWithAdditionalFields inode,
|
||||||
XAttrFeature xaf) {
|
XAttrFeature xaf) {
|
||||||
if (xaf == null || inode.isDirectory()) {
|
if (xaf == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
XAttr xattr = xaf.getXAttr(XATTR_SATISFY_STORAGE_POLICY);
|
XAttr xattr = xaf.getXAttr(XATTR_SATISFY_STORAGE_POLICY);
|
||||||
|
|
|
@ -258,6 +258,9 @@ import org.apache.hadoop.hdfs.server.namenode.metrics.NameNodeMetrics;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.snapshot.DirectorySnapshottableFeature;
|
import org.apache.hadoop.hdfs.server.namenode.snapshot.DirectorySnapshottableFeature;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.snapshot.Snapshot;
|
import org.apache.hadoop.hdfs.server.namenode.snapshot.Snapshot;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.snapshot.SnapshotManager;
|
import org.apache.hadoop.hdfs.server.namenode.snapshot.SnapshotManager;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.sps.IntraSPSNameNodeBlockMoveTaskHandler;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.sps.IntraSPSNameNodeContext;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.sps.IntraSPSNameNodeFileIdCollector;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.sps.StoragePolicySatisfier;
|
import org.apache.hadoop.hdfs.server.namenode.sps.StoragePolicySatisfier;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.startupprogress.Phase;
|
import org.apache.hadoop.hdfs.server.namenode.startupprogress.Phase;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.startupprogress.StartupProgress;
|
import org.apache.hadoop.hdfs.server.namenode.startupprogress.StartupProgress;
|
||||||
|
@ -1291,7 +1294,12 @@ public class FSNamesystem implements Namesystem, FSNamesystemMBean,
|
||||||
FSDirEncryptionZoneOp.warmUpEdekCache(edekCacheLoader, dir,
|
FSDirEncryptionZoneOp.warmUpEdekCache(edekCacheLoader, dir,
|
||||||
edekCacheLoaderDelay, edekCacheLoaderInterval);
|
edekCacheLoaderDelay, edekCacheLoaderInterval);
|
||||||
}
|
}
|
||||||
|
blockManager.getSPSService().init(
|
||||||
|
new IntraSPSNameNodeContext(this, blockManager,
|
||||||
|
blockManager.getSPSService()),
|
||||||
|
new IntraSPSNameNodeFileIdCollector(getFSDirectory(),
|
||||||
|
blockManager.getSPSService()),
|
||||||
|
new IntraSPSNameNodeBlockMoveTaskHandler(blockManager, this));
|
||||||
blockManager.startSPS();
|
blockManager.startSPS();
|
||||||
} finally {
|
} finally {
|
||||||
startingActiveService = false;
|
startingActiveService = false;
|
||||||
|
|
|
@ -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.hdfs.server.namenode.sps;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
|
import org.apache.hadoop.hdfs.server.protocol.BlockStorageMovementCommand.BlockMovingInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for implementing different ways of block moving approaches. One can
|
||||||
|
* connect directly to DN and request block move, and other can talk NN to
|
||||||
|
* schedule via heart-beats.
|
||||||
|
*/
|
||||||
|
@InterfaceAudience.Private
|
||||||
|
@InterfaceStability.Evolving
|
||||||
|
public interface BlockMoveTaskHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an interface method to handle the move tasks. BlockMovingInfo must
|
||||||
|
* contain the required info to move the block, that source location,
|
||||||
|
* destination location and storage types.
|
||||||
|
*/
|
||||||
|
void submitMoveTask(BlockMovingInfo blkMovingInfo,
|
||||||
|
BlockMovementListener blockMoveCompletionListener) throws IOException;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/**
|
||||||
|
* 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.hdfs.server.namenode.sps;
|
||||||
|
|
||||||
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.Block;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for notifying about block movement attempt completion.
|
||||||
|
*/
|
||||||
|
@InterfaceAudience.Private
|
||||||
|
@InterfaceStability.Evolving
|
||||||
|
public interface BlockMovementListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method used to notify to the SPS about block movement attempt
|
||||||
|
* finished. Then SPS will re-check whether it needs retry or not.
|
||||||
|
*
|
||||||
|
* @param moveAttemptFinishedBlks
|
||||||
|
* -list of movement attempt finished blocks
|
||||||
|
*/
|
||||||
|
void notifyMovementTriedBlocks(Block[] moveAttemptFinishedBlks);
|
||||||
|
}
|
|
@ -32,7 +32,6 @@ import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_STORAGE_POLICY_SATISFIER_
|
||||||
|
|
||||||
import org.apache.hadoop.hdfs.protocol.Block;
|
import org.apache.hadoop.hdfs.protocol.Block;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.sps.StoragePolicySatisfier.AttemptedItemInfo;
|
import org.apache.hadoop.hdfs.server.namenode.sps.StoragePolicySatisfier.AttemptedItemInfo;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.sps.StoragePolicySatisfier.ItemInfo;
|
|
||||||
import org.apache.hadoop.util.Daemon;
|
import org.apache.hadoop.util.Daemon;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -47,7 +46,8 @@ import com.google.common.annotations.VisibleForTesting;
|
||||||
* finished for a longer time period, then such items will retries automatically
|
* finished for a longer time period, then such items will retries automatically
|
||||||
* after timeout. The default timeout would be 5 minutes.
|
* after timeout. The default timeout would be 5 minutes.
|
||||||
*/
|
*/
|
||||||
public class BlockStorageMovementAttemptedItems {
|
public class BlockStorageMovementAttemptedItems
|
||||||
|
implements BlockMovementListener {
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
LoggerFactory.getLogger(BlockStorageMovementAttemptedItems.class);
|
LoggerFactory.getLogger(BlockStorageMovementAttemptedItems.class);
|
||||||
|
|
||||||
|
@ -71,19 +71,19 @@ public class BlockStorageMovementAttemptedItems {
|
||||||
//
|
//
|
||||||
private long minCheckTimeout = 1 * 60 * 1000; // minimum value
|
private long minCheckTimeout = 1 * 60 * 1000; // minimum value
|
||||||
private BlockStorageMovementNeeded blockStorageMovementNeeded;
|
private BlockStorageMovementNeeded blockStorageMovementNeeded;
|
||||||
private final Context ctxt;
|
private final SPSService service;
|
||||||
|
|
||||||
public BlockStorageMovementAttemptedItems(Context context,
|
public BlockStorageMovementAttemptedItems(SPSService service,
|
||||||
BlockStorageMovementNeeded unsatisfiedStorageMovementFiles) {
|
BlockStorageMovementNeeded unsatisfiedStorageMovementFiles) {
|
||||||
this.ctxt = context;
|
this.service = service;
|
||||||
long recheckTimeout = ctxt.getConf().getLong(
|
long recheckTimeout = this.service.getConf().getLong(
|
||||||
DFS_STORAGE_POLICY_SATISFIER_RECHECK_TIMEOUT_MILLIS_KEY,
|
DFS_STORAGE_POLICY_SATISFIER_RECHECK_TIMEOUT_MILLIS_KEY,
|
||||||
DFS_STORAGE_POLICY_SATISFIER_RECHECK_TIMEOUT_MILLIS_DEFAULT);
|
DFS_STORAGE_POLICY_SATISFIER_RECHECK_TIMEOUT_MILLIS_DEFAULT);
|
||||||
if (recheckTimeout > 0) {
|
if (recheckTimeout > 0) {
|
||||||
this.minCheckTimeout = Math.min(minCheckTimeout, recheckTimeout);
|
this.minCheckTimeout = Math.min(minCheckTimeout, recheckTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.selfRetryTimeout = ctxt.getConf().getLong(
|
this.selfRetryTimeout = this.service.getConf().getLong(
|
||||||
DFS_STORAGE_POLICY_SATISFIER_SELF_RETRY_TIMEOUT_MILLIS_KEY,
|
DFS_STORAGE_POLICY_SATISFIER_SELF_RETRY_TIMEOUT_MILLIS_KEY,
|
||||||
DFS_STORAGE_POLICY_SATISFIER_SELF_RETRY_TIMEOUT_MILLIS_DEFAULT);
|
DFS_STORAGE_POLICY_SATISFIER_SELF_RETRY_TIMEOUT_MILLIS_DEFAULT);
|
||||||
this.blockStorageMovementNeeded = unsatisfiedStorageMovementFiles;
|
this.blockStorageMovementNeeded = unsatisfiedStorageMovementFiles;
|
||||||
|
@ -111,7 +111,7 @@ public class BlockStorageMovementAttemptedItems {
|
||||||
* @param moveAttemptFinishedBlks
|
* @param moveAttemptFinishedBlks
|
||||||
* storage movement attempt finished blocks
|
* storage movement attempt finished blocks
|
||||||
*/
|
*/
|
||||||
public void addReportedMovedBlocks(Block[] moveAttemptFinishedBlks) {
|
public void notifyMovementTriedBlocks(Block[] moveAttemptFinishedBlks) {
|
||||||
if (moveAttemptFinishedBlks.length == 0) {
|
if (moveAttemptFinishedBlks.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ public class BlockStorageMovementAttemptedItems {
|
||||||
AttemptedItemInfo itemInfo = iter.next();
|
AttemptedItemInfo itemInfo = iter.next();
|
||||||
if (now > itemInfo.getLastAttemptedOrReportedTime()
|
if (now > itemInfo.getLastAttemptedOrReportedTime()
|
||||||
+ selfRetryTimeout) {
|
+ selfRetryTimeout) {
|
||||||
Long blockCollectionID = itemInfo.getTrackId();
|
Long blockCollectionID = itemInfo.getFileId();
|
||||||
synchronized (movementFinishedBlocks) {
|
synchronized (movementFinishedBlocks) {
|
||||||
ItemInfo candidate = new ItemInfo(itemInfo.getStartId(),
|
ItemInfo candidate = new ItemInfo(itemInfo.getStartId(),
|
||||||
blockCollectionID, itemInfo.getRetryCount() + 1);
|
blockCollectionID, itemInfo.getRetryCount() + 1);
|
||||||
|
@ -223,7 +223,7 @@ public class BlockStorageMovementAttemptedItems {
|
||||||
// gets the chance first and can be cleaned from queue quickly as
|
// gets the chance first and can be cleaned from queue quickly as
|
||||||
// all movements already done.
|
// all movements already done.
|
||||||
blockStorageMovementNeeded.add(new ItemInfo(attemptedItemInfo
|
blockStorageMovementNeeded.add(new ItemInfo(attemptedItemInfo
|
||||||
.getStartId(), attemptedItemInfo.getTrackId(),
|
.getStartId(), attemptedItemInfo.getFileId(),
|
||||||
attemptedItemInfo.getRetryCount() + 1));
|
attemptedItemInfo.getRetryCount() + 1));
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
}
|
}
|
||||||
|
@ -246,7 +246,11 @@ public class BlockStorageMovementAttemptedItems {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearQueues() {
|
public void clearQueues() {
|
||||||
movementFinishedBlocks.clear();
|
synchronized (movementFinishedBlocks) {
|
||||||
storageMovementAttemptedItems.clear();
|
movementFinishedBlocks.clear();
|
||||||
|
}
|
||||||
|
synchronized (storageMovementAttemptedItems) {
|
||||||
|
storageMovementAttemptedItems.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hadoop.hdfs.server.namenode.sps;
|
package org.apache.hadoop.hdfs.server.namenode.sps;
|
||||||
|
|
||||||
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_STORAGE_POLICY_SATISFIER_QUEUE_LIMIT_DEFAULT;
|
|
||||||
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_STORAGE_POLICY_SATISFIER_QUEUE_LIMIT_KEY;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
@ -33,12 +29,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.hdfs.protocol.HdfsConstants.StoragePolicySatisfyPathStatus;
|
import org.apache.hadoop.hdfs.protocol.HdfsConstants.StoragePolicySatisfyPathStatus;
|
||||||
import org.apache.hadoop.hdfs.protocol.HdfsFileStatus;
|
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSDirectory;
|
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSTreeTraverser;
|
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSTreeTraverser.TraverseInfo;
|
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INode;
|
|
||||||
import org.apache.hadoop.hdfs.server.namenode.sps.StoragePolicySatisfier.ItemInfo;
|
|
||||||
import org.apache.hadoop.util.Daemon;
|
import org.apache.hadoop.util.Daemon;
|
||||||
import org.apache.hadoop.util.Time;
|
import org.apache.hadoop.util.Time;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -75,22 +65,21 @@ public class BlockStorageMovementNeeded {
|
||||||
|
|
||||||
private final Context ctxt;
|
private final Context ctxt;
|
||||||
|
|
||||||
// List of pending dir to satisfy the policy
|
private Daemon pathIdCollector;
|
||||||
private final Queue<Long> spsDirsToBeTraveresed = new LinkedList<Long>();
|
|
||||||
|
|
||||||
private Daemon inodeIdCollector;
|
private FileIdCollector fileIDCollector;
|
||||||
|
|
||||||
private final int maxQueuedItem;
|
private SPSPathIdProcessor pathIDProcessor;
|
||||||
|
|
||||||
// Amount of time to cache the SUCCESS status of path before turning it to
|
// Amount of time to cache the SUCCESS status of path before turning it to
|
||||||
// NOT_AVAILABLE.
|
// NOT_AVAILABLE.
|
||||||
private static long statusClearanceElapsedTimeMs = 300000;
|
private static long statusClearanceElapsedTimeMs = 300000;
|
||||||
|
|
||||||
public BlockStorageMovementNeeded(Context context) {
|
public BlockStorageMovementNeeded(Context context,
|
||||||
|
FileIdCollector fileIDCollector) {
|
||||||
this.ctxt = context;
|
this.ctxt = context;
|
||||||
this.maxQueuedItem = ctxt.getConf().getInt(
|
this.fileIDCollector = fileIDCollector;
|
||||||
DFS_STORAGE_POLICY_SATISFIER_QUEUE_LIMIT_KEY,
|
pathIDProcessor = new SPSPathIdProcessor();
|
||||||
DFS_STORAGE_POLICY_SATISFIER_QUEUE_LIMIT_DEFAULT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -140,29 +129,6 @@ public class BlockStorageMovementNeeded {
|
||||||
return storageMovementNeeded.poll();
|
return storageMovementNeeded.poll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void addToPendingDirQueue(long id) {
|
|
||||||
spsStatus.put(id, new StoragePolicySatisfyPathStatusInfo(
|
|
||||||
StoragePolicySatisfyPathStatus.PENDING));
|
|
||||||
spsDirsToBeTraveresed.add(id);
|
|
||||||
// Notify waiting FileInodeIdCollector thread about the newly
|
|
||||||
// added SPS path.
|
|
||||||
synchronized (spsDirsToBeTraveresed) {
|
|
||||||
spsDirsToBeTraveresed.notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns queue remaining capacity.
|
|
||||||
*/
|
|
||||||
public synchronized int remainingCapacity() {
|
|
||||||
int size = storageMovementNeeded.size();
|
|
||||||
if (size >= maxQueuedItem) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return (maxQueuedItem - size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns queue size.
|
* Returns queue size.
|
||||||
*/
|
*/
|
||||||
|
@ -171,7 +137,7 @@ public class BlockStorageMovementNeeded {
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void clearAll() {
|
public synchronized void clearAll() {
|
||||||
spsDirsToBeTraveresed.clear();
|
ctxt.removeAllSPSPathIds();
|
||||||
storageMovementNeeded.clear();
|
storageMovementNeeded.clear();
|
||||||
pendingWorkForDirectory.clear();
|
pendingWorkForDirectory.clear();
|
||||||
}
|
}
|
||||||
|
@ -206,13 +172,13 @@ public class BlockStorageMovementNeeded {
|
||||||
} else {
|
} else {
|
||||||
// Remove xAttr if trackID doesn't exist in
|
// Remove xAttr if trackID doesn't exist in
|
||||||
// storageMovementAttemptedItems or file policy satisfied.
|
// storageMovementAttemptedItems or file policy satisfied.
|
||||||
ctxt.removeSPSHint(trackInfo.getTrackId());
|
ctxt.removeSPSHint(trackInfo.getFileId());
|
||||||
updateStatus(trackInfo.getStartId(), isSuccess);
|
updateStatus(trackInfo.getStartId(), isSuccess);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void clearQueue(long trackId) {
|
public synchronized void clearQueue(long trackId) {
|
||||||
spsDirsToBeTraveresed.remove(trackId);
|
ctxt.removeSPSPathId(trackId);
|
||||||
Iterator<ItemInfo> iterator = storageMovementNeeded.iterator();
|
Iterator<ItemInfo> iterator = storageMovementNeeded.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
ItemInfo next = iterator.next();
|
ItemInfo next = iterator.next();
|
||||||
|
@ -249,7 +215,7 @@ public class BlockStorageMovementNeeded {
|
||||||
public synchronized void clearQueuesWithNotification() {
|
public synchronized void clearQueuesWithNotification() {
|
||||||
// Remove xAttr from directories
|
// Remove xAttr from directories
|
||||||
Long trackId;
|
Long trackId;
|
||||||
while ((trackId = spsDirsToBeTraveresed.poll()) != null) {
|
while ((trackId = ctxt.getNextSPSPathId()) != null) {
|
||||||
try {
|
try {
|
||||||
// Remove xAttr for file
|
// Remove xAttr for file
|
||||||
ctxt.removeSPSHint(trackId);
|
ctxt.removeSPSHint(trackId);
|
||||||
|
@ -265,12 +231,12 @@ public class BlockStorageMovementNeeded {
|
||||||
try {
|
try {
|
||||||
// Remove xAttr for file
|
// Remove xAttr for file
|
||||||
if (!itemInfo.isDir()) {
|
if (!itemInfo.isDir()) {
|
||||||
ctxt.removeSPSHint(itemInfo.getTrackId());
|
ctxt.removeSPSHint(itemInfo.getFileId());
|
||||||
}
|
}
|
||||||
} catch (IOException ie) {
|
} catch (IOException ie) {
|
||||||
LOG.warn(
|
LOG.warn(
|
||||||
"Failed to remove SPS xattr for track id "
|
"Failed to remove SPS xattr for track id "
|
||||||
+ itemInfo.getTrackId(), ie);
|
+ itemInfo.getFileId(), ie);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.clearAll();
|
this.clearAll();
|
||||||
|
@ -280,57 +246,33 @@ public class BlockStorageMovementNeeded {
|
||||||
* Take dir tack ID from the spsDirsToBeTraveresed queue and collect child
|
* Take dir tack ID from the spsDirsToBeTraveresed queue and collect child
|
||||||
* ID's to process for satisfy the policy.
|
* ID's to process for satisfy the policy.
|
||||||
*/
|
*/
|
||||||
private class StorageMovementPendingInodeIdCollector extends FSTreeTraverser
|
private class SPSPathIdProcessor implements Runnable {
|
||||||
implements Runnable {
|
|
||||||
|
|
||||||
private int remainingCapacity = 0;
|
|
||||||
|
|
||||||
private List<ItemInfo> currentBatch = new ArrayList<>(maxQueuedItem);
|
|
||||||
|
|
||||||
StorageMovementPendingInodeIdCollector(FSDirectory dir) {
|
|
||||||
super(dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
LOG.info("Starting FileInodeIdCollector!.");
|
LOG.info("Starting FileInodeIdCollector!.");
|
||||||
long lastStatusCleanTime = 0;
|
long lastStatusCleanTime = 0;
|
||||||
while (ctxt.isRunning()) {
|
while (ctxt.isRunning()) {
|
||||||
|
LOG.info("Running FileInodeIdCollector!.");
|
||||||
try {
|
try {
|
||||||
if (!ctxt.isInSafeMode()) {
|
if (!ctxt.isInSafeMode()) {
|
||||||
Long startINodeId = spsDirsToBeTraveresed.poll();
|
Long startINodeId = ctxt.getNextSPSPathId();
|
||||||
if (startINodeId == null) {
|
if (startINodeId == null) {
|
||||||
// Waiting for SPS path
|
// Waiting for SPS path
|
||||||
synchronized (spsDirsToBeTraveresed) {
|
Thread.sleep(3000);
|
||||||
spsDirsToBeTraveresed.wait(5000);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
INode startInode = getFSDirectory().getInode(startINodeId);
|
spsStatus.put(startINodeId,
|
||||||
if (startInode != null) {
|
new StoragePolicySatisfyPathStatusInfo(
|
||||||
try {
|
StoragePolicySatisfyPathStatus.IN_PROGRESS));
|
||||||
remainingCapacity = remainingCapacity();
|
fileIDCollector.scanAndCollectFileIds(startINodeId);
|
||||||
spsStatus.put(startINodeId,
|
// check if directory was empty and no child added to queue
|
||||||
new StoragePolicySatisfyPathStatusInfo(
|
DirPendingWorkInfo dirPendingWorkInfo =
|
||||||
StoragePolicySatisfyPathStatus.IN_PROGRESS));
|
pendingWorkForDirectory.get(startINodeId);
|
||||||
readLock();
|
if (dirPendingWorkInfo != null
|
||||||
traverseDir(startInode.asDirectory(), startINodeId,
|
&& dirPendingWorkInfo.isDirWorkDone()) {
|
||||||
HdfsFileStatus.EMPTY_NAME,
|
ctxt.removeSPSHint(startINodeId);
|
||||||
new SPSTraverseInfo(startINodeId));
|
pendingWorkForDirectory.remove(startINodeId);
|
||||||
} finally {
|
updateStatus(startINodeId, true);
|
||||||
readUnlock();
|
|
||||||
}
|
|
||||||
// Mark startInode traverse is done
|
|
||||||
addAll(startInode.getId(), currentBatch, true);
|
|
||||||
currentBatch.clear();
|
|
||||||
|
|
||||||
// check if directory was empty and no child added to queue
|
|
||||||
DirPendingWorkInfo dirPendingWorkInfo =
|
|
||||||
pendingWorkForDirectory.get(startInode.getId());
|
|
||||||
if (dirPendingWorkInfo.isDirWorkDone()) {
|
|
||||||
ctxt.removeSPSHint(startInode.getId());
|
|
||||||
pendingWorkForDirectory.remove(startInode.getId());
|
|
||||||
updateStatus(startInode.getId(), true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Clear the SPS status if status is in SUCCESS more than 5 min.
|
//Clear the SPS status if status is in SUCCESS more than 5 min.
|
||||||
|
@ -355,71 +297,6 @@ public class BlockStorageMovementNeeded {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void checkPauseForTesting() throws InterruptedException {
|
|
||||||
// TODO implement if needed
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean processFileInode(INode inode, TraverseInfo traverseInfo)
|
|
||||||
throws IOException, InterruptedException {
|
|
||||||
if (LOG.isTraceEnabled()) {
|
|
||||||
LOG.trace("Processing {} for statisy the policy",
|
|
||||||
inode.getFullPathName());
|
|
||||||
}
|
|
||||||
if (!inode.isFile()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (inode.isFile() && inode.asFile().numBlocks() != 0) {
|
|
||||||
currentBatch.add(new ItemInfo(
|
|
||||||
((SPSTraverseInfo) traverseInfo).getStartId(), inode.getId()));
|
|
||||||
remainingCapacity--;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean canSubmitCurrentBatch() {
|
|
||||||
return remainingCapacity <= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void checkINodeReady(long startId) throws IOException {
|
|
||||||
// SPS work won't be scheduled if NN is in standby. So, skipping NN
|
|
||||||
// standby check.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void submitCurrentBatch(long startId)
|
|
||||||
throws IOException, InterruptedException {
|
|
||||||
// Add current child's to queue
|
|
||||||
addAll(startId, currentBatch, false);
|
|
||||||
currentBatch.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void throttle() throws InterruptedException {
|
|
||||||
if (LOG.isDebugEnabled()) {
|
|
||||||
LOG.debug("StorageMovementNeeded queue remaining capacity is zero,"
|
|
||||||
+ " waiting for some free slots.");
|
|
||||||
}
|
|
||||||
remainingCapacity = remainingCapacity();
|
|
||||||
// wait for queue to be free
|
|
||||||
while (remainingCapacity <= 0) {
|
|
||||||
if (LOG.isDebugEnabled()) {
|
|
||||||
LOG.debug("Waiting for storageMovementNeeded queue to be free!");
|
|
||||||
}
|
|
||||||
Thread.sleep(5000);
|
|
||||||
remainingCapacity = remainingCapacity();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean canTraverseDir(INode inode) throws IOException {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -476,29 +353,15 @@ public class BlockStorageMovementNeeded {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: FSDirectory will get removed via HDFS-12911 modularization work
|
public void activate() {
|
||||||
public void init(FSDirectory fsd) {
|
pathIdCollector = new Daemon(pathIDProcessor);
|
||||||
inodeIdCollector = new Daemon(new StorageMovementPendingInodeIdCollector(
|
pathIdCollector.setName("SPSPathIdProcessor");
|
||||||
fsd));
|
pathIdCollector.start();
|
||||||
inodeIdCollector.setName("FileInodeIdCollector");
|
|
||||||
inodeIdCollector.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
if (inodeIdCollector != null) {
|
if (pathIdCollector != null) {
|
||||||
inodeIdCollector.interrupt();
|
pathIdCollector.interrupt();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SPSTraverseInfo extends TraverseInfo {
|
|
||||||
private long startId;
|
|
||||||
|
|
||||||
SPSTraverseInfo(long startId) {
|
|
||||||
this.startId = startId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getStartId() {
|
|
||||||
return startId;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,9 @@
|
||||||
package org.apache.hadoop.hdfs.server.namenode.sps;
|
package org.apache.hadoop.hdfs.server.namenode.sps;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.classification.InterfaceStability;
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
|
||||||
import org.apache.hadoop.fs.ParentNotDirectoryException;
|
import org.apache.hadoop.fs.ParentNotDirectoryException;
|
||||||
import org.apache.hadoop.fs.StorageType;
|
import org.apache.hadoop.fs.StorageType;
|
||||||
import org.apache.hadoop.fs.UnresolvedLinkException;
|
import org.apache.hadoop.fs.UnresolvedLinkException;
|
||||||
|
@ -31,7 +29,6 @@ import org.apache.hadoop.hdfs.protocol.BlockStoragePolicy;
|
||||||
import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
|
import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
|
||||||
import org.apache.hadoop.hdfs.protocol.HdfsFileStatus;
|
import org.apache.hadoop.hdfs.protocol.HdfsFileStatus;
|
||||||
import org.apache.hadoop.hdfs.server.protocol.DatanodeStorageReport;
|
import org.apache.hadoop.hdfs.server.protocol.DatanodeStorageReport;
|
||||||
import org.apache.hadoop.hdfs.server.protocol.BlockStorageMovementCommand.BlockMovingInfo;
|
|
||||||
import org.apache.hadoop.net.NetworkTopology;
|
import org.apache.hadoop.net.NetworkTopology;
|
||||||
import org.apache.hadoop.security.AccessControlException;
|
import org.apache.hadoop.security.AccessControlException;
|
||||||
|
|
||||||
|
@ -42,24 +39,11 @@ import org.apache.hadoop.security.AccessControlException;
|
||||||
@InterfaceStability.Evolving
|
@InterfaceStability.Evolving
|
||||||
public interface Context {
|
public interface Context {
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns configuration object.
|
|
||||||
*/
|
|
||||||
Configuration getConf();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the SPS is running, false otherwise.
|
* Returns true if the SPS is running, false otherwise.
|
||||||
*/
|
*/
|
||||||
boolean isRunning();
|
boolean isRunning();
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the SPS running status.
|
|
||||||
*
|
|
||||||
* @param isSpsRunning
|
|
||||||
* true represents running, false otherwise
|
|
||||||
*/
|
|
||||||
void setSPSRunning(Supplier<Boolean> isSpsRunning);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the Namenode in safe mode, false otherwise.
|
* Returns true if the Namenode in safe mode, false otherwise.
|
||||||
*/
|
*/
|
||||||
|
@ -152,17 +136,6 @@ public interface Context {
|
||||||
*/
|
*/
|
||||||
boolean hasLowRedundancyBlocks(long inodeID);
|
boolean hasLowRedundancyBlocks(long inodeID);
|
||||||
|
|
||||||
/**
|
|
||||||
* Assign the given block movement task to the target node present in
|
|
||||||
* {@link BlockMovingInfo}.
|
|
||||||
*
|
|
||||||
* @param blkMovingInfo
|
|
||||||
* block to storage info
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
void assignBlockMoveTaskToTargetNode(BlockMovingInfo blkMovingInfo)
|
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the given datanode has sufficient space to occupy the given
|
* Checks whether the given datanode has sufficient space to occupy the given
|
||||||
* blockSize data.
|
* blockSize data.
|
||||||
|
@ -178,4 +151,20 @@ public interface Context {
|
||||||
*/
|
*/
|
||||||
boolean verifyTargetDatanodeHasSpaceForScheduling(DatanodeInfo dn,
|
boolean verifyTargetDatanodeHasSpaceForScheduling(DatanodeInfo dn,
|
||||||
StorageType type, long blockSize);
|
StorageType type, long blockSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return next SPS path id to process.
|
||||||
|
*/
|
||||||
|
Long getNextSPSPathId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the SPS path id.
|
||||||
|
*/
|
||||||
|
void removeSPSPathId(long pathId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all SPS path ids.
|
||||||
|
*/
|
||||||
|
void removeAllSPSPathIds();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/**
|
||||||
|
* 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.hdfs.server.namenode.sps;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for scanning the directory recursively and collect file ids
|
||||||
|
* under the given directory.
|
||||||
|
*/
|
||||||
|
@InterfaceAudience.Private
|
||||||
|
@InterfaceStability.Evolving
|
||||||
|
public interface FileIdCollector {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scans the given inode directory and collects the file ids under that
|
||||||
|
* directory and adds to the given BlockStorageMovementNeeded.
|
||||||
|
*
|
||||||
|
* @param inodeID
|
||||||
|
* - The directory ID
|
||||||
|
*/
|
||||||
|
void scanAndCollectFileIds(Long inodeId)
|
||||||
|
throws IOException, InterruptedException;
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
* 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.hdfs.server.namenode.sps;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.hadoop.hdfs.server.blockmanagement.BlockManager;
|
||||||
|
import org.apache.hadoop.hdfs.server.blockmanagement.DatanodeDescriptor;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.Namesystem;
|
||||||
|
import org.apache.hadoop.hdfs.server.protocol.BlockStorageMovementCommand.BlockMovingInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class handles the internal SPS block movements. This will assign block
|
||||||
|
* movement tasks to target datanode descriptors.
|
||||||
|
*/
|
||||||
|
public class IntraSPSNameNodeBlockMoveTaskHandler
|
||||||
|
implements BlockMoveTaskHandler {
|
||||||
|
|
||||||
|
private BlockManager blockManager;
|
||||||
|
private Namesystem namesystem;
|
||||||
|
|
||||||
|
public IntraSPSNameNodeBlockMoveTaskHandler(BlockManager blockManager,
|
||||||
|
Namesystem namesytem) {
|
||||||
|
this.blockManager = blockManager;
|
||||||
|
this.namesystem = namesytem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void submitMoveTask(BlockMovingInfo blkMovingInfo,
|
||||||
|
BlockMovementListener blockMoveCompletionListener) throws IOException {
|
||||||
|
namesystem.readLock();
|
||||||
|
try {
|
||||||
|
DatanodeDescriptor dn = blockManager.getDatanodeManager()
|
||||||
|
.getDatanode(blkMovingInfo.getTarget().getDatanodeUuid());
|
||||||
|
if (dn == null) {
|
||||||
|
throw new IOException("Failed to schedule block movement task:"
|
||||||
|
+ blkMovingInfo + " as target datanode: "
|
||||||
|
+ blkMovingInfo.getTarget() + " doesn't exists");
|
||||||
|
}
|
||||||
|
dn.incrementBlocksScheduled(blkMovingInfo.getTargetStorageType());
|
||||||
|
dn.addBlocksToMoveStorage(blkMovingInfo);
|
||||||
|
} finally {
|
||||||
|
namesystem.readUnlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,10 +20,8 @@ package org.apache.hadoop.hdfs.server.namenode.sps;
|
||||||
import static org.apache.hadoop.hdfs.server.common.HdfsServerConstants.XATTR_SATISFY_STORAGE_POLICY;
|
import static org.apache.hadoop.hdfs.server.common.HdfsServerConstants.XATTR_SATISFY_STORAGE_POLICY;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
|
||||||
import org.apache.hadoop.fs.ParentNotDirectoryException;
|
import org.apache.hadoop.fs.ParentNotDirectoryException;
|
||||||
import org.apache.hadoop.fs.StorageType;
|
import org.apache.hadoop.fs.StorageType;
|
||||||
import org.apache.hadoop.fs.UnresolvedLinkException;
|
import org.apache.hadoop.fs.UnresolvedLinkException;
|
||||||
|
@ -38,7 +36,6 @@ import org.apache.hadoop.hdfs.server.common.HdfsServerConstants;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.INode;
|
import org.apache.hadoop.hdfs.server.namenode.INode;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.Namesystem;
|
import org.apache.hadoop.hdfs.server.namenode.Namesystem;
|
||||||
import org.apache.hadoop.hdfs.server.protocol.DatanodeStorageReport;
|
import org.apache.hadoop.hdfs.server.protocol.DatanodeStorageReport;
|
||||||
import org.apache.hadoop.hdfs.server.protocol.BlockStorageMovementCommand.BlockMovingInfo;
|
|
||||||
import org.apache.hadoop.net.NetworkTopology;
|
import org.apache.hadoop.net.NetworkTopology;
|
||||||
import org.apache.hadoop.security.AccessControlException;
|
import org.apache.hadoop.security.AccessControlException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -55,15 +52,14 @@ public class IntraSPSNameNodeContext implements Context {
|
||||||
|
|
||||||
private final Namesystem namesystem;
|
private final Namesystem namesystem;
|
||||||
private final BlockManager blockManager;
|
private final BlockManager blockManager;
|
||||||
private final Configuration conf;
|
|
||||||
private Supplier<Boolean> isSpsRunning;
|
private SPSService service;
|
||||||
|
|
||||||
public IntraSPSNameNodeContext(Namesystem namesystem,
|
public IntraSPSNameNodeContext(Namesystem namesystem,
|
||||||
BlockManager blockManager, Configuration conf) {
|
BlockManager blockManager, SPSService service) {
|
||||||
this.namesystem = namesystem;
|
this.namesystem = namesystem;
|
||||||
this.blockManager = blockManager;
|
this.blockManager = blockManager;
|
||||||
this.conf = conf;
|
this.service = service;
|
||||||
isSpsRunning = () -> false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -110,11 +106,6 @@ public class IntraSPSNameNodeContext implements Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Configuration getConf() {
|
|
||||||
return conf;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFileExist(long inodeId) {
|
public boolean isFileExist(long inodeId) {
|
||||||
return namesystem.getFSDirectory().getInode(inodeId) != null;
|
return namesystem.getFSDirectory().getInode(inodeId) != null;
|
||||||
|
@ -127,16 +118,7 @@ public class IntraSPSNameNodeContext implements Context {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isRunning() {
|
public boolean isRunning() {
|
||||||
// TODO : 'isSpsRunning' flag has been added to avoid the NN lock inside
|
return namesystem.isRunning() && service.isRunning();
|
||||||
// SPS. Context interface will be further refined as part of HDFS-12911
|
|
||||||
// modularization task. One idea is to introduce a cleaner interface similar
|
|
||||||
// to Namesystem for better abstraction.
|
|
||||||
return namesystem.isRunning() && isSpsRunning.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSPSRunning(Supplier<Boolean> spsRunningFlag) {
|
|
||||||
this.isSpsRunning = spsRunningFlag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -182,25 +164,6 @@ public class IntraSPSNameNodeContext implements Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void assignBlockMoveTaskToTargetNode(BlockMovingInfo blkMovingInfo)
|
|
||||||
throws IOException {
|
|
||||||
namesystem.readLock();
|
|
||||||
try {
|
|
||||||
DatanodeDescriptor dn = blockManager.getDatanodeManager()
|
|
||||||
.getDatanode(blkMovingInfo.getTarget().getDatanodeUuid());
|
|
||||||
if (dn == null) {
|
|
||||||
throw new IOException("Failed to schedule block movement task:"
|
|
||||||
+ blkMovingInfo + " as target datanode: "
|
|
||||||
+ blkMovingInfo.getTarget() + " doesn't exists");
|
|
||||||
}
|
|
||||||
dn.addBlocksToMoveStorage(blkMovingInfo);
|
|
||||||
dn.incrementBlocksScheduled(blkMovingInfo.getTargetStorageType());
|
|
||||||
} finally {
|
|
||||||
namesystem.readUnlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean verifyTargetDatanodeHasSpaceForScheduling(DatanodeInfo dn,
|
public boolean verifyTargetDatanodeHasSpaceForScheduling(DatanodeInfo dn,
|
||||||
StorageType type, long blockSize) {
|
StorageType type, long blockSize) {
|
||||||
|
@ -217,4 +180,19 @@ public class IntraSPSNameNodeContext implements Context {
|
||||||
namesystem.readUnlock();
|
namesystem.readUnlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getNextSPSPathId() {
|
||||||
|
return blockManager.getNextSPSPathId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeSPSPathId(long trackId) {
|
||||||
|
blockManager.removeSPSPathId(trackId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeAllSPSPathIds() {
|
||||||
|
blockManager.removeAllSPSPathIds();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,178 @@
|
||||||
|
/**
|
||||||
|
* 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.hdfs.server.namenode.sps;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.HdfsFileStatus;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.FSDirectory;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.FSTreeTraverser;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.INode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A specific implementation for scanning the directory with Namenode internal
|
||||||
|
* Inode structure and collects the file ids under the given directory ID.
|
||||||
|
*/
|
||||||
|
public class IntraSPSNameNodeFileIdCollector extends FSTreeTraverser
|
||||||
|
implements FileIdCollector {
|
||||||
|
private int maxQueueLimitToScan;
|
||||||
|
private final SPSService service;
|
||||||
|
|
||||||
|
private int remainingCapacity = 0;
|
||||||
|
|
||||||
|
private List<ItemInfo> currentBatch;
|
||||||
|
|
||||||
|
public IntraSPSNameNodeFileIdCollector(FSDirectory dir, SPSService service) {
|
||||||
|
super(dir);
|
||||||
|
this.service = service;
|
||||||
|
this.maxQueueLimitToScan = service.getConf().getInt(
|
||||||
|
DFSConfigKeys.DFS_STORAGE_POLICY_SATISFIER_QUEUE_LIMIT_KEY,
|
||||||
|
DFSConfigKeys.DFS_STORAGE_POLICY_SATISFIER_QUEUE_LIMIT_DEFAULT);
|
||||||
|
currentBatch = new ArrayList<>(maxQueueLimitToScan);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean processFileInode(INode inode, TraverseInfo traverseInfo)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
if (LOG.isTraceEnabled()) {
|
||||||
|
LOG.trace("Processing {} for statisy the policy",
|
||||||
|
inode.getFullPathName());
|
||||||
|
}
|
||||||
|
if (!inode.isFile()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (inode.isFile() && inode.asFile().numBlocks() != 0) {
|
||||||
|
currentBatch.add(new ItemInfo(
|
||||||
|
((SPSTraverseInfo) traverseInfo).getStartId(), inode.getId()));
|
||||||
|
remainingCapacity--;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canSubmitCurrentBatch() {
|
||||||
|
return remainingCapacity <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void checkINodeReady(long startId) throws IOException {
|
||||||
|
// SPS work won't be scheduled if NN is in standby. So, skipping NN
|
||||||
|
// standby check.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void submitCurrentBatch(long startId)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
// Add current child's to queue
|
||||||
|
service.addAllFileIdsToProcess(startId,
|
||||||
|
currentBatch, false);
|
||||||
|
currentBatch.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void throttle() throws InterruptedException {
|
||||||
|
if (LOG.isDebugEnabled()) {
|
||||||
|
LOG.debug("StorageMovementNeeded queue remaining capacity is zero,"
|
||||||
|
+ " waiting for some free slots.");
|
||||||
|
}
|
||||||
|
remainingCapacity = remainingCapacity();
|
||||||
|
// wait for queue to be free
|
||||||
|
while (remainingCapacity <= 0) {
|
||||||
|
if (LOG.isDebugEnabled()) {
|
||||||
|
LOG.debug("Waiting for storageMovementNeeded queue to be free!");
|
||||||
|
}
|
||||||
|
Thread.sleep(5000);
|
||||||
|
remainingCapacity = remainingCapacity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canTraverseDir(INode inode) throws IOException {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void checkPauseForTesting() throws InterruptedException {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scanAndCollectFileIds(final Long startINodeId)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
FSDirectory fsd = getFSDirectory();
|
||||||
|
INode startInode = fsd.getInode(startINodeId);
|
||||||
|
if (startInode != null) {
|
||||||
|
remainingCapacity = remainingCapacity();
|
||||||
|
if (remainingCapacity == 0) {
|
||||||
|
throttle();
|
||||||
|
}
|
||||||
|
if (startInode.isFile()) {
|
||||||
|
currentBatch.add(new ItemInfo(startInode.getId(), startInode.getId()));
|
||||||
|
} else {
|
||||||
|
|
||||||
|
readLock();
|
||||||
|
// NOTE: this lock will not be held until full directory scanning. It is
|
||||||
|
// basically a sliced locking. Once it collects a batch size( at max the
|
||||||
|
// size of maxQueueLimitToScan (default 1000)) file ids, then it will
|
||||||
|
// unlock and submits the current batch to SPSService. Once
|
||||||
|
// service.processingQueueSize() shows empty slots, then lock will be
|
||||||
|
// resumed and scan also will be resumed. This logic was re-used from
|
||||||
|
// EDEK feature.
|
||||||
|
try {
|
||||||
|
traverseDir(startInode.asDirectory(), startINodeId,
|
||||||
|
HdfsFileStatus.EMPTY_NAME, new SPSTraverseInfo(startINodeId));
|
||||||
|
} finally {
|
||||||
|
readUnlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Mark startInode traverse is done, this is last-batch
|
||||||
|
service.addAllFileIdsToProcess(startInode.getId(), currentBatch, true);
|
||||||
|
currentBatch.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns queue remaining capacity.
|
||||||
|
*/
|
||||||
|
public synchronized int remainingCapacity() {
|
||||||
|
int size = service.processingQueueSize();
|
||||||
|
if (size >= maxQueueLimitToScan) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return (maxQueueLimitToScan - size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SPSTraverseInfo extends TraverseInfo {
|
||||||
|
private long startId;
|
||||||
|
|
||||||
|
SPSTraverseInfo(long startId) {
|
||||||
|
this.startId = startId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getStartId() {
|
||||||
|
return startId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
/**
|
||||||
|
* 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.hdfs.server.namenode.sps;
|
||||||
|
|
||||||
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ItemInfo is a file info object for which need to satisfy the policy.
|
||||||
|
*/
|
||||||
|
@InterfaceAudience.Private
|
||||||
|
@InterfaceStability.Evolving
|
||||||
|
public class ItemInfo {
|
||||||
|
private long startId;
|
||||||
|
private long fileId;
|
||||||
|
private int retryCount;
|
||||||
|
|
||||||
|
public ItemInfo(long startId, long fileId) {
|
||||||
|
this.startId = startId;
|
||||||
|
this.fileId = fileId;
|
||||||
|
// set 0 when item is getting added first time in queue.
|
||||||
|
this.retryCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemInfo(final long startId, final long fileId, final int retryCount) {
|
||||||
|
this.startId = startId;
|
||||||
|
this.fileId = fileId;
|
||||||
|
this.retryCount = retryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the start inode id of the current track Id. This indicates that SPS
|
||||||
|
* was invoked on this inode id.
|
||||||
|
*/
|
||||||
|
public long getStartId() {
|
||||||
|
return startId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the File inode Id for which needs to satisfy the policy.
|
||||||
|
*/
|
||||||
|
public long getFileId() {
|
||||||
|
return fileId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the tracking path is a directory, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isDir() {
|
||||||
|
return (startId != fileId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the attempted retry count of the block for satisfy the policy.
|
||||||
|
*/
|
||||||
|
public int getRetryCount() {
|
||||||
|
return retryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the retry count.
|
||||||
|
*/
|
||||||
|
public void increRetryCount() {
|
||||||
|
this.retryCount++;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
/**
|
||||||
|
* 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.hdfs.server.namenode.sps;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Queue;
|
||||||
|
|
||||||
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class which holds the SPS invoked path ids.
|
||||||
|
*/
|
||||||
|
@InterfaceAudience.Private
|
||||||
|
@InterfaceStability.Evolving
|
||||||
|
public class SPSPathIds {
|
||||||
|
|
||||||
|
// List of pending dir to satisfy the policy
|
||||||
|
private final Queue<Long> spsDirsToBeTraveresed = new LinkedList<Long>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the path id to queue.
|
||||||
|
*/
|
||||||
|
public synchronized void add(long pathId) {
|
||||||
|
spsDirsToBeTraveresed.add(pathId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the path id.
|
||||||
|
*/
|
||||||
|
public synchronized void remove(long pathId) {
|
||||||
|
spsDirsToBeTraveresed.remove(pathId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all path ids.
|
||||||
|
*/
|
||||||
|
public synchronized void clear() {
|
||||||
|
spsDirsToBeTraveresed.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return next path id available in queue.
|
||||||
|
*/
|
||||||
|
public synchronized Long pollNext() {
|
||||||
|
return spsDirsToBeTraveresed.poll();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
/**
|
||||||
|
* 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.hdfs.server.namenode.sps;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for SPSService, which exposes life cycle and processing APIs.
|
||||||
|
*/
|
||||||
|
@InterfaceAudience.Private
|
||||||
|
@InterfaceStability.Evolving
|
||||||
|
public interface SPSService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the helper services.
|
||||||
|
*
|
||||||
|
* @param ctxt
|
||||||
|
* - context is an helper service to provide communication channel
|
||||||
|
* between NN and SPS
|
||||||
|
* @param fileIDCollector
|
||||||
|
* - a helper service for scanning the files under a given directory
|
||||||
|
* id
|
||||||
|
* @param handler
|
||||||
|
* - a helper service for moving the blocks
|
||||||
|
*/
|
||||||
|
void init(Context ctxt, FileIdCollector fileIDCollector,
|
||||||
|
BlockMoveTaskHandler handler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the SPS service. Make sure to initialize the helper services before
|
||||||
|
* invoking this method.
|
||||||
|
*
|
||||||
|
* @param reconfigStart
|
||||||
|
* - to indicate whether the SPS startup requested from
|
||||||
|
* reconfiguration service
|
||||||
|
*/
|
||||||
|
void start(boolean reconfigStart);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the SPS service gracefully. Timed wait to stop storage policy
|
||||||
|
* satisfier daemon threads.
|
||||||
|
*/
|
||||||
|
void stopGracefully();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable the SPS service.
|
||||||
|
*
|
||||||
|
* @param forceStop
|
||||||
|
*/
|
||||||
|
void disable(boolean forceStop);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether StoragePolicySatisfier is running.
|
||||||
|
*
|
||||||
|
* @return true if running
|
||||||
|
*/
|
||||||
|
boolean isRunning();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the Item information(file id etc) to processing queue.
|
||||||
|
*
|
||||||
|
* @param itemInfo
|
||||||
|
*/
|
||||||
|
void addFileIdToProcess(ItemInfo itemInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds all the Item information(file id etc) to processing queue.
|
||||||
|
*
|
||||||
|
* @param startId
|
||||||
|
* - directory/file id, on which SPS was called.
|
||||||
|
* @param itemInfoList
|
||||||
|
* - list of item infos
|
||||||
|
* @param scanCompleted
|
||||||
|
* - whether the scanning of directory fully done with itemInfoList
|
||||||
|
*/
|
||||||
|
void addAllFileIdsToProcess(long startId, List<ItemInfo> itemInfoList,
|
||||||
|
boolean scanCompleted);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return current processing queue size.
|
||||||
|
*/
|
||||||
|
int processingQueueSize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the configuration.
|
||||||
|
*/
|
||||||
|
Configuration getConf();
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.StorageType;
|
import org.apache.hadoop.fs.StorageType;
|
||||||
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
||||||
import org.apache.hadoop.hdfs.DFSUtil;
|
import org.apache.hadoop.hdfs.DFSUtil;
|
||||||
|
@ -47,7 +48,6 @@ import org.apache.hadoop.hdfs.protocol.LocatedStripedBlock;
|
||||||
import org.apache.hadoop.hdfs.server.balancer.Matcher;
|
import org.apache.hadoop.hdfs.server.balancer.Matcher;
|
||||||
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants;
|
import org.apache.hadoop.hdfs.server.common.HdfsServerConstants;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.ErasureCodingPolicyManager;
|
import org.apache.hadoop.hdfs.server.namenode.ErasureCodingPolicyManager;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSDirectory;
|
|
||||||
import org.apache.hadoop.hdfs.server.protocol.BlockStorageMovementCommand.BlockMovingInfo;
|
import org.apache.hadoop.hdfs.server.protocol.BlockStorageMovementCommand.BlockMovingInfo;
|
||||||
import org.apache.hadoop.hdfs.server.protocol.BlocksStorageMoveAttemptFinished;
|
import org.apache.hadoop.hdfs.server.protocol.BlocksStorageMoveAttemptFinished;
|
||||||
import org.apache.hadoop.hdfs.server.protocol.DatanodeStorageReport;
|
import org.apache.hadoop.hdfs.server.protocol.DatanodeStorageReport;
|
||||||
|
@ -64,28 +64,34 @@ import com.google.common.annotations.VisibleForTesting;
|
||||||
* storage policy type in Namespace, but physical block storage movement will
|
* storage policy type in Namespace, but physical block storage movement will
|
||||||
* not happen until user runs "Mover Tool" explicitly for such files. The
|
* not happen until user runs "Mover Tool" explicitly for such files. The
|
||||||
* StoragePolicySatisfier Daemon thread implemented for addressing the case
|
* StoragePolicySatisfier Daemon thread implemented for addressing the case
|
||||||
* where users may want to physically move the blocks by HDFS itself instead of
|
* where users may want to physically move the blocks by a dedidated daemon (can
|
||||||
* running mover tool explicitly. Just calling client API to
|
* run inside Namenode or stand alone) instead of running mover tool explicitly.
|
||||||
* satisfyStoragePolicy on a file/dir will automatically trigger to move its
|
* Just calling client API to satisfyStoragePolicy on a file/dir will
|
||||||
* physical storage locations as expected in asynchronous manner. Here Namenode
|
* automatically trigger to move its physical storage locations as expected in
|
||||||
* will pick the file blocks which are expecting to change its storages, then it
|
* asynchronous manner. Here SPS will pick the file blocks which are expecting
|
||||||
* will build the mapping of source block location and expected storage type and
|
* to change its storages, then it will build the mapping of source block
|
||||||
* location to move. After that this class will also prepare commands to send to
|
* location and expected storage type and location to move. After that this
|
||||||
* Datanode for processing the physical block movements.
|
* class will also prepare requests to send to Datanode for processing the
|
||||||
|
* physical block movements.
|
||||||
*/
|
*/
|
||||||
@InterfaceAudience.Private
|
@InterfaceAudience.Private
|
||||||
public class StoragePolicySatisfier implements Runnable {
|
public class StoragePolicySatisfier implements SPSService, Runnable {
|
||||||
public static final Logger LOG =
|
public static final Logger LOG =
|
||||||
LoggerFactory.getLogger(StoragePolicySatisfier.class);
|
LoggerFactory.getLogger(StoragePolicySatisfier.class);
|
||||||
private Daemon storagePolicySatisfierThread;
|
private Daemon storagePolicySatisfierThread;
|
||||||
private final BlockStorageMovementNeeded storageMovementNeeded;
|
private BlockStorageMovementNeeded storageMovementNeeded;
|
||||||
private final BlockStorageMovementAttemptedItems storageMovementsMonitor;
|
private BlockStorageMovementAttemptedItems storageMovementsMonitor;
|
||||||
private volatile boolean isRunning = false;
|
private volatile boolean isRunning = false;
|
||||||
private int spsWorkMultiplier;
|
private int spsWorkMultiplier;
|
||||||
private long blockCount = 0L;
|
private long blockCount = 0L;
|
||||||
private int blockMovementMaxRetry;
|
private int blockMovementMaxRetry;
|
||||||
private final Context ctxt;
|
private Context ctxt;
|
||||||
|
private BlockMoveTaskHandler blockMoveTaskHandler;
|
||||||
|
private Configuration conf;
|
||||||
|
|
||||||
|
public StoragePolicySatisfier(Configuration conf) {
|
||||||
|
this.conf = conf;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Represents the collective analysis status for all blocks.
|
* Represents the collective analysis status for all blocks.
|
||||||
*/
|
*/
|
||||||
|
@ -125,13 +131,17 @@ public class StoragePolicySatisfier implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public StoragePolicySatisfier(Context ctxt) {
|
public void init(final Context context, final FileIdCollector fileIDCollector,
|
||||||
this.ctxt = ctxt;
|
final BlockMoveTaskHandler blockMovementTaskHandler) {
|
||||||
this.storageMovementNeeded = new BlockStorageMovementNeeded(ctxt);
|
this.ctxt = context;
|
||||||
this.storageMovementsMonitor = new BlockStorageMovementAttemptedItems(ctxt,
|
this.storageMovementNeeded =
|
||||||
|
new BlockStorageMovementNeeded(context, fileIDCollector);
|
||||||
|
this.storageMovementsMonitor =
|
||||||
|
new BlockStorageMovementAttemptedItems(this,
|
||||||
storageMovementNeeded);
|
storageMovementNeeded);
|
||||||
this.spsWorkMultiplier = DFSUtil.getSPSWorkMultiplier(ctxt.getConf());
|
this.blockMoveTaskHandler = blockMovementTaskHandler;
|
||||||
this.blockMovementMaxRetry = ctxt.getConf().getInt(
|
this.spsWorkMultiplier = DFSUtil.getSPSWorkMultiplier(getConf());
|
||||||
|
this.blockMovementMaxRetry = getConf().getInt(
|
||||||
DFSConfigKeys.DFS_STORAGE_POLICY_SATISFIER_MAX_RETRY_ATTEMPTS_KEY,
|
DFSConfigKeys.DFS_STORAGE_POLICY_SATISFIER_MAX_RETRY_ATTEMPTS_KEY,
|
||||||
DFSConfigKeys.DFS_STORAGE_POLICY_SATISFIER_MAX_RETRY_ATTEMPTS_DEFAULT);
|
DFSConfigKeys.DFS_STORAGE_POLICY_SATISFIER_MAX_RETRY_ATTEMPTS_DEFAULT);
|
||||||
}
|
}
|
||||||
|
@ -139,12 +149,10 @@ public class StoragePolicySatisfier implements Runnable {
|
||||||
/**
|
/**
|
||||||
* Start storage policy satisfier demon thread. Also start block storage
|
* Start storage policy satisfier demon thread. Also start block storage
|
||||||
* movements monitor for retry the attempts if needed.
|
* movements monitor for retry the attempts if needed.
|
||||||
*
|
|
||||||
* // TODO: FSDirectory will get removed via HDFS-12911 modularization work.
|
|
||||||
*/
|
*/
|
||||||
public synchronized void start(boolean reconfigStart, FSDirectory fsd) {
|
@Override
|
||||||
|
public synchronized void start(boolean reconfigStart) {
|
||||||
isRunning = true;
|
isRunning = true;
|
||||||
ctxt.setSPSRunning(this::isRunning);
|
|
||||||
if (ctxt.isMoverRunning()) {
|
if (ctxt.isMoverRunning()) {
|
||||||
isRunning = false;
|
isRunning = false;
|
||||||
LOG.error(
|
LOG.error(
|
||||||
|
@ -163,20 +171,14 @@ public class StoragePolicySatisfier implements Runnable {
|
||||||
// Ensure that all the previously submitted block movements(if any) have to
|
// Ensure that all the previously submitted block movements(if any) have to
|
||||||
// be stopped in all datanodes.
|
// be stopped in all datanodes.
|
||||||
addDropSPSWorkCommandsToAllDNs();
|
addDropSPSWorkCommandsToAllDNs();
|
||||||
storageMovementNeeded.init(fsd);
|
|
||||||
storagePolicySatisfierThread = new Daemon(this);
|
storagePolicySatisfierThread = new Daemon(this);
|
||||||
storagePolicySatisfierThread.setName("StoragePolicySatisfier");
|
storagePolicySatisfierThread.setName("StoragePolicySatisfier");
|
||||||
storagePolicySatisfierThread.start();
|
storagePolicySatisfierThread.start();
|
||||||
this.storageMovementsMonitor.start();
|
this.storageMovementsMonitor.start();
|
||||||
|
this.storageMovementNeeded.activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Disables storage policy satisfier by stopping its services.
|
|
||||||
*
|
|
||||||
* @param forceStop
|
|
||||||
* true represents that it should stop SPS service by clearing all
|
|
||||||
* pending SPS work
|
|
||||||
*/
|
|
||||||
public synchronized void disable(boolean forceStop) {
|
public synchronized void disable(boolean forceStop) {
|
||||||
isRunning = false;
|
isRunning = false;
|
||||||
if (storagePolicySatisfierThread == null) {
|
if (storagePolicySatisfierThread == null) {
|
||||||
|
@ -195,14 +197,15 @@ public class StoragePolicySatisfier implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Timed wait to stop storage policy satisfier daemon threads.
|
|
||||||
*/
|
|
||||||
public synchronized void stopGracefully() {
|
public synchronized void stopGracefully() {
|
||||||
if (isRunning) {
|
if (isRunning) {
|
||||||
disable(true);
|
disable(true);
|
||||||
}
|
}
|
||||||
this.storageMovementsMonitor.stopGracefully();
|
|
||||||
|
if (this.storageMovementsMonitor != null) {
|
||||||
|
this.storageMovementsMonitor.stopGracefully();
|
||||||
|
}
|
||||||
|
|
||||||
if (storagePolicySatisfierThread == null) {
|
if (storagePolicySatisfierThread == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -213,10 +216,7 @@ public class StoragePolicySatisfier implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Check whether StoragePolicySatisfier is running.
|
|
||||||
* @return true if running
|
|
||||||
*/
|
|
||||||
public boolean isRunning() {
|
public boolean isRunning() {
|
||||||
return isRunning;
|
return isRunning;
|
||||||
}
|
}
|
||||||
|
@ -239,11 +239,11 @@ public class StoragePolicySatisfier implements Runnable {
|
||||||
if(itemInfo.getRetryCount() >= blockMovementMaxRetry){
|
if(itemInfo.getRetryCount() >= blockMovementMaxRetry){
|
||||||
LOG.info("Failed to satisfy the policy after "
|
LOG.info("Failed to satisfy the policy after "
|
||||||
+ blockMovementMaxRetry + " retries. Removing inode "
|
+ blockMovementMaxRetry + " retries. Removing inode "
|
||||||
+ itemInfo.getTrackId() + " from the queue");
|
+ itemInfo.getFileId() + " from the queue");
|
||||||
storageMovementNeeded.removeItemTrackInfo(itemInfo, false);
|
storageMovementNeeded.removeItemTrackInfo(itemInfo, false);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
long trackId = itemInfo.getTrackId();
|
long trackId = itemInfo.getFileId();
|
||||||
BlocksMovingAnalysis status = null;
|
BlocksMovingAnalysis status = null;
|
||||||
DatanodeStorageReport[] liveDnReports;
|
DatanodeStorageReport[] liveDnReports;
|
||||||
BlockStoragePolicy existingStoragePolicy;
|
BlockStoragePolicy existingStoragePolicy;
|
||||||
|
@ -273,7 +273,7 @@ public class StoragePolicySatisfier implements Runnable {
|
||||||
// be removed on storage movement attempt finished report.
|
// be removed on storage movement attempt finished report.
|
||||||
case BLOCKS_TARGETS_PAIRED:
|
case BLOCKS_TARGETS_PAIRED:
|
||||||
this.storageMovementsMonitor.add(new AttemptedItemInfo(itemInfo
|
this.storageMovementsMonitor.add(new AttemptedItemInfo(itemInfo
|
||||||
.getStartId(), itemInfo.getTrackId(), monotonicNow(),
|
.getStartId(), itemInfo.getFileId(), monotonicNow(),
|
||||||
status.assignedBlocks, itemInfo.getRetryCount()));
|
status.assignedBlocks, itemInfo.getRetryCount()));
|
||||||
break;
|
break;
|
||||||
case NO_BLOCKS_TARGETS_PAIRED:
|
case NO_BLOCKS_TARGETS_PAIRED:
|
||||||
|
@ -282,7 +282,7 @@ public class StoragePolicySatisfier implements Runnable {
|
||||||
+ " back to retry queue as none of the blocks"
|
+ " back to retry queue as none of the blocks"
|
||||||
+ " found its eligible targets.");
|
+ " found its eligible targets.");
|
||||||
}
|
}
|
||||||
itemInfo.retryCount++;
|
itemInfo.increRetryCount();
|
||||||
this.storageMovementNeeded.add(itemInfo);
|
this.storageMovementNeeded.add(itemInfo);
|
||||||
break;
|
break;
|
||||||
case FEW_LOW_REDUNDANCY_BLOCKS:
|
case FEW_LOW_REDUNDANCY_BLOCKS:
|
||||||
|
@ -426,7 +426,8 @@ public class StoragePolicySatisfier implements Runnable {
|
||||||
for (BlockMovingInfo blkMovingInfo : blockMovingInfos) {
|
for (BlockMovingInfo blkMovingInfo : blockMovingInfos) {
|
||||||
// Check for at least one block storage movement has been chosen
|
// Check for at least one block storage movement has been chosen
|
||||||
try {
|
try {
|
||||||
ctxt.assignBlockMoveTaskToTargetNode(blkMovingInfo);
|
blockMoveTaskHandler.submitMoveTask(blkMovingInfo,
|
||||||
|
storageMovementsMonitor);
|
||||||
LOG.debug("BlockMovingInfo: {}", blkMovingInfo);
|
LOG.debug("BlockMovingInfo: {}", blkMovingInfo);
|
||||||
assignedBlockIds.add(blkMovingInfo.getBlock());
|
assignedBlockIds.add(blkMovingInfo.getBlock());
|
||||||
blockCount++;
|
blockCount++;
|
||||||
|
@ -611,7 +612,6 @@ public class StoragePolicySatisfier implements Runnable {
|
||||||
|
|
||||||
expected.remove(chosenTarget.storageType);
|
expected.remove(chosenTarget.storageType);
|
||||||
excludeNodes.add(chosenTarget.dn);
|
excludeNodes.add(chosenTarget.dn);
|
||||||
// TODO: We can increment scheduled block count for this node?
|
|
||||||
} else {
|
} else {
|
||||||
LOG.warn(
|
LOG.warn(
|
||||||
"Failed to choose target datanode for the required"
|
"Failed to choose target datanode for the required"
|
||||||
|
@ -830,11 +830,11 @@ public class StoragePolicySatisfier implements Runnable {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
storageMovementsMonitor
|
storageMovementsMonitor
|
||||||
.addReportedMovedBlocks(moveAttemptFinishedBlks.getBlocks());
|
.notifyMovementTriedBlocks(moveAttemptFinishedBlks.getBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
BlockStorageMovementAttemptedItems getAttemptedItemsMonitor() {
|
BlockMovementListener getAttemptedItemsMonitor() {
|
||||||
return storageMovementsMonitor;
|
return storageMovementsMonitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -863,10 +863,6 @@ public class StoragePolicySatisfier implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addInodeToPendingDirQueue(long id) {
|
|
||||||
storageMovementNeeded.addToPendingDirQueue(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear queues for given track id.
|
* Clear queues for given track id.
|
||||||
*/
|
*/
|
||||||
|
@ -874,57 +870,6 @@ public class StoragePolicySatisfier implements Runnable {
|
||||||
storageMovementNeeded.clearQueue(trackId);
|
storageMovementNeeded.clearQueue(trackId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ItemInfo is a file info object for which need to satisfy the
|
|
||||||
* policy.
|
|
||||||
*/
|
|
||||||
public static class ItemInfo {
|
|
||||||
private long startId;
|
|
||||||
private long trackId;
|
|
||||||
private int retryCount;
|
|
||||||
|
|
||||||
public ItemInfo(long startId, long trackId) {
|
|
||||||
this.startId = startId;
|
|
||||||
this.trackId = trackId;
|
|
||||||
//set 0 when item is getting added first time in queue.
|
|
||||||
this.retryCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemInfo(long startId, long trackId, int retryCount) {
|
|
||||||
this.startId = startId;
|
|
||||||
this.trackId = trackId;
|
|
||||||
this.retryCount = retryCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the start inode id of the current track Id.
|
|
||||||
*/
|
|
||||||
public long getStartId() {
|
|
||||||
return startId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the File inode Id for which needs to satisfy the policy.
|
|
||||||
*/
|
|
||||||
public long getTrackId() {
|
|
||||||
return trackId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the tracking path is a directory, false otherwise.
|
|
||||||
*/
|
|
||||||
public boolean isDir() {
|
|
||||||
return (startId != trackId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the attempted retry count of the block for satisfy the policy.
|
|
||||||
*/
|
|
||||||
public int getRetryCount() {
|
|
||||||
return retryCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class contains information of an attempted blocks and its last
|
* This class contains information of an attempted blocks and its last
|
||||||
* attempted or reported time stamp. This is used by
|
* attempted or reported time stamp. This is used by
|
||||||
|
@ -977,4 +922,30 @@ public class StoragePolicySatisfier implements Runnable {
|
||||||
String path) throws IOException {
|
String path) throws IOException {
|
||||||
return storageMovementNeeded.getStatus(ctxt.getFileID(path));
|
return storageMovementNeeded.getStatus(ctxt.getFileID(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addFileIdToProcess(ItemInfo trackInfo) {
|
||||||
|
storageMovementNeeded.add(trackInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAllFileIdsToProcess(long startId, List<ItemInfo> itemInfoList,
|
||||||
|
boolean scanCompleted) {
|
||||||
|
getStorageMovementQueue().addAll(startId, itemInfoList, scanCompleted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int processingQueueSize() {
|
||||||
|
return storageMovementNeeded.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Configuration getConf() {
|
||||||
|
return conf;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public BlockStorageMovementNeeded getStorageMovementQueue() {
|
||||||
|
return storageMovementNeeded;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.hdfs.HdfsConfiguration;
|
import org.apache.hadoop.hdfs.HdfsConfiguration;
|
||||||
import org.apache.hadoop.hdfs.protocol.Block;
|
import org.apache.hadoop.hdfs.protocol.Block;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.sps.StoragePolicySatisfier.AttemptedItemInfo;
|
import org.apache.hadoop.hdfs.server.namenode.sps.StoragePolicySatisfier.AttemptedItemInfo;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.sps.StoragePolicySatisfier.ItemInfo;
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -49,12 +48,14 @@ public class TestBlockStorageMovementAttemptedItems {
|
||||||
public void setup() throws Exception {
|
public void setup() throws Exception {
|
||||||
Configuration config = new HdfsConfiguration();
|
Configuration config = new HdfsConfiguration();
|
||||||
Context ctxt = Mockito.mock(Context.class);
|
Context ctxt = Mockito.mock(Context.class);
|
||||||
Mockito.when(ctxt.getConf()).thenReturn(config);
|
SPSService sps = Mockito.mock(StoragePolicySatisfier.class);
|
||||||
|
Mockito.when(sps.getConf()).thenReturn(config);
|
||||||
Mockito.when(ctxt.isRunning()).thenReturn(true);
|
Mockito.when(ctxt.isRunning()).thenReturn(true);
|
||||||
Mockito.when(ctxt.isInSafeMode()).thenReturn(false);
|
Mockito.when(ctxt.isInSafeMode()).thenReturn(false);
|
||||||
Mockito.when(ctxt.isFileExist(Mockito.anyLong())).thenReturn(true);
|
Mockito.when(ctxt.isFileExist(Mockito.anyLong())).thenReturn(true);
|
||||||
unsatisfiedStorageMovementFiles = new BlockStorageMovementNeeded(ctxt);
|
unsatisfiedStorageMovementFiles =
|
||||||
bsmAttemptedItems = new BlockStorageMovementAttemptedItems(ctxt,
|
new BlockStorageMovementNeeded(ctxt, null);
|
||||||
|
bsmAttemptedItems = new BlockStorageMovementAttemptedItems(sps,
|
||||||
unsatisfiedStorageMovementFiles);
|
unsatisfiedStorageMovementFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +74,7 @@ public class TestBlockStorageMovementAttemptedItems {
|
||||||
while (monotonicNow() < (stopTime)) {
|
while (monotonicNow() < (stopTime)) {
|
||||||
ItemInfo ele = null;
|
ItemInfo ele = null;
|
||||||
while ((ele = unsatisfiedStorageMovementFiles.get()) != null) {
|
while ((ele = unsatisfiedStorageMovementFiles.get()) != null) {
|
||||||
if (item == ele.getTrackId()) {
|
if (item == ele.getFileId()) {
|
||||||
isItemFound = true;
|
isItemFound = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -99,7 +100,7 @@ public class TestBlockStorageMovementAttemptedItems {
|
||||||
bsmAttemptedItems.add(new AttemptedItemInfo(0L, 0L, 0L, blocks, 0));
|
bsmAttemptedItems.add(new AttemptedItemInfo(0L, 0L, 0L, blocks, 0));
|
||||||
Block[] blockArray = new Block[blocks.size()];
|
Block[] blockArray = new Block[blocks.size()];
|
||||||
blocks.toArray(blockArray);
|
blocks.toArray(blockArray);
|
||||||
bsmAttemptedItems.addReportedMovedBlocks(blockArray);
|
bsmAttemptedItems.notifyMovementTriedBlocks(blockArray);
|
||||||
assertEquals("Failed to receive result!", 1,
|
assertEquals("Failed to receive result!", 1,
|
||||||
bsmAttemptedItems.getMovementFinishedBlocksCount());
|
bsmAttemptedItems.getMovementFinishedBlocksCount());
|
||||||
}
|
}
|
||||||
|
@ -137,7 +138,7 @@ public class TestBlockStorageMovementAttemptedItems {
|
||||||
.add(new AttemptedItemInfo(trackID, trackID, 0L, blocks, 0));
|
.add(new AttemptedItemInfo(trackID, trackID, 0L, blocks, 0));
|
||||||
Block[] blksMovementReport = new Block[1];
|
Block[] blksMovementReport = new Block[1];
|
||||||
blksMovementReport[0] = new Block(item);
|
blksMovementReport[0] = new Block(item);
|
||||||
bsmAttemptedItems.addReportedMovedBlocks(blksMovementReport);
|
bsmAttemptedItems.notifyMovementTriedBlocks(blksMovementReport);
|
||||||
|
|
||||||
// start block movement report monitor thread
|
// start block movement report monitor thread
|
||||||
bsmAttemptedItems.start();
|
bsmAttemptedItems.start();
|
||||||
|
@ -162,7 +163,7 @@ public class TestBlockStorageMovementAttemptedItems {
|
||||||
.add(new AttemptedItemInfo(trackID, trackID, 0L, blocks, 0));
|
.add(new AttemptedItemInfo(trackID, trackID, 0L, blocks, 0));
|
||||||
Block[] blksMovementReport = new Block[1];
|
Block[] blksMovementReport = new Block[1];
|
||||||
blksMovementReport[0] = new Block(item);
|
blksMovementReport[0] = new Block(item);
|
||||||
bsmAttemptedItems.addReportedMovedBlocks(blksMovementReport);
|
bsmAttemptedItems.notifyMovementTriedBlocks(blksMovementReport);
|
||||||
|
|
||||||
Thread.sleep(selfRetryTimeout * 2); // Waiting to get timed out
|
Thread.sleep(selfRetryTimeout * 2); // Waiting to get timed out
|
||||||
|
|
||||||
|
@ -190,7 +191,7 @@ public class TestBlockStorageMovementAttemptedItems {
|
||||||
.add(new AttemptedItemInfo(trackID, trackID, 0L, blocks, 0));
|
.add(new AttemptedItemInfo(trackID, trackID, 0L, blocks, 0));
|
||||||
Block[] blksMovementReport = new Block[1];
|
Block[] blksMovementReport = new Block[1];
|
||||||
blksMovementReport[0] = new Block(item);
|
blksMovementReport[0] = new Block(item);
|
||||||
bsmAttemptedItems.addReportedMovedBlocks(blksMovementReport);
|
bsmAttemptedItems.notifyMovementTriedBlocks(blksMovementReport);
|
||||||
assertFalse(
|
assertFalse(
|
||||||
"Should not add in queue again if it is not there in"
|
"Should not add in queue again if it is not there in"
|
||||||
+ " storageMovementAttemptedItems",
|
+ " storageMovementAttemptedItems",
|
||||||
|
|
|
@ -72,7 +72,6 @@ import org.apache.hadoop.test.GenericTestUtils.LogCapturer;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Mockito;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.slf4j.event.Level;
|
import org.slf4j.event.Level;
|
||||||
|
@ -147,12 +146,11 @@ public class TestStoragePolicySatisfier {
|
||||||
startAdditionalDNs(config, 3, numOfDatanodes, newtypes,
|
startAdditionalDNs(config, 3, numOfDatanodes, newtypes,
|
||||||
storagesPerDatanode, capacity, hdfsCluster);
|
storagesPerDatanode, capacity, hdfsCluster);
|
||||||
|
|
||||||
dfs.satisfyStoragePolicy(new Path(file));
|
|
||||||
|
|
||||||
hdfsCluster.triggerHeartbeats();
|
hdfsCluster.triggerHeartbeats();
|
||||||
|
dfs.satisfyStoragePolicy(new Path(file));
|
||||||
// Wait till namenode notified about the block location details
|
// Wait till namenode notified about the block location details
|
||||||
DFSTestUtil.waitExpectedStorageType(
|
DFSTestUtil.waitExpectedStorageType(file, StorageType.ARCHIVE, 3, 35000,
|
||||||
file, StorageType.ARCHIVE, 3, 30000, dfs);
|
dfs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout = 300000)
|
@Test(timeout = 300000)
|
||||||
|
@ -1284,6 +1282,7 @@ public class TestStoragePolicySatisfier {
|
||||||
{StorageType.ARCHIVE, StorageType.SSD},
|
{StorageType.ARCHIVE, StorageType.SSD},
|
||||||
{StorageType.DISK, StorageType.DISK}};
|
{StorageType.DISK, StorageType.DISK}};
|
||||||
config.setLong("dfs.block.size", DEFAULT_BLOCK_SIZE);
|
config.setLong("dfs.block.size", DEFAULT_BLOCK_SIZE);
|
||||||
|
config.setInt(DFS_STORAGE_POLICY_SATISFIER_QUEUE_LIMIT_KEY, 10);
|
||||||
hdfsCluster = startCluster(config, diskTypes, diskTypes.length,
|
hdfsCluster = startCluster(config, diskTypes, diskTypes.length,
|
||||||
storagesPerDatanode, capacity);
|
storagesPerDatanode, capacity);
|
||||||
dfs = hdfsCluster.getFileSystem();
|
dfs = hdfsCluster.getFileSystem();
|
||||||
|
@ -1299,19 +1298,28 @@ public class TestStoragePolicySatisfier {
|
||||||
|
|
||||||
//Queue limit can control the traverse logic to wait for some free
|
//Queue limit can control the traverse logic to wait for some free
|
||||||
//entry in queue. After 10 files, traverse control will be on U.
|
//entry in queue. After 10 files, traverse control will be on U.
|
||||||
StoragePolicySatisfier sps = Mockito.mock(StoragePolicySatisfier.class);
|
StoragePolicySatisfier sps = new StoragePolicySatisfier(config);
|
||||||
Mockito.when(sps.isRunning()).thenReturn(true);
|
Context ctxt = new IntraSPSNameNodeContext(hdfsCluster.getNamesystem(),
|
||||||
Context ctxt = Mockito.mock(Context.class);
|
hdfsCluster.getNamesystem().getBlockManager(), sps) {
|
||||||
config.setInt(DFS_STORAGE_POLICY_SATISFIER_QUEUE_LIMIT_KEY, 10);
|
@Override
|
||||||
Mockito.when(ctxt.getConf()).thenReturn(config);
|
public boolean isInSafeMode() {
|
||||||
Mockito.when(ctxt.isRunning()).thenReturn(true);
|
return false;
|
||||||
Mockito.when(ctxt.isInSafeMode()).thenReturn(false);
|
}
|
||||||
Mockito.when(ctxt.isFileExist(Mockito.anyLong())).thenReturn(true);
|
|
||||||
BlockStorageMovementNeeded movmentNeededQueue =
|
@Override
|
||||||
new BlockStorageMovementNeeded(ctxt);
|
public boolean isRunning() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FileIdCollector fileIDCollector =
|
||||||
|
new IntraSPSNameNodeFileIdCollector(fsDir, sps);
|
||||||
|
sps.init(ctxt, fileIDCollector, null);
|
||||||
|
sps.getStorageMovementQueue().activate();
|
||||||
|
|
||||||
INode rootINode = fsDir.getINode("/root");
|
INode rootINode = fsDir.getINode("/root");
|
||||||
movmentNeededQueue.addToPendingDirQueue(rootINode.getId());
|
hdfsCluster.getNamesystem().getBlockManager()
|
||||||
movmentNeededQueue.init(fsDir);
|
.addSPSPathId(rootINode.getId());
|
||||||
|
|
||||||
//Wait for thread to reach U.
|
//Wait for thread to reach U.
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
|
@ -1321,7 +1329,7 @@ public class TestStoragePolicySatisfier {
|
||||||
// Remove 10 element and make queue free, So other traversing will start.
|
// Remove 10 element and make queue free, So other traversing will start.
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
String path = expectedTraverseOrder.remove(0);
|
String path = expectedTraverseOrder.remove(0);
|
||||||
long trackId = movmentNeededQueue.get().getTrackId();
|
long trackId = sps.getStorageMovementQueue().get().getFileId();
|
||||||
INode inode = fsDir.getInode(trackId);
|
INode inode = fsDir.getInode(trackId);
|
||||||
assertTrue("Failed to traverse tree, expected " + path + " but got "
|
assertTrue("Failed to traverse tree, expected " + path + " but got "
|
||||||
+ inode.getFullPathName(), path.equals(inode.getFullPathName()));
|
+ inode.getFullPathName(), path.equals(inode.getFullPathName()));
|
||||||
|
@ -1332,7 +1340,7 @@ public class TestStoragePolicySatisfier {
|
||||||
// Check other element traversed in order and R,S should not be added in
|
// Check other element traversed in order and R,S should not be added in
|
||||||
// queue which we already removed from expected list
|
// queue which we already removed from expected list
|
||||||
for (String path : expectedTraverseOrder) {
|
for (String path : expectedTraverseOrder) {
|
||||||
long trackId = movmentNeededQueue.get().getTrackId();
|
long trackId = sps.getStorageMovementQueue().get().getFileId();
|
||||||
INode inode = fsDir.getInode(trackId);
|
INode inode = fsDir.getInode(trackId);
|
||||||
assertTrue("Failed to traverse tree, expected " + path + " but got "
|
assertTrue("Failed to traverse tree, expected " + path + " but got "
|
||||||
+ inode.getFullPathName(), path.equals(inode.getFullPathName()));
|
+ inode.getFullPathName(), path.equals(inode.getFullPathName()));
|
||||||
|
@ -1352,6 +1360,7 @@ public class TestStoragePolicySatisfier {
|
||||||
{StorageType.ARCHIVE, StorageType.SSD},
|
{StorageType.ARCHIVE, StorageType.SSD},
|
||||||
{StorageType.DISK, StorageType.DISK}};
|
{StorageType.DISK, StorageType.DISK}};
|
||||||
config.setLong("dfs.block.size", DEFAULT_BLOCK_SIZE);
|
config.setLong("dfs.block.size", DEFAULT_BLOCK_SIZE);
|
||||||
|
config.setInt(DFS_STORAGE_POLICY_SATISFIER_QUEUE_LIMIT_KEY, 10);
|
||||||
hdfsCluster = startCluster(config, diskTypes, diskTypes.length,
|
hdfsCluster = startCluster(config, diskTypes, diskTypes.length,
|
||||||
storagesPerDatanode, capacity);
|
storagesPerDatanode, capacity);
|
||||||
dfs = hdfsCluster.getFileSystem();
|
dfs = hdfsCluster.getFileSystem();
|
||||||
|
@ -1366,21 +1375,33 @@ public class TestStoragePolicySatisfier {
|
||||||
expectedTraverseOrder.remove("/root/D/M");
|
expectedTraverseOrder.remove("/root/D/M");
|
||||||
expectedTraverseOrder.remove("/root/E");
|
expectedTraverseOrder.remove("/root/E");
|
||||||
FSDirectory fsDir = hdfsCluster.getNamesystem().getFSDirectory();
|
FSDirectory fsDir = hdfsCluster.getNamesystem().getFSDirectory();
|
||||||
StoragePolicySatisfier sps = Mockito.mock(StoragePolicySatisfier.class);
|
|
||||||
Mockito.when(sps.isRunning()).thenReturn(true);
|
|
||||||
// Queue limit can control the traverse logic to wait for some free
|
// Queue limit can control the traverse logic to wait for some free
|
||||||
// entry in queue. After 10 files, traverse control will be on U.
|
// entry in queue. After 10 files, traverse control will be on U.
|
||||||
Context ctxt = Mockito.mock(Context.class);
|
// StoragePolicySatisfier sps = new StoragePolicySatisfier(config);
|
||||||
config.setInt(DFS_STORAGE_POLICY_SATISFIER_QUEUE_LIMIT_KEY, 10);
|
StoragePolicySatisfier sps = new StoragePolicySatisfier(config);
|
||||||
Mockito.when(ctxt.getConf()).thenReturn(config);
|
Context ctxt = new IntraSPSNameNodeContext(hdfsCluster.getNamesystem(),
|
||||||
Mockito.when(ctxt.isRunning()).thenReturn(true);
|
hdfsCluster.getNamesystem().getBlockManager(), sps) {
|
||||||
Mockito.when(ctxt.isInSafeMode()).thenReturn(false);
|
@Override
|
||||||
Mockito.when(ctxt.isFileExist(Mockito.anyLong())).thenReturn(true);
|
public boolean isInSafeMode() {
|
||||||
BlockStorageMovementNeeded movmentNeededQueue =
|
return false;
|
||||||
new BlockStorageMovementNeeded(ctxt);
|
}
|
||||||
movmentNeededQueue.init(fsDir);
|
|
||||||
|
@Override
|
||||||
|
public boolean isRunning() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FileIdCollector fileIDCollector =
|
||||||
|
new IntraSPSNameNodeFileIdCollector(fsDir, sps);
|
||||||
|
sps.init(ctxt, fileIDCollector, null);
|
||||||
|
sps.getStorageMovementQueue().activate();
|
||||||
|
|
||||||
INode rootINode = fsDir.getINode("/root");
|
INode rootINode = fsDir.getINode("/root");
|
||||||
movmentNeededQueue.addToPendingDirQueue(rootINode.getId());
|
hdfsCluster.getNamesystem().getBlockManager()
|
||||||
|
.addSPSPathId(rootINode.getId());
|
||||||
|
|
||||||
// Wait for thread to reach U.
|
// Wait for thread to reach U.
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
@ -1389,7 +1410,7 @@ public class TestStoragePolicySatisfier {
|
||||||
// Remove 10 element and make queue free, So other traversing will start.
|
// Remove 10 element and make queue free, So other traversing will start.
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
String path = expectedTraverseOrder.remove(0);
|
String path = expectedTraverseOrder.remove(0);
|
||||||
long trackId = movmentNeededQueue.get().getTrackId();
|
long trackId = sps.getStorageMovementQueue().get().getFileId();
|
||||||
INode inode = fsDir.getInode(trackId);
|
INode inode = fsDir.getInode(trackId);
|
||||||
assertTrue("Failed to traverse tree, expected " + path + " but got "
|
assertTrue("Failed to traverse tree, expected " + path + " but got "
|
||||||
+ inode.getFullPathName(), path.equals(inode.getFullPathName()));
|
+ inode.getFullPathName(), path.equals(inode.getFullPathName()));
|
||||||
|
@ -1400,7 +1421,7 @@ public class TestStoragePolicySatisfier {
|
||||||
// Check other element traversed in order and E, M, U, R, S should not be
|
// Check other element traversed in order and E, M, U, R, S should not be
|
||||||
// added in queue which we already removed from expected list
|
// added in queue which we already removed from expected list
|
||||||
for (String path : expectedTraverseOrder) {
|
for (String path : expectedTraverseOrder) {
|
||||||
long trackId = movmentNeededQueue.get().getTrackId();
|
long trackId = sps.getStorageMovementQueue().get().getFileId();
|
||||||
INode inode = fsDir.getInode(trackId);
|
INode inode = fsDir.getInode(trackId);
|
||||||
assertTrue("Failed to traverse tree, expected " + path + " but got "
|
assertTrue("Failed to traverse tree, expected " + path + " but got "
|
||||||
+ inode.getFullPathName(), path.equals(inode.getFullPathName()));
|
+ inode.getFullPathName(), path.equals(inode.getFullPathName()));
|
||||||
|
@ -1502,17 +1523,20 @@ public class TestStoragePolicySatisfier {
|
||||||
hdfsCluster = new MiniDFSCluster.Builder(config).numDataNodes(2)
|
hdfsCluster = new MiniDFSCluster.Builder(config).numDataNodes(2)
|
||||||
.storageTypes(storagetypes).build();
|
.storageTypes(storagetypes).build();
|
||||||
hdfsCluster.waitActive();
|
hdfsCluster.waitActive();
|
||||||
BlockStorageMovementNeeded.setStatusClearanceElapsedTimeMs(20000);
|
// BlockStorageMovementNeeded.setStatusClearanceElapsedTimeMs(200000);
|
||||||
dfs = hdfsCluster.getFileSystem();
|
dfs = hdfsCluster.getFileSystem();
|
||||||
Path filePath = new Path("/file");
|
Path filePath = new Path("/file");
|
||||||
DFSTestUtil.createFile(dfs, filePath, 1024, (short) 2,
|
DFSTestUtil.createFile(dfs, filePath, 1024, (short) 2,
|
||||||
0);
|
0);
|
||||||
dfs.setStoragePolicy(filePath, "COLD");
|
dfs.setStoragePolicy(filePath, "COLD");
|
||||||
dfs.satisfyStoragePolicy(filePath);
|
dfs.satisfyStoragePolicy(filePath);
|
||||||
|
Thread.sleep(3000);
|
||||||
StoragePolicySatisfyPathStatus status = dfs.getClient()
|
StoragePolicySatisfyPathStatus status = dfs.getClient()
|
||||||
.checkStoragePolicySatisfyPathStatus(filePath.toString());
|
.checkStoragePolicySatisfyPathStatus(filePath.toString());
|
||||||
Assert.assertTrue("Status should be IN_PROGRESS",
|
Assert.assertTrue(
|
||||||
StoragePolicySatisfyPathStatus.IN_PROGRESS.equals(status));
|
"Status should be IN_PROGRESS/SUCCESS, but status is " + status,
|
||||||
|
StoragePolicySatisfyPathStatus.IN_PROGRESS.equals(status)
|
||||||
|
|| StoragePolicySatisfyPathStatus.SUCCESS.equals(status));
|
||||||
DFSTestUtil.waitExpectedStorageType(filePath.toString(),
|
DFSTestUtil.waitExpectedStorageType(filePath.toString(),
|
||||||
StorageType.ARCHIVE, 2, 30000, dfs);
|
StorageType.ARCHIVE, 2, 30000, dfs);
|
||||||
|
|
||||||
|
@ -1530,7 +1554,7 @@ public class TestStoragePolicySatisfier {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}, 100, 60000);
|
}, 100, 60000);
|
||||||
|
BlockStorageMovementNeeded.setStatusClearanceElapsedTimeMs(1000);
|
||||||
// wait till status is NOT_AVAILABLE
|
// wait till status is NOT_AVAILABLE
|
||||||
GenericTestUtils.waitFor(new Supplier<Boolean>() {
|
GenericTestUtils.waitFor(new Supplier<Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -1719,8 +1743,10 @@ public class TestStoragePolicySatisfier {
|
||||||
public Boolean get() {
|
public Boolean get() {
|
||||||
LOG.info("expectedAttemptedItemsCount={} actualAttemptedItemsCount={}",
|
LOG.info("expectedAttemptedItemsCount={} actualAttemptedItemsCount={}",
|
||||||
expectedBlkMovAttemptedCount,
|
expectedBlkMovAttemptedCount,
|
||||||
sps.getAttemptedItemsMonitor().getAttemptedItemsCount());
|
((BlockStorageMovementAttemptedItems) (sps
|
||||||
return sps.getAttemptedItemsMonitor()
|
.getAttemptedItemsMonitor())).getAttemptedItemsCount());
|
||||||
|
return ((BlockStorageMovementAttemptedItems) (sps
|
||||||
|
.getAttemptedItemsMonitor()))
|
||||||
.getAttemptedItemsCount() == expectedBlkMovAttemptedCount;
|
.getAttemptedItemsCount() == expectedBlkMovAttemptedCount;
|
||||||
}
|
}
|
||||||
}, 100, timeout);
|
}, 100, timeout);
|
||||||
|
@ -1736,8 +1762,11 @@ public class TestStoragePolicySatisfier {
|
||||||
public Boolean get() {
|
public Boolean get() {
|
||||||
LOG.info("MovementFinishedBlocks: expectedCount={} actualCount={}",
|
LOG.info("MovementFinishedBlocks: expectedCount={} actualCount={}",
|
||||||
expectedMovementFinishedBlocksCount,
|
expectedMovementFinishedBlocksCount,
|
||||||
sps.getAttemptedItemsMonitor().getMovementFinishedBlocksCount());
|
((BlockStorageMovementAttemptedItems) (sps
|
||||||
return sps.getAttemptedItemsMonitor().getMovementFinishedBlocksCount()
|
.getAttemptedItemsMonitor())).getMovementFinishedBlocksCount());
|
||||||
|
return ((BlockStorageMovementAttemptedItems) (sps
|
||||||
|
.getAttemptedItemsMonitor()))
|
||||||
|
.getMovementFinishedBlocksCount()
|
||||||
>= expectedMovementFinishedBlocksCount;
|
>= expectedMovementFinishedBlocksCount;
|
||||||
}
|
}
|
||||||
}, 100, timeout);
|
}, 100, timeout);
|
||||||
|
|
|
@ -500,9 +500,11 @@ public class TestStoragePolicySatisfierWithStripedFile {
|
||||||
public Boolean get() {
|
public Boolean get() {
|
||||||
LOG.info("expectedAttemptedItemsCount={} actualAttemptedItemsCount={}",
|
LOG.info("expectedAttemptedItemsCount={} actualAttemptedItemsCount={}",
|
||||||
expectedBlkMovAttemptedCount,
|
expectedBlkMovAttemptedCount,
|
||||||
sps.getAttemptedItemsMonitor().getAttemptedItemsCount());
|
((BlockStorageMovementAttemptedItems) sps
|
||||||
return sps.getAttemptedItemsMonitor()
|
.getAttemptedItemsMonitor()).getAttemptedItemsCount());
|
||||||
.getAttemptedItemsCount() == expectedBlkMovAttemptedCount;
|
return ((BlockStorageMovementAttemptedItems) sps
|
||||||
|
.getAttemptedItemsMonitor())
|
||||||
|
.getAttemptedItemsCount() == expectedBlkMovAttemptedCount;
|
||||||
}
|
}
|
||||||
}, 100, timeout);
|
}, 100, timeout);
|
||||||
}
|
}
|
||||||
|
@ -560,7 +562,7 @@ public class TestStoragePolicySatisfierWithStripedFile {
|
||||||
// Check whether the block movement attempt report has been arrived at the
|
// Check whether the block movement attempt report has been arrived at the
|
||||||
// Namenode(SPS).
|
// Namenode(SPS).
|
||||||
private void waitForBlocksMovementAttemptReport(MiniDFSCluster cluster,
|
private void waitForBlocksMovementAttemptReport(MiniDFSCluster cluster,
|
||||||
long expectedMovementFinishedBlocksCount, int timeout)
|
long expectedMoveFinishedBlks, int timeout)
|
||||||
throws TimeoutException, InterruptedException {
|
throws TimeoutException, InterruptedException {
|
||||||
BlockManager blockManager = cluster.getNamesystem().getBlockManager();
|
BlockManager blockManager = cluster.getNamesystem().getBlockManager();
|
||||||
final StoragePolicySatisfier sps = blockManager.getStoragePolicySatisfier();
|
final StoragePolicySatisfier sps = blockManager.getStoragePolicySatisfier();
|
||||||
|
@ -570,10 +572,11 @@ public class TestStoragePolicySatisfierWithStripedFile {
|
||||||
@Override
|
@Override
|
||||||
public Boolean get() {
|
public Boolean get() {
|
||||||
LOG.info("MovementFinishedBlocks: expectedCount={} actualCount={}",
|
LOG.info("MovementFinishedBlocks: expectedCount={} actualCount={}",
|
||||||
expectedMovementFinishedBlocksCount,
|
expectedMoveFinishedBlks, ((BlockStorageMovementAttemptedItems) sps
|
||||||
sps.getAttemptedItemsMonitor().getMovementFinishedBlocksCount());
|
.getAttemptedItemsMonitor()).getMovementFinishedBlocksCount());
|
||||||
return sps.getAttemptedItemsMonitor().getMovementFinishedBlocksCount()
|
return ((BlockStorageMovementAttemptedItems) sps
|
||||||
>= expectedMovementFinishedBlocksCount;
|
.getAttemptedItemsMonitor())
|
||||||
|
.getMovementFinishedBlocksCount() >= expectedMoveFinishedBlks;
|
||||||
}
|
}
|
||||||
}, 100, timeout);
|
}, 100, timeout);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue