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

Anu Engineer commented on HDFS-9543:
------------------------------------

[~eddyxu] Thank you for  the code review comments. Please see some of my 
thoughts on your suggestions.

bq.Could you put getNextBlock() logic into a separate Iterator, and make it 
Closable, which will include getBlockToCopy(), openPoolIters(), getNextBlock(), 
closePoolIters(). There are a few draw backs of separating them into different 
functions. 

I thought that this is an excellent idea, and I explored this path of code 
organization. But I got stuck in an intractable problem which makes me want to 
abandon this path. Please do let me know if you have suggestions on how you 
think I can solve this.

In supporting an Iterator interface, we have to support hasNext. In our case it 
is a scan of the block list and finding a block that is small than the required 
move size. There are 2 ways to do this, look for the block and report true if 
found, but there is no gurantee that it will indeed be returned in the next() 
call since these blocks can go away underneath us. 

So a common pattern of iterator code becomes complex to write -- 
while(hasNext()) next() -- pattern now needs to worry next() failing even when 
hasNext has been successful.

We can keep a pointer to the found block in memory, and return that in the next 
call, but that means that we have to do some unnecessary block state management 
in the iterator.

I ended up writing all this and found that code is getting more complex instead 
of simpler and has kind of decided to abandon this approach.


bq. 1) The states (i.e. poolIndex,) are stored outside these functions, the 
caller needs maintain these states. 

These are part of BlockMover class, and copyblocks in the only call made by 
other classes. So it is not visible to caller at all.

bq. 2) poolIndex is never initialized and is not able be reset.
PoolIndex is a index to a circular array,  if you like I can initialize this to 
0, but in most cases we just move to next block pool and get the next block. 
Before each block fetch we init the count variable so that we know if we have 
visited all the block pools. In other words, users should not be able to see 
this, nor need to reset this variable.

bq. Please always log the IOEs. And I think it is better to throw IOE here as 
well as many other places.
I will log a debug trace here. The reason why we are not throwing is because it 
is possible that we might encounter a damaged block when we try to move large 
number of blocks from one volume to another. Instead of failing or aborting the 
action we keep a count of errors we have encountered. We will just ignore that 
block and continue copy, until we hit max_error_counts. For each move -- that 
is a source disk, destination disk, bytes to move -- you can specify the max 
error count. Hence we are not throwing but keeping track of the error count.

bq. Can it be a private static List<BlockIterator> openPoolIters() ?
Since we are not doing the iterator interface, I am skipping this too.

bq. In a few such places, should we actually break the while loop? Wouldn't 
continue here just generate a lot of LOGS and spend CPU cycles?
You are right  and I did think of writing a break here. The reason that I chose 
continue over break was this. It is easier to reason about a loop if it has 
only one exit point. With break, you have to reason about all exit points. This 
loop is a pretty complicated one since it can exit in many ways. Here are some :

# when we meet the maximum error count.
# if we have reach close enough to move bytes -- say close to 10% of the target 
# if we get an interrupt call from the client.
# if we get a shutdown call.
# if we are not able to find any blocks to move.
# if we are out of destination space.

so instead of making people reason about each of these, we set exit flag and 
loop back up. Since the while will turn to false, it will have one single exit, 
and will exit without any extra logging.

bq. Why do you need to change float to double. In this case, wouldn't float 
good enough ? 
This is a stylistic change, Java docs recommend double as the default choice 
over float. Hence this fix.

> DiskBalancer : Add Data mover 
> ------------------------------
>
>                 Key: HDFS-9543
>                 URL: https://issues.apache.org/jira/browse/HDFS-9543
>             Project: Hadoop HDFS
>          Issue Type: Sub-task
>          Components: datanode
>            Reporter: Anu Engineer
>            Assignee: Anu Engineer
>         Attachments: HDFS-9543-HDFS-1312.001.patch
>
>
> This patch adds the actual mover logic to the datanode.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to