Data block receiver on Datanode node--blockreceiver

Source: Internet
Author: User
Tags flush

In the previous blog post detailed how datanode to the client or other Datanode node to send block block, that is, the data block transmitter blocksender, then the corresponding, Datanode node or the client should be able to properly accept the data block, This is the receiver Blockreceiver of the data block we're going to talk about. Of course, the HDFs client and the Datanode node receive blocks differently, but this article will focus on the data block sinks on the Datanode node.

As we all know, HDFs uses pipelined replication to transmit every copy of a block of data, so when a Datanode node receives a block of data, it needs to consider whether it needs to send the received block data to the next Datanode node. When explaining the block transmitter on the Datanode node, it was said that the Datanode node is sending block data in the same way as the packet, so the Datanode on the receiving end will accept the block data in the same way as the packet. It also sends the received packet to the next Datanode node in the same way as the packet, and it is sent to the sending side after all the Datanode nodes have received the pipe after the confirmation frame of the packet, together with the packet confirmation frame, as shown in the following figure:

But what I always puzzled is that the Datanode block transmitter ignores all the confirmation frames from the receiving side about packet, and if there is any reason for that classmate to tell or discuss with me.

Let's take a look at the basic information about classes that are first closed with Blockreceiver

In fact, there is a background thread packetresponder inside the DATANODE data block receiver that accepts each packet acknowledgement frame from the receiving end and sends each packet confirmation frame to the sender, So there are two key points for Blockreceiver, one is how it accepts and sends packets, and the other is how to accept and send each packet confirmation frame.

1.BlockReceiver

Private block Block;  
The basic information for the block to be accepted protected Boolean finalized; Private datainputstream in = null; Block data read stream private datachecksum checksum; The validator for block data private outputstream out = null; The write stream of the block data (written to Datanode Local disk) <pre name= "code" class= "java" >private dataoutputstream checksumout = null; Block data checksum write stream (local disk written to datanode) private int bytesperchecksum;//data check block size private int checksumsize;//data check fast corresponding checksum size PRI Vate Bytebuffer buf; Packet data cache block private int bufread;  
The size of the data that has been read in the cache block private int maxpacketreadlen; Protected long offsetinblock;//The IP address of the packet received in the block protected the final String inaddr;//send End (datanode/client) Protec Ted Final String myaddr;//the IP address of the current receive side (DataNode) Private String mirroraddr;//The IP address of the next receiving end (DataNode) Private dataoutputstr EAM mirrorout;//down one receiver sends packet write stream private Daemon responder = Null;//packet Responder private Blocktransferthrottler Thrott  
Ler  
Private Fsdataset.blockwritestreams streams;  
Private Boolean isrecovery = false; PRivate String ClientName;  
Datanodeinfo srcdatanode = null;  
Private Checksum PARTIALCRC = null;  Private DataNode DataNode = null;
Blockreceiver first try to accept a full packet at a time, and put this packet all in the cache block, and then write the received packet to the local disk, on the one hand, and then send it to the next receiving end, Finally, give this packet to Packetresponder to confirm. Of course, before the second step there is a data validation operation, but this data validation has a condition, that is: if the first sender is the client, then only the last Datanode node in the pipe to verify the data, if the first sender is the Datanode node, Validation is required on each datanode node in the pipe (the validation here refers to verifying that the accepted data is corrupted by the accepted checksum). Ideally, the main process for Blockreceiver to accept a block is as follows:

1). Initialize

The initialization here is to request storage space on the local disk for the incoming block data, create a validator for the block based on the received header information, and obtain the corresponding checksum configuration information.

Blockreceiver (block block, DataInputStream in, String inaddr, String myaddr, Boolean isrecovery, String ClientName, Datanodeinfo Srcdatanode, DataNode DataNode) throws IOException {try{this.b  
      lock = block;  
      This.in = in;  
      THIS.INADDR = inaddr;  
      THIS.MYADDR = myaddr;  
      This.isrecovery = Isrecovery;  
      This.clientname = ClientName;  
      This.offsetinblock = 0;  
      This.srcdatanode = Srcdatanode;  
      This.datanode = Datanode; This.checksum = Datachecksum.newdatachecksum (in);//Create Data validator from header information this.bytesperchecksum = Checksum.getbytespercheck sum ();//The size of the data check block this.checksumsize = Checksum.getchecksumsize ();//the checksum size corresponding to the data check block//create temporary storage space for the block data that will be accepted  
      (Create block data file and checksum file) streams = Datanode.data.writeToBlock (block, isrecovery);  
      this.finalized = Datanode.data.isValidBlock (block);  
        if (streams! = null) {this.out = Streams.dataout; THis.checksumout = new DataOutputStream (new Bufferedoutputstream (Streams.checksumout, small_buffer_size));  
        if (Datanode.blockscanner! = null && isrecovery) {datanode.blockScanner.deleteBlock (block);  
    }}} catch (Blockalreadyexistsexception Bae) {throw BAE;  
      } catch (IOException IoE) {ioutils.closestream (this);  
      Cleanupblock ();  
      IOException cause = Fsdataset.getcauseifdiskerror (IoE);  
        if (cause! = NULL) {//possible disk error IoE = cause; Datanode.checkdiskerror (IoE);  
    May throw a exception here} throw IoE;   }  
  }

