eu.stratosphere.runtime.io.api.AbstractUnionRecordReader Maven / Gradle / Ivy
/***********************************************************************************************************************
* Copyright (C) 2010-2013 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.runtime.io.api;
import eu.stratosphere.core.io.IOReadableWritable;
import eu.stratosphere.nephele.event.task.AbstractTaskEvent;
import eu.stratosphere.runtime.io.gates.InputChannelResult;
import eu.stratosphere.runtime.io.gates.RecordAvailabilityListener;
import eu.stratosphere.runtime.io.gates.InputGate;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.HashSet;
import java.util.Set;
public abstract class AbstractUnionRecordReader extends AbstractRecordReader implements RecordAvailabilityListener {
/**
* The set of all input gates.
*/
private final InputGate[] allInputGates;
/**
* The set of unclosed input gates.
*/
private final Set> remainingInputGates;
/**
* Queue with indices of channels that store at least one available record.
*/
private final ArrayDeque> availableInputGates = new ArrayDeque>();
/**
* The next input gate to read a record from.
*/
private InputGate nextInputGateToReadFrom;
@Override
public boolean isInputClosed() {
return this.remainingInputGates.isEmpty();
}
/**
* Constructs a new mutable union record reader.
*
* @param recordReaders
* the individual mutable record readers whose input is used to construct the union
*/
@SuppressWarnings("unchecked")
protected AbstractUnionRecordReader(MutableRecordReader[] recordReaders) {
if (recordReaders == null) {
throw new IllegalArgumentException("Provided argument recordReaders is null");
}
if (recordReaders.length < 2) {
throw new IllegalArgumentException(
"The mutable union record reader must at least be initialized with two individual mutable record readers");
}
this.allInputGates = new InputGate[recordReaders.length];
this.remainingInputGates = new HashSet>((int) (recordReaders.length * 1.6f));
for (int i = 0; i < recordReaders.length; i++) {
InputGate inputGate = recordReaders[i].getInputGate();
inputGate.registerRecordAvailabilityListener(this);
this.allInputGates[i] = inputGate;
this.remainingInputGates.add(inputGate);
}
}
@Override
public void publishEvent(AbstractTaskEvent event) throws IOException, InterruptedException {
for (InputGate gate : this.allInputGates) {
gate.publishEvent(event);
}
}
@Override
public void reportRecordAvailability(InputGate inputGate) {
synchronized (this.availableInputGates) {
this.availableInputGates.add(inputGate);
this.availableInputGates.notifyAll();
}
}
protected boolean getNextRecord(T target) throws IOException, InterruptedException {
while (true) {
// has the current input gate more data?
if (this.nextInputGateToReadFrom == null) {
if (this.remainingInputGates.isEmpty()) {
return false;
}
this.nextInputGateToReadFrom = getNextAvailableInputGate();
}
InputChannelResult result = this.nextInputGateToReadFrom.readRecord(target);
switch (result) {
case INTERMEDIATE_RECORD_FROM_BUFFER: // record is available and we can stay on the same channel
return true;
case LAST_RECORD_FROM_BUFFER: // record is available, but we need to re-check the channels
this.nextInputGateToReadFrom = null;
return true;
case END_OF_SUPERSTEP:
this.nextInputGateToReadFrom = null;
if (incrementEndOfSuperstepEventAndCheck()) {
return false; // end of the superstep
}
else {
break; // fall through and wait for next record/event
}
case TASK_EVENT: // event for the subscribers is available
handleEvent(this.nextInputGateToReadFrom.getCurrentEvent());
this.nextInputGateToReadFrom = null;
break;
case END_OF_STREAM: // one gate is empty
this.remainingInputGates.remove(this.nextInputGateToReadFrom);
this.nextInputGateToReadFrom = null;
break;
case NONE: // gate processed an internal event and could not return a record on this call
this.nextInputGateToReadFrom = null;
break;
}
}
}
private InputGate getNextAvailableInputGate() throws InterruptedException {
synchronized (this.availableInputGates) {
while (this.availableInputGates.isEmpty()) {
this.availableInputGates.wait();
}
return this.availableInputGates.pop();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy