script.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. package rds
  2. import (
  3. "github.com/go-redis/redis"
  4. "io/ioutil"
  5. "os"
  6. "path/filepath"
  7. )
  8. /**
  9. 提供对 redis 中 lua 脚本的简单封装
  10. lua 主要用于逻辑层面的批量 key 操作。 这和 multi 命令不同:
  11. 1. lua 脚本是 atomic 的, 可以看作事务。(和DBMS事务不同,主要不支持回滚,这里仅仅是提供了“一次性”的逻辑)
  12. 2. lua 脚本执行不会中途打断。
  13. 3. lua 脚本相比 multi 有更小的数据传数量
  14. 实现目标
  15. 支持 lua 从 lua 文件加载
  16. 支持从字符串加载
  17. 支持从目录加载
  18. 加载后,需要保存 redis 保存脚本后返回的对应的 hash
  19. 調用方可根据文件名调用
  20. 从字符串加载的,可自己设置名字
  21. 名字不能重名
  22. */
  23. // LuaBlock
  24. type LuaBlock struct {
  25. *redis.Script
  26. name string
  27. }
  28. type luablocker interface {
  29. Eval(script string, keys []string, args ...interface{}) *redis.Cmd
  30. EvalSha(sha1 string, keys []string, args ...interface{}) *redis.Cmd
  31. ScriptExists(hashes ...string) *redis.BoolSliceCmd
  32. ScriptLoad(script string) *redis.StringCmd
  33. }
  34. var _ luablocker = (*redis.Client)(nil)
  35. var _ luablocker = (*redis.Ring)(nil)
  36. var _ luablocker = (*redis.ClusterClient)(nil)
  37. func newLuaBlock(name, block string) *LuaBlock {
  38. return &LuaBlock{
  39. Script: redis.NewScript(block),
  40. name: name,
  41. }
  42. }
  43. // LuaBlockManager
  44. type LuaScripts struct {
  45. m map[string]*LuaBlock
  46. h luablocker
  47. }
  48. func NewLuaScripts(handle luablocker) *LuaScripts {
  49. return &LuaScripts{
  50. m: make(map[string]*LuaBlock),
  51. h: handle,
  52. }
  53. }
  54. func (self *LuaScripts) Run(name string, keys []string, args ...interface{})*redis.Cmd{
  55. luablock, ok := self.m[name]
  56. if !ok {
  57. panic("not load lua script:" + name)
  58. }
  59. return luablock.Run(self.h, keys, args)
  60. }
  61. func (self * LuaScripts)LoadString(name string, block string) error {
  62. _, err := self.h.ScriptLoad(block).Result()
  63. if err != nil {
  64. return err
  65. }
  66. self.m[name] = newLuaBlock(name, block)
  67. return nil
  68. }
  69. func (self *LuaScripts) LoadFile(f string) error {
  70. data, err := ioutil.ReadFile(f)
  71. if err != nil {
  72. return err
  73. }
  74. name := filepath.Base(f)
  75. return self.LoadString(name, string(data))
  76. }
  77. func (self *LuaScripts) LoadPath(p string) error {
  78. err := filepath.Walk(p, func(path string, info os.FileInfo, err error) error {
  79. if err != nil {
  80. return err
  81. }
  82. return self.LoadFile(path)
  83. })
  84. return err
  85. }