Decodes the response of an RPC and triggers its Deferred. This method is only invoked by Netty from a Netty IO thread and will not be invoked on the same instance concurrently, so it only needs to be careful when accessing shared state, but certain synchronization constraints may be rela
(final ChannelHandlerContext ctx,
final Channel chan,
final ChannelBuffer channel_buffer,
final VoidEnum unused)
| 1408 | * @return {@code null}, always. |
| 1409 | */ |
| 1410 | @Override |
| 1411 | protected Object decode(final ChannelHandlerContext ctx, |
| 1412 | final Channel chan, |
| 1413 | final ChannelBuffer channel_buffer, |
| 1414 | final VoidEnum unused) { |
| 1415 | ChannelBuffer buf = channel_buffer; |
| 1416 | final long start = System.nanoTime(); |
| 1417 | final int rdx = buf.readerIndex(); |
| 1418 | LOG.debug("------------------>> ENTERING DECODE >>------------------"); |
| 1419 | final int rpcid; |
| 1420 | final RPCPB.ResponseHeader header; |
| 1421 | |
| 1422 | if (secure_rpc_helper != null) { |
| 1423 | buf = secure_rpc_helper.handleResponse(buf, chan); |
| 1424 | if (buf == null) { |
| 1425 | // everything in the buffer was part of the security handshake so we're |
| 1426 | // done here. |
| 1427 | return null; |
| 1428 | } |
| 1429 | } |
| 1430 | |
| 1431 | final int size; |
| 1432 | if (server_version >= SERVER_VERSION_095_OR_ABOVE) { |
| 1433 | size = buf.readInt(); |
| 1434 | ensureReadable(buf, size); |
| 1435 | HBaseRpc.checkArrayLength(buf, size); |
| 1436 | header = HBaseRpc.readProtobuf(buf, RPCPB.ResponseHeader.PARSER); |
| 1437 | if (!header.hasCallId()) { |
| 1438 | final String msg = "RPC response (size: " + size + ") doesn't" |
| 1439 | + " have a call ID: " + header + ", buf=" + Bytes.pretty(buf); |
| 1440 | throw new NonRecoverableException(msg); |
| 1441 | } |
| 1442 | rpcid = header.getCallId(); |
| 1443 | } else { // HBase 0.94 and before. |
| 1444 | size = 0; |
| 1445 | header = null; // No protobuf back then. |
| 1446 | rpcid = buf.readInt(); |
| 1447 | } |
| 1448 | |
| 1449 | final HBaseRpc rpc = rpcs_inflight.get(rpcid); |
| 1450 | if (rpc == null) { |
| 1451 | // make sure to consume the RPC body so that we can decode the next |
| 1452 | // RPC in the buffer if there is one. Do this before incrementing counters |
| 1453 | // as with pre-protobuf RPCs we may throw replays while consuming. |
| 1454 | if (server_version >= SERVER_VERSION_095_OR_ABOVE) { |
| 1455 | buf.readerIndex(rdx + size + 4); |
| 1456 | if (LOG.isDebugEnabled()) { |
| 1457 | LOG.debug("Skipped timed out RPC ID " + rpcid + " of " + size + |
| 1458 | " bytes on " + this); |
| 1459 | } |
| 1460 | } else { |
| 1461 | consumeTimedoutNonPBufRPC(buf, rdx, rpcid); |
| 1462 | } |
| 1463 | |
| 1464 | // TODO - account for the rpcid overflow |
| 1465 | if (rpcid > -1 && rpcid <= this.rpcid.get()) { |
| 1466 | if (LOG.isDebugEnabled()) { |
| 1467 | LOG.debug("Received a response for rpcid: " + rpcid + |