redberry-redberry-pipe-7323a27293f8/.hg_archival.txt 0000644 0000000 0000000 00000000201 13353377423 020264 0 ustar 0000000 0000000 repo: 7914145f3a4e71eb7e190f8da8c4f56eeaa1e194
node: 7323a27293f8a9fee5f4eda2c06c42d6b32fae9f
branch: default
tag: v1.0.0-alpha0
redberry-redberry-pipe-7323a27293f8/.flow 0000644 0000000 0000000 00000000173 13353377423 016156 0 ustar 0000000 0000000 [branchname]
master = default
develop = develop
feature = feature/
release = release/
hotfix = hotfix/
support = support/
redberry-redberry-pipe-7323a27293f8/.hgflow 0000644 0000000 0000000 00000000174 13353377423 016476 0 ustar 0000000 0000000 [branchname]
master = default
develop = develop
feature = feature/
release = release/
hotfix = hotfix/
support = support/
redberry-redberry-pipe-7323a27293f8/.hgignore 0000644 0000000 0000000 00000000146 13353377423 017011 0 ustar 0000000 0000000 target
nbactions.*\.xml$
nb-configuration.xml$
\.log$
\.log\.
\.iml$
\.ipr$
\.iws$
\.idea
\.DS_Store$
redberry-redberry-pipe-7323a27293f8/.hgtags 0000644 0000000 0000000 00000000576 13353377423 016473 0 ustar 0000000 0000000 6888a683c930f5ddaf0c6ccd97f2709ebedda7e9 v0.9
fd180a2531ee9268d7b8f3b0724db52acb9a7fb5 v0.9.1
0fc6a342c9c6f0f516353eb8248120e2416bae0c v0.9.2
32ac825eca9c81e9fca2018e5f707c3c1e646a8a v0.9.3
7f330fab9bed5b039021e4a2661721a57d906c19 v0.9.4
7a6fa9fc0b45f54c99ad028766cd12130ec64c8b v0.9.5
5117244cf5e36a1f0fa536724b912d7262e2209e v0.9.6
0c85a16ffc6b0d43b501c48e523e4dcb94c6e095 v0.9.7
redberry-redberry-pipe-7323a27293f8/pom.xml 0000644 0000000 0000000 00000015222 13353377423 016524 0 ustar 0000000 0000000
4.0.0cc.redberrypipe1.0.0-alpha0org.sonatype.ossoss-parent9pipe
Java library for implementation of concurrent pipelines.
GNU General Public License, version 3http://www.gnu.org/licenses/gpl-3.0.htmlrepodbolotinbolotin.dmitriy@gmail.comBolotin DmitriyIBCH RAShttp://www.ibch.ru/architectdevelopertesterdocumentationUTC+04:00https://bitbucket.org/dbolotinmikeshmikhail.shugay@gmail.comMikhail ShugayIBCH RAShttp://www.ibch.ru/documentationUTC+04:00https://bitbucket.org/mikeshscm:hg:http://bitbucket.org/redberry/redberry-pipehttps://bitbucket.org/redberry/redberry-pipe/src/Bitbuckethttps://bitbucket.org/redberry/redberry-pipe/issuesjunitjunit4.8.2testorg.apache.commonscommons-math2.2testUTF-8releaseorg.apache.maven.pluginsmaven-source-plugin3.0.1attach-sourcesjar-no-forkorg.apache.maven.pluginsmaven-javadoc-plugin3.0.1attach-javadocsjarnoneorg.apache.maven.pluginsmaven-gpg-plugin1.6sign-artifactsverifysignorg.apache.maven.pluginsmaven-compiler-plugin3.8.01.81.8org.sonatype.pluginsnexus-staging-maven-plugin1.6.8trueossrhhttps://oss.sonatype.org/
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/CUtils.java 0000644 0000000 0000000 00000042524 13353377423 025056 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe;
import cc.redberry.pipe.blocks.Merger;
import cc.redberry.pipe.util.Chunk;
import cc.redberry.pipe.util.SimpleProcessorWrapper;
import cc.redberry.pipe.util.SimpleProcessorWrapperSynchronized;
import cc.redberry.pipe.util.SimpleVoidProcessorExecutor;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
/**
* Utility methods.
*/
public final class CUtils {
public static final OutputPort EMPTY_OUTPUT_PORT = new OutputPort() {
@Override
public Object take() {
return null;
}
};
public static final OutputPortCloseable EMPTY_OUTPUT_PORT_CLOSEABLE = new OutputPortCloseable() {
@Override
public void close() {
}
@Override
public Object take() {
return null;
}
};
/**
* Wraps processor and input port into single output port.
*
* @param inputPort output port to be wrapped
* @param processor processor to wrap
* @param type of input objects
* @param type of output objects
* @return wrapped output port
*/
public static OutputPort wrap(OutputPort extends InputT> inputPort, Processor super InputT, ? extends OutputT> processor) {
return new SimpleProcessorWrapper<>(inputPort, processor);
}
/**
* Wraps processor and input port into single output port. Wrapper will introduce additional synchronization.
*
* @param inputPort output port to be wrapped
* @param processor processor to wrap
* @param type of input objects
* @param type of output objects
* @return wrapped output port
*/
public static OutputPort wrapSynchronized(OutputPort extends InputT> inputPort, Processor super InputT, ? extends OutputT> processor) {
return new SimpleProcessorWrapperSynchronized<>(inputPort, processor);
}
/**
* Returns void processor wrapper of an input port.
*
* @param inputPort input port to wrap
* @param type of objects
* @return wrapped input port
*/
public static VoidProcessor asVoidProcessor(final InputPort inputPort) {
return new VoidProcessor() {
@Override
public void process(T input) {
inputPort.put(input);
}
};
}
/**
* Drains all content of output port into input port. This method will close a to port by putting null into
* it.
*
* @param from port to take elements from
* @param to port to put elements to
* @param type of elements
* @throws InterruptedException
*/
public static void drain(OutputPort extends T> from, InputPort super T> to) throws InterruptedException {
T element;
while ((element = from.take()) != null)
to.put(element);
to.put(null); //Closing
}
/**
* Drains all content of output port into input port.
*
* @param from port to take elements from
* @param to port to put elements to
* @param type of elements
* @throws InterruptedException
*/
public static void drainWithoutClose(OutputPort from, InputPort to) throws InterruptedException {
T element;
while ((element = from.take()) != null)
to.put(element);
}
/**
* Converts VoidProcessor to Processor
*
* @param processor VoidProcessor to convert
* @return Processor wrapper of VoidProcessor
*/
public static Processor asProcessor(final VoidProcessor processor) {
return new Processor() {
@Override
public T process(T input) {
processor.process(input);
return input;
}
};
}
/**
* Process no more than {@code maxCount} elements from input by provided processor in current thread.
*
* @param input input object stream
* @param processor void processor
* @param maxCount maximum number of objects to process
* @param type of processed objects
* @return true if some objects left in input, false if not
* @throws InterruptedException
*/
public static boolean processPart(OutputPort input, VoidProcessor processor, int maxCount) throws InterruptedException {
if (maxCount <= 0)
throw new IllegalArgumentException("maxCount should be greater than 0");
T object = null;
while ((--maxCount) >= 0 && (object = input.take()) != null)
processor.process(object);
return object != null;
}
/**
* Process all elements from output port in current thread.
*
* @param input input object stream
* @param processor void processor
* @param type of processed objects
* @throws InterruptedException
*/
public static void processAll(OutputPort input, VoidProcessor super T> processor) throws InterruptedException {
T object;
while ((object = input.take()) != null)
processor.process(object);
}
/**
* Process all elements from output port in current thread.
*
* @param input input object stream
* @param processor void processor
* @param threadCount number of parallel threads
* @param type of processed objects
* @throws InterruptedException
*/
public static void processAllInParallel(OutputPort input, VoidProcessor super T> processor, int threadCount)
throws InterruptedException {
--threadCount;
Thread[] threads = new Thread[threadCount];
for (int i = 0; i < threadCount; ++i) {
threads[i] = new Thread(new SimpleVoidProcessorExecutor<>(input, processor));
threads[i].start();
}
T object;
while ((object = input.take()) != null)
processor.process(object);
for (int i = 0; i < threadCount; ++i)
threads[i].join();
}
/**
* Process all elements from output port in current thread.
*
* @param input input object stream
* @param processor void processor
* @param threadCount number of parallel threads
* @param executorService executor service to create threads
* @param type of processed objects
* @throws InterruptedException
*/
public static void processAllInParallel(OutputPort input, VoidProcessor super T> processor, int threadCount,
ExecutorService executorService) throws InterruptedException {
--threadCount;
Future>[] futures = new Future[threadCount];
for (int i = 0; i < threadCount; ++i)
futures[i] = executorService.submit(new SimpleVoidProcessorExecutor<>(input, processor));
T object;
while ((object = input.take()) != null)
processor.process(object);
try {
for (int i = 0; i < threadCount; ++i)
futures[i].get();
} catch (ExecutionException ex) {
throw (RuntimeException) ex.getCause();
}
}
/**
* Process all elements from output port in current thread.
*
* @param input input object stream
* @param processorsFactory void processor factory
* @param threadCount number of parallel threads
* @param type of processed objects
* @throws InterruptedException
*/
public static void processAllInParallel(OutputPort input, VoidProcessorFactory super T> processorsFactory, int threadCount)
throws InterruptedException {
--threadCount;
Thread[] threads = new Thread[threadCount];
for (int i = 0; i < threadCount; ++i) {
threads[i] = new Thread(new SimpleVoidProcessorExecutor(input, processorsFactory.create()));
threads[i].start();
}
VoidProcessor super T> processor = processorsFactory.create();
T object;
while ((object = input.take()) != null)
processor.process(object);
for (int i = 0; i < threadCount; ++i)
threads[i].join();
}
/**
* Processes elements in N different threads. For each thread a separate processor is created by a provided
* factory. In this implementation threads are created by an ExecutorsService.
*
* @param input elements to process
* @param processorsFactory factory to createInputStream processors
* @param threadCount count of parallel processing threads
* @param executorService service to execute this task (thread pool)
* @param type of processed objects
*/
public static void processAllInParallel(OutputPort input, VoidProcessorFactory super T> processorsFactory, int threadCount,
ExecutorService executorService) throws InterruptedException {
--threadCount;
Future>[] futures = new Future[threadCount];
for (int i = 0; i < threadCount; ++i)
futures[i] = executorService.submit(new SimpleVoidProcessorExecutor<>(input, processorsFactory.create()));
VoidProcessor super T> processor = processorsFactory.create();
T object;
while ((object = input.take()) != null)
processor.process(object);
try {
for (int i = 0; i < threadCount; ++i)
futures[i].get();
} catch (ExecutionException ex) {
throw (RuntimeException) ex.getCause();
}
}
public static OutputPort asOutputPort(Iterable iterable) {
final Iterator iterator = iterable.iterator();
return new OutputPort() {
@Override
public synchronized T take() {
if (iterator.hasNext())
return iterator.next();
else
return null;
}
};
}
public static OutputPort asUnsafeOutputPort(Iterable iterable) {
final Iterator iterator = iterable.iterator();
return new OutputPort() {
@Override
public T take() {
if (iterator.hasNext())
return iterator.next();
else
return null;
}
};
}
public static OutputPort> chunked(final OutputPortCloseable input, final int chunkSize) {
return new OutputPortCloseable>() {
@Override
public void close() {
input.close();
}
@Override
public Chunk take() {
return Chunk.readChunk(input, chunkSize);
}
};
}
public static OutputPort> chunked(final OutputPort input, final int chunkSize) {
if (input instanceof OutputPortCloseable)
return chunked((OutputPortCloseable) input, chunkSize);
else
return new OutputPort>() {
@Override
public Chunk take() {
return Chunk.readChunk(input, chunkSize);
}
};
}
public static OutputPortCloseable unchunked(OutputPort> chunkedPort) {
return new UnChunkingPort<>(chunkedPort);
}
public static Processor, Chunk> chunked(final Processor processor) {
return new Processor, Chunk>() {
@Override
public Chunk process(Chunk input) {
Object[] buffer = new Object[input.size()];
for (int i = 0; i < input.size(); ++i)
buffer[i] = processor.process(input.get(i));
return new Chunk<>(buffer);
}
};
}
public static VoidProcessor> chunked(final VoidProcessor processor) {
return new VoidProcessor>() {
@Override
public void process(Chunk input) {
for (I i : input)
processor.process(i);
}
};
}
public static Merger buffered(OutputPort input, int bufferSize) {
Merger merger = new Merger<>(bufferSize);
merger.merge(input);
merger.start();
return merger;
}
public static Merger buffered(OutputPort input, int bufferSize, ExecutorService executorService) {
Merger merger = new Merger<>(bufferSize);
merger.merge(input, executorService);
merger.start();
return merger;
}
public static OutputPort asOutputPort(T... array) {
return asOutputPort(Arrays.asList(array));
}
public static OutputPort asOutputPort(final List list) {
return new OutputPort() {
final AtomicInteger counter = new AtomicInteger();
@Override
public T take() {
int index = counter.getAndIncrement();
if (index >= list.size())
return null;
return list.get(index);
}
};
}
public static Iterable it(final OutputPort input) {
return new Iterable() {
@Override
public Iterator iterator() {
return new OPIterator<>(input);
}
};
}
public static class OPIterator implements Iterator {
protected final OutputPort op;
T next = null;
public OPIterator(OutputPort op) {
this.op = op;
}
@Override
public boolean hasNext() {
if (next != null)
return true;
else
return (next = op.take()) != null;
}
@Override
public T next() {
T n = next;
next = null;
return n;
}
@Override
public void remove() {
throw new IllegalStateException("Not supported.");
}
}
private static final class UnChunkingPort implements OutputPortCloseable {
final OutputPort> innerPort;
final AtomicReference> currentChunk = new AtomicReference();
private UnChunkingPort(OutputPort> innerPort) {
this.innerPort = innerPort;
}
@Override
public void close() {
if (innerPort instanceof OutputPortCloseable)
((OutputPortCloseable) innerPort).close();
}
@Override
public T take() {
ChunkHolder holder = currentChunk.get();
T element;
while (holder == null || (element = holder.take()) == null) {
// Current holder is empty
// Checking if this holder is final in the sequence
if (holder != null && holder.isFinal())
// End of sequence
return null;
// Creating new holder
ChunkHolder newHolder = new ChunkHolder<>();
// Trying to acquire reference to holder
if (currentChunk.compareAndSet(holder, newHolder)) {
// Reference to holder successfully acquired
// Initializing holder (this call also supports null as input)
newHolder.set(innerPort.take());
holder = newHolder;
} else
// Somebody already acquired reference to holder
// Getting this reference
holder = currentChunk.get();
}
return element;
}
}
private static final class ChunkHolder implements OutputPort {
private volatile OutputPort chunkPort;
private OutputPort getPort() {
// Spin-loop
while (chunkPort == null) ;
return chunkPort;
}
@Override
public T take() {
return getPort().take();
}
public boolean isFinal() {
return getPort() == EMPTY_OUTPUT_PORT;
}
public void set(Chunk value) {
if (value == null)
chunkPort = EMPTY_OUTPUT_PORT;
else
chunkPort = value.outputPort();
}
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/InputPort.java 0000644 0000000 0000000 00000002642 13353377423 025614 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe;
/**
* Base interface for passive object consumer.
*
* @param type of consumed objects
* @author Bolotin Dmitriy (bolotin.dmitriy@gmail.com)
*/
public interface InputPort {
/**
* Put an element into this input port.
*
*
Putting of {@code null} is allowed only once and this indicates that the port should be closed. No
* invocations of this method allowed for closed input port.
*
* @param object object to put into this input port, or {@code null} if port should be closed
* @throws InterruptedException
*/
void put(T object);
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/OutputPort.java 0000644 0000000 0000000 00000002376 13353377423 026021 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe;
/**
* Base interface for passive object producer.
*
* @param type of produced objects
* @author Bolotin Dmitriy (bolotin.dmitriy@gmail.com)
* @see cc.redberry.pipe.blocks.AbstractOutputPort
*/
public interface OutputPort {
/**
* Returns next element from this output port, or {@code null} if port is closed.
*
* @return next element from this output port, or {@code null} if port is closed
*/
T take();
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/OutputPortCloseable.java 0000644 0000000 0000000 00000002723 13353377423 027627 0 ustar 0000000 0000000 package cc.redberry.pipe;
/**
* This interface should be implemented along with the {@link OutputPort} interface to indicate that current output port
* should be closed (by invoking {@link #close()} method) after downstream consumer (e.g. {@link
* cc.redberry.pipe.blocks.Merger}) is closed. All standard blocks will automatically and thread-safe (the latter will
* be applied only if output port is not marked as thread-safe using {@link ThreadSafe}) close current output port after
* their own job is finished.
*
* Don't use this method to indicate that {@link InputPort} should be closed, because all input ports are by default
* closable, and will be closed by putting null into them.
*/
public interface OutputPortCloseable extends AutoCloseable, OutputPort {
/**
* Close current output port and frees all resources used by it (threads, file streams, etc...).
*
*
Contract for implementation:
*
*
The implementation of this method must not throw an exceptions if port is already closed.
*
*
*
*
If the implementation of this method does not fulfill this contract, than methods {@link
* cc.redberry.pipe.blocks.Merger#close()}, {@link cc.redberry.pipe.blocks.ParallelProcessor#close()}, etc... will
* have an unpredictable behavior.
*
*
Use {@link cc.redberry.pipe.blocks.AbstractOutputPort} for proper synchronization.
*/
@Override
void close();
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/PInterruptedException.java 0000644 0000000 0000000 00000000626 13353377423 030154 0 ustar 0000000 0000000 package cc.redberry.pipe;
public class PInterruptedException extends RuntimeException {
public PInterruptedException(Throwable cause) {
super(cause);
}
public PInterruptedException(String message, Throwable cause) {
super(message, cause);
}
public PInterruptedException(String message) {
super(message);
}
public PInterruptedException() {
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/Processor.java 0000644 0000000 0000000 00000002212 13353377423 025620 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe;
/**
* Interface for processor which produces a single output object from a single input object.
*
* @param type of consumed object
* @param type of produced object
* @author Bolotin Dmitriy (bolotin.dmitriy@gmail.com)
*/
public interface Processor {
OutputT process(InputT input);
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/ProcessorFactory.java 0000644 0000000 0000000 00000002204 13353377423 027151 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe;
/**
* {@link Processor} factory.
*
* @param type of consumed object of processor
* @param type of produced object of processor
* @author Bolotin Dmitriy (bolotin.dmitriy@gmail.com)
* @see Processor
*/
public interface ProcessorFactory {
Processor create();
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/VoidProcessor.java 0000644 0000000 0000000 00000002013 13353377423 026441 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe;
/**
* Interface for processor without output.
*
* @param
* @author Bolotin Dmitriy (bolotin.dmitriy@gmail.com)
*/
public interface VoidProcessor {
void process(InputT input);
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/VoidProcessorFactory.java 0000644 0000000 0000000 00000001776 13353377423 030010 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe;
/**
* Factory for {@link VoidProcessor}.
*
* @author Bolotin Dmitriy (bolotin.dmitriy@gmail.com)
*/
public interface VoidProcessorFactory {
VoidProcessor create();
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/blocks/Buffer.java 0000644 0000000 0000000 00000021202 13353377423 026327 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.blocks;
import cc.redberry.pipe.InputPort;
import cc.redberry.pipe.OutputPort;
import cc.redberry.pipe.PInterruptedException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* Fixed size FIFO buffer that concatenates data streams from several created (by {@link #createInputPort()} method)
* input ports and acting as a single output port.
*
*
Code is adapted from {@link java.util.concurrent.ArrayBlockingQueue}.
*
* @param type of objects to route
* @author Bolotin Dmitriy
* @author Mikhail Shugay
*/
public final class Buffer implements OutputPort, BufferStatusProvider {
public static final int DEFAULT_SIZE = 512;
/**
* The queued items
*/
final Object[] items;
/**
* Collection to store created input ports
*/
final List inputPorts = new ArrayList<>();
/**
* Main lock guarding all access
*/
final ReentrantLock lock;
/**
* Condition for waiting - take
*/
private final Condition notEmpty;
/**
* Condition for waiting - put
*/
private final Condition notFull;
/**
* Condition for waitClosed
*/
private final Condition closedCondition;
/**
* Buffer state counters
*/
private long putCount, takeCount;
/*
* Concurrency control uses the classic double-condition algorithm
* found in any textbook.
*/
/**
* Is this port closed
*/
boolean closed;
/**
* Index of item for next take, pull, peek or remove
*/
int takeIndex;
/**
* Index of item for next put, offer, or add
*/
int putIndex;
/**
* Number of elements in the queue
*/
int count;
/**
* Creates a {@code Buffer} with default size.
*/
public Buffer() {
this(DEFAULT_SIZE);
}
/**
* Creates a {@code Buffer} with the given (fixed) size.
*
* @param size the size of this queue
* @throws IllegalArgumentException if {@code size < 1}
*/
public Buffer(int size) {
this(size, false);
}
/**
* Creates a {@code Buffer} with the given (fixed) size and the specified access policy.
*
* @param size the size of this queue
* @param fair if {@code true} then queue accesses for threads blocked on insertion or removal are processed in FIFO
* order; the access order is unspecified otherwise
* @throws IllegalArgumentException if {@code size < 1}
*/
public Buffer(int size, boolean fair) {
if (size <= 0)
throw new IllegalArgumentException();
this.items = new Object[size];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
closedCondition = lock.newCondition();
}
// Internal helper methods
@SuppressWarnings("unchecked")
static E cast(Object item) {
return (E) item;
}
/**
* Inserts the specified element at the tail of this queue, waiting for space to become available if the queue is
* full. Invoked only through {@link Buffer.BufferInputPort} instances.
*/
private void put(E e) {
final ReentrantLock lock = this.lock;
try {
lock.lockInterruptibly();
try {
while (count == items.length && !closed)
notFull.await();
if (closed)
return; //If buffer is closed drop input object
insert(e);
} finally {
lock.unlock();
}
} catch (InterruptedException ie) {
throw new PInterruptedException(ie);
}
}
/**
* Take first object that was put through some of input ports owned by this buffer.
*
* @return {@inheritDoc}
* @throws InterruptedException
*/
@Override
public E take() {
if (inputPorts.isEmpty())
throw new IllegalStateException("No input ports created for this Buffer.");
final ReentrantLock lock = this.lock;
try {
lock.lockInterruptibly();
try {
while (count == 0 && !closed)
notEmpty.await();
if (closed && count == 0)
return null;
return extract();
} finally {
lock.unlock();
}
} catch (InterruptedException ie) {
throw new PInterruptedException(ie);
}
}
/**
* Closes current buffer.
*
*
Any objects putted to this buffer through {@link InputPort#put(Object)} method of owned input ports will be
* dropped and will never reach the output.
*/
public void close() {
lock.lock();
try {
closed = true;
notFull.signalAll();
notEmpty.signalAll();
closedCondition.signalAll();
} finally {
lock.unlock();
}
}
/**
* Creates new input port to put elements to this buffer. Buffer will be closed after all created input ports are
* closed.
*
* @return new InputPort for this buffer
*/
public InputPort createInputPort() {
BufferInputPort port = new BufferInputPort();
inputPorts.add(port);
return port;
}
/**
* This method will return after this buffer is closed.
*
* @throws InterruptedException
*/
public void waitClosed() throws InterruptedException {
lock.lock();
try {
while (!closed)
closedCondition.await();
} finally {
lock.unlock();
}
}
@Override
public BufferStatus getStatus() {
lock.lock();
try {
return new BufferStatus(closed, items.length, putCount, takeCount);
} finally {
lock.unlock();
}
}
//Helper methods
/**
* Invoked on each input port closing event. Tests whether each input port is closed, and if so closes the buffer.
*/
private void testClosed() {
lock.lock();
try {
if (closed)
return;
for (BufferInputPort port : inputPorts)
if (!port.currentPortClosed.get())
return;
closed = true;
notEmpty.signalAll();
closedCondition.signalAll();
} finally {
lock.unlock();
}
}
/**
* Circularly increment i.
*/
final int inc(int i) {
return (++i == items.length) ? 0 : i;
}
/**
* Inserts element at current put position, advances, and signals. Call only when holding lock.
*/
private void insert(E x) {
items[putIndex] = x;
putIndex = inc(putIndex);
++count;
notEmpty.signal();
++putCount;
}
/**
* Extracts element at current take position, advances, and signals. Call only when holding lock.
*/
private E extract() {
final Object[] items = this.items;
E x = this.cast(items[takeIndex]);
items[takeIndex] = null;
takeIndex = inc(takeIndex);
--count;
notFull.signal();
++takeCount;
return x;
}
/**
* Implementation of InputPort for buffer.
*/
private class BufferInputPort implements InputPort {
AtomicBoolean currentPortClosed = new AtomicBoolean(false);
public void put(E object) {
if (object == null) {
if (!currentPortClosed.compareAndSet(false, true))
throw new IllegalArgumentException("Worker is already closed.");
testClosed();
return;
}
Buffer.this.put(object);
}
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/blocks/BufferStatus.java 0000644 0000000 0000000 00000005723 13353377423 027545 0 ustar 0000000 0000000 package cc.redberry.pipe.blocks;
import java.util.Objects;
/**
* Buffer status snapshot.
*/
public final class BufferStatus {
/**
* Is buffer closed (no more elements will be added by upstream process, it may still contain some elements to be
* consumed by downstream process)
*/
public final boolean closed;
/**
* Current buffer capacity (maximal number of objects it can hold)
*/
public final int capacity;
/**
* Number of objects added to the buffer by upstream process(es)
*/
public final long putCount;
/**
* Number of objects taken from the buffer bu downstream process(es)
*/
public final long takeCount;
/**
* Value of System.currentTimeMillis() for the moment of object creation
*/
public final long timestamp;
public BufferStatus(boolean closed, int capacity, long putCount, long takeCount) {
this(closed, capacity, putCount, takeCount, System.currentTimeMillis());
}
public BufferStatus(boolean closed, int capacity, long putCount, long takeCount, long timestamp) {
if (putCount < takeCount)
throw new IllegalArgumentException();
if (putCount - takeCount > capacity)
throw new IllegalArgumentException();
this.closed = closed;
this.capacity = capacity;
this.putCount = putCount;
this.takeCount = takeCount;
this.timestamp = timestamp;
}
/**
* Returns buffer size (current number of elements in the buffer).
*
* size = putCount - takeCount
*
* @return buffer size
*/
public int size() {
return (int) (putCount - takeCount);
}
/**
* Returns buffer fullness: double value from 1.0 to 0.0, 1.0 - for completely full buffer, 0.0 for empty buffer.
*
* fullness = size() / capacity
*
* @return buffer fullness
*/
public double fullness() {
return 1.0 * size() / capacity;
}
/**
* Returns true if this buffer is closed and contain no elements
*/
public boolean isClosedAndEmpty() {
return size() == 0 && closed;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BufferStatus)) return false;
BufferStatus that = (BufferStatus) o;
return closed == that.closed &&
capacity == that.capacity &&
putCount == that.putCount &&
takeCount == that.takeCount &&
timestamp == that.timestamp;
}
@Override
public int hashCode() {
return Objects.hash(closed, capacity, putCount, takeCount, timestamp);
}
@Override
public String toString() {
return "BufferStatus{" +
"closed=" + closed +
", capacity=" + capacity +
", putCount=" + putCount +
", takeCount=" + takeCount +
", timestamp=" + timestamp +
'}';
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/blocks/BufferStatusProvider.java 0000644 0000000 0000000 00000000446 13353377423 031255 0 ustar 0000000 0000000 package cc.redberry.pipe.blocks;
/**
* Interface for the object that can report buffer status (fullness and total number of objects being transferred)
*/
public interface BufferStatusProvider {
/**
* Returns snapshot of current buffer status
*/
BufferStatus getStatus();
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/blocks/CCUtils.java 0000644 0000000 0000000 00000002434 13353377423 026432 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.blocks;
import cc.redberry.pipe.Processor;
import cc.redberry.pipe.ProcessorFactory;
/**
* Inner utility methods.
*/
final class CCUtils {
private CCUtils() {
}
static Processor[] createArray(ProcessorFactory factory, int size) {
Processor[] result = new Processor[size];
for (int i = 0; i < size; ++i)
result[i] = factory.create();
return result;
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/blocks/FilteringPort.java 0000644 0000000 0000000 00000006110 13353377423 027707 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.blocks;
import cc.redberry.pipe.InputPort;
import cc.redberry.pipe.OutputPort;
import cc.redberry.pipe.OutputPortCloseable;
import cc.redberry.primitives.Filter;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Filtering OutputPort wrapper. Propagates only elements accepted by filter.
*
* @param type of filtered objects
* @author Bolotin Dmitriy (bolotin.dmitriy@gmail.com)
*/
public final class FilteringPort implements OutputPortCloseable {
private final OutputPort port;
private final Filter super T> filter;
private final AtomicInteger accepted = new AtomicInteger(0);
private final AtomicInteger rejected = new AtomicInteger(0);
private InputPort discardedPort;
/**
* Creates filtering port.
*
* @param port input object stream
* @param filter filter
*/
public FilteringPort(OutputPort port, Filter super T> filter) {
this(port, filter, null);
}
/**
* Creates filtering port.
*
* @param port input object stream
* @param filter filter
* @param discardedPort input port to put rejected objects of {@code null}
*/
public FilteringPort(OutputPort port, Filter super T> filter, InputPort discardedPort) {
if (port == null || filter == null)
throw new NullPointerException();
this.port = port;
this.filter = filter;
this.discardedPort = discardedPort;
}
@Override
public T take() {
T o;
while ((o = port.take()) != null && !filter.accept(o)) {
if (o != null && discardedPort != null)
discardedPort.put(o);
rejected.incrementAndGet();
}
if (o != null)
accepted.incrementAndGet();
return o;
}
public void attachDiscardPort(InputPort discardedPort) {
this.discardedPort = discardedPort;
}
public int getAcceptedCount() {
return accepted.get();
}
public int getRejectedCount() {
return rejected.get();
}
public int getTotalCount() {
return accepted.get() + rejected.get();
}
@Override
public void close() {
if (port instanceof OutputPortCloseable)
((OutputPortCloseable) port).close();
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/blocks/InputOutputPair.java 0000644 0000000 0000000 00000000706 13353377423 030260 0 ustar 0000000 0000000 package cc.redberry.pipe.blocks;
/**
* Tuple storing input value passed to {@link cc.redberry.pipe.Processor} and result it has produced.
*
* @param input type
* @param output type
*/
public final class InputOutputPair {
public final InputT input;
public final OutputT result;
public InputOutputPair(InputT input, OutputT result) {
this.input = input;
this.result = result;
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/blocks/Merger.java 0000644 0000000 0000000 00000016020 13353377423 026341 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.blocks;
import cc.redberry.pipe.InputPort;
import cc.redberry.pipe.OutputPort;
import cc.redberry.pipe.OutputPortCloseable;
import cc.redberry.pipe.util.ExceptionHandler;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Merges data streams form several output ports.
*
*
It starts a new thread for each attached output port to pull data from it and place it into output buffer.
*
* @param type of merged stream objects
* @author Bolotin Dmitriy
* @author Mikhail Shugay
*/
// TODO better implementation possible, with only one thread
public final class Merger implements OutputPortCloseable {
final Buffer buffer;
final List> inputPorts = new ArrayList<>();
final List> futures = new ArrayList<>();
final List threads = new ArrayList<>();
final List transmitters = new ArrayList<>();
private final ExceptionHandler exceptionsHandler = new ExceptionHandler() {
@Override
public void handle(RuntimeException exception, O2ITransmitter source) {
if (thrown == null)
thrown = exception;
close();
}
};
private final AtomicBoolean closed = new AtomicBoolean(false);
List targetExecutors = new ArrayList<>();
private boolean failSafe = false;
private volatile RuntimeException thrown = null;
/**
* Creates merger with default output buffer size.
*/
public Merger() {
this(Buffer.DEFAULT_SIZE);
}
/**
* Creates merger with defined output buffer size.
*
* @param bufferSize size of output buffer
*/
public Merger(int bufferSize) {
this.buffer = new Buffer<>(bufferSize);
}
public void setFailSafe(boolean failSafe) {
this.failSafe = failSafe;
}
/**
* Attache output port to merger.
*
*
Each port will be processed in individual thread, so no concurrent calls to {@link
* cc.redberry.pipe.OutputPort#take()} will be performed.
*
* @param port port to be served
* @param executorService executor service that should be used to create new thread to serve provided output port
*/
public void merge(OutputPort port, ExecutorService executorService) {
if (targetExecutors == null)
throw new RuntimeException("This merger is already started.");
inputPorts.add(port);
targetExecutors.add(executorService);
}
/**
* Attache output port to merger.
*
*
Each port will be processed in individual thread, so no concurrent calls to {@link
* cc.redberry.pipe.OutputPort#take()} will be performed.
*
* @param port port to be served
*/
public void merge(OutputPort port) {
if (targetExecutors == null)
throw new RuntimeException("This merger is already started.");
inputPorts.add(port);
targetExecutors.add(null);
}
/**
* Starts threads for current merger
*/
public synchronized void start() {
if (targetExecutors == null)
throw new RuntimeException("This merger is already started.");
ExecutorService service;
OutputPort extends E> port;
O2ITransmitter task;
int i;
InputPort[] iPorts = new InputPort[inputPorts.size()];
for (i = 0; i < inputPorts.size(); ++i)
iPorts[i] = buffer.createInputPort();
for (i = 0; i < inputPorts.size(); ++i) {
service = targetExecutors.get(i);
port = inputPorts.get(i);
transmitters.add(task = new O2ITransmitter<>(port, iPorts[i], exceptionsHandler));
if (service == null) {
Thread thread = new Thread(task);
threads.add(thread);
thread.start();
} else
futures.add(service.submit(task));
}
targetExecutors = null;
}
/**
* Join all threads owned by this buffer.
*
* @throws RuntimeException if some of {@link cc.redberry.pipe.OutputPort#take()} thrown som exception
* @throws InterruptedException
*/
public void join() throws InterruptedException {
try {
for (Future> future : futures)
future.get();
} catch (ExecutionException ee) {
throw new RuntimeException("This expression should not be thrown.", ee);
}
for (Thread thread : threads)
thread.join();
if (Thread.interrupted())
throw new InterruptedException();
}
/**
* Take object from output buffer
*
* @return {@inheritDoc}
* @throws InterruptedException
*/
@Override
public E take() {
E result = buffer.take();
// Checking whether some processor has thrown an exception if buffer is closed
if (result == null) {
if (thrown != null)
synchronized (this) {
if (thrown != null) {
RuntimeException e = thrown;
thrown = null;
throw e;
}
}
return null;
}
return result;
}
/**
* Stops current merger.
*
*
This method propagates close signal to upstream (input) output port.
*/
@Override
public void close() {
if (!closed.compareAndSet(false, true))
return;
for (OutputPort extends E> input : inputPorts)
if (input instanceof OutputPortCloseable)
((OutputPortCloseable) input).close();
for (O2ITransmitter tasks : transmitters)
tasks.stop();
if (!failSafe)
buffer.close();
}
/**
* Returns output buffer status provider to monitor its fullness and other characteristics.
*/
public BufferStatusProvider getBufferStatusProvider() {
return buffer;
}
@Override
public String toString() {
return buffer.toString();
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/blocks/O2ITransmitter.java 0000644 0000000 0000000 00000004525 13353377423 027755 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.blocks;
import cc.redberry.pipe.InputPort;
import cc.redberry.pipe.OutputPort;
import cc.redberry.pipe.PInterruptedException;
import cc.redberry.pipe.util.ExceptionHandler;
/**
* Output to input transmitter.
*
* @param type of transmitted objects
* @author Bolotin Dmitriy
* @author Mikhail Shugay
*/
public final class O2ITransmitter implements Runnable {
public final ExceptionHandler handler;
public final OutputPort extends T> oPort;
public final InputPort iPort;
public volatile boolean stopped = false;
public O2ITransmitter(OutputPort extends T> output, InputPort input,
ExceptionHandler exceptionHandler) {
this.handler = exceptionHandler;
this.oPort = output;
this.iPort = input;
}
public O2ITransmitter(OutputPort output, InputPort input) {
this(output, input, null);
}
public OutputPort extends T> getInput() {
return oPort;
}
public InputPort getOutput() {
return iPort;
}
public void stop() {
stopped = true;
}
@Override
public void run() {
try {
T element;
while (!stopped && (element = oPort.take()) != null)
iPort.put(element);
} catch (PInterruptedException ex) {
} catch (RuntimeException re) {
if (handler != null)
handler.handle(re, this);
} finally {
iPort.put(null); //close upstream input port any way
}
}
}
././@LongLink 0000000 0000000 0000000 00000000146 00000000000 011216 L ustar 0000000 0000000 redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/blocks/OutputPortSynchronizer.java redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/blocks/OutputPortSynchronizer.jav0000644 0000000 0000000 00000000312 13353377423 031537 0 ustar 0000000 0000000 package cc.redberry.pipe.blocks;
import cc.redberry.pipe.OutputPort;
public class OutputPortSynchronizer implements OutputPort {
@Override
public T take() {
return null;
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/blocks/ParallelProcessor.java 0000644 0000000 0000000 00000031341 13353377423 030557 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.blocks;
import cc.redberry.pipe.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicLong;
/**
* This class helps to process data from one OutputPort in N parallel threads, collecting results in one output buffer.
*
*
It could be used either to access one processor concurrently or N processors from their corresponding threads. See
* constructor descriptions for details.
*
* @param input type
* @param output type
* @author Bolotin Dmitriy
* @author Mikhail Shugay
*/
public final class ParallelProcessor implements OutputPortCloseable {
private static AtomicLong processorIdCounter = new AtomicLong(0);
private final Buffer outputBuffer;
private final Worker[] workers;
private final Thread[] threads;
private final Future>[] futures;
private final OutputPort input;
private volatile boolean closed = false, failSafe = false;
private volatile RuntimeException thrown = null;
/**
* Creates ParallelProcessor working in one thread per processor mode with default buffer size.
*
* @param input Worker to take elements from.
* @param factory Factory to createInputStream processors.
* @param threads Number of parallel threads for processing. Also it is the number of processors to
* createInputStream.
* @param executorService Executor service to create threads with.
*/
public ParallelProcessor(OutputPort input, ProcessorFactory factory, int threads,
ExecutorService executorService) {
this(input, CCUtils.createArray(factory, threads), Buffer.DEFAULT_SIZE, executorService);
}
/**
* Creates ParallelProcessor working in one thread per processor mode.
*
* @param input Worker to take elements from.
* @param factory Factory to createInputStream processors.
* @param bufferSize Buffer size.
* @param threads Number of parallel threads for processing. Also it is the number of processors to
* createInputStream.
* @param executorService Executor service to create threads with.
*/
public ParallelProcessor(OutputPort input, ProcessorFactory factory, int bufferSize, int threads,
ExecutorService executorService) {
this(input, CCUtils.createArray(factory, threads), bufferSize, executorService);
}
/**
* Creates ParallelProcessor working in one thread per processor mode.
*
* @param input Worker to take elements from.
* @param factory Factory to createInputStream processors.
* @param bufferSize Buffer size.
* @param threads Number of parallel threads of processing. Also it is the number of processors to
* createInputStream.
*/
public ParallelProcessor(OutputPort input, ProcessorFactory factory, int bufferSize, int threads) {
this(input, CCUtils.createArray(factory, threads), bufferSize);
}
/**
* Creates ParallelProcessor working in one thread per processor mode with default buffer size.
*
* @param input Worker to take elements from.
* @param factory Factory to createInputStream processors.
* @param threads Number of parallel threads of processing. Also it is the number of processors to
* createInputStream.
*/
public ParallelProcessor(OutputPort input, ProcessorFactory factory, int threads) {
this(input, CCUtils.createArray(factory, threads), Buffer.DEFAULT_SIZE);
}
/**
* Creates ParallelProcessor working in concurrent processor access mode.
*
* @param input Worker to take elements from.
* @param processor Processor. It will be accessed concurrently.
* @param bufferSize Buffer size.
* @param threads Number of parallel threads of processing.
*/
public ParallelProcessor(OutputPort input, Processor processor, int bufferSize, int threads) {
this(input, toArray(processor, threads), bufferSize);
}
/**
* Creates ParallelProcessor working in concurrent processor access mode with default buffer size.
*
* @param input Worker to take elements from.
* @param processor Processor. It will be accessed concurrently.
* @param threads Number of parallel threads of processing.
*/
public ParallelProcessor(OutputPort input, Processor processor, int threads) {
this(input, toArray(processor, threads), Buffer.DEFAULT_SIZE);
}
/**
* Creates ParallelProcessor working in concurrent processor access mode.
*
* @param input Worker to take elements from.
* @param processor Processor. It will be accessed concurrently.
* @param bufferSize Buffer size.
* @param threads Number of parallel threads of processing.
* @param executorService Executor service to create threads with.
*/
public ParallelProcessor(OutputPort input, Processor processor, int bufferSize, int threads,
ExecutorService executorService) {
this(input, toArray(processor, threads), bufferSize, executorService);
}
/**
* Creates ParallelProcessor working in one thread per processor mode.
*
* @param input Worker to take elements from.
* @param processors Processors. Each processor will be accessed only by one thread.
* @param bufferSize Buffer size.
*/
public ParallelProcessor(OutputPort input, Processor[] processors, int bufferSize) {
this.input = input;
this.outputBuffer = new Buffer<>(bufferSize);
this.workers = new ParallelProcessor.Worker[processors.length];
this.threads = new Thread[processors.length];
this.futures = null;
int i;
InputPort[] iPorts = new InputPort[processors.length];
for (i = 0; i < processors.length; ++i)
iPorts[i] = this.outputBuffer.createInputPort();
long id = processorIdCounter.incrementAndGet();
for (i = 0; i < processors.length; ++i) {
this.workers[i] = new Worker(iPorts[i], processors[i]);
this.threads[i] = new Thread(this.workers[i], "ParallelProcessor-" + id + "-" + i);
this.threads[i].start();
}
}
/**
* Creates ParallelProcessor working in one thread per processor mode.
*
* @param input Worker to take elements from.
* @param processors Processors. Each processor will be accessed only by one thread.
* @param bufferSize Buffer size.
* @param executorService Executor service to create threads with.
*/
public ParallelProcessor(OutputPort input, Processor[] processors, int bufferSize,
ExecutorService executorService) {
this.input = input;
this.outputBuffer = new Buffer<>(bufferSize);
this.workers = new ParallelProcessor.Worker[processors.length];
this.threads = null;
this.futures = new Future[processors.length];
int i;
InputPort[] iPorts = new InputPort[processors.length];
for (i = 0; i < processors.length; ++i)
iPorts[i] = this.outputBuffer.createInputPort();
for (i = 0; i < processors.length; ++i) {
this.workers[i] = new Worker(iPorts[i], processors[i]);
this.futures[i] = executorService.submit(this.workers[i]);
}
}
private static Processor[] toArray(Processor processor, int size) {
//if (size > 1
// && !(processor instanceof ThreadSafe))
// throw new IllegalArgumentException("Processor not marked as thread-safe. Use ThreadSafe interface to mark " +
// "thread-safe Processor implementations.");
Processor[] processors = new Processor[size];
for (int i = 0; i < size; ++i)
processors[i] = processor;
return processors;
}
public ParallelProcessor setFailSafe(boolean failSafe) {
this.failSafe = failSafe;
return this;
}
/**
* Join all threads owned by this parallel processor.
*
* @throws InterruptedException if this thread was interrupted
*/
public void join() throws InterruptedException {
if (futures == null)
for (Thread t : threads)
t.join();
else
try {
for (Future> future : futures)
future.get();
} catch (ExecutionException ee) {
throw new RuntimeException("This exception should not be thrown.", ee);
}
if (thrown != null)
throw new RuntimeException(thrown);
if (Thread.interrupted())
throw new InterruptedException();
}
/**
* Take first object that was processed so far from output buffer.
*
* @return {@inheritDoc}
*/
public OutputT take() {
OutputT result = outputBuffer.take();
// Checking whether some processor has thrown an exception if buffer is closed
if (result == null) {
if (thrown != null)
synchronized (this) {
if (thrown != null) {
RuntimeException re = thrown;
thrown = null;
throw re;
}
}
return null;
}
return result;
}
/**
* Returns output buffer status provider to monitor its fullness and other characteristics.
*/
public BufferStatusProvider getOutputBufferStatusProvider() {
return outputBuffer;
}
@Override
public String toString() {
return outputBuffer.toString();
}
/**
* Stops current processor.
*
*
Some elements taken from input may be dropped, and may never reach the output if {@code failSafe} flag is set
* to false.
*
*
This method propagates close signal to upstream (input) output port.
*/
@Override
public void close() {
closed = true;
if (input instanceof OutputPortCloseable)
((OutputPortCloseable) input).close();
if (!failSafe)
outputBuffer.close();
}
private class Worker implements Runnable {
private final InputPort toBuffer;
private final Processor processor;
private Worker(InputPort toBuffer, Processor processor) {
this.toBuffer = toBuffer;
this.processor = processor;
}
@Override
public void run() {
//For performance
final OutputPort input = ParallelProcessor.this.input;
try {
InputT inputValue;
OutputT outputValue;
while (!closed && (inputValue = input.take()) != null) {
outputValue = processor.process(inputValue);
toBuffer.put(outputValue);
if (Thread.interrupted()) //Just in case
return;
}
} catch (PInterruptedException in) {
} catch (RuntimeException re) {
if (thrown == null)
synchronized (ParallelProcessor.this) {
if (thrown == null)
thrown = re;
}
close(); //Close all!
} finally {
toBuffer.put(null); //close upstream input port in any case
}
}
}
}
././@LongLink 0000000 0000000 0000000 00000000150 00000000000 011211 L ustar 0000000 0000000 redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/blocks/ResultAttachingProcessor.java redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/blocks/ResultAttachingProcessor.j0000644 0000000 0000000 00000001525 13353377423 031435 0 ustar 0000000 0000000 package cc.redberry.pipe.blocks;
import cc.redberry.pipe.Processor;
/**
* {@link cc.redberry.pipe.Processor} wrapper used to save input value passed to the wrapped processor and attache it to
* the output.
*
* @author Bolotin Dmitriy
* @see InputOutputPair
*/
public class ResultAttachingProcessor implements Processor> {
private final Processor processor;
/**
* Use factory method.
*
* @param processor
*/
public ResultAttachingProcessor(Processor processor) {
this.processor = processor;
}
@Override
public final InputOutputPair process(InputT input) {
OutputT output = processor.process(input);
return new InputOutputPair(input, output);
}
}
././@LongLink 0000000 0000000 0000000 00000000157 00000000000 011220 L ustar 0000000 0000000 redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/blocks/ResultAttachingProcessorFactory.java redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/blocks/ResultAttachingProcessorFa0000644 0000000 0000000 00000001361 13353377423 031452 0 ustar 0000000 0000000 package cc.redberry.pipe.blocks;
import cc.redberry.pipe.Processor;
import cc.redberry.pipe.ProcessorFactory;
/**
* {@link cc.redberry.pipe.ProcessorFactory} wrapper to produce {@link ResultAttachingProcessor}.
*/
public final class ResultAttachingProcessorFactory implements ProcessorFactory> {
private final ProcessorFactory processorFactory;
public ResultAttachingProcessorFactory(ProcessorFactory processorFactory) {
this.processorFactory = processorFactory;
}
@Override
public Processor> create() {
return new ResultAttachingProcessor<>(processorFactory.create());
}
}
././@LongLink 0000000 0000000 0000000 00000000153 00000000000 011214 L ustar 0000000 0000000 redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/blocks/ThreadSafeOutputPortWrapper.java redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/blocks/ThreadSafeOutputPortWrappe0000644 0000000 0000000 00000000341 13353377423 031452 0 ustar 0000000 0000000 package cc.redberry.pipe.blocks;
/**
* Created with IntelliJ IDEA. User: dbolotin Date: 24.09.13 Time: 19:37 To change this template use File | Settings |
* File Templates.
*/
public class ThreadSafeOutputPortWrapper {
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/blocks/package-info.java 0000644 0000000 0000000 00000001601 13353377423 027443 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
/**
* Core building blocks for pipelines construction
*/
package cc.redberry.pipe.blocks; redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/package-info.java 0000644 0000000 0000000 00000001532 13353377423 026171 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
/**
* Core interfaces
*/
package cc.redberry.pipe; redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/Chunk.java 0000644 0000000 0000000 00000005167 13353377423 025702 0 ustar 0000000 0000000 package cc.redberry.pipe.util;
import cc.redberry.pipe.OutputPort;
import java.util.Arrays;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicInteger;
public final class Chunk implements Iterable {
final Object[] data;
final int size;
public Chunk(Object[] data, int size) {
this.data = data;
this.size = size;
}
public Chunk(Object[] data) {
this.data = data;
this.size = data.length;
}
public Object[] toArray() {
if (data.length == size)
return data;
else
return Arrays.copyOf(data, size);
}
@SuppressWarnings("unchecked")
public T get(int index) {
return (T) data[index];
}
public int size() {
return size;
}
@Override
public Iterator iterator() {
return new It();
}
public OutputPort outputPort() {
return new Op();
}
/**
* Reads a chunk from input port.
*
*
Normally returns chunk with {@code size == chunkSize}. Or chunk with {@code size < chunkSize} if there are no
* elements left in port after this operation or {@code null} if there are no elements in port.
*
* @param port output port to read from
* @param chunkSize desired chunk size
* @return returns chunk with {@code size == chunkSize}, or chunk with {@code size < chunkSize} if there are no
* elements left in port after this operation, or {@code null} if there are no elements in port
*/
public static Chunk readChunk(OutputPort port, int chunkSize) {
Object[] buffer = new Object[chunkSize];
int size = 0;
for (; size < chunkSize; ++size) {
Object element = port.take();
if (element == null)
break;
buffer[size] = element;
}
if (size == 0)
return null;
return new Chunk<>(buffer, size);
}
private final class It implements Iterator {
int pointer = 0;
@Override
public boolean hasNext() {
return pointer < size;
}
@Override
public T next() {
return get(pointer++);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
private final class Op implements OutputPort {
final AtomicInteger pointer = new AtomicInteger();
@Override
public T take() {
int index = pointer.getAndIncrement();
if (index >= size)
return null;
return get(index);
}
}
}
././@LongLink 0000000 0000000 0000000 00000000155 00000000000 011216 L ustar 0000000 0000000 redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/ClosePreventingInputPortWrapper.java redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/ClosePreventingInputPortWrap0000644 0000000 0000000 00000003241 13353377423 031527 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.util;
import cc.redberry.pipe.InputPort;
/**
* This class prevents putting null to the nested input port.
*
*
To close nested port use {@code close()} method.
*
* @param type of port
*/
public class ClosePreventingInputPortWrapper implements InputPort {
private final InputPort innerInputPort;
public ClosePreventingInputPortWrapper(InputPort innerInputPort) {
if (innerInputPort == null)
throw new NullPointerException();
this.innerInputPort = innerInputPort;
}
@Override
public void put(T object) {
if (object != null)
innerInputPort.put(object);
}
/**
* Use this method to close (put null) inner port.
*
* @throws InterruptedException
*/
public void close() throws InterruptedException {
innerInputPort.put(null);
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/CountLimitingOutputPort.java0000644 0000000 0000000 00000004673 13353377423 031506 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.util;
import cc.redberry.pipe.OutputPort;
import cc.redberry.pipe.OutputPortCloseable;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
public class CountLimitingOutputPort implements OutputPortCloseable {
private final OutputPort innerPort;
private final long limit;
private final AtomicLong count;
private final AtomicBoolean finished = new AtomicBoolean(false);
public CountLimitingOutputPort(OutputPort innerPort, long limit) {
if (innerPort == null)
throw new NullPointerException();
this.innerPort = innerPort;
this.limit = limit;
this.count = new AtomicLong(-limit);
}
public long getLimit() {
return limit;
}
public long getElementsLeft() {
long left = count.get();
if (left > 0)
return 0;
return -left;
}
public boolean isClosed() {
return finished.get();
}
@Override
public T take() {
if (finished.get())
return null;
long index = count.incrementAndGet();
if (index > 0) {
if (finished.compareAndSet(false, true))
if (innerPort instanceof OutputPortCloseable)
((OutputPortCloseable) innerPort).close();
return null;
}
T value = innerPort.take();
if (value == null)
finished.set(true);
return value;
}
@Override
public void close() {
finished.set(true);
if (innerPort instanceof OutputPortCloseable)
((OutputPortCloseable) innerPort).close();
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/CountingInputPort.java 0000644 0000000 0000000 00000002614 13353377423 030277 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.util;
import cc.redberry.pipe.InputPort;
import java.util.concurrent.atomic.AtomicInteger;
public final class CountingInputPort implements InputPort {
private final AtomicInteger counter = new AtomicInteger();
private final InputPort inherited;
public CountingInputPort() {
this.inherited = null;
}
public CountingInputPort(InputPort inherited) {
this.inherited = inherited;
}
@Override
public void put(T object) {
counter.incrementAndGet();
if (inherited != null)
inherited.put(object);
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/CountingOutputPort.java 0000644 0000000 0000000 00000004302 13353377423 030474 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.util;
import cc.redberry.pipe.OutputPort;
import cc.redberry.pipe.OutputPortCloseable;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
/**
* Counting wrapper for {@link OutputPort}.
*
* @author Bolotin Dmitriy
*/
public class CountingOutputPort implements OutputPortCloseable {
private final OutputPort innerOutputPort;
private final AtomicBoolean closed = new AtomicBoolean(false);
private final AtomicLong counter = new AtomicLong();
public CountingOutputPort(OutputPort innerOutputPort) {
this.innerOutputPort = innerOutputPort;
}
@Override
public T take() {
if (closed.get())
return null;
T value = innerOutputPort.take();
if (value != null)
counter.incrementAndGet();
else
closed.set(true);
return value;
}
/**
* Returns the count of object passed through this port.
*/
public long getCount() {
return counter.get();
}
public boolean isClosed() {
return closed.get();
}
@Override
public String toString() {
return Integer.toString(counter.intValue());
}
@Override
public void close() {
if (innerOutputPort instanceof OutputPortCloseable)
((OutputPortCloseable) innerOutputPort).close();
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/DummyInputPort.java 0000644 0000000 0000000 00000002107 13353377423 027601 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.util;
import cc.redberry.pipe.InputPort;
public class DummyInputPort implements InputPort {
public final static DummyInputPort INSTANCE = new DummyInputPort();
private DummyInputPort() {
}
@Override
public void put(T object) {
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/ExceptionHandler.java 0000644 0000000 0000000 00000002441 13353377423 030056 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.util;
/**
* Interface to handle exceptions thrown by {@link cc.redberry.pipe.OutputPort#take()}, {@link
* cc.redberry.pipe.Processor#process(Object)} and {@link cc.redberry.pipe.VoidProcessor#process(Object)} methods in
* threads created by framework infrastructure..
*/
public interface ExceptionHandler {
/**
* Executed from execution threads.
*
* @param exception thrown exception
*/
public void handle(RuntimeException exception, S source);
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/FlatteningOutputPort.java 0000644 0000000 0000000 00000002155 13353377423 031005 0 ustar 0000000 0000000 package cc.redberry.pipe.util;
import cc.redberry.pipe.OutputPortCloseable;
import cc.redberry.pipe.OutputPort;
//TODO much better implementation is possible
public class FlatteningOutputPort implements OutputPortCloseable {
private OutputPort extends OutputPort extends T>> opop;
private OutputPort extends T> op;
public FlatteningOutputPort(OutputPort extends OutputPort extends T>> opop) {
this.opop = opop;
}
@Override
public synchronized T take() {
T result;
//First invocation
if (op == null)
op = opop.take();
do {
if (op == null)
return null;
result = op.take();
if (result == null)
op = opop.take();
} while (result == null);
return result;
}
@Override
public synchronized void close() {
if (opop instanceof OutputPortCloseable)
((OutputPortCloseable) opop).close();
if (op != null && op instanceof OutputPortCloseable)
((OutputPortCloseable) op).close();
opop = null;
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/Indexer.java 0000644 0000000 0000000 00000000135 13353377423 026216 0 ustar 0000000 0000000 package cc.redberry.pipe.util;
public interface Indexer {
long getIndex(T object);
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/InputPortBuffer.java 0000644 0000000 0000000 00000003741 13353377423 027724 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.util;
import cc.redberry.pipe.InputPort;
import cc.redberry.pipe.OutputPort;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Concurrent unlimited objects buffer based on ConcurrentLinkedQueue. It is a simple wrapper for
* ConcurrentLinkedQueue. For normal functioning all objects must be putted before first object can be taken.
*
* @param
* @author Bolotin Dmitriy (bolotin.dmitriy@gmail.com)
*/
public final class InputPortBuffer implements InputPort, OutputPort {
private final AtomicInteger elements = new AtomicInteger();
private final Queue queue;
public InputPortBuffer() {
queue = new ConcurrentLinkedQueue<>();
}
@Override
public void put(T object) {
if (object == null) //Do nothing on close
return;
elements.incrementAndGet();
queue.add(object);
}
@Override
public T take() {
T element;
if ((element = queue.poll()) != null)
elements.decrementAndGet();
return element;
}
public int size() {
return elements.get();
}
}
././@LongLink 0000000 0000000 0000000 00000000147 00000000000 011217 L ustar 0000000 0000000 redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/IteratorOutputPortAdapter.java redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/IteratorOutputPortAdapter.ja0000644 0000000 0000000 00000001152 13353377423 031451 0 ustar 0000000 0000000 package cc.redberry.pipe.util;
import cc.redberry.pipe.OutputPort;
import java.util.Iterator;
public class IteratorOutputPortAdapter implements OutputPort {
private Iterator iterator;
public IteratorOutputPortAdapter(Iterator iterator) {
this.iterator = iterator;
}
public IteratorOutputPortAdapter(Iterable iterable) {
this.iterator = iterable.iterator();
}
@Override
public synchronized T take() {
if (iterator == null)
return null;
if (!iterator.hasNext())
return null;
return iterator.next();
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/OrderedOutputPort.java 0000644 0000000 0000000 00000003356 13353377423 030302 0 ustar 0000000 0000000 package cc.redberry.pipe.util;
import cc.redberry.pipe.OutputPort;
import java.util.Comparator;
import java.util.TreeSet;
public final class OrderedOutputPort implements OutputPort {
private final OutputPort innerOutputPort;
private final Indexer super T> indexer;
private final TreeSet sortedSet;
private long nextIndex;
public OrderedOutputPort(OutputPort innerOutputPort, Indexer super T> indexer) {
this(innerOutputPort, indexer, 0);
}
public OrderedOutputPort(OutputPort innerOutputPort, Indexer super T> indexer, long startsFrom) {
this.innerOutputPort = innerOutputPort;
this.indexer = indexer;
this.sortedSet = new TreeSet<>(new IndexComparator<>(indexer));
this.nextIndex = startsFrom;
}
@Override
public T take() {
if (!sortedSet.isEmpty() && indexer.getIndex(sortedSet.first()) == nextIndex) {
++nextIndex;
return sortedSet.pollFirst();
}
T obj;
while ((obj = innerOutputPort.take()) != null) {
if (indexer.getIndex(obj) == nextIndex) {
++nextIndex;
return obj;
}
sortedSet.add(obj);
}
if (!sortedSet.isEmpty())
throw new IllegalStateException("Some elements left in buffer.");
return null;
}
private final static class IndexComparator implements Comparator {
private final Indexer super T> indexer;
private IndexComparator(Indexer super T> indexer) {
this.indexer = indexer;
}
@Override
public int compare(T o1, T o2) {
return Long.compare(indexer.getIndex(o1), indexer.getIndex(o2));
}
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/SimpleProcessorWrapper.java 0000644 0000000 0000000 00000003741 13353377423 031320 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.util;
import cc.redberry.pipe.OutputPort;
import cc.redberry.pipe.OutputPortCloseable;
import cc.redberry.pipe.Processor;
/**
* This class is used by {@link cc.redberry.pipe.CUtils#wrap(cc.redberry.pipe.OutputPort, cc.redberry.pipe.Processor)}
* method.
*
* @param type of consumed object
* @param type of produced object
* @author Bolotin Dmitriy (bolotin.dmitriy@gmail.com)
*/
public class SimpleProcessorWrapper implements OutputPortCloseable {
private final OutputPort extends InputT> innerPort;
private final Processor super InputT, ? extends OutputT> processor;
public SimpleProcessorWrapper(OutputPort extends InputT> innerPort, Processor super InputT, ? extends OutputT> processor) {
this.innerPort = innerPort;
this.processor = processor;
}
@Override
public OutputT take() {
InputT input = innerPort.take();
if (input == null)
return null;
return processor.process(input);
}
@Override
public void close() {
if (innerPort instanceof OutputPortCloseable)
((OutputPortCloseable) innerPort).close();
}
}
././@LongLink 0000000 0000000 0000000 00000000160 00000000000 011212 L ustar 0000000 0000000 redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/SimpleProcessorWrapperSynchronized.java redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/SimpleProcessorWrapperSynchr0000644 0000000 0000000 00000004134 13353377423 031564 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.util;
import cc.redberry.pipe.OutputPort;
import cc.redberry.pipe.OutputPortCloseable;
import cc.redberry.pipe.Processor;
/**
* This class is used by {@link cc.redberry.pipe.CUtils#wrap(cc.redberry.pipe.OutputPort, cc.redberry.pipe.Processor)}
* method.
*
* @param type of consumed object
* @param type of produced object
* @author Bolotin Dmitriy (bolotin.dmitriy@gmail.com)
*/
public class SimpleProcessorWrapperSynchronized implements OutputPortCloseable {
private final OutputPort extends InputT> innerPort;
private final Processor super InputT, ? extends OutputT> processor;
public SimpleProcessorWrapperSynchronized(OutputPort extends InputT> innerPort, Processor super InputT, ? extends OutputT> processor) {
this.innerPort = innerPort;
this.processor = processor;
}
@Override
public OutputT take() {
InputT input = innerPort.take();
if (input == null)
return null;
OutputT result;
synchronized (processor) {
result = processor.process(input);
}
return result;
}
@Override
public void close() {
if (innerPort instanceof OutputPortCloseable)
((OutputPortCloseable) innerPort).close();
}
}
././@LongLink 0000000 0000000 0000000 00000000151 00000000000 011212 L ustar 0000000 0000000 redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/SimpleVoidProcessorExecutor.java redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/SimpleVoidProcessorExecutor.0000644 0000000 0000000 00000002676 13353377423 031464 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.util;
import cc.redberry.pipe.OutputPort;
import cc.redberry.pipe.VoidProcessor;
/**
* @param
* @author Bolotin Dmitriy (bolotin.dmitriy@gmail.com)
*/
public class SimpleVoidProcessorExecutor implements Runnable {
private final OutputPort input;
private final VoidProcessor super T> processor;
public SimpleVoidProcessorExecutor(OutputPort input, VoidProcessor super T> processor) {
this.input = input;
this.processor = processor;
}
@Override
public void run() {
T object;
while ((object = input.take()) != null)
processor.process(object);
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/StatusReporter.java 0000644 0000000 0000000 00000012460 13353377423 027632 0 ustar 0000000 0000000 package cc.redberry.pipe.util;
import cc.redberry.pipe.blocks.BufferStatus;
import cc.redberry.pipe.blocks.BufferStatusProvider;
import java.io.IOException;
import java.io.OutputStream;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
* Universal periodic reporter
*/
public class StatusReporter extends Thread {
private static int FULLNESS_SLOTS = 20;
private static final DecimalFormat decFormat = new DecimalFormat("##.#");
final int reportPeriod;
final OutputStream outputStream;
final ArrayList buffers = new ArrayList<>();
public StatusReporter() {
this(5000);
}
public StatusReporter(int reportPeriod) {
this(reportPeriod, System.err);
}
/**
* @param reportPeriod report period in milliseconds
* @param outputStream stream to print report
*/
public StatusReporter(int reportPeriod, OutputStream outputStream) {
this.reportPeriod = reportPeriod;
this.outputStream = outputStream;
this.setDaemon(true);
}
public synchronized void addBuffer(String name, BufferStatusProvider buffer) {
buffers.add(new BufferHolder(name, buffer));
}
public synchronized void addCustomProvider(StatusProvider provider) {
buffers.add(provider);
}
public synchronized void addCustomProviderFromLambda(Supplier statusSupplier) {
buffers.add(new StatusProvider() {
volatile Status status;
@Override
public void updateStatus() {
status = statusSupplier.get();
}
@Override
public boolean isFinished() {
return status.isFinished;
}
@Override
public String getStatus() {
return status.status;
}
});
}
@Override
public void run() {
try {
while (true) {
synchronized (this) {
// Updating status
buffers.forEach(StatusProvider::updateStatus);
// Removing all closed and empty buffers
buffers.removeIf(StatusProvider::isFinished);
// Stopping reporting thread if there are no mre buffers
if (buffers.isEmpty())
break;
// Putting report to the stream
// In single transaction, hoping this will be printed as single chunk of information
outputStream.write(
("\n" + buffers.stream()
.map(StatusProvider::getStatus)
.collect(Collectors.joining("\n")) + "\n")
.getBytes());
// Sleep until next cycle
Thread.sleep(reportPeriod);
}
}
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
}
private final static class BufferHolder implements StatusProvider {
final String bufferName;
final BufferStatusProvider statusProvider;
BufferStatus currentStatus, previousStatus;
public BufferHolder(String bufferName, BufferStatusProvider statusProvider) {
this.bufferName = bufferName;
this.statusProvider = statusProvider;
}
@Override
public void updateStatus() {
previousStatus = currentStatus;
currentStatus = statusProvider.getStatus();
}
@Override
public boolean isFinished() {
return currentStatus.isClosedAndEmpty();
}
@Override
public String getStatus() {
if (currentStatus == null)
return "status unknown";
int fullnessBlocks = (int) (currentStatus.fullness() * FULLNESS_SLOTS);
String mainPart = bufferName + ": -" + (currentStatus.closed ? "X" : ">") + " [" +
new String(new char[fullnessBlocks]).replace("\0", "=") +
new String(new char[FULLNESS_SLOTS - fullnessBlocks]).replace("\0", " ") +
"] (" + currentStatus.size() + "/" + currentStatus.capacity + ") -> ";
if (previousStatus == null)
return mainPart;
return mainPart + decFormat.format((currentStatus.takeCount - previousStatus.takeCount) * 1000.0 /
(currentStatus.timestamp - previousStatus.timestamp)) + " ops/s";
}
}
public interface StatusProvider {
/**
* This method should get the information from underlying status source, and save it into internal state.
*/
void updateStatus();
/**
* No status reporting required for this item.
*
* If true returned it will be removed from the reporters list.
*/
boolean isFinished();
/**
* Return string status.
*/
String getStatus();
}
public static final class Status {
final String status;
final boolean isFinished;
public Status(String status, boolean isFinished) {
this.status = status;
this.isFinished = isFinished;
}
}
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/TBranchOutputPort.java 0000644 0000000 0000000 00000004513 13353377423 030233 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.util;
import cc.redberry.pipe.OutputPortCloseable;
import cc.redberry.pipe.InputPort;
import cc.redberry.pipe.OutputPort;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* T-branch like element putting each taken from OutputPort object into InputPort and propagating it forward by it's
* take method.
*
* @author Bolotin Dmitriy (bolotin.dmitriy@gmail.com)
*/
public class TBranchOutputPort implements OutputPortCloseable {
private final InputPort super T> inputPort;
private final OutputPort extends T> outputPort;
private final AtomicBoolean closed = new AtomicBoolean(false);
public TBranchOutputPort(InputPort super T> inputPort, OutputPort extends T> outputPort) {
this.inputPort = inputPort;
this.outputPort = outputPort;
}
public static TBranchOutputPort wrap(InputPort super T> inputPort, OutputPort extends T> outputPort) {
return new TBranchOutputPort(inputPort, outputPort);
}
@Override
public T take() {
if (closed.get())
return null;
T object = outputPort.take();
if (object == null) {
if (closed.compareAndSet(false, true))
inputPort.put(null);
} else
inputPort.put(object);
return object;
}
@Override
public void close() {
if (outputPort instanceof OutputPortCloseable)
((OutputPortCloseable) outputPort).close();
if (closed.compareAndSet(false, true))
inputPort.put(null);
}
}
././@LongLink 0000000 0000000 0000000 00000000146 00000000000 011216 L ustar 0000000 0000000 redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/UncaughtExceptionHandler.java redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/UncaughtExceptionHandler.jav0000644 0000000 0000000 00000002451 13353377423 031415 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.util;
/**
* Interface to handle exceptions thrown by {@link cc.redberry.pipe.OutputPort#take()}, {@link
* cc.redberry.pipe.Processor#process(Object)} and {@link cc.redberry.pipe.VoidProcessor#process(Object)}
* methods in threads created by framework infrastructure..
*/
public interface UncaughtExceptionHandler {
/**
* Executed from execution threads.
*
* @param exception thrown exception
*/
public void handle(RuntimeException exception, S source);
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/pipe/util/package-info.java 0000644 0000000 0000000 00000001537 13353377423 027153 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
/**
* Utility classes
*/
package cc.redberry.pipe.util; redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/primitives/Filter.java 0000644 0000000 0000000 00000001603 13353377423 026327 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.primitives;
public interface Filter {
boolean accept(T object);
}
redberry-redberry-pipe-7323a27293f8/src/main/java/cc/redberry/primitives/FilterUtil.java 0000644 0000000 0000000 00000005530 13353377423 027170 0 ustar 0000000 0000000 /*
* cc.redberry.pipe: java library for implementation of concurrent pipelines
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.primitives;
public class FilterUtil {
public static final Filter ACCEPT_ALL = new Filter() {
@Override
public boolean accept(Object object) {
return true;
}
};
public static final Filter REJECT_ALL = new Filter() {
@Override
public boolean accept(Object object) {
return true;
}
};
private FilterUtil() {
}
public static Filter getTrueFilter() {
return new Filter() {
@Override
public boolean accept(Object object) {
return true;
}
};
}
public static Filter or(final Filter super T>... filters) {
return new Filter() {
@Override
public boolean accept(T object) {
for (Filter super T> f : filters)
if (f.accept(object))
return true;
return false;
}
};
}
public static Filter and(final Filter super T>... filters) {
return new Filter() {
@Override
public boolean accept(T object) {
for (Filter super T> f : filters)
if (!f.accept(object))
return false;
return true;
}
};
}
public static Filter not(final Filter filter) {
return new Filter() {
@Override
public boolean accept(T object) {
return !filter.accept(object);
}
};
}
public static Filter count(final int min, final int max, final Filter super T>... filters) {
return new Filter() {
@Override
public boolean accept(T object) {
int count = 0;
for (Filter super T> f : filters)
if (f.accept(object))
if (++count > max)
return false;
return count >= min;
}
};
}
}
redberry-redberry-pipe-7323a27293f8/src/test/java/cc/redberry/pipe/CUtilsTest.java 0000644 0000000 0000000 00000011746 13353377423 025753 0 ustar 0000000 0000000 package cc.redberry.pipe;
import cc.redberry.pipe.blocks.Merger;
import cc.redberry.pipe.blocks.ParallelProcessor;
import cc.redberry.pipe.util.Chunk;
import org.apache.commons.math.random.RandomGenerator;
import org.apache.commons.math.random.Well19937c;
import org.junit.Assert;
import org.junit.Test;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import static cc.redberry.pipe.CUtils.*;
public class CUtilsTest {
@Test
public void testAsOutputPort1() throws Exception {
OutputPort op = asOutputPort(Arrays.asList(1));
Assert.assertEquals((Integer) 1, op.take());
Assert.assertNull(op.take());
}
@Test
public void testAsOutputPort2() throws Exception {
OutputPort op = asOutputPort(Arrays.asList(1, 3));
Assert.assertEquals((Integer) 1, op.take());
Assert.assertEquals((Integer) 3, op.take());
Assert.assertNull(op.take());
}
@Test
public void testChunks1() throws Exception {
int count = 100000;
RandomGenerator rd = new Well19937c();
Set values = new HashSet<>();
for (int i = 0; i < count; ++i)
values.add(rd.nextInt());
Set valuesCopy = new HashSet<>(values);
Merger> buffered = buffered(chunked(asUnsafeOutputPort(values), 128), 16);
Processor proc = new Processor() {
@Override
public Integer process(Integer input) {
return input + 1;
}
};
ParallelProcessor, Chunk> cParallelProcessor =
new ParallelProcessor<>(buffered, chunked(proc), 16, 20);
for (Integer integer : it(unchunked(cParallelProcessor)))
Assert.assertTrue(valuesCopy.remove(integer - 1));
Assert.assertTrue(valuesCopy.isEmpty());
}
@Test
public void testChunks2() throws Exception {
Assert.assertNull(unchunked(EMPTY_OUTPUT_PORT).take());
Assert.assertNull(unchunked(EMPTY_OUTPUT_PORT_CLOSEABLE).take());
}
@Test
public void testChunks3() throws Exception {
int count = 100000;
RandomGenerator rd = new Well19937c();
Set values = new HashSet<>();
for (int i = 0; i < count; ++i)
values.add(rd.nextInt());
final ConcurrentHashMap valuesCopy = new ConcurrentHashMap<>(values.size());
for (Integer value : values)
valuesCopy.put(value, value);
Merger> buffered = buffered(chunked(asUnsafeOutputPort(values), 128), 16);
Processor proc = new Processor() {
@Override
public Integer process(Integer input) {
return input + 1;
}
};
ParallelProcessor, Chunk> cParallelProcessor =
new ParallelProcessor<>(buffered, chunked(proc), 16, 20);
processAllInParallel(unchunked(cParallelProcessor), new VoidProcessor() {
@Override
public void process(Integer input) {
Assert.assertTrue(valuesCopy.remove(input - 1) != null);
}
}, 20);
Assert.assertTrue(valuesCopy.isEmpty());
}
@Test
public void testChunks4() throws Exception {
int count = 100000;
RandomGenerator rd = new Well19937c();
Set values = new HashSet<>();
for (int i = 0; i < count; ++i)
values.add(rd.nextInt());
final ConcurrentHashMap valuesCopy = new ConcurrentHashMap<>(values.size());
for (Integer value : values)
valuesCopy.put(value, value);
Merger> buffered = buffered(chunked(asUnsafeOutputPort(values), 128), 16);
processAllInParallel(unchunked(buffered), new VoidProcessor() {
@Override
public void process(Integer input) {
Assert.assertTrue(valuesCopy.remove(input) != null);
}
}, 20);
Assert.assertTrue(valuesCopy.isEmpty());
}
@Test
public void testChunks5() throws Exception {
int count = 100000;
RandomGenerator rd = new Well19937c();
Set values = new HashSet<>();
for (int i = 0; i < count; ++i)
values.add(rd.nextInt());
final ConcurrentHashMap valuesCopy = new ConcurrentHashMap<>(values.size());
for (Integer value : values)
valuesCopy.put(value, value);
OutputPort> chunked = chunked(asUnsafeOutputPort(values), 128);
processAllInParallel(unchunked(chunked), new VoidProcessor() {
@Override
public void process(Integer input) {
Assert.assertTrue(valuesCopy.remove(input) != null);
}
}, 20);
Assert.assertTrue(valuesCopy.isEmpty());
}
} redberry-redberry-pipe-7323a27293f8/src/test/java/cc/redberry/pipe/blocks/MergerTest.java 0000644 0000000 0000000 00000021175 13353377423 027243 0 ustar 0000000 0000000 /*
* cc.redberry.concurrent: high-level Java concurrent library.
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
package cc.redberry.pipe.blocks;
import cc.redberry.pipe.OutputPort;
import org.junit.Assert;
import org.junit.Test;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
public class MergerTest {
public static final int THREADS = 20;
@Test
public void simpleTestThreads() throws InterruptedException {
RandomGenerator[] rgs = new RandomGenerator[THREADS];
for (int i = 0; i < THREADS; ++i)
rgs[i] = new RandomGenerator(1000);
Merger merger = new Merger<>(1000);
for (int i = 0; i < THREADS; ++i)
merger.merge(rgs[i]);
merger.start();
long sum = 0;
Integer value;
while ((value = merger.take()) != null) {
sum += value;
}
Assert.assertTrue(sum > 0);
for (int i = 0; i < THREADS; ++i)
sum -= rgs[i].sum.longValue();
Assert.assertEquals(sum, 0L);
}
@Test
public void simpleTestExecutorService() throws InterruptedException {
ExecutorService es = Executors.newCachedThreadPool();
try {
RandomGenerator[] rgs = new RandomGenerator[THREADS];
for (int i = 0; i < THREADS; ++i)
rgs[i] = new RandomGenerator(1000);
Merger merger = new Merger<>(1000);
for (int i = 0; i < THREADS; ++i)
merger.merge(rgs[i], es);
merger.start();
long sum = 0;
Integer value;
while ((value = merger.take()) != null) {
sum += value;
}
Assert.assertTrue(sum > 0);
for (int i = 0; i < THREADS; ++i)
sum -= rgs[i].sum.longValue();
Assert.assertEquals(sum, 0L);
} finally {
es.shutdownNow();
}
}
@Test
public void closeTest0() throws InterruptedException {
ExecutorService es = Executors.newCachedThreadPool();
try {
RandomGenerator[] rgs = new RandomGenerator[THREADS];
for (int i = 0; i < THREADS; ++i)
rgs[i] = new RandomGenerator(Integer.MAX_VALUE);
final Merger merger = new Merger<>(1000);
for (int i = 0; i < THREADS; ++i)
merger.merge(rgs[i], es);
merger.start();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(100);
merger.close();
} catch (InterruptedException e) {
}
}
}).start();
long sum = 0;
Integer value;
while ((value = merger.take()) != null) {
sum += value;
}
Assert.assertTrue(sum > 0); //Something was consumed
for (int i = 0; i < THREADS; ++i) {
sum -= rgs[i].sum.longValue();
}
Assert.assertTrue(sum <= 0L); //Some elements between producers and consumer were lost (elements that were in buffer when close() method was called)
} finally {
Assert.assertEquals(es.shutdownNow().size(), 0); //All threads stopped.
}
}
@Test
public void closeTest1() throws InterruptedException {
ExecutorService es = Executors.newCachedThreadPool();
try {
RandomGenerator[] rgs = new RandomGenerator[THREADS];
for (int i = 0; i < THREADS; ++i)
rgs[i] = new RandomGenerator(Integer.MAX_VALUE);
final Merger merger = new Merger<>(1000);
merger.setFailSafe(true);
for (int i = 0; i < THREADS; ++i)
merger.merge(rgs[i], es);
merger.start();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(100);
merger.close();
} catch (InterruptedException e) {
}
}
}).start();
long sum = 0;
Integer value;
while ((value = merger.take()) != null) {
sum += value;
}
Assert.assertTrue(sum > 0); //Something was consumed
for (int i = 0; i < THREADS; ++i) {
sum -= rgs[i].sum.longValue();
}
Assert.assertEquals(sum, 0L);
} finally {
Assert.assertEquals(es.shutdownNow().size(), 0); //All threads stopped.
}
}
@Test
public void exceptionTest1() throws InterruptedException {
ExecutorService es = Executors.newCachedThreadPool();
try {
ExceptionRandomGenerator[] rgs = new ExceptionRandomGenerator[THREADS];
for (int i = 0; i < THREADS; ++i)
rgs[i] = new ExceptionRandomGenerator();
final Merger merger = new Merger<>(1000);
merger.setFailSafe(true);
for (int i = 0; i < THREADS; ++i)
merger.merge(rgs[i], es);
merger.start();
long sum = 0;
boolean ex = false;
try {
Integer value;
while ((value = merger.take()) != null) {
sum += value;
}
} catch (RuntimeException e) {
ex = true;
}
Assert.assertTrue(ex);
Assert.assertTrue(sum > 0); //Something was consumed
for (int i = 0; i < THREADS; ++i) {
sum -= rgs[i].sum.longValue();
}
Assert.assertEquals(sum, 0L);
} finally {
Assert.assertEquals(es.shutdownNow().size(), 0); //All threads stopped.
}
}
@Test
public void exceptionTest2() throws InterruptedException {
ExceptionRandomGenerator[] rgs = new ExceptionRandomGenerator[THREADS];
for (int i = 0; i < THREADS; ++i)
rgs[i] = new ExceptionRandomGenerator();
final Merger merger = new Merger<>(1000);
merger.setFailSafe(true);
for (int i = 0; i < THREADS; ++i)
merger.merge(rgs[i]);
merger.start();
long sum = 0;
boolean ex = false;
try {
Integer value;
while ((value = merger.take()) != null) {
sum += value;
}
} catch (RuntimeException e) {
ex = true;
}
Assert.assertTrue(ex);
Assert.assertTrue(sum > 0); //Something was consumed
for (int i = 0; i < THREADS; ++i) {
sum -= rgs[i].sum.longValue();
}
Assert.assertEquals(sum, 0L);
}
private static class RandomGenerator implements OutputPort {
final Random random = new Random();
final AtomicLong sum = new AtomicLong();
final AtomicInteger limit;
private RandomGenerator(int limit) {
this.limit = new AtomicInteger(limit);
}
@Override
public synchronized Integer take() {
if (limit.decrementAndGet() <= 0)
return null;
int next = random.nextInt(100);
sum.addAndGet(next);
return next;
}
}
private static class ExceptionRandomGenerator implements OutputPort {
final Random random = new Random();
final AtomicLong sum = new AtomicLong();
@Override
public synchronized Integer take() {
int next = random.nextInt(100);
if (next == 42)
throw new TestException();
sum.addAndGet(next);
return next;
}
}
private static class TestException extends RuntimeException {
}
}
redberry-redberry-pipe-7323a27293f8/src/test/java/cc/redberry/pipe/blocks/ParallelProcessorTest.java0000644 0000000 0000000 00000021407 13353377423 031454 0 ustar 0000000 0000000 /*
* cc.redberry.concurrent: high-level Java concurrent library.
* Copyright (c) 2010-2012
* Bolotin Dmitriy
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see