Skip to content

Commit

Permalink
fix #162 finish the algorithm of self-id-generator
Browse files Browse the repository at this point in the history
  • Loading branch information
hanahmily authored and gaohongtao committed Nov 10, 2016
1 parent 6fc065e commit 9d3df76
Show file tree
Hide file tree
Showing 15 changed files with 720 additions and 0 deletions.
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<module>sharding-jdbc-core</module>
<module>sharding-jdbc-config-parent</module>
<module>sharding-jdbc-transaction-parent</module>
<module>sharding-jdbc-id-generator-parent</module>
</modules>

<properties>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/

package com.dangdang.ddframe.rdb.sharding.id.generator;

/**
* Id 生成接口.
*
* @author gaohongtao
*/
public interface IdGenerator {

/**
* 初始化配置环境.
*
* @param tableName 逻辑表名称
* @param columnName 需要生成的列名称
*/
void initContext(String tableName, String columnName);

/**
* 生成Id.
*
* @return 返回生成的Id,返回值应为@{@link Number}对象或者为@{@link String}对象
*/
Object generateId();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/

package com.dangdang.ddframe.rdb.sharding.id.generator.fixture;

import com.dangdang.ddframe.rdb.sharding.id.generator.IdGenerator;

import java.util.concurrent.atomic.AtomicInteger;

public class IncrementIdGenerator implements IdGenerator{

private final AtomicInteger i = new AtomicInteger();

@Override
public void initContext(final String tableName, final String columnName) {

}

@Override
public Object generateId() {
return i.incrementAndGet();
}
}
64 changes: 64 additions & 0 deletions sharding-jdbc-id-generator-parent/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 1999-2015 dangdang.com.
~ <p>
~ 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.
~ </p>
-->

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sharding-jdbc</artifactId>
<groupId>com.dangdang</groupId>
<version>1.4.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>sharding-jdbc-id-generator-parent</artifactId>
<packaging>pom</packaging>
<modules>
<module>sharding-jdbc-self-id-generator</module>
</modules>


<dependencies>
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>sharding-jdbc</artifactId>
<version>${project.parent.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-rules</artifactId>
<version>1.16.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 1999-2015 dangdang.com.
~ <p>
~ 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.
~ </p>
-->

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sharding-jdbc-id-generator-parent</artifactId>
<groupId>com.dangdang</groupId>
<version>1.4.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>sharding-jdbc-self-id-generator</artifactId>

<dependencies>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-rules</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/

package com.dangdang.ddframe.rdb.sharding.id.generator.self;

import com.dangdang.ddframe.rdb.sharding.id.generator.IdGenerator;
import com.dangdang.ddframe.rdb.sharding.id.generator.self.time.AbstractClock;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import lombok.Getter;
import lombok.Setter;

/**
* 自生成Id生成器.
*
* <p/>
* 长度为64bit,从高位到低位依次为
* <pre>
* 1bit 符号位
* 41bits 时间偏移量从2016年11月1日零点到现在的毫秒数
* 10bits 工作进程Id
* 12bits 同一个毫秒内的自增量
* </pre>
*
* <p/>
* 工作进程Id获取优先级: 系统变量{@code sjdbc.self.id.generator.worker.id} > 环境变量{@code SJDBC_SELF_ID_GENERATOR_WORKER_ID}
* ,另外可以调用@{@code CommonSelfIdGenerator.setWorkerId}进行设置
*
* @author gaohongtao.
*/
@Getter
public class CommonSelfIdGenerator implements IdGenerator {

public static final long SJDBC_EPOCH = 1477933200000L;

private static final long SEQUENCE_BITS = 12L;

private static final long WORKER_ID_BITS = 10L;

private static final long SEQUENCE_MASK = (1 << SEQUENCE_BITS) - 1;

private static final long WORKER_ID_LEFT_SHIFT_BITS = SEQUENCE_BITS;

private static final long TIMESTAMP_LEFT_SHIFT_BITS = WORKER_ID_LEFT_SHIFT_BITS + WORKER_ID_BITS;

private static final long WORKER_ID_MAX_VALUE = 1L << WORKER_ID_BITS;

@Setter
private static AbstractClock clock = AbstractClock.systemClock();

@Getter
private static long workerId;

static {
initWorkerId();
}

private long sequence;

private long lastTime;

private String tableName;

private String columnName;

static void initWorkerId() {
String workerId = System.getProperty("sjdbc.self.id.generator.worker.id");
if (!Strings.isNullOrEmpty(workerId)) {
setWorkerId(Long.valueOf(workerId));
return;
}
workerId = System.getenv("SJDBC_SELF_ID_GENERATOR_WORKER_ID");
if (Strings.isNullOrEmpty(workerId)) {
return;
}
setWorkerId(Long.valueOf(workerId));
}

public static void setWorkerId(final Long workerId) {
Preconditions.checkArgument(workerId >= 0L && workerId < WORKER_ID_MAX_VALUE);
CommonSelfIdGenerator.workerId = workerId;
}

/**
* 初始化环境.
*
* @param tableName 逻辑表名称
* @param columnName 需要生成的列名称
*/
@Override
public void initContext(final String tableName, final String columnName) {
this.tableName = tableName;
this.columnName = columnName;
}

/**
* 生成Id.
*
* @return 返回@{@link Long}类型的Id
*/
@Override
public synchronized Object generateId() {
long time = clock.millis();
Preconditions.checkState(lastTime <= time, "Clock is moving backwards, last time is %d milliseconds, current time is %d milliseconds", lastTime, time);
if (lastTime == time) {
if (0L == (++sequence & SEQUENCE_MASK)) {
time = waitUntilNextTime(time);
}
} else {
sequence = 0;
}
lastTime = time;
return ((time - SJDBC_EPOCH) << TIMESTAMP_LEFT_SHIFT_BITS) | (workerId << WORKER_ID_LEFT_SHIFT_BITS) | sequence;
}

private long waitUntilNextTime(final long lastTime) {
long time = clock.millis();
while (time <= lastTime) {
time = clock.millis();
}
return time;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/

package com.dangdang.ddframe.rdb.sharding.id.generator.self.time;

/**
* 时钟定义.
*
* @author gaohongtao
*/
public abstract class AbstractClock {

/**
* 创建系统时钟.
*
* @return 系统时钟
*/
public static AbstractClock systemClock() {
return new SystemClock();
}

/**
* 返回从纪元开始的毫秒数.
*
* @return 从纪元开始的毫秒数
*/
public abstract long millis();

private static final class SystemClock extends AbstractClock {

@Override
public long millis() {
return System.currentTimeMillis();
}
}
}
Loading

0 comments on commit 9d3df76

Please sign in to comment.