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

cc.siyecao.uid.impl.CachedUidGenerator Maven / Gradle / Ivy

There is a newer version: 2.2
Show 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 cc.siyecao.uid.impl;

import cc.siyecao.uid.BitsAllocator;
import cc.siyecao.uid.UidGenerator;
import cc.siyecao.uid.buffer.BufferPaddingExecutor;
import cc.siyecao.uid.buffer.RejectedPutBufferHandler;
import cc.siyecao.uid.buffer.RejectedTakeBufferHandler;
import cc.siyecao.uid.buffer.RingBuffer;
import cc.siyecao.uid.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 setPaddingFactor(int paddingFactor) { this.paddingFactor = paddingFactor; } 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