├── LICENSE
├── README.md
├── README.zh_cn.md
├── doc
├── dlock-architecture.png
├── throughput0.png
└── throughput1.png
├── pom.xml
└── src
├── main
└── java
│ └── com
│ └── baidu
│ └── fsg
│ └── dlock
│ ├── DistributedReentrantLock.java
│ ├── domain
│ ├── DLockConfig.java
│ ├── DLockEntity.java
│ ├── DLockStatus.java
│ └── DLockType.java
│ ├── exception
│ ├── DLockProcessException.java
│ ├── OptimisticLockingException.java
│ └── RedisProcessException.java
│ ├── jedis
│ └── JedisClient.java
│ ├── processor
│ ├── DLockProcessor.java
│ └── impl
│ │ └── RedisLockProcessor.java
│ ├── support
│ └── DLockGenerator.java
│ └── utils
│ ├── EnumUtils.java
│ ├── NetUtils.java
│ ├── ReflectionUtils.java
│ └── ValuedEnum.java
└── test
├── java
└── com
│ └── baidu
│ └── fsg
│ └── dlock
│ ├── DLockGeneratorTest.java
│ ├── DLockSimpleTest.java
│ └── DistributedReentrantLockTest.java
└── resources
├── dlock
├── config-dlock.properties
├── redis.properties
└── spring-dlock.xml
└── logback.xml
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017 Baidu, Inc. All Rights Reserved
2 |
3 | Apache License
4 | Version 2.0, January 2004
5 | http://www.apache.org/licenses/
6 |
7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
8 |
9 | 1. Definitions.
10 |
11 | "License" shall mean the terms and conditions for use, reproduction,
12 | and distribution as defined by Sections 1 through 9 of this document.
13 |
14 | "Licensor" shall mean the copyright owner or entity authorized by
15 | the copyright owner that is granting the License.
16 |
17 | "Legal Entity" shall mean the union of the acting entity and all
18 | other entities that control, are controlled by, or are under common
19 | control with that entity. For the purposes of this definition,
20 | "control" means (i) the power, direct or indirect, to cause the
21 | direction or management of such entity, whether by contract or
22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
23 | outstanding shares, or (iii) beneficial ownership of such entity.
24 |
25 | "You" (or "Your") shall mean an individual or Legal Entity
26 | exercising permissions granted by this License.
27 |
28 | "Source" form shall mean the preferred form for making modifications,
29 | including but not limited to software source code, documentation
30 | source, and configuration files.
31 |
32 | "Object" form shall mean any form resulting from mechanical
33 | transformation or translation of a Source form, including but
34 | not limited to compiled object code, generated documentation,
35 | and conversions to other media types.
36 |
37 | "Work" shall mean the work of authorship, whether in Source or
38 | Object form, made available under the License, as indicated by a
39 | copyright notice that is included in or attached to the work
40 | (an example is provided in the Appendix below).
41 |
42 | "Derivative Works" shall mean any work, whether in Source or Object
43 | form, that is based on (or derived from) the Work and for which the
44 | editorial revisions, annotations, elaborations, or other modifications
45 | represent, as a whole, an original work of authorship. For the purposes
46 | of this License, Derivative Works shall not include works that remain
47 | separable from, or merely link (or bind by name) to the interfaces of,
48 | the Work and Derivative Works thereof.
49 |
50 | "Contribution" shall mean any work of authorship, including
51 | the original version of the Work and any modifications or additions
52 | to that Work or Derivative Works thereof, that is intentionally
53 | submitted to Licensor for inclusion in the Work by the copyright owner
54 | or by an individual or Legal Entity authorized to submit on behalf of
55 | the copyright owner. For the purposes of this definition, "submitted"
56 | means any form of electronic, verbal, or written communication sent
57 | to the Licensor or its representatives, including but not limited to
58 | communication on electronic mailing lists, source code control systems,
59 | and issue tracking systems that are managed by, or on behalf of, the
60 | Licensor for the purpose of discussing and improving the Work, but
61 | excluding communication that is conspicuously marked or otherwise
62 | designated in writing by the copyright owner as "Not a Contribution."
63 |
64 | "Contributor" shall mean Licensor and any individual or Legal Entity
65 | on behalf of whom a Contribution has been received by Licensor and
66 | subsequently incorporated within the Work.
67 |
68 | 2. Grant of Copyright License. Subject to the terms and conditions of
69 | this License, each Contributor hereby grants to You a perpetual,
70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
71 | copyright license to reproduce, prepare Derivative Works of,
72 | publicly display, publicly perform, sublicense, and distribute the
73 | Work and such Derivative Works in Source or Object form.
74 |
75 | 3. Grant of Patent License. Subject to the terms and conditions of
76 | this License, each Contributor hereby grants to You a perpetual,
77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
78 | (except as stated in this section) patent license to make, have made,
79 | use, offer to sell, sell, import, and otherwise transfer the Work,
80 | where such license applies only to those patent claims licensable
81 | by such Contributor that are necessarily infringed by their
82 | Contribution(s) alone or by combination of their Contribution(s)
83 | with the Work to which such Contribution(s) was submitted. If You
84 | institute patent litigation against any entity (including a
85 | cross-claim or counterclaim in a lawsuit) alleging that the Work
86 | or a Contribution incorporated within the Work constitutes direct
87 | or contributory patent infringement, then any patent licenses
88 | granted to You under this License for that Work shall terminate
89 | as of the date such litigation is filed.
90 |
91 | 4. Redistribution. You may reproduce and distribute copies of the
92 | Work or Derivative Works thereof in any medium, with or without
93 | modifications, and in Source or Object form, provided that You
94 | meet the following conditions:
95 |
96 | (a) You must give any other recipients of the Work or
97 | Derivative Works a copy of this License; and
98 |
99 | (b) You must cause any modified files to carry prominent notices
100 | stating that You changed the files; and
101 |
102 | (c) You must retain, in the Source form of any Derivative Works
103 | that You distribute, all copyright, patent, trademark, and
104 | attribution notices from the Source form of the Work,
105 | excluding those notices that do not pertain to any part of
106 | the Derivative Works; and
107 |
108 | (d) If the Work includes a "NOTICE" text file as part of its
109 | distribution, then any Derivative Works that You distribute must
110 | include a readable copy of the attribution notices contained
111 | within such NOTICE file, excluding those notices that do not
112 | pertain to any part of the Derivative Works, in at least one
113 | of the following places: within a NOTICE text file distributed
114 | as part of the Derivative Works; within the Source form or
115 | documentation, if provided along with the Derivative Works; or,
116 | within a display generated by the Derivative Works, if and
117 | wherever such third-party notices normally appear. The contents
118 | of the NOTICE file are for informational purposes only and
119 | do not modify the License. You may add Your own attribution
120 | notices within Derivative Works that You distribute, alongside
121 | or as an addendum to the NOTICE text from the Work, provided
122 | that such additional attribution notices cannot be construed
123 | as modifying the License.
124 |
125 | You may add Your own copyright statement to Your modifications and
126 | may provide additional or different license terms and conditions
127 | for use, reproduction, or distribution of Your modifications, or
128 | for any such Derivative Works as a whole, provided Your use,
129 | reproduction, and distribution of the Work otherwise complies with
130 | the conditions stated in this License.
131 |
132 | 5. Submission of Contributions. Unless You explicitly state otherwise,
133 | any Contribution intentionally submitted for inclusion in the Work
134 | by You to the Licensor shall be under the terms and conditions of
135 | this License, without any additional terms or conditions.
136 | Notwithstanding the above, nothing herein shall supersede or modify
137 | the terms of any separate license agreement you may have executed
138 | with Licensor regarding such Contributions.
139 |
140 | 6. Trademarks. This License does not grant permission to use the trade
141 | names, trademarks, service marks, or product names of the Licensor,
142 | except as required for reasonable and customary use in describing the
143 | origin of the Work and reproducing the content of the NOTICE file.
144 |
145 | 7. Disclaimer of Warranty. Unless required by applicable law or
146 | agreed to in writing, Licensor provides the Work (and each
147 | Contributor provides its Contributions) on an "AS IS" BASIS,
148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
149 | implied, including, without limitation, any warranties or conditions
150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
151 | PARTICULAR PURPOSE. You are solely responsible for determining the
152 | appropriateness of using or redistributing the Work and assume any
153 | risks associated with Your exercise of permissions under this License.
154 |
155 | 8. Limitation of Liability. In no event and under no legal theory,
156 | whether in tort (including negligence), contract, or otherwise,
157 | unless required by applicable law (such as deliberate and grossly
158 | negligent acts) or agreed to in writing, shall any Contributor be
159 | liable to You for damages, including any direct, indirect, special,
160 | incidental, or consequential damages of any character arising as a
161 | result of this License or out of the use or inability to use the
162 | Work (including but not limited to damages for loss of goodwill,
163 | work stoppage, computer failure or malfunction, or any and all
164 | other commercial damages or losses), even if such Contributor
165 | has been advised of the possibility of such damages.
166 |
167 | 9. Accepting Warranty or Additional Liability. While redistributing
168 | the Work or Derivative Works thereof, You may choose to offer,
169 | and charge a fee for, acceptance of support, warranty, indemnity,
170 | or other liability obligations and/or rights consistent with this
171 | License. However, in accepting such obligations, You may act only
172 | on Your own behalf and on Your sole responsibility, not on behalf
173 | of any other Contributor, and only if You agree to indemnify,
174 | defend, and hold each Contributor harmless for any liability
175 | incurred by, or claims asserted against, such Contributor by reason
176 | of your accepting any such warranty or additional liability.
177 |
178 | END OF TERMS AND CONDITIONS
179 |
180 | APPENDIX: How to apply the Apache License to your work.
181 |
182 | To apply the Apache License to your work, attach the following
183 | boilerplate notice, with the fields enclosed by brackets "[]"
184 | replaced with your own identifying information. (Don't include
185 | the brackets!) The text should be enclosed in the appropriate
186 | comment syntax for the file format. We also recommend that a
187 | file or class name and description of purpose be included on the
188 | same "printed page" as the copyright notice for easier
189 | identification within third-party archives.
190 |
191 | Copyright (c) 2017 Baidu, Inc. All Rights Reserved
192 |
193 | Licensed under the Apache License, Version 2.0 (the "License");
194 | you may not use this file except in compliance with the License.
195 | You may obtain a copy of the License at
196 |
197 | http://www.apache.org/licenses/LICENSE-2.0
198 |
199 | Unless required by applicable law or agreed to in writing, software
200 | distributed under the License is distributed on an "AS IS" BASIS,
201 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
202 | See the License for the specific language governing permissions and
203 | limitations under the License.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | DLock - Distributed Lock
2 | ==========================
3 | [In Chinese 中文版](README.zh_cn.md)
4 |
5 | DLock is a Java implemented, effective and reliable Distributed Lock. It uses Redis to store lock object,
6 | and executes atomic operation on lock via [Lua](https://en.wikipedia.org/wiki/Lua_(programming_language)) script.
7 | Based on Redis expire mechanism, DLock implements lock [lease](https://en.wikipedia.org/wiki/Lease_(computer_science))
8 | to ensure release. In order to provide high performance, DLock adopts process level lock model and uses
9 | variant CLH queue to manage lock competitors.
10 |
11 | Requirements:[Java8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)+、
12 | [Redis2.6.12](https://redis.io/download)+(Require Redis Set -> NX PX command)
13 |
14 | Architecture
15 | --------
16 | 
17 |
18 | #### Features ####
19 | * Atomic lock operation
20 |
21 | One Lock Operation will correspond to one Lua script. Since Redis can execute Lua script atomically,
22 | Lock Operation such as lock, release and expand lease will be atomic.
23 |
24 | * Reentrant ability
25 |
26 | The variable ```holdCount ```is maintained by local DLock object. ```holdCount``` will be increased by one when
27 | locker re-enter, and decreased by one when leave.
28 |
29 | * Lock lease
30 |
31 | On the basis of Redis expire mechanism, the lock lease is integrated to release lock after the locker
32 | crashed. That is to say, infinite lock hold will never happen.
33 |
34 | * High performance lock model
35 |
36 | A lock-free variant CLH queue is used to maintain the competitor threads. And the retry thread will periodically
37 | awake the CLH queue's head thread to retry, so that only one thread per process can participate in lock competition,
38 | which will avoid unnecessary lock competition. Meanwhile, the unfair lock is also provided for throughput.
39 |
40 |
41 | Quick Start
42 | ------------
43 | Here we have a demo with 3 steps to introduce how to integrate DLock into Spring based projects.
44 |
45 | ### Step 1: Install Java8, Maven, Redis
46 | If you have already installed Maven, JDK and Redis, just skip to next.
47 | Download [Java8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html),
48 | [Maven](https://maven.apache.org/download.cgi) and [Redis2.6.12](https://redis.io/download), then install. For maven,
49 | extracting and setting MAVEN_HOME is enough.
50 | Download, extract and compile Redis with:
51 | ```sh
52 | wget http://download.redis.io/releases/redis-3.2.6.tar.gz
53 | tar xzf redis-3.2.6.tar.gz
54 | cd redis-3.2.6
55 | make
56 | ```
57 | The binaries that are now compiled are available in the src directory. Run Redis with:
58 | ```sh
59 | src/redis-server
60 | ```
61 | Now, Redis server is ready to accept connections on port 6379 by default.
62 |
63 | #### Set JAVA_HOME & MAVEN_HOME
64 | Here is a sample script to set JAVA_HOME and MAVEN_HOME
65 | ```shell
66 | export MAVEN_HOME=/xxx/xxx/software/maven/apache-maven-3.3.9
67 | export PATH=$MAVEN_HOME/bin:$PATH
68 | JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home";
69 | export JAVA_HOME;
70 | ```
71 |
72 | ### Step 2: Reset Redis configuration
73 | Reset property of 'redis.host' and 'redis.port' in [redis.properties](src/test/resources/dlock/redis.properties)
74 |
75 |
76 | ### Step 3: Run UnitTest
77 | DLock implements the interface of `java.util.concurrent.Lock`, and so, you can use DLock like that.
78 | [DLockSimpleTest](src/test/java/com/baidu/fsg/dlock/DLockSimpleTest.java) shows basic use of DLock;
79 | [DistributedReentrantLockTest](src/test/java/com/baidu/fsg/dlock/DistributedReentrantLockTest.java) show more complex use such like multi-competitors, reentrant lock.
80 |
81 | DLock TPS
82 | -------------
83 | DLock will group lock competitors into several groups, only one competitor of a group is able to compete, and
84 | competitors within a group obtain the competition chance sequentially by default. This will avoid unnecessary
85 | competition. To verify that, we compare DLock with tradition Lock Model(```tradition```) using the concept 'Lock Trip',
86 | and a 'Lock Trip' consists of ```lock()```, ```calculate()```, and ```unlock()```.
87 | In experiment, we set ```calculate()``` time and DLock's lease time to 10ms and 60ms separately, and vary concurrency
88 | from 8 to 128 with step 8. Finally, the TPS ratio of DLock to ```tradition``` is calculated, i.e:
89 | R = TPSDLock / TPStradition
90 |
91 | |threads|8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128
92 | |:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
93 | |R|1.01 |1.07 |1.21 |1.45 |1.56 |1.60 |1.66 |1.67 |1.69 |1.70 |1.71 |1.72 |1.74 |1.74 |1.67 |1.71 |
94 |
95 | ####Attention
96 | The Lock Model's TPS is related to ```calculate()```, so we just consider the performance trend.
97 | 
98 |
99 | However, R value has nothing to with ```calculate()``` time, and so it is significant.
100 | 
101 |
102 | From above data, we find ```tradition``` has comparable performance to DLock in low concurrency environment.
103 | With the increase of concurrency, ```tradition```'s performance degrade rapidly. But DLock is still good, this is
104 | because DLock will group competitors into a few groups with only one active competitor per group, as a result, DLock's
105 | performance will not worsen with concurrency increase. Furthermore, DLock implements non-fair Lock, which can respond
106 | to high priority request.
--------------------------------------------------------------------------------
/README.zh_cn.md:
--------------------------------------------------------------------------------
1 | DLock - Distributed Lock
2 | ==========================
3 | [In English](README.md)
4 |
5 | DLock是由Java实现的,一套高效高可靠的分布式锁方案。
6 | 使用Redis存储锁,通过[Lua](https://en.wikipedia.org/wiki/Lua_(programming_language))脚本进行原子性锁操作,
7 | 实现了基于Redis过期机制的[lease](https://en.wikipedia.org/wiki/Lease_(computer_science)),并提供了一种基于变种CLH队列的进程级锁竞争模型。
8 |
9 | 依赖版本:[Java8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)及以上版本、[Redis-2.6.12](http://redis.cn)及以上版本(使用到Redis Set -> NX PX指令)
10 |
11 | 架构设计
12 | --------
13 | 
14 |
15 | #### 特点 ####
16 | * 原子性
17 |
18 | 加锁、释放锁、延长租约等锁操作,均通过Lua脚本操作Redis,保证锁操作的原子性。
19 |
20 | * 可重入性
21 |
22 | 由本地锁对象内部存储持有者重入次数,等于零时释放锁, 从而保证锁的可重入.
23 |
24 | * 锁租约
25 |
26 | 基于Redis过期机制,实现了锁的租约和自动续租,既保证锁持有者有充足时间完成相应动作, 又避免持有者crash后锁不被释放的情形,提高了锁的可用性。
27 |
28 | * 高性能锁模型
29 |
30 | 采用lock-free的变种CLH锁队列维护竞争线程,并由重试线程唤醒Head去竞争锁, 从而将锁竞争粒度限定在进程级, 有效避免不必要的锁竞争. 此外还实现了非公平锁,以提升吞吐量。
31 |
32 |
33 | Quick Start
34 | ------------
35 | 这里介绍如何在基于Spring的项目中使用DLock,具体流程如下:
36 |
37 | ### 步骤1: 安装依赖Java8、Maven、Redis
38 | 下载[Java8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)、[maven](https://maven.apache.org/download.cgi)和[Redis2.6.12](http://redis.cn),然后安装部署。
39 | 对于Redis,可执行下述脚本来下载,解压和编译;
40 | ```sh
41 | wget http://download.redis.io/releases/redis-3.2.6.tar.gz
42 | tar xzf redis-3.2.6.tar.gz
43 | cd redis-3.2.6
44 | make
45 | ```
46 | 再执行下述脚本来部署Redis;
47 | ```sh
48 | src/redis-server
49 | ```
50 | 至此, Redis节点已在默认端口6379监听服务
51 |
52 | #### 设置环境变量
53 | maven无须安装,设置好MAVEN_HOME即可。可像下述脚本这样设置JAVA_HOME和MAVEN_HOME,如已设置请忽略。
54 | ```shell
55 | export MAVEN_HOME=/xxx/xxx/software/maven/apache-maven-3.3.9
56 | export PATH=$MAVEN_HOME/bin:$PATH
57 | JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home";
58 | export JAVA_HOME;
59 | ```
60 | ### 步骤2: 修改Redis连接配置
61 | 修改[redis.properties](src/test/resources/dlock/redis.properties)配置中, redis.host和redis.port为本地redis的配置。
62 |
63 | ### 步骤3: 运行示例单测
64 | DLock实现了JAVA的锁接口`java.util.concurrent.Lock`,其语法与Lock一致,无额外使用成本。
65 | 单测[DLockSimpleTest](src/test/java/com/baidu/fsg/dlock/DLockSimpleTest.java),展示了锁的基本用法;
66 | 单测[DistributedReentrantLockTest](src/test/java/com/baidu/fsg/dlock/DistributedReentrantLockTest.java),展示了如重入、多线程/进程竞争下锁等场景
67 |
68 |
69 | DLock TPS
70 | ----------
71 | DLock进程级的锁模型,采用了变种CLH队列维护待竞争线程,仅令单一线程参与竞争,从而有效降低无效锁竞争,提升整体性能。
72 | 为此,这里将传统锁模型(所有线程一起去竞争)与DLock的性能进行对比。以单位时间(秒)一次完整锁操作(获取锁 -> 计算 -> 释放锁)作为衡量指标。
73 | 在实验时,将获取锁后的计算时间设置为10ms,DLock的锁lease设置为60ms,并统计线程数分别为8至128(间隔为8)时的完整锁操作速度,并以百分比的形式展示,即:
74 | R = TPSDLock / TPStradition
75 | 数据如下表所示:
76 |
77 | |threads|8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128
78 | |:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
79 | |R|1.01 |1.07 |1.21 |1.45 |1.56 |1.60 |1.66 |1.67 |1.69 |1.70 |1.71 |1.72 |1.74 |1.74 |1.67 |1.71 |
80 |
81 | ####注意
82 | 由于完整锁操作的TPS值跟持有锁的时间有关,因此,单纯关注TPS值是没有意义的,这里比较TPS的变化趋势。
83 |
84 | 
85 |
86 | 变量R代表两种锁模型的TPS比值,与持有锁的时间无关,其数值是有意义的。
87 |
88 | 
89 |
90 | ####结论
91 | 在并发度很低时,DLock与传统锁模型的性能相当; 随着并发度的不断增加,传统锁模型性能开始下降,但DLock由于会将新增的竞争者添加到CLH队列中
92 | 进行等待(因为此时一起去竞争必然会有大量的线程竞争失败),依次参与锁竞争,减少了无效的锁竞争开销,从而使得锁性能保持不变。
93 | 同时DLock还支持非公平锁, 增加锁处理的吞吐量。
--------------------------------------------------------------------------------
/doc/dlock-architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baidu/dlock/9b8a82a0da327c3a4dc7128ad0707d26802f3b43/doc/dlock-architecture.png
--------------------------------------------------------------------------------
/doc/throughput0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baidu/dlock/9b8a82a0da327c3a4dc7128ad0707d26802f3b43/doc/throughput0.png
--------------------------------------------------------------------------------
/doc/throughput1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baidu/dlock/9b8a82a0da327c3a4dc7128ad0707d26802f3b43/doc/throughput1.png
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
35 | *
42 | *
43 | * We use a variant of CLH lock queue for the competitor threads, provides an unfair implement to make high
44 | * throughput.
45 | *
46 | * @author chenguoqing
47 | * @author yutianbao
48 | */
49 | public class DistributedReentrantLock implements Lock {
50 |
51 | /**
52 | * Lock configuration
53 | */
54 | private final DLockConfig lockConfig;
55 | /**
56 | * Lock processor
57 | */
58 | private final DLockProcessor lockProcessor;
59 |
60 | /**
61 | * Head of the wait queue, lazily initialized. Except for initialization, it is modified only via method setHead.
62 | * Note: If head exists, its waitStatus is guaranteed not to be CANCELLED.
63 | */
64 | private final AtomicReference
239 | *
240 | * If the current thread is the holder of this lock then the hold
241 | * count is decremented. If the hold count is now zero then the lock
242 | * is released. If the current thread is not the holder of this
243 | * lock then {@link IllegalMonitorStateException} is thrown.
244 | *
245 | * @throws IllegalMonitorStateException if the current thread does not
246 | * hold this lock
247 | */
248 | @Override
249 | public void unlock() throws IllegalMonitorStateException {
250 | // lock must be hold by current thread
251 | if (Thread.currentThread() != this.exclusiveOwnerThread.get()) {
252 | throw new IllegalMonitorStateException();
253 | }
254 |
255 | // lock is still be hold
256 | if (holdCount.decrementAndGet() > 0) {
257 | return;
258 | }
259 |
260 | // clear remote lock
261 | DLockEntity currentLock = new DLockEntity();
262 | currentLock.setLocker(generateLocker());
263 | currentLock.setLockStatus(DLockStatus.PROCESSING);
264 |
265 | try {
266 | // release remote lock
267 | lockProcessor.updateForUnlock(currentLock, lockConfig);
268 |
269 | } catch (OptimisticLockingException | DLockProcessException e) {
270 | // NOPE. Lock will deleted automatic after the expire time.
271 |
272 | } finally {
273 | // Release exclusive owner
274 | this.exclusiveOwnerThread.compareAndSet(Thread.currentThread(), null);
275 |
276 | // Shutdown expand thread
277 | shutdownExpandThread();
278 |
279 | // wake up the head node for compete lock
280 | unparkQueuedNode();
281 | }
282 | }
283 |
284 | /**
285 | * wake up the head node for compete lock
286 | */
287 | private void unparkQueuedNode() {
288 | // wake up the head node for compete lock
289 | Node h = head.get();
290 | if (h != null && h.next.get() != null) {
291 | LockSupport.unpark(h.next.get().t);
292 | }
293 | }
294 |
295 | /**
296 | * Generate current locker. IP_Thread ID
297 | */
298 | private String generateLocker() {
299 | return NetUtils.getLocalAddress() + "-" + Thread.currentThread().getId();
300 | }
301 |
302 | /**
303 | * Task for expanding the lock lease
304 | */
305 | abstract class LockThread extends Thread {
306 | /**
307 | * Synchronizes
308 | */
309 | final Object sync = new Object();
310 | /**
311 | * Delay time for start(ms)
312 | */
313 | final int delay;
314 | /**
315 | * Retry interval(ms)
316 | */
317 | final int retryInterval;
318 |
319 | final AtomicInteger startState = new AtomicInteger(0);
320 | /**
321 | * Control variable for shutdown
322 | */
323 | private boolean shouldShutdown = false;
324 | /**
325 | * Is first running
326 | */
327 | private boolean firstRunning = true;
328 |
329 | LockThread(String name, int delay, int retryInterval) {
330 | setDaemon(true);
331 | this.delay = delay;
332 | this.retryInterval = retryInterval;
333 | setName(name + "-" + getId());
334 | }
335 |
336 | @Override
337 | public void run() {
338 | while (!shouldShutdown) {
339 | synchronized (sync) {
340 | try {
341 | // first running, delay
342 | if (firstRunning && delay > 0) {
343 | firstRunning = false;
344 | sync.wait(delay);
345 | }
346 |
347 | // execute task
348 | execute();
349 |
350 | // wait for interval
351 | sync.wait(retryInterval);
352 |
353 | } catch (InterruptedException e) {
354 | shouldShutdown = true;
355 | }
356 | }
357 | }
358 |
359 | // clear associated resources for implementations
360 | beforeShutdown();
361 | }
362 |
363 | abstract void execute() throws InterruptedException;
364 |
365 | void beforeShutdown() {
366 | }
367 | }
368 |
369 | /**
370 | * Task for expanding the lock lease
371 | */
372 | private class ExpandLockLeaseThread extends LockThread {
373 |
374 | final DLockEntity lock;
375 |
376 | ExpandLockLeaseThread(DLockEntity lock, int delay, int retryInterval) {
377 | super("ExpandLockLeaseThread", delay, retryInterval);
378 | this.lock = lock;
379 | }
380 |
381 | @Override
382 | void execute() throws InterruptedException {
383 | try {
384 | // set lock time
385 | lock.setLockTime(System.currentTimeMillis());
386 |
387 | // update lock
388 | lockProcessor.expandLockExpire(lock, lockConfig);
389 |
390 | } catch (OptimisticLockingException e) {
391 | // if lock has been released, kill current thread
392 | throw new InterruptedException("Lock released.");
393 |
394 | } catch (DLockProcessException e) {
395 | // retry
396 | }
397 | }
398 |
399 | @Override
400 | void beforeShutdown() {
401 | expandLockRef.compareAndSet(this, null);
402 | }
403 | }
404 |
405 | private void startExpandLockLeaseThread(DLockEntity lock) {
406 | ExpandLockLeaseThread t = expandLockRef.get();
407 |
408 | while (t == null || t.getState() == Thread.State.TERMINATED) {
409 | // set new expand lock thread
410 | int retryInterval = (int) (lockConfig.getMillisLease() * 0.75);
411 | expandLockRef.compareAndSet(t, new ExpandLockLeaseThread(lock, 1, retryInterval));
412 |
413 | // retrieve the new expand thread instance
414 | t = expandLockRef.get();
415 | }
416 |
417 | if (t.startState.compareAndSet(0, 1)) {
418 | t.start();
419 | }
420 | }
421 |
422 | private void shutdownExpandThread() {
423 | ExpandLockLeaseThread t = expandLockRef.get();
424 | if (t != null && t.isAlive()) {
425 | t.interrupt();
426 | }
427 | }
428 |
429 | /**
430 | * Start when: (1) no threads hold lock; (2) CLH has waiting thread(s). And shutdown when one thread
431 | * posses the lock, because it does not has necessary to start retry thread.
432 | */
433 | private class RetryLockThread extends LockThread {
434 |
435 | RetryLockThread(int delay, int retryInterval) {
436 | super("RetryLockThread", delay, retryInterval);
437 | }
438 |
439 | @Override
440 | void execute() throws InterruptedException {
441 |
442 | // if existing running thread, kill self
443 | if (exclusiveOwnerThread.get() != null) {
444 | throw new InterruptedException("Has running thread.");
445 | }
446 |
447 | Node h = head.get();
448 |
449 | // no thread for lock, kill self
450 | if (h == null) {
451 | throw new InterruptedException("No waiting thread.");
452 | }
453 |
454 | boolean needRetry = false;
455 | try {
456 | needRetry = lockProcessor.isLockFree(lockConfig.getLockUniqueKey());
457 | } catch (DLockProcessException e) {
458 | needRetry = true;
459 | }
460 |
461 | // if the lock has been releases or expired, re-competition
462 | if (needRetry) {
463 | // wake up the head node for compete lock
464 | unparkQueuedNode();
465 | }
466 | }
467 |
468 | @Override
469 | void beforeShutdown() {
470 | retryLockRef.compareAndSet(this, null);
471 | }
472 | }
473 |
474 | /**
475 | * Start the retry thread
476 | */
477 | private void startRetryThread() {
478 | RetryLockThread t = retryLockRef.get();
479 |
480 | while (t == null || t.getState() == Thread.State.TERMINATED) {
481 | retryLockRef.compareAndSet(t, new RetryLockThread((int) (lockConfig.getMillisLease() / 10),
482 | (int) (lockConfig.getMillisLease() / 6)));
483 |
484 | t = retryLockRef.get();
485 | }
486 |
487 | if (t.startState.compareAndSet(0, 1)) {
488 | t.start();
489 | }
490 | }
491 |
492 | /**
493 | * Shutdown retry thread
494 | */
495 | private void shutdownRetryThread() {
496 | RetryLockThread t = retryLockRef.get();
497 | if (t != null && t.isAlive()) {
498 | t.interrupt();
499 | }
500 | }
501 | }
502 |
--------------------------------------------------------------------------------
/src/main/java/com/baidu/fsg/dlock/domain/DLockConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.baidu.fsg.dlock.domain;
17 |
18 | import java.io.Serializable;
19 | import java.util.concurrent.TimeUnit;
20 |
21 | import org.apache.commons.lang.StringUtils;
22 | import org.apache.commons.lang.builder.ToStringBuilder;
23 | import org.apache.commons.lang.builder.ToStringStyle;
24 |
25 | /**
26 | * This class representing a distribute lock configuration.
29 | *
30 | * Sample:
33 | *
34 | * LockType: BATCH_PROCESS_LOCK, LockTartget: MAP_NODE, Lease: 300
42 | *
43 | *
57 | *
58 | *
37 | *
38 | * DataModel:
44 | *
45 | *
27 | * The minimum granularity of the lock entity is LockUniqueKey, which consists of $UK_PRE_$LockType_$LockTarget,
28 | * You can set a specified lease time for each lockUniqueKey
31 | * LockType: USER_LOCK, LockTartget: 2356784, Lease: 500
32 | * LockType: USER_LOCK, LockTartget: 2356783, Lease: 500
35 | * LockType: BATCH_PROCESS_LOCK, LockTartget: REDUCE_NODE, Lease: 400
36 | *
37 | * @author yutianbao
38 | */
39 | public class DLockConfig implements Serializable {
40 | private static final long serialVersionUID = -1332663877601479136L;
41 |
42 | /** Prefix for unique key generating */
43 | public static final String UK_PRE = "DLOCK";
44 |
45 | /** Separator for unique key generating */
46 | public static final String UK_SP = "_";
47 |
48 | /**
49 | * Lock type represents a group lockTargets with the same type.
50 | * The type is divided by different business scenarios, kind of USER_LOCK, ORDER_LOCK, BATCH_PROCCESS_LOCK...
51 | */
52 | private final String lockType;
53 |
54 | /**
55 | * Lock target represents a real lock target. lockType: USER_LOCK, lockTarget should be the UserID.
56 | */
57 | private final String lockTarget;
58 |
59 | /**
60 | * Lock unique key represents the minimum granularity of the lock.
61 | * The naming policy is $UK_PRE_$lockType_$lockTarget
62 | */
63 | private final String lockUniqueKey;
64 |
65 | /**
66 | * Lock lease duration
67 | */
68 | private final int lease;
69 |
70 | /**
71 | * Lock Lease time unit
72 | */
73 | private final TimeUnit leaseTimeUnit;
74 |
75 | /**
76 | * Constructor with lockType & lockTarget & leaseTime & leaseTimeUnit
77 | */
78 | public DLockConfig(String lockType, String lockTarget, int lease, TimeUnit leaseTimeUnit) {
79 | this.lockType = lockType;
80 | this.lockTarget = lockTarget;
81 | this.lockUniqueKey = UK_PRE + UK_SP + lockType + UK_SP + StringUtils.trimToEmpty(lockTarget);
82 | this.lease = lease;
83 | this.leaseTimeUnit = leaseTimeUnit;
84 | }
85 |
86 | /**
87 | * Getters
88 | */
89 | public String getLockType() {
90 | return lockType;
91 | }
92 |
93 | public String getLockTarget() {
94 | return lockTarget;
95 | }
96 |
97 | public int getLease() {
98 | return lease;
99 | }
100 |
101 | public TimeUnit getLeaseTimeUnit() {
102 | return leaseTimeUnit;
103 | }
104 |
105 | public String getLockUniqueKey() {
106 | return lockUniqueKey;
107 | }
108 |
109 | /**
110 | * Get the lease of millis unit
111 | */
112 | public long getMillisLease() {
113 | return leaseTimeUnit.toMillis(lease);
114 | }
115 |
116 | @Override
117 | public String toString() {
118 | return ToStringBuilder.reflectionToString(this, ToStringStyle.DEFAULT_STYLE);
119 | }
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/src/main/java/com/baidu/fsg/dlock/domain/DLockEntity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.baidu.fsg.dlock.domain;
17 |
18 | import java.io.Serializable;
19 |
20 | import org.apache.commons.lang.builder.ToStringBuilder;
21 | import org.apache.commons.lang.builder.ToStringStyle;
22 |
23 | /**
24 | * DLockEntity represents an distributed lock entity, consists of lock status, locker, lockTime.
25 | *
26 | * @author chenguoqing
27 | * @author yutianbao
28 | */
29 | public class DLockEntity implements Serializable, Cloneable {
30 | private static final long serialVersionUID = 8479390959137749786L;
31 |
32 | /**
33 | * Task status default as {@link DLockStatus#INITIAL}
34 | */
35 | private DLockStatus lockStatus = DLockStatus.INITIAL;
36 |
37 | /**
38 | * The server ip address that locked the task
39 | */
40 | private String locker;
41 |
42 | /**
43 | * Lock time for milliseconds
44 | */
45 | private Long lockTime = -1L;
46 |
47 | /**
48 | * Constructor
49 | */
50 | public DLockEntity() {
51 | }
52 |
53 | /**
54 | * Getters & Setters
55 | */
56 | public DLockStatus getLockStatus() {
57 | return lockStatus;
58 | }
59 |
60 | public void setLockStatus(DLockStatus lockStatus) {
61 | this.lockStatus = lockStatus;
62 | }
63 |
64 | public String getLocker() {
65 | return locker;
66 | }
67 |
68 | public void setLocker(String locker) {
69 | this.locker = locker;
70 | }
71 |
72 | public Long getLockTime() {
73 | return lockTime;
74 | }
75 |
76 | public void setLockTime(Long lockTime) {
77 | this.lockTime = lockTime;
78 | }
79 |
80 | @Override
81 | public String toString() {
82 | return ToStringBuilder.reflectionToString(this, ToStringStyle.DEFAULT_STYLE);
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/src/main/java/com/baidu/fsg/dlock/domain/DLockStatus.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.baidu.fsg.dlock.domain;
17 |
18 | import com.baidu.fsg.dlock.utils.ValuedEnum;
19 |
20 | /**
21 | * Lock status
22 | *
23 | * @author chenguoqing
24 | */
25 | public enum DLockStatus implements ValuedEnum
39 | *
54 | *
77 | *
78 | *
82 | *
83 | *
39 | * Key: LockUniqueKey, Value: Locker(IP + ThreadID), Expire: lease duration(ms).
40 | *
41 | * @author yutianbao
42 | */
43 | @Service
44 | public class RedisLockProcessor implements DLockProcessor {
45 | private static final Logger LOGGER = LoggerFactory.getLogger(RedisLockProcessor.class);
46 |
47 | /**
48 | * Redis command & result code constant
49 | */
50 | private static final String SET_ARG_NOT_EXIST = "NX";
51 | private static final String SET_ARG_EXPIRE = "PX";
52 | private static final String RES_OK = "OK";
53 |
54 | @Resource
55 | private JedisClient jedisClient;
56 |
57 | /**
58 | * Load by unique key. For redis implement, you can find locker & status from the result entity.
59 | *
60 | * @param uniqueKey key
61 | * @throws RedisProcessException if catch any exception from {@link redis.clients.jedis.Jedis}
62 | */
63 | @Override
64 | public DLockEntity load(String uniqueKey) throws RedisProcessException {
65 | // GET command
66 | String locker;
67 | try {
68 | locker = jedisClient.get(uniqueKey);
69 | } catch (Exception e) {
70 | LOGGER.warn("Exception occurred by GET command for key:" + uniqueKey, e);
71 | throw new RedisProcessException("Exception occurred by GET command for key:" + uniqueKey, e);
72 | }
73 |
74 | if (locker == null) {
75 | return null;
76 | }
77 |
78 | // build entity
79 | DLockEntity lockEntity = new DLockEntity();
80 | lockEntity.setLocker(locker);
81 | lockEntity.setLockStatus(DLockStatus.PROCESSING);
82 |
83 | return lockEntity;
84 | }
85 |
86 | /**
87 | * Update for lock using redis SET(NX, PX) command.
88 | *
89 | * @param newLock with locker in it
90 | * @param lockConfig
91 | * @throws RedisProcessException Redis command execute exception
92 | * @throws OptimisticLockingException the lock is hold by the other request.
93 | */
94 | @Override
95 | public void updateForLock(DLockEntity newLock, DLockConfig lockConfig)
96 | throws RedisProcessException, OptimisticLockingException {
97 | // SET(NX, PX) command
98 | String lockRes;
99 | try {
100 | lockRes = jedisClient.set(lockConfig.getLockUniqueKey(), newLock.getLocker(), SET_ARG_NOT_EXIST,
101 | SET_ARG_EXPIRE, lockConfig.getMillisLease());
102 |
103 | } catch (Exception e) {
104 | LOGGER.warn("Exception occurred by SET(NX, PX) command for key:" + lockConfig.getLockUniqueKey(), e);
105 | throw new RedisProcessException(
106 | "Exception occurred by SET(NX, PX) command for key:" + lockConfig.getLockUniqueKey(), e);
107 | }
108 |
109 | if (!RES_OK.equals(lockRes)) {
110 | LOGGER.warn("Fail to get lock for key:{} ,locker={}", lockConfig.getLockUniqueKey(), newLock.getLocker());
111 | throw new OptimisticLockingException(
112 | "Fail to get lock for key:" + lockConfig.getLockUniqueKey() + " ,locker=" + newLock.getLocker());
113 | }
114 | }
115 |
116 | /**
117 | * The redis expire mechanism guaranteed the expired key is removed automatic.
118 | * It is not necessary to check condition(status=1 && expire=true)
119 | */
120 | @Override
121 | public void updateForLockWithExpire(DLockEntity expireLock, DLockEntity dbLock, DLockConfig lockConfig) {
122 | throw new UnsupportedOperationException("updateForLockWithExpire is not supported");
123 | }
124 |
125 | /**
126 | * Extend lease for lock with lua script.
127 | *
128 | * @param leaseLock with locker in it
129 | * @param lockConfig
130 | * @throws RedisProcessException if catch any exception from {@link redis.clients.jedis.Jedis}
131 | * @throws OptimisticLockingException if the lock is released or be hold by another one.
132 | */
133 | @Override
134 | public void expandLockExpire(DLockEntity leaseLock, DLockConfig lockConfig)
135 | throws RedisProcessException, OptimisticLockingException {
136 | // Expire if key is existed and equal with the specified value(locker).
137 | String leaseScript = "if (redis.call('get', KEYS[1]) == ARGV[1]) then "
138 | + " return redis.call('pexpire', KEYS[1], ARGV[2]); "
139 | + "else"
140 | + " return nil; "
141 | + "end; ";
142 |
143 | Object leaseRes;
144 | try {
145 | leaseRes = jedisClient.eval(leaseScript, Arrays.asList(lockConfig.getLockUniqueKey()),
146 | Arrays.asList(leaseLock.getLocker(), lockConfig.getMillisLease() + ""));
147 | } catch (Exception e) {
148 | LOGGER.warn("Exception occurred by ExpandLease lua script for key:" + lockConfig.getLockUniqueKey(), e);
149 | throw new RedisProcessException(
150 | "Exception occurred by ExpandLease lua script for key:" + lockConfig.getLockUniqueKey(), e);
151 | }
152 |
153 | // null means lua return nil (the lock is released or be hold by the other request)
154 | if (leaseRes == null) {
155 | LOGGER.warn("Fail to lease for key:{} ,locker={}", lockConfig.getLockUniqueKey(), leaseLock.getLocker());
156 | throw new OptimisticLockingException(
157 | "Fail to lease for key:" + lockConfig.getLockUniqueKey() + " ,locker=" + leaseLock.getLocker());
158 | }
159 | }
160 |
161 | /**
162 | * Release lock using lua script.
163 | *
164 | * @param currentLock with locker in it
165 | * @param lockConfig
166 | * @throws RedisProcessException if catch any exception from {@link redis.clients.jedis.Jedis}
167 | * @throws OptimisticLockingException if the lock is released or be hold by another one.
168 | */
169 | @Override
170 | public void updateForUnlock(DLockEntity currentLock, DLockConfig lockConfig)
171 | throws RedisProcessException, OptimisticLockingException {
172 | // Delete if key is existed and equal with the specified value(locker).
173 | String unlockScript = "if (redis.call('get', KEYS[1]) == ARGV[1]) then "
174 | + " return redis.call('del', KEYS[1]); "
175 | + "else "
176 | + " return nil; "
177 | + "end;";
178 |
179 | Object unlockRes;
180 | try {
181 | unlockRes = jedisClient.eval(unlockScript, Arrays.asList(lockConfig.getLockUniqueKey()),
182 | Arrays.asList(currentLock.getLocker()));
183 | } catch (Exception e) {
184 | LOGGER.warn("Exception occurred by Unlock lua script for key:" + lockConfig.getLockUniqueKey(), e);
185 | throw new RedisProcessException(
186 | "Exception occurred by Unlock lua script for key:" + lockConfig.getLockUniqueKey(), e);
187 | }
188 |
189 | // null means lua return nil (the lock is released or be hold by the other request)
190 | if (unlockRes == null) {
191 | LOGGER.warn("Fail to unlock for key:{} ,locker={}", lockConfig.getLockUniqueKey(), currentLock.getLocker());
192 | throw new OptimisticLockingException("Fail to unlock for key:" + lockConfig.getLockUniqueKey()
193 | + ",locker=" + currentLock.getLocker());
194 | }
195 | }
196 |
197 | @Override
198 | public boolean isLockFree(String uniqueKey) {
199 | DLockEntity locked = this.load(uniqueKey);
200 | return locked == null;
201 | }
202 |
203 | }
204 |
--------------------------------------------------------------------------------
/src/main/java/com/baidu/fsg/dlock/support/DLockGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.baidu.fsg.dlock.support;
17 |
18 | import java.util.HashMap;
19 | import java.util.Map;
20 | import java.util.Map.Entry;
21 | import java.util.Properties;
22 | import java.util.concurrent.TimeUnit;
23 | import java.util.concurrent.locks.Lock;
24 |
25 | import javax.annotation.PostConstruct;
26 | import javax.annotation.Resource;
27 |
28 | import org.apache.commons.collections.MapUtils;
29 | import org.apache.commons.lang.StringUtils;
30 | import org.springframework.core.io.support.PropertiesLoaderUtils;
31 | import org.springframework.stereotype.Service;
32 | import org.springframework.util.Assert;
33 |
34 | import com.baidu.fsg.dlock.DistributedReentrantLock;
35 | import com.baidu.fsg.dlock.domain.DLockConfig;
36 | import com.baidu.fsg.dlock.domain.DLockType;
37 | import com.baidu.fsg.dlock.processor.DLockProcessor;
38 | import com.baidu.fsg.dlock.utils.EnumUtils;
39 |
40 | /**
41 | * DLockGenerator represents a generator for {@link DistributedReentrantLock}
42 | * It will load the lease time of {@link DLockType} configured in file config-dlock.properties, key is DLockType Enum
43 | * name, value is lease time(ms). Sample as below:CUSTOMER_LOCK=1000
46 | * XXXXXXXX_LOCK=2000
47 | *
48 | * @author yutianbao
49 | */
50 | @Service
51 | public class DLockGenerator {
52 |
53 | /** Default dlock configuration path */
54 | private static final String DEFAULT_CONF_PATH = "dlock/config-dlock.properties";
55 |
56 | @Resource
57 | private DLockProcessor lockProcessor;
58 |
59 | /**
60 | * Key for DLockType enum, Value for lease time (ms)
61 | */
62 | private Map