2). Accept Block Data

void Receiveblock (DataOutputStream mirrout, DataInputStream Mirrin, DataOutputStream replyout, String mirrAddr, Blocktransferthrottler throttlerarg, int numtargets) throws IOException {mirrorout = mirrout;//sent to next Datanode node  
      The Write stream mirroraddr = mirraddr;  
  
    Throttler = Throttlerarg; try {//write data chunk header if (!finalized) {Blockmetadataheader.writeheader (checksumout,  
      CHECKSUM); } if (Clientname.length () > 0) {//Create packet Responder responder = new Daemon (Datanode.threadgroup,  
        New Packetresponder (this, block, Mirrin,replyout, numtargets)); Responder.start ();  
  
      Start thread to Processes reponses}//But accept/Send packet while (Receivepacket () > 0) {} End a Datanode send data if (mirrorout! = null) {try {mirrorout.writeint (0);//Mark Th  
        E End of The Block Mirrorout.flush ();  
} catch (IOException e) {          Handlemirrorouterror (e); }}//wait for Packetresponder to complete confirmation of all packet if (responder! = null) {(Packetresponder) RESP  
      Onder.getrunnable ()). Close ();  
  
        } if (clientname.length () = = 0) {//close the BLOCK/CRC files close (); Finalize The block.  
        Does this fsync ()?  
        Block.setnumbytes (Offsetinblock);  
        Datanode.data.finalizeBlock (block);  
      Datanode.myMetrics.blocksWritten.inc ();  
      }} catch (IOException IoE) {log.info ("Exception in Receiveblock for block" + block + "+ IoE");  
      Ioutils.closestream (this);  
      if (responder! = null) {responder.interrupt ();  
      } cleanupblock ();  
    Throw IoE;  
        } finally {if (responder! = null) {try {responder.join ();  
        } catch (Interruptedexception e) {throw new IOException ("Interrupted Receiveblock"); }  
        responder = null;   }  
    }  
  }

3). Accept/Send a packet

private int readtobuf (int toread) throws IOException {if (Toread < 0) {Toread = (Maxpacketreadlen > 0?  
    MaxPacketReadLen:buf.capacity ())-Buf.limit ();  
      
    }//Read data into buf int nread = In.read (Buf.array (), Buf.limit (), toread);  
    if (Nread < 0) {throw new Eofexception ("while trying to read" + toread + "bytes");  
    } Bufread = Buf.limit () + nread;  
    Buf.limit (Bufread);  
  Returns the size of the read data return nread; /** * Read a full packet */private int readnextpacket () throws IOException {//Calculate the cache size quickly and apply  
      The corresponding memory space if (BUF = = null) {int chunkSize = bytesperchecksum + checksumsize;  
      int chunksperpacket = (Datanode.writepacketsize-datanode.pkt_header_len-size_of_integer + chunkSize-1)/chunkSize;  
      BUF = bytebuffer.allocate (Datanode.pkt_header_len + Size_of_integer + math.max (chunksperpacket, 1) * chunkSize);  
    Buf.limit (0);  
      
    }See if there are data left in the Buffer:if (Bufread > Buf.limit ()) {buf.limit (bufread);  }//constant reading of packet data to cache while (Buf.remaining () < Size_of_integer) {if (buf.position () > 0)  
      {Shiftbufdata ();  
    } readtobuf (-1);  
    }/* We mostly has the full packet or at least enough for a int */Buf.mark ();  
    int payloadlen = Buf.getint ();  
      
    Buf.reset ();  
      if (Payloadlen = = 0) {//end of stream!  
      Buf.limit (buf.position () + Size_of_integer);  
    return 0;  
    }//Check corrupt values for Pktlen, 100MB upper limit should is OK? if (Payloadlen < 0 | | Payloadlen > (100*1024*1024)) {throw new IOException ("Incorrect value for packet Payl  
    Oad: "+ Payloadlen);  
      
    } int pktsize = Payloadlen + Datanode.pkt_header_len;  
     if (buf.remaining () < pktsize) { We need to read more data int toread = pktsize-buf.remaining ();          
      First make sure buf have enough space.  
      int spaceleft = buf.capacity ()-Buf.limit ();  
        if (Toread > Spaceleft && buf.position () > 0) {shiftbufdata ();  
      Spaceleft = buf.capacity ()-Buf.limit ();  
        } if (Toread > Spaceleft) {byte oldbuf[] = Buf.array ();  
        int tocopy = Buf.limit ();  
        BUF = bytebuffer.allocate (tocopy + toread);  
        System.arraycopy (oldbuf, 0, Buf.array (), 0, tocopy);  
      Buf.limit (tocopy);  
      }//now read:while (Toread > 0) {toread-= Readtobuf (Toread);  
    }} if (Buf.remaining () > Pktsize) {buf.limit (buf.position () + pktsize);  
    } if (Pktsize > Maxpacketreadlen) {maxpacketreadlen = pktsize;  
  } return Payloadlen; }/** * accepts a PAcket, and save to the local disk, at the same time to the next receiving end */private int receivepacket () throws IOException {//accept a packet of data int Payl  
      
    Oadlen = Readnextpacket ();  
    if (Payloadlen <= 0) {return payloadlen;  
    } buf.mark (); Read the packet header information Buf.getint (); Packet length Offsetinblock = Buf.getlong ();    Get offset of packet in block long seqno = Buf.getlong ();  
      
    Get seqno Boolean lastpacketinblock = (Buf.get ()! = 0);  
    int endofheader = Buf.position ();  
    Buf.reset ();  
      
    Setblockposition (Offsetinblock);  
        First write the packet to the mirror:if (mirrorout! = null) {try {//packet header information sent to the next receive end  
        Mirrorout.write (Buf.array (), Buf.position (), buf.remaining ());  
      Mirrorout.flush ();  
      } catch (IOException e) {handlemirrorouterror (e);          
    }} buf.position (Endofheader);  
  
    int len = Buf.getint (); Data length in//packetif (Len < 0) {throw new IOException ("Got wrong length during writeblock (" + Block + ") from" + Inaddr + "at   
    Offset "+ Offsetinblock +": "+ len);  
    } if (len = = 0) {log.debug ("receiving empty packet for block" + block);  
  
      } else {offsetinblock + = Len;  
  
      Verify the length of the data int checksumlen = ((len + bytesPerChecksum-1)/bytesperchecksum) * checksumsize; if (buf.remaining ()! = (Checksumlen + len)) {throw new IOException ("Data remaining in packet does not match"  
      + "Sum of Checksumlen and Datalen"); } int checksumoff = Buf.position ();//Check data start in packet int dataoff = Checksumoff + checksumlen;//  
  
      Where the real data begins in packet byte pktbuf[] = Buf.array (); Buf.position (Buf.limit ());  
  
      Move to the end of the data. Verify data if (Mirrorout = = NULL | | clientname.length () = = 0) {verifychunks (Pktbuf, Dataoff, Len, PKTBUF, ch  
      Ecksumoff);  
 } 
      try {if (!finalized) {//) writes data from packet to the disk cache Out.write (Pktbuf, Dataoff, Len); If This is a partial chunk and then verify that's the only//chunk in the packet.  
          Calculate New CRC for this chunk. if (PARTIALCRC! = null) {if (len > Bytesperchecksum) {throw new IOException ("Got wrong Length during WriteBlock ("+ Block +") from "+ Inaddr +" "+" A packet can has only one partial chunk. "  
            + "Len =" + len + "Bytesperchecksum" + bytesperchecksum);  
            } partialcrc.update (Pktbuf, Dataoff, Len);  
            byte[] buf = Fsoutputsummer.converttobytestream (PARTIALCRC, checksumsize);  
            Checksumout.write (BUF);  
            Log.debug ("Writing out partial CRC for Data Len" + len);  
          PARTIALCRC = null; } else {//writes the checksum data in packet to the disk cache Checksumout.write (Pktbuf, Checksumoff, Checksumlen); 
          } datanode.myMetrics.bytesWritten.inc (len);  
        }} catch (IOException IEX) {datanode.checkdiskerror (IEX);  
      Throw IEX;  
  
    }}//flush the packet data and checksum data to disk flush (); Give the packet to Packetresponder to confirm if (responder! = null) {(Packetresponder) responder.getrunnable ()). Enqueue (SE   
    Qno, Lastpacketinblock);  
    } if (Throttler! = null) {//throttle I/O throttler.throttle (Payloadlen);  
  } return Payloadlen;   }

4). Confirm Packet

Private linkedlist<packet> Ackqueue = new linkedlist<packet> (); Packet queue for confirmation  
private volatile Boolean running = true;  
private block block;  
DataInputStream Mirrorin;   Accept the packet confirmation frame of the network read stream  
dataoutputstream replyout;  Send packet to confirm the frame of the network write stream  
private int numtargets;     
The Packetresponder accepts/sends the corresponding confirmation frame in the order of the accepted packet frames, such as packet, which is currently processing the number seqno, and it first accepts the acknowledgement from the receiving end of the packet. It then sends the acknowledgment information received and its confirmation to the packet to its sender. During the Datanode node's pipelining, if an error occurs in a Datanode node, such as a received packet error, the blockreceiver of the datanode automatically ends the thread and does not send a confirmation frame to the sending end. The sending side will not receive the acknowledgement frame at the receiving end, so that the receiving end on the task after all the Datanode node in the acceptance of the block packet is an error, and this situation sent to the sender side.



Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.