package com.fdkankan.disruptormq;

import com.lmax.disruptor.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.ToString;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author Xiewj
 * @date 2024/1/17
 */
@Data
@Component
@ConditionalOnProperty(prefix  = "disruptor",name = "wait-type")
public class DisruptorProperties {
    /**
     * 等待类型
     */
    private WaitType waitType = WaitType.BLOCKING_WAIT;
    /**
     * handler配置参数
     */
    private Map<String, HandlerProperties> handlers = new LinkedHashMap<>();

    @Data
    public static class HandlerProperties {
        /**
         * 缓冲区大小，默认1024*1024，必须是2的N次幂
         */
        private int ringBufferSize = 1024 * 1024;
        /**
         * 单生产者/多生产者
         */
        private boolean multiProducer = false;
    }

    /**
     * 决定一个消费者将如何等待生产者将Event置入Disruptor的策略，用来权衡当生产者无法将新的事件放进RingBuffer时的处理策略
     * （例如：当生产者太快，消费者太慢，会导致生成者获取不到新的事件槽来插入新事件，则会根据该策略进行处理，默认会堵塞）
     */
    @Getter
    @ToString
    @AllArgsConstructor
    public enum WaitType {
        /**
         * BlockingWaitStrategy是最低效的策略，但其对CPU的消耗最小并且在各种不同部署环境中能提供更加一致的性能表现
         */
        BLOCKING_WAIT(new BlockingWaitStrategy()),
        /**
         * SleepingWaitStrategy的性能表现跟BlockingWaitStrategy差不多，对CPU的消耗也类似，但其对生产者线程的影响最小，适合用于异步日志类似的场景
         */
        SLEEPING_WAIT(new SleepingWaitStrategy()),
        /**
         * YieldingWaitStrategy是可以被用在低延迟系统中的两个策略之一，这种策略在减低系统延迟的同时也会增加CPU运算量
         * YieldingWaitStrategy策略会循环等待sequence增加到合适的值，循环中调用Thread.yield()允许其他准备好的线程执行
         * 如果需要高性能而且事件消费者线程比逻辑内核少的时候，推荐使用YieldingWaitStrategy策略，例如在开启超线程时
         */
        YIELDING_WAIT(new YieldingWaitStrategy()),
        /**
         * BusySpinWaitStrategy是性能最高的等待策略，同时也是对部署环境要求最高的策略
         * 这个性能最好用在事件处理线程比物理内核数目还要小的时候，例如在禁用超线程技术时
         */
        BUSY_SPIN_WAIT(new BusySpinWaitStrategy());
        private final WaitStrategy waitStrategy;
    }
}