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

io.github.wujun728.uidgenerator.impl.CachedUidGenerator Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.github.wujun728.uidgenerator.impl;

import io.github.wujun728.uidgenerator.BitsAllocator;
import io.github.wujun728.uidgenerator.UidGenerator;
import io.github.wujun728.uidgenerator.buffer.BufferPaddingExecutor;
import io.github.wujun728.uidgenerator.buffer.RejectedPutBufferHandler;
import io.github.wujun728.uidgenerator.buffer.RejectedTakeBufferHandler;
import io.github.wujun728.uidgenerator.buffer.RingBuffer;
import io.github.wujun728.uidgenerator.exception.UidGenerateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;

/**
 * Represents a cached implementation of {@link UidGenerator} extends
 * from {@link DefaultUidGenerator}, based on a lock free {@link RingBuffer}

* * The spring properties you can specified as below:
*

  • boostPower: RingBuffer size boost for a power of 2, Sample: boostPower is 3, it means the buffer size * will be ({@link BitsAllocator#getMaxSequence()} + 1) << * {@link #boostPower}, Default as {@value #DEFAULT_BOOST_POWER} *
  • paddingFactor: Represents a percent value of (0 - 100). When the count of rest available UIDs reach the * threshold, it will trigger padding buffer. Default as{@link RingBuffer#DEFAULT_PADDING_PERCENT} * Sample: paddingFactor=20, bufferSize=1000 -> threshold=1000 * 20 /100, padding buffer will be triggered when tail-cursorscheduleInterval: Padding buffer in a schedule, specify padding buffer interval, Unit as second *
  • rejectedPutBufferHandler: Policy for rejected put buffer. Default as discard put request, just do logging *
  • rejectedTakeBufferHandler: Policy for rejected take buffer. Default as throwing up an exception * * @author yutianbao */ public class CachedUidGenerator extends DefaultUidGenerator implements DisposableBean { private static final Logger LOGGER = LoggerFactory.getLogger(CachedUidGenerator.class); private static final int DEFAULT_BOOST_POWER = 3; /** Spring properties */ private int boostPower = DEFAULT_BOOST_POWER; private int paddingFactor = RingBuffer.DEFAULT_PADDING_PERCENT; private Long scheduleInterval; private RejectedPutBufferHandler rejectedPutBufferHandler; private RejectedTakeBufferHandler rejectedTakeBufferHandler; /** RingBuffer */ private RingBuffer ringBuffer; private BufferPaddingExecutor bufferPaddingExecutor; @Override public void afterPropertiesSet() throws Exception { // initialize workerId & bitsAllocator super.afterPropertiesSet(); // initialize RingBuffer & RingBufferPaddingExecutor this.initRingBuffer(); LOGGER.info("Initialized RingBuffer successfully."); } @Override public long getUID() { try { return ringBuffer.take(); } catch (Exception e) { LOGGER.error("Generate unique id exception. ", e); throw new UidGenerateException(e); } } @Override public String parseUID(long uid) { return super.parseUID(uid); } @Override public void destroy() throws Exception { bufferPaddingExecutor.shutdown(); } /** * Get the UIDs in the same specified second under the max sequence * * @param currentSecond * @return UID list, size of {@link BitsAllocator#getMaxSequence()} + 1 */ protected List nextIdsForOneSecond(long currentSecond) { // Initialize result list size of (max sequence + 1) int listSize = (int) bitsAllocator.getMaxSequence() + 1; List uidList = new ArrayList<>(listSize); // Allocate the first sequence of the second, the others can be calculated with the offset long firstSeqUid = bitsAllocator.allocate(currentSecond - epochSeconds, workerId, 0L); for (int offset = 0; offset < listSize; offset++) { uidList.add(firstSeqUid + offset); } return uidList; } /** * Initialize RingBuffer & RingBufferPaddingExecutor */ private void initRingBuffer() { // initialize RingBuffer int bufferSize = ((int) bitsAllocator.getMaxSequence() + 1) << boostPower; this.ringBuffer = new RingBuffer(bufferSize, paddingFactor); LOGGER.info("Initialized ring buffer size:{}, paddingFactor:{}", bufferSize, paddingFactor); // initialize RingBufferPaddingExecutor boolean usingSchedule = (scheduleInterval != null); this.bufferPaddingExecutor = new BufferPaddingExecutor(ringBuffer, this::nextIdsForOneSecond, usingSchedule); if (usingSchedule) { bufferPaddingExecutor.setScheduleInterval(scheduleInterval); } LOGGER.info("Initialized BufferPaddingExecutor. Using schdule:{}, interval:{}", usingSchedule, scheduleInterval); // set rejected put/take handle policy this.ringBuffer.setBufferPaddingExecutor(bufferPaddingExecutor); if (rejectedPutBufferHandler != null) { this.ringBuffer.setRejectedPutHandler(rejectedPutBufferHandler); } if (rejectedTakeBufferHandler != null) { this.ringBuffer.setRejectedTakeHandler(rejectedTakeBufferHandler); } // fill in all slots of the RingBuffer bufferPaddingExecutor.paddingBuffer(); // start buffer padding threads bufferPaddingExecutor.start(); } /** * Setters for spring property */ public void setBoostPower(int boostPower) { Assert.isTrue(boostPower > 0, "Boost power must be positive!"); this.boostPower = boostPower; } public void setRejectedPutBufferHandler(RejectedPutBufferHandler rejectedPutBufferHandler) { Assert.notNull(rejectedPutBufferHandler, "RejectedPutBufferHandler can't be null!"); this.rejectedPutBufferHandler = rejectedPutBufferHandler; } public void setRejectedTakeBufferHandler(RejectedTakeBufferHandler rejectedTakeBufferHandler) { Assert.notNull(rejectedTakeBufferHandler, "RejectedTakeBufferHandler can't be null!"); this.rejectedTakeBufferHandler = rejectedTakeBufferHandler; } public void setScheduleInterval(long scheduleInterval) { Assert.isTrue(scheduleInterval > 0, "Schedule interval must positive!"); this.scheduleInterval = scheduleInterval; } }




  • © 2015 - 2024 Weber Informatics LLC | Privacy Policy