-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathredis_helper.go
executable file
·1663 lines (1510 loc) · 55.5 KB
/
redis_helper.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Description : redis 相关方法 TODO 测试
* Author : ManGe
* Mail : [email protected]
**/
package gathertool
import (
"errors"
"fmt"
"net"
"strings"
"sync"
"time"
"github.com/gomodule/redigo/redis"
)
// Rds Redis客户端
type Rds struct {
SSHUser string
SSHPassword string
SSHAddr string
RedisHost string
RedisPost string
RedisPassword string
// redis DB
RedisDB int
// 单个连接
Conn redis.Conn
// 最大闲置数,用于redis连接池
RedisMaxIdle int
// 最大连接数
RedisMaxActive int
// 单条连接Timeout
RedisIdleTimeoutSec int
// 连接池
Pool *redis.Pool
}
// SSHConnInfo ssh连接通道
type SSHConnInfo struct {
SSHUser string
SSHPassword string
SSHAddr string
}
// NewSSHInfo 新建ssh连接通道
func NewSSHInfo(addr, user, password string) *SSHConnInfo {
return &SSHConnInfo{
SSHUser: user,
SSHPassword: password,
SSHAddr: addr,
}
}
// NewRedis 新建Redis客户端对象
func NewRedis(host, port, password string, db int, vs ...any) (*Rds, error) {
var sshConnInfo SSHConnInfo
for _, v := range vs {
switch vv := v.(type) {
case *SSHConnInfo:
sshConnInfo = *vv
case SSHConnInfo:
sshConnInfo = vv
}
}
rds := &Rds{
SSHUser: sshConnInfo.SSHUser,
SSHPassword: sshConnInfo.SSHPassword,
SSHAddr: sshConnInfo.SSHAddr,
RedisHost: host,
RedisPost: port,
RedisPassword: password,
RedisDB: db,
}
err := rds.RedisConn()
return rds, err
}
// NewRedisPool 新建Redis连接池对象
func NewRedisPool(host, port, password string, db, maxIdle, maxActive, idleTimeoutSec int, vs ...any) *Rds {
var sshConnInfo SSHConnInfo
for _, v := range vs {
switch vv := v.(type) {
case *SSHConnInfo:
sshConnInfo = *vv
case SSHConnInfo:
sshConnInfo = vv
}
}
return &Rds{
SSHUser: sshConnInfo.SSHUser,
SSHPassword: sshConnInfo.SSHPassword,
SSHAddr: sshConnInfo.SSHAddr,
RedisHost: host,
RedisPost: port,
RedisPassword: password,
RedisDB: db,
RedisMaxIdle: maxIdle,
RedisMaxActive: maxActive,
RedisIdleTimeoutSec: idleTimeoutSec,
}
}
// RedisConn redis连接
func (r *Rds) RedisConn() (err error) {
host := fmt.Sprintf("%s:%s", r.RedisHost, r.RedisPost)
if r.SSHPassword != "" && r.SSHUser != "" && r.SSHAddr != "" {
if sshClient, err := SSHClient(r.SSHUser, r.SSHPassword, r.SSHAddr); err == nil {
var conn net.Conn
conn, err = sshClient.Dial("tcp", host)
r.Conn = redis.NewConn(conn, -1, -1)
}
} else {
r.Conn, err = redis.Dial("tcp", host)
}
if err != nil {
return
}
if r.Conn == nil {
err = errors.New("redis conn is null")
return
}
if r.RedisPassword != "" {
if _, authErr := r.Conn.Do("AUTH", r.RedisPassword); authErr != nil {
err = fmt.Errorf("redis auth password error: %s", authErr)
return
}
}
if r.RedisDB < 1 {
r.RedisDB = 0
}
_, err = r.Conn.Do("select", fmt.Sprintf("%d", r.RedisDB))
return
}
// RedisPool 连接池连接
// 返回redis连接池 *redis.Pool.Get() 获取redis连接
func (r *Rds) RedisPool() error {
host := fmt.Sprintf("%s:%s", r.RedisHost, r.RedisPost)
r.Pool = &redis.Pool{
MaxIdle: r.RedisMaxIdle,
MaxActive: r.RedisMaxActive,
IdleTimeout: time.Duration(r.RedisIdleTimeoutSec) * time.Second,
Dial: func() (redis.Conn, error) {
var (
c redis.Conn
err error
)
if r.SSHPassword != "" && r.SSHUser != "" && r.SSHAddr != "" {
//ssh Client
sshClient, err := SSHClient(r.SSHUser, r.SSHPassword, r.SSHAddr)
if err != nil {
return nil, err
}
conn, err := sshClient.Dial("tcp", host)
if err != nil {
return nil, err
}
c = redis.NewConn(conn, 60, 60)
//if sshClient != nil {
// var conn net.Conn
// conn, err = sshClient.Dial("tcp", host)
// c = redis.NewConn(conn, -1, -1)
//}
//if err != nil{
// return nil, err
//}
} else {
c, err = redis.Dial("tcp", host)
if err != nil {
return nil, fmt.Errorf("redis connection error: %s", err)
}
}
if c == nil {
return nil, fmt.Errorf("redis connection is null")
}
//验证redis密码
if r.RedisPassword != "" {
if _, authErr := c.Do("AUTH", r.RedisPassword); authErr != nil {
return nil, fmt.Errorf("redis auth password error: %s", authErr)
}
}
_, err = c.Do("select", fmt.Sprintf("%d", r.RedisDB))
return c, err
},
TestOnBorrow: func(c redis.Conn, t time.Time) error {
_, err := c.Do("PING")
if err != nil {
return fmt.Errorf("ping redis error: %s", err)
}
return nil
},
}
return nil
}
// GetConn 获取redis连接
func (r *Rds) GetConn() redis.Conn {
if r.Conn != nil {
return r.Conn
}
rc := r.Pool.Get()
if rc != nil {
return rc
}
return nil
}
// SelectDB 切换redis db
func (r *Rds) SelectDB(dbNumber int) error {
rc := r.GetConn()
if rc == nil {
return errors.New("redis conn is nil")
}
_, err := rc.Do("select", fmt.Sprintf("%d", dbNumber))
return err
}
// RedisDELKeys Del key
// 使用常见: 并发删除大量key
func RedisDELKeys(rds *Rds, keys string, jobNumber int) {
CPUMax()
rds.RedisMaxActive = rds.RedisMaxActive + jobNumber*2
rds.RedisMaxIdle = rds.RedisMaxIdle + jobNumber*2
_ = rds.RedisPool()
conn := rds.Pool.Get()
queue := NewQueue()
res, err := redis.Strings(conn.Do("keys", keys))
if err != nil {
Error(err)
}
_ = conn.Close()
for _, v := range res {
_ = queue.Add(&Task{Url: v})
}
allNumber := queue.Size()
var wg sync.WaitGroup
for job := 0; job < jobNumber; job++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
Info("启动第", i, "个任务")
for {
if queue.IsEmpty() || queue.Size() < 2 {
break
}
task := queue.Poll()
Info("第", i, "个任务取的值: ", task.Url)
c := rds.Pool.Get()
s, err := redis.Int64(c.Do("DEL", task.Url))
if err != nil || s == 0 {
Info("redis command: err : ", err)
} else {
Info("删除成功 !!!")
}
_ = c.Close()
Info(fmt.Sprintf("[进度] %d/%d %f %%", allNumber-queue.Size(),
allNumber, (float64(allNumber-queue.Size())/float64(allNumber))*100))
}
Info("第", i, "个任务结束!!")
}(job)
}
wg.Wait()
Info("执行完成!!!")
}
// 使用List实现消息队列
// MqProducer Redis消息队列生产方
func (r *Rds) MqProducer(mqName string, data any) error {
args := redis.Args{}.Add(mqName)
args = args.Add(data)
_, err := r.GetConn().Do("LPUSH", args...)
return err
}
// MqConsumer Redis消息队列消费方
func (r *Rds) MqConsumer(mqName string) (reply any, err error) {
if r.MqLen(mqName) < 1 {
return nil, fmt.Errorf("data len is 0")
}
return r.GetConn().Do("RPOP", mqName)
}
// MqLen Redis消息队列消息数量
func (r *Rds) MqLen(mqName string) int64 {
number, err := redis.Int64(r.GetConn().Do("LLEN", mqName))
if err != nil {
number = 0
}
return number
}
func (r *Rds) ToString(reply any, err error) (string, error) {
return redis.String(reply, err)
}
func (r *Rds) ToInt(reply any, err error) (int, error) {
return redis.Int(reply, err)
}
func (r *Rds) ToInt64(reply any, err error) (int64, error) {
return redis.Int64(reply, err)
}
func (r *Rds) ToBool(reply any, err error) (bool, error) {
return redis.Bool(reply, err)
}
func (r *Rds) ToBytes(reply any, err error) ([]byte, error) {
return redis.Bytes(reply, err)
}
func (r *Rds) ToByteSlices(reply any, err error) ([][]byte, error) {
return redis.ByteSlices(reply, err)
}
func (r *Rds) ToFloat64(reply any, err error) (float64, error) {
return redis.Float64(reply, err)
}
func (r *Rds) ToFloat64s(reply any, err error) ([]float64, error) {
return redis.Float64s(reply, err)
}
func (r *Rds) ToInt64Map(reply any, err error) (map[string]int64, error) {
return redis.Int64Map(reply, err)
}
func (r *Rds) ToInt64s(reply any, err error) ([]int64, error) {
return redis.Int64s(reply, err)
}
func (r *Rds) ToIntMap(reply any, err error) (map[string]int, error) {
return redis.IntMap(reply, err)
}
func (r *Rds) ToInts(reply any, err error) ([]int, error) {
return redis.Ints(reply, err)
}
func (r *Rds) ToStringMap(reply any, err error) (map[string]string, error) {
return redis.StringMap(reply, err)
}
func (r *Rds) ToStrings(reply any, err error) ([]string, error) {
return redis.Strings(reply, err)
}
// Keys ===============================================================================================================
// GetAllKeys 获取所有的key
func (r *Rds) GetAllKeys(match string) (ksyList map[string]int) {
//初始化拆分值
matchSplit := match
//match :匹配值,没有则匹配所有 *
if match == "" {
match = "*"
} else {
match = fmt.Sprintf("*%s*", match)
}
//cursor :初始游标为0
cursor := "0"
ksyList = make(map[string]int)
ksyList, cursor = r.addGetKey(ksyList, cursor, match, matchSplit)
//当游标等于0的时候停止获取key
//线性获取,一直循环获取key,直到游标为0
if cursor != "0" {
for {
ksyList, cursor = r.addGetKey(ksyList, cursor, match, matchSplit)
if cursor == "0" {
break
}
}
}
return
}
// addGetKey 内部方法
// 针对分组的key进行分组合并处理
func (r *Rds) addGetKey(ksyList map[string]int, cursor, match, matchSplit string) (map[string]int, string) {
countNumber := "10000"
res, err := redis.Values(r.Conn.Do("scan", cursor, "MATCH", match, "COUNT", countNumber))
InfoTimes(3, "[Redis Log] execute :", "scan ", cursor, " MATCH ", match, " COUNT ", countNumber)
if err != nil {
Error("GET error", err.Error())
}
//获取 match 含有多少:
cfNumber := strings.Count(match, ":")
//获取新的游标
newCursor := string(res[0].([]byte))
allKey := res[1]
allKeyData := allKey.([]any)
for _, v := range allKeyData {
keyData := string(v.([]byte))
//没有:的key 则不集合
if strings.Count(keyData, ":") == cfNumber || keyData == match {
ksyList[keyData] = 0
continue
}
//有:需要集合
keyDataNew, _ := fenGeYinHaoOne(keyData, matchSplit)
ksyList[keyDataNew] = ksyList[keyDataNew] + 1
}
return ksyList, newCursor
}
// fenGeYinHaoOne 对查询出来的key进行拆分,集合,分组处理
func fenGeYinHaoOne(str string, matchSplit string) (string, int) {
likeKey := ""
if matchSplit != "" {
likeKey = fmt.Sprintf("%s", matchSplit)
}
str = strings.Replace(str, likeKey, "", 1)
fg := strings.Split(str, ":")
if len(fg) > 0 {
return fmt.Sprintf("%s%s", likeKey, fg[0]), len(fg)
}
return "", len(fg)
}
// SearchKeys 搜索key
func (r *Rds) SearchKeys(match string) (ksyList map[string]int) {
ksyList = make(map[string]int)
if match == "" {
return
} else {
match = fmt.Sprintf("*%s*", match)
}
cursor := "0"
ksyList = make(map[string]int)
ksyList, cursor = r.addSearchKey(ksyList, cursor, match)
//当游标等于0的时候停止获取key
//线性获取,一直循环获取key,直到游标为0
if cursor != "0" {
for {
ksyList, cursor = r.addSearchKey(ksyList, cursor, match)
if cursor == "0" {
break
}
}
}
return
}
// addGetKey 内部方法获取key
func (r *Rds) addSearchKey(ksyList map[string]int, cursor, match string) (map[string]int, string) {
countNumber := "10000"
res, err := redis.Values(r.Conn.Do("scan", cursor, "MATCH", match, "COUNT", countNumber))
InfoTimes(3, "[Redis Log] execute :", "scan ", cursor, " MATCH ", match, " COUNT ", countNumber)
if err != nil {
Error("GET error", err.Error())
}
//获取新的游标
newCursor := string(res[0].([]byte))
allKey := res[1]
allKeyData := allKey.([]any)
for _, v := range allKeyData {
keyData := string(v.([]byte))
ksyList[keyData] = 0
}
return ksyList, newCursor
}
// Type 获取key的类型
func (r *Rds) Type(key string) string {
InfoFTimes(3, "[Redis Log] execute : TYPE %s", key)
res, err := redis.String(r.Conn.Do("TYPE", key))
if err != nil {
ErrorTimes(3, "GET error", err.Error())
}
return res
}
// Ttl 获取key的过期时间
func (r *Rds) Ttl(key string) int64 {
InfoFTimes(3, "[Redis Log] execute : TTL %s", key)
res, err := redis.Int64(r.Conn.Do("TTL", key))
if err != nil {
ErrorTimes(3, "GET error", err.Error())
}
return res
}
// DUMP 检查给定 key 是否存在。
func (r *Rds) DUMP(key string) bool {
InfoFTimes(3, "[Redis Log] execute : DUMP %s", key)
data, err := redis.String(r.Conn.Do("DUMP", key))
if err != nil {
ErrorTimes(3, "GET error", err.Error())
return false
} else if data == "0" {
return false
}
return true
}
// Rename 修改key名称
func (r *Rds) Rename(name, newName string) bool {
arg := redis.Args{}.Add(name).Add(newName)
InfoFTimes(3, "[Redis Log] execute : RENAME %s %v", name, newName)
_, err := r.Conn.Do("RENAME", arg...)
if err != nil {
ErrorTimes(3, "GET error", err.Error())
return false
}
return true
}
// Expire 更新key ttl
func (r *Rds) Expire(key string, ttl int64) bool {
arg := redis.Args{}.Add(key).Add(ttl)
InfoFTimes(3, "[Redis Log] execute : EXPIRE %s %v", key, ttl)
_, err := r.Conn.Do("EXPIRE", arg...)
if err != nil {
ErrorTimes(3, err.Error())
return false
}
return true
}
// ExpireAt 指定key多久过期 接收的是unix时间戳
func (r *Rds) ExpireAt(key string, date int64) bool {
arg := redis.Args{}.Add(key).Add(date)
InfoFTimes(3, "[Redis Log] execute : EXPIREAT %s %v", key, date)
_, err := r.Conn.Do("EXPIREAT", arg...)
if err != nil {
ErrorTimes(3, err.Error())
return false
}
return true
}
// DelKey 删除key
func (r *Rds) DelKey(key string) bool {
InfoFTimes(3, "[Redis Log] execute : DEL %s", key)
_, err := r.Conn.Do("DEL", key)
if err != nil {
ErrorTimes(3, err.Error())
return false
}
return true
}
var RdsNotConnError = fmt.Errorf("未连接redis")
// String =============================================================================================================
// Get GET 获取String value
func (r *Rds) Get(key string) (string, error) {
if r.Conn == nil {
return "", RdsNotConnError
}
InfoFTimes(3, "[Redis Log] execute : GET %s", key)
return redis.String(r.Conn.Do("GET", key))
}
// Set SET新建String
func (r *Rds) Set(key string, value any) error {
if r.Conn == nil {
return RdsNotConnError
}
arg := redis.Args{}.Add(key).Add(value)
InfoFTimes(3, "[Redis Log] execute : SET %s %v", key, value)
_, err := r.Conn.Do("SET", arg...)
return err
}
// SetEx SETEX 新建String 含有时间
func (r *Rds) SetEx(key string, ttl int64, value any) error {
if r.Conn == nil {
return RdsNotConnError
}
arg := redis.Args{}.Add(key).Add(ttl).Add(value)
InfoFTimes(3, "[Redis Log] execute : SETEX %s %v %v", key, ttl, value)
_, err := r.Conn.Do("SETEX", arg...)
return err
}
// PSetEx PSETEX key milliseconds value
// 这个命令和 SETEX 命令相似,但它以毫秒为单位设置 key 的生存时间,而不是像 SETEX 命令那样,以秒为单位。
func (r *Rds) PSetEx(key string, ttl int64, value any) error {
if r.Conn == nil {
return RdsNotConnError
}
arg := redis.Args{}.Add(key).Add(ttl).Add(value)
InfoFTimes(3, "[Redis Log] execute : PSETEX %s %v %v", key, ttl, value)
_, err := r.Conn.Do("PSETEX", arg...)
return err
}
// SetNx key value
// 将 key 的值设为 value ,当且仅当 key 不存在。
// 若给定的 key 已经存在,则 SETNX 不做任何动作。
func (r *Rds) SetNx(key string, value any) error {
if r.Conn == nil {
return RdsNotConnError
}
InfoFTimes(3, "[Redis Log] execute : SETNX %s %v", key, value)
arg := redis.Args{}.Add(key).Add(value)
_, err := r.Conn.Do("SETNX", arg...)
return err
}
// SetRange SETRANGE key offset value
// 用 value 参数覆写(overwrite)给定 key 所储存的字符串值,从偏移量 offset 开始。
// 不存在的 key 当作空白字符串处理。
func (r *Rds) SetRange(key string, offset int64, value any) error {
if r.Conn == nil {
return RdsNotConnError
}
arg := redis.Args{}.Add(key).Add(offset).Add(value)
InfoFTimes(3, "[Redis Log] execute : SETRANGE %s %v %v", key, offset, value)
_, err := r.Conn.Do("SETRANGE", arg...)
return err
}
// Append APPEND key value
// 如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾。
// 如果 key 不存在, APPEND 就简单地将给定 key 设为 value ,就像执行 SET key value 一样。
func (r *Rds) Append(key string, value any) error {
if r.Conn == nil {
return RdsNotConnError
}
arg := redis.Args{}.Add(key).Add(value)
InfoFTimes(3, "[Redis Log] execute : APPEND %s %v", key, value)
_, err := redis.String(r.Conn.Do("APPEND", arg...))
return err
}
// SetBit SETBIT key offset value
// 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。
// value : 位的设置或清除取决于 value 参数,可以是 0 也可以是 1 。
// 注意 offset 不能太大,越大key越大
func (r *Rds) SetBit(key string, offset, value int64) error {
if r.Conn == nil {
return RdsNotConnError
}
arg := redis.Args{}.Add(key).Add(offset).Add(value)
InfoFTimes(3, "[Redis Log] execute : SETBIT %s %d %d", key, offset, value)
_, err := r.Conn.Do("SETBIT", arg...)
return err
}
// BitCount BITCOUNT key [start] [end]
// 计算给定字符串中,被设置为 1 的比特位的数量。
func (r *Rds) BitCount(key string) (int64, error) {
if r.Conn == nil {
return 0, RdsNotConnError
}
InfoFTimes(3, "[Redis Log] execute : BITCOUNT %s", key)
return redis.Int64(r.Conn.Do("BITCOUNT", key))
}
// GetBit GETBIT key offset
// 对 key 所储存的字符串值,获取指定偏移量上的位(bit)。
// 当 offset 比字符串值的长度大,或者 key 不存在时,返回 0 。
func (r *Rds) GetBit(key string, offset int64) (int64, error) {
if r.Conn == nil {
return 0, RdsNotConnError
}
arg := redis.Args{}.Add(key).Add(offset)
InfoFTimes(3, "[Redis Log] execute : GETBIT %s %d", key, offset)
return redis.Int64(r.Conn.Do("GETBIT", arg...))
}
// TODO StringBITOP BITOP operation destkey key [key ...]
// 对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。
// BITOP AND destkey key [key ...] ,对一个或多个 key 求逻辑并,并将结果保存到 destkey 。
// BITOP OR destkey key [key ...] ,对一个或多个 key 求逻辑或,并将结果保存到 destkey 。
// BITOP XOR destkey key [key ...] ,对一个或多个 key 求逻辑异或,并将结果保存到 destkey 。
// BITOP NOT destkey key ,对给定 key 求逻辑非,并将结果保存到 destkey 。
// Decr key
// 将 key 中储存的数字值减一。
// 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。
// 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
func (r *Rds) Decr(key string) (int64, error) {
if r.Conn == nil {
return 0, RdsNotConnError
}
InfoFTimes(3, "[Redis Log] execute : DECR %s", key)
return redis.Int64(r.Conn.Do("DECR", key))
}
// DecrBy DECRBY key decrement
// 将 key 所储存的值减去减量 decrement 。
func (r *Rds) DecrBy(key, decrement string) (int64, error) {
if r.Conn == nil {
return 0, RdsNotConnError
}
arg := redis.Args{}.Add(key).Add(decrement)
InfoFTimes(3, "[Redis Log] execute : DECRBY %s %v", key, decrement)
return redis.Int64(r.Conn.Do("DECRBY", arg...))
}
// GetRange GETRANGE key start end
// 返回 key 中字符串值的子字符串,字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)。
func (r *Rds) GetRange(key string, start, end int64) (string, error) {
if r.Conn == nil {
return "", RdsNotConnError
}
arg := redis.Args{}.Add(key).Add(start).Add(end)
InfoFTimes(3, "[Redis Log] execute : GETRANGE %s %v %v", key, start, end)
return redis.String(r.Conn.Do("GETRANGE", arg...))
}
// GetSet GETSET key value
// 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。
// 当 key 存在但不是字符串类型时,返回一个错误。
func (r *Rds) GetSet(key string, value any) (string, error) {
if r.Conn == nil {
return "", RdsNotConnError
}
arg := redis.Args{}.Add(key).Add(value)
InfoFTimes(3, "[Redis Log] execute : GETSET %s %v", key, value)
return redis.String(r.Conn.Do("GETSET", arg...))
}
// Incr INCR key
// 将 key 中储存的数字值增一。
// 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。
// 如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
func (r *Rds) Incr(key string) (int64, error) {
if r.Conn == nil {
return 0, RdsNotConnError
}
InfoFTimes(3, "[Redis Log] execute : INCR %s", key)
return redis.Int64(r.Conn.Do("INCR", key))
}
// IncrBy INCRBY key increment
// 将 key 所储存的值加上增量 increment 。
func (r *Rds) IncrBy(key, increment string) (int64, error) {
if r.Conn == nil {
return 0, RdsNotConnError
}
arg := redis.Args{}.Add(key).Add(increment)
InfoFTimes(3, "[Redis Log] execute : INCRBY %s %v", key, increment)
return redis.Int64(r.Conn.Do("INCRBY", arg...))
}
// IncrByFloat INCRBYFLOAT key increment
// 为 key 中所储存的值加上浮点数增量 increment 。
func (r *Rds) IncrByFloat(key, increment float64) (float64, error) {
if r.Conn == nil {
return 0, RdsNotConnError
}
arg := redis.Args{}.Add(key).Add(increment)
InfoFTimes(3, "[Redis Log] execute : INCRBYFLOAT %s %v", key, increment)
return redis.Float64(r.Conn.Do("INCRBYFLOAT", arg...))
}
// MGet MGET key [key ...]
// 返回所有(一个或多个)给定 key 的值。
// 如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil 。因此,该命令永不失败。
func (r *Rds) MGet(key []any) ([]string, error) {
if r.Conn == nil {
return nil, RdsNotConnError
}
args := redis.Args{}
for _, value := range key {
args = args.Add(value)
}
InfoFTimes(3, "[Redis Log] execute : MGET %s %s", key, strings.Join(Any2Strings(key), " "))
return redis.Strings(r.Conn.Do("MGET", args...))
}
// MSet MSET key value [key value ...]
// 同时设置一个或多个 key-value 对。
// 如果某个给定 key 已经存在,那么 MSET 会用新值覆盖原来的旧值,如果这不是你所希望的效果,
// 请考虑使用 MSETNX 命令:它只会在所有给定 key 都不存在的情况下进行设置操作。
// MSET 是一个原子性(atomic)操作,所有给定 key 都会在同一时间内被设置,某些给定 key 被更新而另一些给定 key 没有改变的情况,不可能发生。
func (r *Rds) MSet(values []any) error {
if r.Conn == nil {
return RdsNotConnError
}
args := redis.Args{}
for _, value := range values {
args = args.Add(value)
}
InfoFTimes(3, "[Redis Log] execute : MSET %s", strings.Join(Any2Strings(values), " "))
_, err := r.Conn.Do("MSET", args...)
return err
}
// MSetNx MSETNX key value [key value ...]
// 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。
// 即使只有一个给定 key 已存在, MSETNX 也会拒绝执行所有给定 key 的设置操作。
// MSETNX 是原子性的,因此它可以用作设置多个不同 key 表示不同字段(field)的唯一性逻辑对象(unique logic object),
// 所有字段要么全被设置,要么全不被设置。
func (r *Rds) MSetNx(values []any) error {
if r.Conn == nil {
return RdsNotConnError
}
args := redis.Args{}
for _, value := range values {
args = args.Add(value)
}
InfoFTimes(3, "[Redis Log] execute : MSETNX %s", strings.Join(Any2Strings(values), " "))
_, err := r.Conn.Do("MSETNX", args...)
return err
}
// TODO StringSTRLEN STRLEN key
// 返回 key 所储存的字符串值的长度。
// 当 key 储存的不是字符串值时,返回一个错误。
// List ===============================================================================================================
// LRange LRANGE 获取List value
func (r *Rds) LRange(key string) ([]any, error) {
if r.Conn == nil {
return nil, RdsNotConnError
}
InfoFTimes(3, "[Redis Log] execute : LRANGE %s 0 -1", key)
return redis.Values(r.Conn.Do("LRANGE", key, 0, -1))
}
// LRangeST LRANGE key start stop
// 返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。
func (r *Rds) LRangeST(key string, start, stop int64) ([]any, error) {
if r.Conn == nil {
return nil, RdsNotConnError
}
arg := redis.Args{}.Add(key).Add(start).Add(stop)
InfoFTimes(3, "[Redis Log] execute : LRANGE %s %v %v", key, start, stop)
return redis.Values(r.Conn.Do("LRANGE", arg...))
}
// LPush LPUSH 新创建list 将一个或多个值 value 插入到列表 key 的表头
func (r *Rds) LPush(key string, values []any) error {
if r.Conn == nil {
return RdsNotConnError
}
args := redis.Args{}.Add(key)
for _, value := range values {
args = args.Add(value)
}
InfoFTimes(3, "[Redis Log] execute : LPUSH %s %s", key, strings.Join(Any2Strings(values), " "))
_, err := r.Conn.Do("LPUSH", args...)
return err
}
// RPush RPUSH key value [value ...]
// 将一个或多个值 value 插入到列表 key 的表尾(最右边)。
// 如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表尾:比如对一个空列表 mylist 执行
// RPUSH mylist a b c ,得出的结果列表为 a b c ,等同于执行命令 RPUSH mylist a 、 RPUSH mylist b 、 RPUSH mylist c 。
// 新创建List 将一个或多个值 value 插入到列表 key 的表尾(最右边)。
func (r *Rds) RPush(key string, values []any) error {
if r.Conn == nil {
return RdsNotConnError
}
args := redis.Args{}.Add(key)
for _, value := range values {
args = args.Add(value)
}
InfoFTimes(3, "[Redis Log] execute : RPUSH %s %s", key, strings.Join(Any2Strings(values), " "))
_, err := r.Conn.Do("RPUSH", args...)
return err
}
// TODO ListBLPOP BLPOP key [key ...] timeout
// BLPOP 是列表的阻塞式(blocking)弹出原语。
// 它是 LPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BLPOP 命令阻塞,直到等待超时或发现可弹出元素为止。
// TODO ListBRPOP BRPOP key [key ...] timeout
// BRPOP 是列表的阻塞式(blocking)弹出原语。
// 它是 RPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BRPOP 命令阻塞,直到等待超时或发现可弹出元素为止。
// TODO ListBRPOPLPUSH BRPOPLPUSH source destination timeout
// BRPOPLPUSH 是 RPOPLPUSH 的阻塞版本,当给定列表 source 不为空时, BRPOPLPUSH 的表现和 RPOPLPUSH 一样。
// 当列表 source 为空时, BRPOPLPUSH 命令将阻塞连接,直到等待超时,或有另一个客户端对 source 执行 LPUSH 或 RPUSH 命令为止。
// LIndex LINDEX key index
// 返回列表 key 中,下标为 index 的元素。
func (r *Rds) LIndex(key string, index int64) (string, error) {
if r.Conn == nil {
return "", RdsNotConnError
}
arg := redis.Args{}.Add(key).Add(index)
InfoFTimes(3, "[Redis Log] execute : LINDEX %s %v", key, index)
return redis.String(r.Conn.Do("LINDEX", arg...))
}
// LInsert LINSERT key BEFORE|AFTER pivot value
// 将值 value 插入到列表 key 当中,位于值 pivot 之前或之后。
// 当 pivot 不存在于列表 key 时,不执行任何操作。
// 当 key 不存在时, key 被视为空列表,不执行任何操作。
// 如果 key 不是列表类型,返回一个错误。
// direction : 方向 bool true:BEFORE(前) false: AFTER(后)
func (r *Rds) LInsert(direction bool, key, pivot, value string) error {
if r.Conn == nil {
return RdsNotConnError
}
directionStr := "AFTER"
if direction {
directionStr = "BEFORE"
}
arg := redis.Args{}.Add(key).Add(directionStr).Add(pivot).Add(value)
InfoFTimes(3, "[Redis Log] execute : LINSERT %s %v %v %v", key, directionStr, pivot, value)
_, err := r.Conn.Do("LINSERT", arg...)
return err
}
// LLen LLEN key
// 返回列表 key 的长度。
// 如果 key 不存在,则 key 被解释为一个空列表,返回 0 .
func (r *Rds) LLen(key string) (int64, error) {
if r.Conn == nil {
return 0, RdsNotConnError
}
InfoFTimes(3, "[Redis Log] execute : LLEN %s", key)
return redis.Int64(r.Conn.Do("LLEN", key))
}
// ListLPOP LPOP key
// 移除并返回列表 key 的头元素。
func (r *Rds) ListLPOP(key string) (string, error) {
if r.Conn == nil {
return "", RdsNotConnError
}
InfoFTimes(3, "[Redis Log] execute : LPOP %s", key)
return redis.String(r.Conn.Do("LPOP", key))
}
// LPusHx LPUSHX key value
// 将值 value 插入到列表 key 的表头,当且仅当 key 存在并且是一个列表。
// 和 LPUSH 命令相反,当 key 不存在时, LPUSHX 命令什么也不做。
func (r *Rds) LPusHx(key string, value any) error {
if r.Conn == nil {
return RdsNotConnError
}
arg := redis.Args{}.Add(key).Add(value)
InfoFTimes(3, "[Redis Log] execute : LPUSHX %s %v", key, value)
_, err := r.Conn.Do("LPUSHX", arg...)
return err
}
// LRem LREM key count value
// 根据参数 count 的值,移除列表中与参数 value 相等的元素。
// count 的值可以是以下几种:
// count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。
// count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。
// count = 0 : 移除表中所有与 value 相等的值。
func (r *Rds) LRem(key string, count int64, value any) error {
if r.Conn == nil {
return RdsNotConnError
}
arg := redis.Args{}.Add(key).Add(count).Add(value)
InfoFTimes(3, "[Redis Log] execute : LREM %s %v %v", key, count, value)
_, err := r.Conn.Do("LREM", arg...)
return err
}
// LSet LSET key index value
// 将列表 key 下标为 index 的元素的值设置为 value 。
// 当 index 参数超出范围,或对一个空列表( key 不存在)进行 LSET 时,返回一个错误。
func (r *Rds) LSet(key string, index int64, value any) error {
if r.Conn == nil {
return RdsNotConnError
}
arg := redis.Args{}.Add(key).Add(index).Add(value)
InfoFTimes(3, "[Redis Log] execute : LSET %s %v %v", key, index, value)
_, err := r.Conn.Do("LSET", arg...)
return err
}
// LTrim LTRIM key start stop
// 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
// 举个例子,执行命令 LTRIM list 0 2 ,表示只保留列表 list 的前三个元素,其余元素全部删除。
func (r *Rds) LTrim(key string, start, stop int64) error {
if r.Conn == nil {
return RdsNotConnError
}
arg := redis.Args{}.Add(key).Add(start).Add(stop)
InfoFTimes(3, "[Redis Log] execute : LTRIM %s %v %v", key, start, stop)
_, err := r.Conn.Do("LTRIM", arg...)
return err
}
// RPop RPOP key
// 移除并返回列表 key 的尾元素。
func (r *Rds) RPop(key string) (string, error) {
if r.Conn == nil {