len
bytes from the specified byte array starting at offset off
to
75 | * this buffered output stream.
76 | *
77 | * Ordinarily this method stores bytes from the given array into the current underlying Msg's out buffer, flushing the buffer to the underlying
78 | * output by sending a request with the ClientSeesion as needed. If the requested length is at least as large as this stream's buffer, however,
79 | * then this method will flush by sending a request with the ClientSeesion and current Msg. No data will be copied.
80 | *
81 | * @param b
82 | * the data.
83 | * @param off
84 | * the start offset in the data.
85 | * @param len
86 | * the number of bytes to write.
87 | * @exception IOException
88 | * if an I/O error occurs.
89 | */
90 | public synchronized void write(byte b[], int off, int len) throws IOException {
91 | if (this.msg == null) {
92 | this.msg = msgPool.getMsg();
93 | }
94 | if (len > msg.getOut().remaining()) {
95 | throw new IOException("No enough space remained on MSG's out buffer");
96 | // TODO: format msg with numbers
97 | }
98 |
99 | msg.getOut().put(b, off, len);
100 | flushed = false;
101 | }
102 |
103 | /**
104 | * TODO:UPDATE!! Flushes this buffered output stream. This forces any buffered output bytes to be written out to the
105 | * underlying output stream.
106 | *
107 | * @exception IOException
108 | * if an I/O error occurs.
109 | * @see java.io.FilterOutputStream#out
110 | */
111 | public synchronized void flush() throws IOException {
112 | if (!flushed) {
113 | R4HProtocol.wrappedSendRequest(cs, msg, LogFactory.getLog(JXOutputStream.class));
114 | msg = null;
115 | flushed = true;
116 | }
117 | }
118 |
119 | /**
120 | * Close the stream.
121 | * Actually it closes the client session.
122 | */
123 | public synchronized void close() {
124 | cs.close();
125 | }
126 |
127 | }
128 |
--------------------------------------------------------------------------------
/src/common/src/com/mellanox/r4h/MessageAction.java:
--------------------------------------------------------------------------------
1 | package com.mellanox.r4h;
2 |
3 | import org.accelio.jxio.Msg;
4 |
5 | public interface MessageAction {
6 |
7 | public void onMessageAction(Msg msg);
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/src/common/src/com/mellanox/r4h/PacketMessageContext.java:
--------------------------------------------------------------------------------
1 | package com.mellanox.r4h;
2 |
3 | import java.nio.ByteBuffer;
4 | import java.util.concurrent.atomic.AtomicInteger;
5 |
6 | import org.accelio.jxio.Msg;
7 | import org.apache.hadoop.hdfs.protocol.datatransfer.PacketHeader;
8 | import org.apache.hadoop.hdfs.protocol.datatransfer.PipelineAck;
9 |
10 | class PacketMessageContext {
11 |
12 | private final AtomicInteger referenceCounter;
13 | private ByteBuffer ioBuffer;
14 | private PipelineAck messageAck;
15 | private long seqNo;
16 | private long offsetInBlock;
17 | private boolean isLastPkt;
18 | private boolean syncBlock;
19 |
20 | PacketMessageContext() {
21 | this.referenceCounter = new AtomicInteger(0);
22 | }
23 |
24 | ByteBuffer getIOBuffer() {
25 | return this.ioBuffer;
26 | }
27 |
28 | void setPacketData(PacketHeader packetHeader, ByteBuffer ioBuffer) {
29 | this.offsetInBlock = packetHeader.getOffsetInBlock();
30 | this.seqNo = packetHeader.getSeqno();
31 | this.syncBlock = packetHeader.getSyncBlock();
32 | this.isLastPkt = packetHeader.isLastPacketInBlock();
33 | this.ioBuffer = ioBuffer;
34 | }
35 |
36 | void setMessageAck(PipelineAck messageAck) {
37 | this.messageAck = messageAck;
38 | }
39 |
40 | PipelineAck getMessageAck() {
41 | return this.messageAck;
42 | }
43 |
44 | boolean getSyncBlock() {
45 | return this.syncBlock;
46 | }
47 |
48 | boolean isLastPacketInBlock() {
49 | return this.isLastPkt;
50 | }
51 |
52 | long getSeqno() {
53 | return this.seqNo;
54 | }
55 |
56 | long getUpdatedOffsetInBlock() {
57 | return this.offsetInBlock;
58 | }
59 |
60 | int incrementReferenceCounter() {
61 | return this.referenceCounter.incrementAndGet();
62 | }
63 |
64 | int decrementReferenceCounter() {
65 | return this.referenceCounter.decrementAndGet();
66 | }
67 |
68 | static PacketMessageContext getPacketMessageContext(Msg msg) {
69 | return (PacketMessageContext) msg.getUserContext();
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/common/src/com/mellanox/r4h/R4HDatanodePlugin.java:
--------------------------------------------------------------------------------
1 | /*
2 | ** Copyright (C) 2014 Mellanox Technologies
3 | **
4 | ** Licensed under the Apache License, Version 2.0 (the "License");
5 | ** you may not use this file except in compliance with the License.
6 | ** You may obtain a copy of the License at:
7 | **
8 | ** http://www.apache.org/licenses/LICENSE-2.0
9 | **
10 | ** Unless required by applicable law or agreed to in writing, software
11 | ** distributed under the License is distributed on an "AS IS" BASIS,
12 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13 | ** either express or implied. See the License for the specific language
14 | ** governing permissions and limitations under the License.
15 | **
16 | */
17 |
18 | package com.mellanox.r4h;
19 |
20 | import java.io.IOException;
21 | import java.net.URISyntaxException;
22 |
23 | import org.accelio.jxio.EventQueueHandler;
24 | import org.apache.commons.logging.Log;
25 | import org.apache.commons.logging.LogFactory;
26 | import org.apache.hadoop.hdfs.server.datanode.DataNode;
27 | import org.apache.hadoop.hdfs.server.datanode.DataNodeBridge;
28 | import org.apache.hadoop.util.Daemon;
29 | import org.apache.hadoop.util.ServicePlugin;
30 |
31 | /**
32 | * R4H implementation for a datanode service plugin to run a R4H serve side by side to HDFS server. Datanode starts
33 | * service plugins during initialization by going through the comma separated list of ServicePlugin implementation
34 | * classes configured on dfs.datanode.plugins parameter
35 | */
36 | public class R4HDatanodePlugin implements ServicePlugin {
37 | private DataNode dn;
38 | private DataXceiverServer dxs;
39 | private Daemon daemon;
40 | private static Log LOG = LogFactory.getLog(R4HDatanodePlugin.class.getName());
41 | private DataNodeBridge dnExposer;
42 |
43 | // is not called on datanode
44 | public void close() throws IOException {
45 | stop();
46 | }
47 |
48 | /*
49 | * Starts a new thread of R4H server. Designed to be called by Datanode as a service.
50 | *
51 | * @param service must be a Datanode instance or Object[] for standalone untitest
52 | *
53 | * @see org.apache.hadoop.util.ServicePlugin#start(java.lang.Object)
54 | */
55 | public void start(Object service) {
56 | LOG.debug("Starting plugin");
57 | if (!(service instanceof DataNode)) {
58 | throw new IllegalArgumentException("Unexpected service object type");
59 | }
60 | LOG.debug("Service object is DataNode");
61 | dn = (DataNode) service;
62 | dnExposer = new DataNodeBridge(dn);
63 |
64 | try {
65 | DataNodeBridge dnBridge = new DataNodeBridge(dn);
66 | dxs = new DataXceiverServer(dnBridge);
67 | } catch (URISyntaxException e) {
68 | throw new IllegalArgumentException("Failed to create URI for DataXceriverServer", e);
69 | }
70 | daemon = new Daemon(dxs);
71 | daemon.setName(String.format("DataXceiverServer-JXIO-Listener-%d", daemon.getId()));
72 | daemon.start();
73 |
74 | LOG.info("Started");
75 | // JXIO version
76 | LOG.info("JXIO version :\t" + EventQueueHandler.class.getPackage().getImplementationVersion());
77 | // R4H version
78 | LOG.info("R4H verison :\t" + DataXceiver.class.getPackage().getImplementationVersion());
79 | }
80 |
81 | /*
82 | * Stop R4H server and wait until it closes all it's resources
83 | *
84 | * @see org.apache.hadoop.util.ServicePlugin#stop()
85 | */
86 | public void stop() {
87 | stop(-1); // Infinite wait for daemon to stop
88 | }
89 |
90 | /**
91 | * Stop R4H server
92 | *
93 | * @param waitForDaemon
94 | * milliseconds to wait for resources to be closed or -1 for infinate wait
95 | */
96 | public void stop(int waitForDaemon) {
97 | if (waitForDaemon < -1) {
98 | throw new IllegalArgumentException("Illegal (begative) number of milliseconds argument to wait for deamon to stop");
99 | }
100 |
101 | LOG.debug("Stopping R4H Datanode plugin");
102 | Daemon dm = new Daemon(new Runnable() {
103 |
104 | @Override
105 | public void run() {
106 | dxs.stop();
107 | }
108 | });
109 | dm.start();
110 |
111 | try {
112 | if (waitForDaemon == -1) {
113 | daemon.join();
114 | } else {
115 | daemon.join(waitForDaemon);
116 | }
117 | } catch (InterruptedException e) {
118 | LOG.debug("daemon join interrupted. Exception: " + e.toString());
119 | }
120 |
121 | if (dm.isAlive()) {
122 | LOG.error("timeout waiting for R4H plugin to stop");
123 | } else {
124 | LOG.info("R4H Datanode plugin stopped");
125 | }
126 | }
127 |
128 | /**
129 | * @return true if server thread is still alive
130 | */
131 | public boolean isAlive() {
132 | if (daemon == null)
133 | return false;
134 |
135 | return daemon.isAlive();
136 | }
137 |
138 | @Override
139 | public String toString() {
140 | if (daemon == null) {
141 | return super.toString() + " is not started yet";
142 | } else {
143 | return String.format("R4HDatanodePlugin{DN='%s', DXS='%s', isAlive='%s'}", (dn == null) ? "-" : dn.toString(), dxs.toString(),
144 | daemon.isAlive() ? "TRUE" : "FALSE");
145 | }
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/src/common/src/com/mellanox/r4h/R4HEventHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | ** Copyright (C) 2014 Mellanox Technologies
3 | **
4 | ** Licensed under the Apache License, Version 2.0 (the "License");
5 | ** you may not use this file except in compliance with the License.
6 | ** You may obtain a copy of the License at:
7 | **
8 | ** http://www.apache.org/licenses/LICENSE-2.0
9 | **
10 | ** Unless required by applicable law or agreed to in writing, software
11 | ** distributed under the License is distributed on an "AS IS" BASIS,
12 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13 | ** either express or implied. See the License for the specific language
14 | ** governing permissions and limitations under the License.
15 | **
16 | */
17 |
18 | package com.mellanox.r4h;
19 |
20 | import org.apache.commons.logging.Log;
21 | import org.apache.commons.logging.LogFactory;
22 | import org.apache.hadoop.util.StringUtils;
23 | import org.accelio.jxio.EventQueueHandler;
24 |
25 | public class R4HEventHandler extends EventQueueHandler {
26 | Runnable onBreakEqh;
27 |
28 | /**
29 | * @param callbacks
30 | */
31 | public R4HEventHandler(Callbacks callbacks, Runnable onBreakEqhFunc) {
32 | super(callbacks);
33 | this.onBreakEqh = onBreakEqhFunc;
34 | }
35 |
36 | public R4HEventHandler(Callbacks callbacks) {
37 | super(callbacks);
38 | }
39 |
40 | private final static Log LOG = LogFactory.getLog(R4HEventHandler.class.getName());
41 | private boolean stopR4HLoop = false;
42 | private boolean wasEvLoopReturnedAfterStop = false;
43 |
44 | @Override
45 | public void run() {
46 | try {
47 | while (!this.stopR4HLoop) {
48 | int ne = runEventLoop(INFINITE_EVENTS, INFINITE_DURATION);
49 | if (ne == -1) {
50 | LOG.error("JXIO catched exception during event processing");
51 | if (this.didExceptionOccur()) {
52 | LOG.error(StringUtils.stringifyException(this.getCaughtException()));
53 | } else {
54 | LOG.warn("No exception to retrieve after JXIO indication for exception during event processing");
55 | }
56 | }
57 | if (stopR4HLoop) {
58 | synchronized (this) {
59 | wasEvLoopReturnedAfterStop = true;
60 | this.notify();
61 | }
62 | } else {
63 | onBreakEqh();
64 | }
65 |
66 | }
67 | } catch (Throwable t) {
68 | LOG.fatal("A R4H event handler worker was crashed. " + StringUtils.stringifyException(t));
69 | }
70 | }
71 |
72 | private void onBreakEqh() {
73 | if (onBreakEqh != null) {
74 | onBreakEqh.run();
75 | }
76 | }
77 |
78 | @Override
79 | public void breakEventLoop() {
80 | super.breakEventLoop();
81 | }
82 |
83 | @Override
84 | public void stop() {
85 |
86 | synchronized (this) {
87 | stopR4HLoop = true;
88 | super.stop();
89 | while (!wasEvLoopReturnedAfterStop) {
90 | try {
91 | wait();
92 | } catch (InterruptedException e) {
93 | }
94 | }
95 | }
96 | this.close();
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/common/src/com/mellanox/r4h/R4HExecutor.java:
--------------------------------------------------------------------------------
1 | package com.mellanox.r4h;
2 |
3 | import java.util.List;
4 | import java.util.concurrent.ExecutorService;
5 | import java.util.concurrent.Executors;
6 | import java.util.concurrent.ThreadFactory;
7 |
8 | import org.accelio.jxio.Msg;
9 |
10 | public class R4HExecutor {
11 |
12 | private ExecutorService executor;
13 |
14 | R4HExecutor(ThreadFactory threadFactory) {
15 | this.executor = Executors.newSingleThreadExecutor(threadFactory);
16 | }
17 |
18 | public void execute(final Msg msg, final MessageAction action, final Runnable task) {
19 |
20 | final PacketMessageContext pmc = PacketMessageContext.getPacketMessageContext(msg);
21 |
22 | // increment counter
23 | pmc.incrementReferenceCounter();
24 |
25 | // execute
26 | this.executor.execute(new Runnable() {
27 |
28 | @Override
29 | public void run() {
30 | task.run();
31 |
32 | // decrement and send
33 | int refCount = pmc.decrementReferenceCounter();
34 |
35 | if (refCount == 0) {
36 |
37 | action.onMessageAction(msg);
38 | }
39 | }
40 | });
41 | }
42 |
43 | public void execute(Runnable task) {
44 | this.executor.execute(task);
45 | }
46 |
47 | public List