/*********************************************************************************************************************** * * Copyright (C) 2010 by the Stratosphere project (http://stratosphere.eu) * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. * **********************************************************************************************************************/ package eu.stratosphere.nephele.taskmanager.runtime; import java.io.IOException; import eu.stratosphere.nephele.checkpointing.EphemeralCheckpoint; import eu.stratosphere.nephele.checkpointing.EphemeralCheckpointForwarder; import eu.stratosphere.nephele.io.AbstractID; import eu.stratosphere.nephele.io.GateID; import eu.stratosphere.nephele.io.OutputGate; import eu.stratosphere.nephele.io.channels.AbstractOutputChannel; import eu.stratosphere.nephele.io.channels.Buffer; import eu.stratosphere.nephele.io.channels.ChannelID; import eu.stratosphere.nephele.io.channels.ChannelType; import eu.stratosphere.nephele.io.channels.bytebuffered.AbstractByteBufferedOutputChannel; import eu.stratosphere.nephele.io.compression.CompressionException; import eu.stratosphere.nephele.io.compression.CompressionLoader; import eu.stratosphere.nephele.io.compression.Compressor; import eu.stratosphere.nephele.taskmanager.bufferprovider.BufferAvailabilityListener; import eu.stratosphere.nephele.taskmanager.bufferprovider.BufferProvider; import eu.stratosphere.nephele.taskmanager.bytebuffered.AbstractOutputChannelForwarder; import eu.stratosphere.nephele.taskmanager.bytebuffered.OutputChannelContext; import eu.stratosphere.nephele.taskmanager.bytebuffered.OutputChannelForwardingChain; import eu.stratosphere.nephele.taskmanager.bytebuffered.OutputGateContext; import eu.stratosphere.nephele.types.Record; final class RuntimeOutputGateContext implements BufferProvider, OutputGateContext { private final RuntimeTaskContext taskContext; private final OutputGate<? extends Record> outputGate; private Compressor compressor = null; RuntimeOutputGateContext(final RuntimeTaskContext taskContext, final OutputGate<? extends Record> outputGate) { this.taskContext = taskContext; this.outputGate = outputGate; } AbstractID getFileOwnerID() { return this.taskContext.getFileOwnerID(); } /** * {@inheritDoc} */ @Override public int getMaximumBufferSize() { return this.taskContext.getMaximumBufferSize(); } /** * {@inheritDoc} */ @Override public Buffer requestEmptyBuffer(int minimumSizeOfBuffer) throws IOException { return this.taskContext.requestEmptyBuffer(minimumSizeOfBuffer); } /** * {@inheritDoc} */ @Override public Buffer requestEmptyBufferBlocking(int minimumSizeOfBuffer) throws IOException, InterruptedException { Buffer buffer = this.taskContext.requestEmptyBuffer(minimumSizeOfBuffer); // No memory-based buffer available if (buffer == null) { // Report exhaustion of memory buffers to the task context this.taskContext.reportExhaustionOfMemoryBuffers(); // Wait until a memory-based buffer is available buffer = this.taskContext.requestEmptyBufferBlocking(minimumSizeOfBuffer); } return buffer; } /** * {@inheritDoc} */ @Override public boolean isShared() { return this.taskContext.isShared(); } /** * {@inheritDoc} */ @Override public void reportAsynchronousEvent() { this.taskContext.reportAsynchronousEvent(); } /** * {@inheritDoc} */ @Override public GateID getGateID() { return this.outputGate.getGateID(); } /** * {@inheritDoc} */ @Override public OutputChannelContext createOutputChannelContext(ChannelID channelID, OutputChannelContext previousContext, boolean isReceiverRunning, boolean mergeSpillBuffers) { if (previousContext != null) { throw new IllegalStateException("Found previous output context for channel " + channelID); } AbstractOutputChannel<? extends Record> channel = null; for (int i = 0; i < this.outputGate.getNumberOfOutputChannels(); ++i) { AbstractOutputChannel<? extends Record> candidateChannel = this.outputGate.getOutputChannel(i); if (candidateChannel.getID().equals(channelID)) { channel = candidateChannel; break; } } if (channel == null) { throw new IllegalArgumentException("Cannot find output channel with ID " + channelID); } if (!(channel instanceof AbstractByteBufferedOutputChannel)) { throw new IllegalStateException("Channel with ID" + channelID + " is not of type AbstractByteBufferedOutputChannel"); } // The output channel for this context final AbstractByteBufferedOutputChannel<? extends Record> outputChannel = (AbstractByteBufferedOutputChannel<? extends Record>) channel; // Construct the forwarding chain RuntimeOutputChannelBroker outputChannelBroker; AbstractOutputChannelForwarder last; if (outputChannel.getType() == ChannelType.FILE) { // Special case for file channels final EphemeralCheckpoint checkpoint = this.taskContext.getEphemeralCheckpoint(); if (checkpoint == null) { throw new IllegalStateException("No ephemeral checkpoint for file channel " + outputChannel.getID()); } final EphemeralCheckpointForwarder checkpointForwarder = new EphemeralCheckpointForwarder(checkpoint, null); outputChannelBroker = new RuntimeOutputChannelBroker(this, outputChannel, checkpointForwarder); last = checkpointForwarder; } else { // Construction for in-memory and network channels final RuntimeDispatcher runtimeDispatcher = new RuntimeDispatcher( this.taskContext.getTransferEnvelopeDispatcher()); /* * final SpillingBarrier spillingBarrier = new SpillingBarrier(isReceiverRunning, mergeSpillBuffers, * runtimeDispatcher); * final ForwardingBarrier forwardingBarrier = new ForwardingBarrier(channelID, spillingBarrier); */ final ForwardingBarrier forwardingBarrier = new ForwardingBarrier(channelID, runtimeDispatcher); final EphemeralCheckpoint checkpoint = this.taskContext.getEphemeralCheckpoint(); if (checkpoint != null) { final EphemeralCheckpointForwarder checkpointForwarder = new EphemeralCheckpointForwarder(checkpoint, forwardingBarrier); outputChannelBroker = new RuntimeOutputChannelBroker(this, outputChannel, checkpointForwarder); } else { outputChannelBroker = new RuntimeOutputChannelBroker(this, outputChannel, forwardingBarrier); } last = runtimeDispatcher; } final OutputChannelForwardingChain forwardingChain = new OutputChannelForwardingChain(outputChannelBroker, last); // Set forwarding chain for broker outputChannelBroker.setForwardingChain(forwardingChain); return new RuntimeOutputChannelContext(outputChannel, forwardingChain); } /** * {@inheritDoc} */ @Override public boolean registerBufferAvailabilityListener(final BufferAvailabilityListener bufferAvailabilityListener) { return this.taskContext.registerBufferAvailabilityListener(bufferAvailabilityListener); } /** * Returns (and if necessary previously creates) the compressor to be used by the attached output channels. * * @return the compressor to be used by the attached output channels or <code>null</code> if no compression shall be * applied * @throws CompressionException * thrown if an error occurs while creating the compressor */ Compressor getCompressor() throws CompressionException { if (this.compressor == null) { this.compressor = CompressionLoader.getCompressorByCompressionLevel(this.outputGate.getCompressionLevel(), this.taskContext.getCompressionBufferProvider()); } else { this.compressor.increaseChannelCounter(); } return this.compressor; } }