baidu / uid-generator

UniqueID generator
Apache License 2.0
5.47k stars 1.56k forks source link

写入Ringbuffer时,生成的ID会跳过某些时间 #96

Open qqyycom opened 4 months ago

qqyycom commented 4 months ago

JDK VERSION:openjdk@17.0.11 uid-genertor version: Latest

// com.baidu.fsg.uid.buffer.BufferPaddingExecutor#paddingBuffer()
public void paddingBuffer() {
        LOGGER.info("Ready to padding buffer lastSecond:{}. {}", lastSecond.get(), ringBuffer);

        // is still running
        if (!running.compareAndSet(false, true)) {
            LOGGER.info("Padding buffer is still running. {}", ringBuffer);
            return;
        }

        // fill the rest slots until to catch the cursor
        boolean isFullRingBuffer = false;
        while (!isFullRingBuffer) {
            List<Long> uidList = uidProvider.provide(lastSecond.incrementAndGet());
            for (Long uid : uidList) {
                isFullRingBuffer = !ringBuffer.put(uid);
                if (isFullRingBuffer) {
                    break;
                }
            }
        }

        // not running now
        running.compareAndSet(true, false);
        LOGGER.info("End to padding buffer lastSecond:{}. {}", lastSecond.get(), ringBuffer);
    }
// com.baidu.fsg.uid.buffer.RingBuffer#paddingBuffer()
public synchronized boolean put(long uid) {
        long currentTail = tail.get();
        long currentCursor = cursor.get();
        // 判读ringBuffer是否填满的逻辑在最开始
        // tail catches the cursor, means that you can't put any cause of RingBuffer is full
        long distance = currentTail - (currentCursor == START_POINT ? 0 : currentCursor);
        if (distance == bufferSize - 1) {
            rejectedPutHandler.rejectPutBuffer(this, uid);
            return false;
        }

        // 1. pre-check whether the flag is CAN_PUT_FLAG
        int nextTailIndex = calSlotIndex(currentTail + 1);
        if (flags[nextTailIndex].get() != CAN_PUT_FLAG) {
            rejectedPutHandler.rejectPutBuffer(this, uid);
            return false;
        }

        // 2. put UID in the next slot
        // 3. update next slot' flag to CAN_TAKE_FLAG
        // 4. publish tail with sequence increase by one
        slots[nextTailIndex] = uid;
        flags[nextTailIndex].set(CAN_TAKE_FLAG);
        tail.incrementAndGet();

        // The atomicity of operations above, guarantees by 'synchronized'. In another word,
        // the take operation can't consume the UID we just put, until the tail is published(tail.incrementAndGet())
        return true;
    }

问题:当填入ID时,预先生成ID,判断ringBuffer是否填满的逻辑在ringBuffer.put()最开始。导致总有lastSecond生成了ID,但因为ringBuffer已满,而被废弃。 当padding-factor = 50时 每boost-power + 1 个 lastSecond,就有一个被废弃 解决:通过配置padding-factor != 50,使每次生成的UID序列不能完整的加入ringbuffer就出发了ringBuffer已满已满的逻辑 优化:修改put()方法, 当填入一个后,再次判断是否填满

// com.baidu.fsg.uid.buffer.RingBuffer#paddingBuffer()
public synchronized boolean put(long uid) {
        long currentTail = tail.get();
        long currentCursor = cursor.get();
        // 判读ringBuffer是否填满的逻辑在最开始
        // tail catches the cursor, means that you can't put any cause of RingBuffer is full
        long distance = currentTail - (currentCursor == START_POINT ? 0 : currentCursor);
        if (distance == bufferSize - 1) {
            rejectedPutHandler.rejectPutBuffer(this, uid);
            return false;
        }

        // 1. pre-check whether the flag is CAN_PUT_FLAG
        int nextTailIndex = calSlotIndex(currentTail + 1);
        if (flags[nextTailIndex].get() != CAN_PUT_FLAG) {
            rejectedPutHandler.rejectPutBuffer(this, uid);
            return false;
        }

        // 2. put UID in the next slot
        // 3. update next slot' flag to CAN_TAKE_FLAG
        // 4. publish tail with sequence increase by one
        slots[nextTailIndex] = uid;
        flags[nextTailIndex].set(CAN_TAKE_FLAG);
        // ++++++++++++++
        // 判断buffer是否在加入当前ID之后就满了。
        boolean result = distance != bufferSize - 2 ;
        tail.incrementAndGet();

        // The atomicity of operations above, guarantees by 'synchronized'. In another word,
        // the take operation can't consume the UID we just put, until the tail is published(tail.incrementAndGet())
        return result;
    }
ijaychang commented 2 weeks ago

其实感觉跳过几个lastSecond又怎么样呢,这个也不能叫浪费吧,不过你的解决方案挺秒的!