kopia lustrzana https://github.com/onthegomap/planetiler
165 wiersze
5.0 KiB
Java
165 wiersze
5.0 KiB
Java
package com.onthegomap.flatmap.worker;
|
|
|
|
import com.onthegomap.flatmap.monitoring.ProgressLoggers;
|
|
import com.onthegomap.flatmap.monitoring.Stats;
|
|
import java.time.Duration;
|
|
import java.util.Collection;
|
|
import java.util.Iterator;
|
|
import java.util.function.Consumer;
|
|
import java.util.function.Supplier;
|
|
|
|
public record Topology<T>(
|
|
String name,
|
|
com.onthegomap.flatmap.worker.Topology<?> previous,
|
|
WorkQueue<T> inputQueue,
|
|
Worker worker
|
|
) {
|
|
|
|
public static Empty start(String prefix, Stats stats) {
|
|
return new Empty(prefix, stats);
|
|
}
|
|
|
|
// track time since last log and stagger initial log interval for each step to keep logs
|
|
// coming at consistent intervals
|
|
private void doAwaitAndLog(ProgressLoggers loggers, Duration logInterval, long startNanos) {
|
|
if (previous != null) {
|
|
previous.doAwaitAndLog(loggers, logInterval, startNanos);
|
|
if (inputQueue != null) {
|
|
inputQueue.close();
|
|
}
|
|
}
|
|
if (worker != null) {
|
|
long elapsedSoFar = System.nanoTime() - startNanos;
|
|
Duration sinceLastLog = Duration.ofNanos(elapsedSoFar % logInterval.toNanos());
|
|
Duration untilNextLog = logInterval.minus(sinceLastLog);
|
|
worker.awaitAndLog(loggers, untilNextLog, logInterval);
|
|
}
|
|
}
|
|
|
|
public void awaitAndLog(ProgressLoggers loggers, Duration logInterval) {
|
|
doAwaitAndLog(loggers, logInterval, System.nanoTime());
|
|
loggers.log();
|
|
}
|
|
|
|
public void await() {
|
|
if (previous != null) {
|
|
previous.await();
|
|
if (inputQueue != null) {
|
|
inputQueue.close();
|
|
}
|
|
}
|
|
if (worker != null) {
|
|
worker.await();
|
|
}
|
|
}
|
|
|
|
public interface SourceStep<O> {
|
|
|
|
void run(Consumer<O> next) throws Exception;
|
|
}
|
|
|
|
public interface WorkerStep<I, O> {
|
|
|
|
void run(Supplier<I> prev, Consumer<O> next) throws Exception;
|
|
}
|
|
|
|
public interface SinkStep<I> {
|
|
|
|
void run(Supplier<I> prev) throws Exception;
|
|
}
|
|
|
|
public interface Bufferable<I, O> {
|
|
|
|
Builder<I, O> addBuffer(String name, int size, int batchSize);
|
|
|
|
default Builder<I, O> addBuffer(String name, int size) {
|
|
|
|
return addBuffer(name, size, 1);
|
|
}
|
|
}
|
|
|
|
public static record Empty(String prefix, Stats stats) {
|
|
|
|
public <T> Bufferable<?, T> fromGenerator(String name, SourceStep<T> producer, int threads) {
|
|
return (queueName, size, batchSize) -> {
|
|
var nextQueue = new WorkQueue<T>(prefix + "_" + queueName, size, batchSize, stats);
|
|
Worker worker = new Worker(prefix + "_" + name, stats, threads, () -> producer.run(nextQueue));
|
|
return new Builder<>(prefix, name, nextQueue, worker, stats);
|
|
};
|
|
}
|
|
|
|
public <T> Bufferable<?, T> fromGenerator(String name, SourceStep<T> producer) {
|
|
return fromGenerator(name, producer, 1);
|
|
}
|
|
|
|
public <T> Bufferable<?, T> readFrom(String name, Iterable<T> iterable) {
|
|
Iterator<T> iter = iterable.iterator();
|
|
return fromGenerator(name, next -> {
|
|
while (iter.hasNext()) {
|
|
next.accept(iter.next());
|
|
}
|
|
}, 1);
|
|
}
|
|
|
|
public <T> Builder<?, T> readFromTiny(String name, Collection<T> items) {
|
|
WorkQueue<T> queue = new WorkQueue<>(prefix + "_" + name, items.size(), 1, stats);
|
|
for (T item : items) {
|
|
queue.accept(item);
|
|
}
|
|
return readFromQueue(queue);
|
|
}
|
|
|
|
public <T> Builder<?, T> readFromQueue(WorkQueue<T> input) {
|
|
return new Builder<>(input, stats);
|
|
}
|
|
}
|
|
|
|
public static record Builder<I, O>(
|
|
String prefix,
|
|
String name,
|
|
Topology.Builder<?, I> previous,
|
|
WorkQueue<I> inputQueue,
|
|
WorkQueue<O> outputQueue,
|
|
Worker worker, Stats stats
|
|
) {
|
|
|
|
public Builder(String prefix, String name, WorkQueue<O> outputQueue, Worker worker, Stats stats) {
|
|
this(prefix, name, null, null, outputQueue, worker, stats);
|
|
}
|
|
|
|
public Builder(WorkQueue<O> outputQueue, Stats stats) {
|
|
this(null, null, outputQueue, null, stats);
|
|
}
|
|
|
|
public <O2> Bufferable<O, O2> addWorker(String name, int threads, WorkerStep<O, O2> step) {
|
|
Builder<I, O> curr = this;
|
|
return (queueName, size, batchSize) -> {
|
|
var nextOutputQueue = new WorkQueue<O2>(prefix + "_" + queueName, size, batchSize, stats);
|
|
var worker = new Worker(prefix + "_" + name, stats, threads, () -> step.run(outputQueue, nextOutputQueue));
|
|
return new Builder<>(prefix, name, curr, outputQueue, nextOutputQueue, worker, stats);
|
|
};
|
|
}
|
|
|
|
private Topology<I> build() {
|
|
var previousTopology = previous == null || previous.worker == null ? null : previous.build();
|
|
return new Topology<>(name, previousTopology, inputQueue, worker);
|
|
}
|
|
|
|
public Topology<O> sinkTo(String name, int threads, SinkStep<O> step) {
|
|
var previousTopology = build();
|
|
var worker = new Worker(prefix + "_" + name, stats, threads, () -> step.run(outputQueue));
|
|
return new Topology<>(name, previousTopology, outputQueue, worker);
|
|
}
|
|
|
|
public Topology<O> sinkToConsumer(String name, int threads, Consumer<O> step) {
|
|
return sinkTo(name, threads, (prev) -> {
|
|
O item;
|
|
while ((item = prev.get()) != null) {
|
|
step.accept(item);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
}
|