All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fiolino.common.processing.sink.ThreadsafeAggregatingSink Maven / Gradle / Ivy

Go to download

General structure to easily create dynamic logic via MethodHandles and others.

There is a newer version: 1.0.10
Show newest version
package org.fiolino.common.processing.sink;

import org.fiolino.common.container.Container;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Created by kuli on 27.03.16.
 */
public final class ThreadsafeAggregatingSink extends ThreadsafeChainedSink> {

    private static final Logger logger = Logger.getLogger(ThreadsafeAggregatingSink.class.getName());

    private final BlockingQueue queue;
    private final Lock lock = new ReentrantLock();
    private volatile Container lastMetadata = Container.empty();

    public ThreadsafeAggregatingSink(ThreadsafeSink> target, int chunkSize) {
        super(target);
        queue = new ArrayBlockingQueue(chunkSize);
    }

    @Override
    public void accept(T value, Container metadata) throws Exception {
        do {
            if (queue.offer(value)) {
                lastMetadata = metadata;
                return;
            }
            if (!lock.tryLock()) {
                // Spin wait
                try {
                    TimeUnit.MILLISECONDS.sleep(20);
                } catch (InterruptedException ex) {
                    logger.log(Level.WARNING, () -> "Interrupted while waiting for queue. Discarding " + value);
                    Thread.currentThread().interrupt();
                    return;
                }
                continue;
            }
            List list;
            try {
                // Test again - it could be cleaned in between by another thread
                if (queue.offer(value)) {
                    lastMetadata = metadata;
                    return;
                }
                list = new ArrayList<>(queue);
                queue.clear();
            } finally {
                lock.unlock();
            }
            getTarget().accept(list, metadata);
            // Then add again

        } while (true);
    }

    @Override
    public void commit(Container metadata) throws Exception {
        List list = new ArrayList<>(queue);
        queue.removeAll(list);
        if (!list.isEmpty()) {
            getTarget().accept(list, lastMetadata);
        }
        lastMetadata = Container.empty();
        super.commit(metadata);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy