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

org.rx.io.WriteBehindQueue Maven / Gradle / Ivy

package org.rx.io;

import lombok.Getter;
import lombok.NonNull;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.rx.bean.IntWaterMark;
import org.rx.bean.Tuple;
import org.rx.core.*;
import org.rx.util.function.BiAction;

import java.util.*;
import java.util.concurrent.ConcurrentSkipListMap;

import static org.rx.core.Extends.quietly;

@Slf4j
final class WriteBehindQueue extends Disposable {
    @Getter
    final long writeDelayed;
    @Getter
    final IntWaterMark funcWaterMark;
    //sequential
    final ConcurrentSkipListMap>> funcs = new ConcurrentSkipListMap<>();
    final ResetEventWait syncRoot = new ResetEventWait();

    WriteBehindQueue(long writeDelayed, int highFuncWaterMark) {
        this(writeDelayed, new IntWaterMark((int) Math.ceil(highFuncWaterMark / 2d), highFuncWaterMark));
    }

    WriteBehindQueue(long writeDelayed, @NonNull IntWaterMark funcWaterMark) {
        this.writeDelayed = writeDelayed;
        this.funcWaterMark = funcWaterMark;
    }

    @Override
    protected void freeObjects() {
        consume();
    }

    public void reset() {
        funcs.clear();
        syncRoot.set();
    }

    @SneakyThrows
    public void offer(@NonNull K posKey, V writeVal, BiAction writeFunc) {
        if (isClosed()) {
            writeFunc.invoke(writeVal);
            return;
        }

        funcs.put(posKey, Tuple.of(writeVal, writeFunc));
        if (funcs.size() > funcWaterMark.getHigh()) {
            log.warn("high water mark threshold");
            Tasks.timer().setTimeout(this::consume, d -> d == 0 ? 1 : writeDelayed, this, TimeoutFlag.SINGLE);
            syncRoot.waitOne();
            syncRoot.reset();
            log.info("below low water mark");
        }

        Tasks.setTimeout(this::consume, writeDelayed, this, TimeoutFlag.SINGLE);
        log.debug("offer {} delay={}", posKey, writeDelayed);
    }

    public boolean remove(@NonNull K posKey) {
        return funcs.remove(posKey) != null;
    }

    public V peek(@NonNull K posKey) {
        Tuple> tuple = funcs.get(posKey);
        if (tuple == null) {
            return null;
        }
        return tuple.left;
    }

    public synchronized void consume() {
        int size = funcs.size();
        while (size > 0) {
            Map.Entry>> entry = funcs.pollFirstEntry();
            if (funcs.size() <= funcWaterMark.getLow()) {
                log.debug("low water mark threshold");
                syncRoot.set();
            }
            if (entry == null) {
                break;
            }
            Tuple> tuple = entry.getValue();
            quietly(() -> tuple.right.invoke(tuple.left));
            log.debug("consume {}", entry.getKey());
            size--;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy