├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── README.md ├── slock.c ├── slock.h └── tests ├── golang ├── go.mod ├── go.sum └── main.go └── php ├── client.php ├── client1.php └── rlock_client.php /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.xo 9 | *.elf 10 | 11 | # Linker output 12 | *.ilk 13 | *.map 14 | *.exp 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Libraries 21 | *.lib 22 | *.a 23 | *.la 24 | *.lo 25 | 26 | # Shared objects (inc. Windows DLLs) 27 | *.dll 28 | *.so 29 | *.so.* 30 | *.dylib 31 | 32 | # Executables 33 | *.exe 34 | *.out 35 | *.app 36 | *.i*86 37 | *.x86_64 38 | *.hex 39 | 40 | # Debug files 41 | *.dSYM/ 42 | *.su 43 | *.idb 44 | *.pdb 45 | 46 | # Kernel Module Compile Results 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | .idea/ 54 | /cmake-build-debug -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 3.5) 2 | project(slock C) 3 | 4 | 5 | AUX_SOURCE_DIRECTORY(. SRC_LIST) 6 | add_library(slock SHARED ${SRC_LIST}) 7 | set_target_properties(slock PROPERTIES output_name "slock") 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Adam 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | # find the OS 3 | uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') 4 | 5 | # Compile flags for linux / osx 6 | ifeq ($(uname_S),Linux) 7 | SHOBJ_CFLAGS ?= -W -Wall -fno-common -g -ggdb -std=c99 -O2 8 | SHOBJ_LDFLAGS ?= -shared 9 | else 10 | SHOBJ_CFLAGS ?= -W -Wall -dynamic -fno-common -g -ggdb -std=c99 -O2 11 | SHOBJ_LDFLAGS ?= -bundle -undefined dynamic_lookup 12 | endif 13 | 14 | .SUFFIXES: .c .so .xo .o 15 | 16 | all: slock.so 17 | 18 | .c.xo: 19 | $(CC) -I. $(CFLAGS) $(SHOBJ_CFLAGS) -fPIC -c $< -o $@ 20 | 21 | slock.xo: ../src/redismodule.h 22 | 23 | slock.so: slock.xo 24 | $(LD) -o $@ $< $(SHOBJ_LDFLAGS) $(LIBS) -lc 25 | 26 | clean: 27 | rm -rf *.xo *.so 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![jk](https://img.shields.io/github/stars/wujunwei/redlock?color=blue)](https://github.com/wujunwei/redlock) 2 | [![jk](https://img.shields.io/github/watchers/wujunwei/redlock?color=green)](https://github.com/wujunwei/redlock) 3 | [![jk](https://img.shields.io/github/forks/wujunwei/redlock?color=red)](https://github.com/wujunwei/redlock) 4 | [![jk](https://img.shields.io/badge/support_by-adam-C70039.svg?style=flat-square)]() 5 | 6 | # redlock 7 | a way to achieve distributed lock by redis module 8 | 9 | redis 10 | 11 | 12 | ### build 13 | 14 | ``` 15 | git clone --depth=1 git@github.com:redis/redis.git 16 | cd redis 17 | git clone https://github.com/wujunwei/redlock 18 | cd redlock 19 | make 20 | ``` 21 | 22 | ### install 23 | 24 | ``` 25 | //run it in redis cli or add it into the conf 26 | module load redlock.so 27 | ``` 28 | ### How to use 29 | 30 | * **slock.lock lock_key (expire_time)** 31 |
The command will return result immediately ,you shall call lock in a while or give up locking 32 | * **slock.unlock key** 33 |
Release the write-lock, if the lock wasn't been created by the same client, it will fail with 0. 34 | * **slock.rlock key (expire_time)** 35 |
Acquire the read-lock(share lock), if the lock wasn't been created by the same client, it will fail with 0. 36 | * **slock.runlock key** 37 |
Reduce the readers count of read-lock(share lock), if the readers count equal to 0 ,it will be released. 38 |
This command won't be limited by the different client. if the lock isn't created by the command "slock.rlock", it will fail with 0. 39 | * **slock.info key** 40 |
This command will return an array with four integers, first is the client id , second is the time when lock was created , the third one is whether the lock is write-lock or not (reply with 0 present lock fail, and otherwise success) and the last one is the count of require the read lock(about the lock command ,it 's always 0). 41 | 42 | **PLEASE NOTE:** The module recommend to be used for stand-alone or Sharding mode,use it carefully. 43 | -------------------------------------------------------------------------------- /slock.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by adam on 2018-11-28. 3 | // 4 | #include "slock.h" 5 | 6 | /** 7 | * slock.lock lock_key expire 8 | * the command lock will return result immediately , 9 | * you shall call lock in a while or give up locking 10 | * @param ctx 11 | * @param argv 12 | * @param argc 13 | * @return int 14 | */ 15 | SLock *createSlock(RedisModuleCtx *ctx, int is_write) { 16 | SLock *lock = RedisModule_Alloc(sizeof(*lock)); 17 | lock->write_client_id = RedisModule_GetClientId(ctx); 18 | lock->reader_count = 0; 19 | lock->lock_time = RedisModule_Milliseconds(); 20 | lock->is_write = is_write ? TRUE : FALSE; 21 | return lock; 22 | } 23 | 24 | int SlockLock_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { 25 | RedisModule_AutoMemory(ctx); 26 | if (argc < 2) { 27 | return RedisModule_WrongArity(ctx); 28 | } 29 | RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ | REDISMODULE_WRITE); 30 | int keyType = RedisModule_KeyType(key); 31 | if (keyType == REDISMODULE_KEYTYPE_EMPTY) { 32 | SLock *lock = createSlock(ctx, TRUE); 33 | RedisModule_ModuleTypeSetValue(key, SLockType, lock); 34 | if (argc == 3) { 35 | long long expire_time; 36 | if (RedisModule_StringToLongLong(argv[2], &expire_time) != REDISMODULE_OK) { 37 | return RedisModule_ReplyWithError(ctx, ERR_INVALID_EXPIRE_TIME); 38 | } 39 | RedisModule_SetExpire(key, expire_time); 40 | } 41 | RedisModule_ReplyWithLongLong(ctx, 1); 42 | } else { 43 | if (RedisModule_ModuleTypeGetType(key) != SLockType) { 44 | return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); 45 | } 46 | RedisModule_ReplyWithLongLong(ctx, 0); 47 | } 48 | RedisModule_CloseKey(key); 49 | return REDISMODULE_OK; 50 | } 51 | 52 | /** 53 | * Slock.unlock key 54 | * @param ctx 55 | * @param argv 56 | * @param argc 57 | * @return int 58 | */ 59 | int SlockUnLock_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { 60 | RedisModule_AutoMemory(ctx); 61 | if (argc != 2) { 62 | return RedisModule_WrongArity(ctx); 63 | } 64 | 65 | RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE | REDISMODULE_READ); 66 | if (RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_EMPTY) { 67 | return RedisModule_ReplyWithNull(ctx); 68 | } 69 | if (RedisModule_ModuleTypeGetType(key) != SLockType) { 70 | return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); 71 | } else { 72 | SLock *lock = RedisModule_ModuleTypeGetValue(key); 73 | if (lock->write_client_id == RedisModule_GetClientId(ctx) && lock->is_write) { 74 | RedisModule_DeleteKey(key); 75 | RedisModule_ReplyWithLongLong(ctx, 1); 76 | } else { 77 | RedisModule_ReplyWithLongLong(ctx, 0); 78 | } 79 | } 80 | RedisModule_CloseKey(key); 81 | return REDISMODULE_OK; 82 | } 83 | 84 | 85 | /** 86 | * slock.rlock lock_key expire 87 | * the command lock will return result immediately , 88 | * you shall call lock in a while or give up locking 89 | * @param ctx 90 | * @param argv 91 | * @param argc 92 | * @return int 93 | */ 94 | int SlockRLock_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { 95 | RedisModule_AutoMemory(ctx); 96 | if (argc < 2) { 97 | return RedisModule_WrongArity(ctx); 98 | } 99 | RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ | REDISMODULE_WRITE); 100 | int keyType = RedisModule_KeyType(key); 101 | if (keyType == REDISMODULE_KEYTYPE_EMPTY) { 102 | SLock *lock = createSlock(ctx, FALSE); 103 | RedisModule_ModuleTypeSetValue(key, SLockType, lock); 104 | } else { 105 | // Exclude write-lock 106 | if (RedisModule_ModuleTypeGetType(key) != SLockType) { 107 | return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); 108 | } 109 | SLock *lock = RedisModule_ModuleTypeGetValue(key); 110 | if (lock->is_write) { 111 | return RedisModule_ReplyWithLongLong(ctx, 0); 112 | } 113 | lock->reader_count += 1; 114 | } 115 | if (argc == 3) { 116 | long long expire_time; 117 | if (RedisModule_StringToLongLong(argv[2], &expire_time) != REDISMODULE_OK) { 118 | return RedisModule_ReplyWithError(ctx, ERR_INVALID_EXPIRE_TIME); 119 | } 120 | RedisModule_SetExpire(key, expire_time); 121 | } 122 | RedisModule_ReplyWithLongLong(ctx, 1); 123 | RedisModule_CloseKey(key); 124 | return REDISMODULE_OK; 125 | } 126 | 127 | /** 128 | * Slock.unlock key 129 | * @param ctx 130 | * @param argv 131 | * @param argc 132 | * @return int 133 | */ 134 | int SlockRUnLock_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { 135 | RedisModule_AutoMemory(ctx); 136 | if (argc != 2) { 137 | return RedisModule_WrongArity(ctx); 138 | } 139 | 140 | RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE | REDISMODULE_READ); 141 | if (RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_EMPTY) { 142 | return RedisModule_ReplyWithNull(ctx); 143 | } 144 | if (RedisModule_ModuleTypeGetType(key) != SLockType) { 145 | return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); 146 | } 147 | SLock *lock; 148 | lock = RedisModule_ModuleTypeGetValue(key); 149 | if (!lock->is_write) { 150 | if (--lock->reader_count <= 0) { 151 | RedisModule_DeleteKey(key); 152 | } 153 | RedisModule_ReplyWithLongLong(ctx, 1); 154 | } else { 155 | RedisModule_ReplyWithLongLong(ctx, 0); 156 | } 157 | RedisModule_CloseKey(key); 158 | return REDISMODULE_OK; 159 | } 160 | 161 | /** 162 | * SLOCK.INFO key 163 | * this command will return an array with four integers, first is the client id , second is the time when lock was created , the third one is whether the lock is write-lock or not (reply with 0 present lock fail, and otherwise success) and the last one is the count of require the read lock(about the lock command ,it 's always 0). 164 | * @param ctx 165 | * @param argv 166 | * @param agrc 167 | * @return int 168 | */ 169 | int SlockInfo_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { 170 | RedisModule_AutoMemory(ctx); 171 | if (argc != 2) { 172 | return RedisModule_WrongArity(ctx); 173 | } 174 | 175 | RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ); 176 | if (RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_EMPTY) { 177 | return RedisModule_ReplyWithNull(ctx); 178 | } 179 | //判断键类型 180 | if (RedisModule_ModuleTypeGetType(key) != SLockType) { 181 | return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); 182 | } else { 183 | SLock *lock = RedisModule_ModuleTypeGetValue(key); 184 | RedisModule_ReplyWithArray(ctx, 4); 185 | RedisModule_ReplyWithLongLong(ctx, lock->write_client_id); 186 | RedisModule_ReplyWithLongLong(ctx, lock->lock_time); 187 | RedisModule_ReplyWithLongLong(ctx, lock->is_write); 188 | RedisModule_ReplyWithLongLong(ctx, lock->reader_count); 189 | } 190 | RedisModule_CloseKey(key); 191 | return REDISMODULE_OK; 192 | } 193 | 194 | /* ========================== type methods ======================= */ 195 | 196 | void *SLockRdbLoad(RedisModuleIO *rdb, int encver) { 197 | if (encver != 0) { 198 | /* RedisModule_Log("warning","Can't load data with version %d", encver);*/ 199 | return NULL; 200 | } 201 | SLock *sl = RedisModule_Alloc(sizeof(sl)); 202 | sl->write_client_id = RedisModule_LoadUnsigned(rdb); 203 | sl->lock_time = RedisModule_LoadSigned(rdb); 204 | sl->is_write = RedisModule_LoadSigned(rdb); 205 | sl->reader_count = RedisModule_LoadUnsigned(rdb); 206 | return sl; 207 | } 208 | 209 | void SLockRdbSave(RedisModuleIO *rdb, void *value) { 210 | SLock *sl = value; 211 | RedisModule_SaveUnsigned(rdb, sl->write_client_id); 212 | RedisModule_SaveSigned(rdb, sl->lock_time); 213 | RedisModule_SaveSigned(rdb, sl->is_write); 214 | RedisModule_SaveUnsigned(rdb, sl->reader_count); 215 | } 216 | 217 | void SLockAofRewrite(RedisModuleIO *aof, RedisModuleString *key, void *value) { 218 | SLock *sl = value; 219 | if (sl->is_write) { 220 | RedisModule_EmitAOF(aof, "SLOCK.LOCK", "s", key); 221 | return; 222 | } 223 | 224 | unsigned long long count = sl->reader_count; 225 | while (count--){ 226 | RedisModule_EmitAOF(aof, "SLOCK.rLOCK", "s", key); 227 | } 228 | 229 | } 230 | 231 | /* The goal of this function is to return the amount of memory used by 232 | * the HelloType value. */ 233 | size_t SLockMemUsage(const void *value) { 234 | const SLock *hto = value; 235 | return sizeof(*hto); 236 | } 237 | 238 | void SLockFree(void *value) { 239 | RedisModule_Free(value); 240 | } 241 | 242 | void SLockDigest(RedisModuleDigest *md, void *value) { 243 | SLock *sl = value; 244 | RedisModule_DigestAddLongLong(md, sl->write_client_id); 245 | RedisModule_DigestAddLongLong(md, sl->is_write); 246 | RedisModule_DigestAddLongLong(md, sl->reader_count); 247 | RedisModule_DigestAddLongLong(md, sl->lock_time); 248 | RedisModule_DigestEndSequence(md); 249 | } 250 | 251 | /* This function must be present on each Redis module. It is used in order to 252 | * register the commands into the Redis server. */ 253 | int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { 254 | REDISMODULE_NOT_USED(argv); 255 | REDISMODULE_NOT_USED(argc); 256 | 257 | if (RedisModule_Init(ctx, MODULE_NAME, MODULE_VERSION, REDISMODULE_APIVER_1) 258 | == REDISMODULE_ERR) 259 | return REDISMODULE_ERR; 260 | RedisModuleTypeMethods tm = { 261 | .version = REDISMODULE_TYPE_METHOD_VERSION, 262 | .rdb_load = SLockRdbLoad, 263 | .rdb_save = SLockRdbSave, 264 | .aof_rewrite = SLockAofRewrite, 265 | .mem_usage = SLockMemUsage, 266 | .free = SLockFree, 267 | .digest = SLockDigest 268 | }; 269 | 270 | SLockType = RedisModule_CreateDataType(ctx, "slocktype", 0, &tm); 271 | if (SLockType == NULL) return REDISMODULE_ERR; 272 | 273 | if (RedisModule_CreateCommand(ctx, COMMAND_SLOCK_UNLOCK, SlockUnLock_RedisCommand, "write", 1, 1, 1) == 274 | REDISMODULE_ERR) 275 | return REDISMODULE_ERR; 276 | 277 | if (RedisModule_CreateCommand(ctx, COMMAND_SLOCK_LOCK, SlockLock_RedisCommand, "write", 1, 1, 1) == REDISMODULE_ERR) 278 | return REDISMODULE_ERR; 279 | 280 | 281 | if (RedisModule_CreateCommand(ctx, COMMAND_SLOCK_RLOCK, SlockRLock_RedisCommand, "write", 1, 1, 1) == 282 | REDISMODULE_ERR) 283 | return REDISMODULE_ERR; 284 | 285 | if (RedisModule_CreateCommand(ctx, COMMAND_SLOCK_RUNLOCK, SlockRUnLock_RedisCommand, "write", 1, 1, 1) == 286 | REDISMODULE_ERR) 287 | return REDISMODULE_ERR; 288 | 289 | if (RedisModule_CreateCommand(ctx, COMMAND_SLOCK_INFO, SlockInfo_RedisCommand, "readonly", 1, 1, 1) == 290 | REDISMODULE_ERR) 291 | return REDISMODULE_ERR; 292 | 293 | return REDISMODULE_OK; 294 | } 295 | -------------------------------------------------------------------------------- /slock.h: -------------------------------------------------------------------------------- 1 | #ifndef SLOCK_H 2 | #define SLOCK_H 3 | 4 | #include "../src/redismodule.h" 5 | #include 6 | 7 | static RedisModuleType *SLockType; 8 | 9 | #define TRUE 1 10 | #define FALSE 0 11 | 12 | typedef struct slock { 13 | mstime_t lock_time; 14 | int is_write; 15 | unsigned long long reader_count; 16 | unsigned long long write_client_id; 17 | } SLock; 18 | 19 | 20 | //Error message definition 21 | #define ERR_INVALID_EXPIRE_TIME "ERR invalid expireTime" 22 | 23 | //COMMAND TYPE 24 | #define COMMAND_SLOCK_UNLOCK "slock.unlock" 25 | #define COMMAND_SLOCK_LOCK "slock.lock" 26 | #define COMMAND_SLOCK_INFO "slock.info" 27 | #define COMMAND_SLOCK_RLOCK "slock.rlock" 28 | #define COMMAND_SLOCK_RUNLOCK "slock.runlock" 29 | 30 | //MODULE INFO 31 | #define MODULE_NAME "slock" 32 | #define MODULE_VERSION 1 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /tests/golang/go.mod: -------------------------------------------------------------------------------- 1 | module test 2 | 3 | go 1.19 4 | 5 | require github.com/go-redis/redis/v8 v8.11.5 6 | 7 | require ( 8 | github.com/cespare/xxhash/v2 v2.1.2 // indirect 9 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect 10 | ) 11 | -------------------------------------------------------------------------------- /tests/golang/go.sum: -------------------------------------------------------------------------------- 1 | github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= 2 | github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 3 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= 4 | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= 5 | github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= 6 | github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= 7 | github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= 8 | github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= 9 | github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= 10 | github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= 11 | golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= 12 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= 13 | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= 14 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 15 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 16 | -------------------------------------------------------------------------------- /tests/golang/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/go-redis/redis/v8" 7 | ) 8 | 9 | var ctx = context.Background() 10 | 11 | func main() { 12 | rdb := redis.NewClient(&redis.Options{ 13 | Addr: "localhost:6379", 14 | Password: "", // no password set 15 | DB: 0, // use default DB 16 | }) 17 | defer func(rdb *redis.Client) { 18 | err := rdb.Close() 19 | if err != nil { 20 | fmt.Println(err) 21 | } 22 | }(rdb) 23 | //lock test 24 | fmt.Println(rdb.Do(ctx , "slock.lock","test",10000).String()) 25 | //try unlock 26 | fmt.Println(rdb.Do(ctx, "slock.info","test").String()) 27 | fmt.Println(rdb.Do(ctx, "slock.unlock","test").String()) 28 | 29 | } 30 | -------------------------------------------------------------------------------- /tests/php/client.php: -------------------------------------------------------------------------------- 1 | connect("127.0.0.1", "6379"); 5 | //try lock 6 | var_dump($a->rawCommand("slock.lock", ...["test", 10000])); 7 | var_dump($a->rawCommand("slock.lock", ...["test", 10000])); 8 | //try unlock 9 | var_dump($a->rawCommand("slock.info", "test")); 10 | var_dump($a->rawCommand("slock.unlock", "test")); 11 | $a->close(); 12 | -------------------------------------------------------------------------------- /tests/php/client1.php: -------------------------------------------------------------------------------- 1 | connect("127.0.0.1", "6379"); 6 | //try lock,it will fail 7 | var_dump($a->rawCommand("slock.lock", ["test", 10000])); 8 | //try unlock it will fail too when the lock was locked by client.php 9 | var_dump($a->rawCommand("slock.unlock", "test")); 10 | $a->close(); 11 | -------------------------------------------------------------------------------- /tests/php/rlock_client.php: -------------------------------------------------------------------------------- 1 | connect("127.0.0.1", "6379"); 6 | //try lock,it will fail 7 | var_dump($a->rawCommand("slock.rlock", ["test", 10000])); 8 | sleep(5); 9 | var_dump($a->rawCommand("slock.rlock", ["test", 10000])); 10 | var_dump($a->ttl("slock.rlock")); 11 | // the expired time will be refresh. 12 | var_dump($a->rawCommand("slock.unlock", "test")); 13 | $a->close(); 14 | --------------------------------------------------------------------------------