[ 
https://issues.apache.org/jira/browse/HDFS-14854?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16952156#comment-16952156
 ] 

Stephen O'Donnell commented on HDFS-14854:
------------------------------------------

[~belugabehr] Thanks for the comments. I have addressed some in the 009 patch 
and a few I have not addressed. Please see below which gives the summary:

{quote}
Best practice is to grab the lock outside of the try statement.
{quote}

Maybe there is something I don't understand and I see it does state the best 
practice you mentioned in the link, but I don't see how:
{code:java}
 lock
try {
   ...
} finally {
unlock
}{code}
Is better than:
{code:java}
 try {
   lock()
   ...
} finally {
   unlock()
}{code}

{quote}
The cancelledNodes data structure is a List but it should be a Queue
{quote}

True, I have changed it to an ArrayDeque like with pendingNodes.

{quote}
Using 'null' values is very out of vogue. Better to put a new HashMap here. 
Allows for simplification of the code by assuming that values will never be 
'null'.
{quote}

I use the fact that the value is null to decide whether the datanode needs an 
initial scan or not. The flow is:

1. Take a nodes from pendingNodes and add to outOfServiceNodeBlocks with a null 
value.

2. Later, in the check() method, for each null entry in outofServiceNodeBlocks 
scan the node and add a hashmap of the blocks needing processed.

{quote}
The method scanDatanodeStorage uses the namesystem.readLock(); in a pretty 
verbose and complicated way.
{quote}

We need to hold the read lock when calling dn.getStorageInfos() in the outer 
loop, but we want to drop the lock after processing each storage and then take 
it again. I could refactor this to call dn.getStorageInfos() in a block, eg:
{code:java}
DatanodeStorageInfo[] storages;
namesystem.readLock()
try {
 storages = dn.getStorageInfo();
} finally {
 namesystem.readUnlock();
} {code}
And then simplify the locking code which is there, but I feel this isn't much 
better than what is there.


{quote}
This method is accessed by the local running Thread. However, pendingNodes does 
not appear to be a thread-safe Collection. Perhaps the collection cannot be 
modified because of the external locking of the writeLock but there is no 
requirement to have the lock stated in the startTrackingNode method javadoc.
{quote}

For nodes to be added to pendingNodes, that is always done under the namenode 
writeLock which is taken in fsnamesystem. Then the only place pendingNodes is 
processed in BackOffMonitor in via the monitor thread, and it ensures it holds 
the write lock when processing pendingNodes here:
{code:java}
@Override
 public void run() {
 LOG.debug("DatanodeAdminMonitorV2 is running.");
 if (!namesystem.isRunning()) {
 LOG.info("Namesystem is not running, skipping " +
 "decommissioning/maintenance checks.");
 return;
 }
 // Reset the checked count at beginning of each iteration
 numBlocksChecked = 0;
 // Check decommission or maintenance progress.
 try {
 try {
 /**
 * Other threads can modify the pendingNode list and the cancelled
 * node list, so we must process them under the NN write lock to
 * prevent any concurrent modifications.
 */
 namesystem.writeLock();
 // Always process the cancelled list before the pending list, as
 // it is possible for a node to be cancelled, and then quickly added
 // back again. If we process these the other way around, the added
 // node will be removed from tracking by the pending cancel.
 processCancelledNodes();
 processPendingNodes();
 } finally {
 namesystem.writeUnlock();
 } {code}

{quote}
Nit: this is not very java-y...
{quote}

I think we could argue this one either way. I think my version looks cleaner, 
but I admit modifying the passed in structure can be slightly confusing.


{quote}
Please remove this method. It can be replaced with map.computeIfAbsent(key, k 
-> new LinkedList<V>()).add(v);
{quote}

Thanks for pointing this out. I did not know about that method. I have changed 
this to use computeIfAbsent.

{quote}
This code knows the pendingCount value and the pendingRepLimit... do not grab 
the write lock if the function is going to immediately return anyway.
{quote}

The problem is, we need the lock to check 
blockManager.getLowRedundancyBlocksCount() and if the pendingCount is not 
reducing, then I would really like to log the replication queue size, as it may 
be due to an overloaded replication queue that the pendingCount is not 
reducing. In an earlier version I did have the check outside the lock but then 
I wanted to added the rep queue size to the log and moved it back in. This code 
is only run once per 30 seconds and the lock would only be held a tiny amount 
of time, so I think the additional details in the log are worth the lock price.


{quote}
I think it should return 'true' if the block is orphaned, no? It should skip 
them in the same way that an 'unknown' block is.
{quote}

That code is take from the original decommissioning code, and I have not 
changed it. I believe it returns false as it keeps tracking the block in the 
decommission structures until the NN cleans it out. Then it would become an 
unknown block and be deleted by the "unknown block" code.

> Create improved decommission monitor implementation
> ---------------------------------------------------
>
>                 Key: HDFS-14854
>                 URL: https://issues.apache.org/jira/browse/HDFS-14854
>             Project: Hadoop HDFS
>          Issue Type: Improvement
>          Components: namenode
>    Affects Versions: 3.3.0
>            Reporter: Stephen O'Donnell
>            Assignee: Stephen O'Donnell
>            Priority: Major
>         Attachments: Decommission_Monitor_V2_001.pdf, HDFS-14854.001.patch, 
> HDFS-14854.002.patch, HDFS-14854.003.patch, HDFS-14854.004.patch, 
> HDFS-14854.005.patch, HDFS-14854.006.patch, HDFS-14854.007.patch, 
> HDFS-14854.008.patch
>
>
> In HDFS-13157, we discovered a series of problems with the current 
> decommission monitor implementation, such as:
>  * Blocks are replicated sequentially disk by disk and node by node, and 
> hence the load is not spread well across the cluster
>  * Adding a node for decommission can cause the namenode write lock to be 
> held for a long time.
>  * Decommissioning nodes floods the replication queue and under replicated 
> blocks from a future node or disk failure may way for a long time before they 
> are replicated.
>  * Blocks pending replication are checked many times under a write lock 
> before they are sufficiently replicate, wasting resources
> In this Jira I propose to create a new implementation of the decommission 
> monitor that resolves these issues. As it will be difficult to prove one 
> implementation is better than another, the new implementation can be enabled 
> or disabled giving the option of the existing implementation or the new one.
> I will attach a pdf with some more details on the design and then a version 1 
> patch shortly.



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

---------------------------------------------------------------------
To unsubscribe, e-mail: hdfs-issues-unsubscr...@hadoop.apache.org
For additional commands, e-mail: hdfs-issues-h...@hadoop.apache.org

Reply via email to