/*
 * Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 */

package main

import (
	"fmt"
	"github.com/bruceshao/lockfree"
	"math/rand"
	"sync"
	"sync/atomic"
	"time"
)

func main() {
	fmt.Println("========== start write by discard ==========")
	writeByDiscard()
	fmt.Println("========== complete write by discard ==========")
	fmt.Println("========== start write by cursor ==========")
	writeByCursor()
	fmt.Println("========== complete write by cursor ==========")
}

func writeByDiscard() {
	var counter = uint64(0)
	// 写入超时，如何使用
	eh := &fixedSleepEventHandler[uint64]{
		sm: time.Millisecond * 10,
	}
	disruptor := lockfree.NewLockfree[uint64](2, eh, lockfree.NewSleepBlockStrategy(time.Microsecond))
	disruptor.Start()
	producer := disruptor.Producer()
	// 假设有100个写g
	var wg sync.WaitGroup
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			for j := 0; j < 10; j++ {
				v := atomic.AddUint64(&counter, 1)
				ww := producer.WriteWindow()
				if ww <= 0 {
					// 表示无法写入，丢弃
					fmt.Println("discard ", v)
					continue
				}
				// 表示可以写入，写入即可
				err := producer.Write(v)
				if err != nil {
					panic(err)
				}
				fmt.Println("write ", v)
			}
			wg.Done()
		}()
	}
	wg.Wait()
	time.Sleep(3 * time.Second)
	disruptor.Close()
}

func writeByCursor() {
	var counter = uint64(0)
	// 写入超时，如何使用
	eh := &randomSleepEventHandler[uint64]{}
	disruptor := lockfree.NewLockfree[uint64](2, eh, lockfree.NewSleepBlockStrategy(time.Microsecond))
	disruptor.Start()
	producer := disruptor.Producer()
	// 假设有100个写g
	var wg sync.WaitGroup
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			for j := 0; j < 10; j++ {
				v := atomic.AddUint64(&counter, 1)
				wc, exist, err := producer.WriteTimeout(v, time.Millisecond)
				if err != nil {
					return
				}
				if !exist {
					// 重复写入1次，写入不成功则丢弃重新写其他的
					if ok, _ := producer.WriteByCursor(v, wc); ok {
						continue
					}
					fmt.Println("discard ", v)
					// 重新生成值，一直等待写入
					v = atomic.AddUint64(&counter, 1)
					for {
						if ok, _ := producer.WriteByCursor(v, wc); ok {
							fmt.Println("write ", v, " with x times")
							break
						}
						// 写入不成功则休眠，防止CPU暴增
						time.Sleep(100 * time.Microsecond)
					}
				} else {
					fmt.Println("write ", v, " with 1 time")
				}
			}
			wg.Done()
		}()
	}
	wg.Wait()
	time.Sleep(3 * time.Second)
	disruptor.Close()
}


type fixedSleepEventHandler[T uint64] struct {
	sm time.Duration
}

func (h *fixedSleepEventHandler[T]) OnEvent(v uint64) {
	time.Sleep(h.sm)
	fmt.Println("consumer ", v)
}

type randomSleepEventHandler[T uint64] struct {
	count int32
}

func (h *randomSleepEventHandler[T]) OnEvent(v uint64) {
	// 每次处理都会进行随机休眠，可以导致消费端变慢
	intn := rand.Intn(1000)
	time.Sleep(time.Duration(intn * 1000))
	fmt.Println("consumer count ", atomic.AddInt32(&h.count, 1))
}