github.com/hdt3213/godis@v1.2.9/database/router.go (about)

     1  package database
     2  
     3  import (
     4  	"github.com/hdt3213/godis/interface/redis"
     5  	"github.com/hdt3213/godis/redis/protocol"
     6  	"strings"
     7  )
     8  
     9  var cmdTable = make(map[string]*command)
    10  
    11  type command struct {
    12  	name     string
    13  	executor ExecFunc
    14  	// prepare returns related keys command
    15  	prepare PreFunc
    16  	// undo generates undo-log before command actually executed, in case the command needs to be rolled back
    17  	undo UndoFunc
    18  	// arity means allowed number of cmdArgs, arity < 0 means len(args) >= -arity.
    19  	// for example: the arity of `get` is 2, `mget` is -2
    20  	arity int
    21  	flags int
    22  	extra *commandExtra
    23  }
    24  
    25  type commandExtra struct {
    26  	signs    []string
    27  	firstKey int
    28  	lastKey  int
    29  	keyStep  int
    30  }
    31  
    32  const flagWrite = 0
    33  
    34  const (
    35  	flagReadOnly = 1 << iota
    36  	flagSpecial  // command invoked in Exec
    37  )
    38  
    39  // registerCommand registers a normal command, which only read or modify a limited number of keys
    40  func registerCommand(name string, executor ExecFunc, prepare PreFunc, rollback UndoFunc, arity int, flags int) *command {
    41  	name = strings.ToLower(name)
    42  	cmd := &command{
    43  		name:     name,
    44  		executor: executor,
    45  		prepare:  prepare,
    46  		undo:     rollback,
    47  		arity:    arity,
    48  		flags:    flags,
    49  	}
    50  	cmdTable[name] = cmd
    51  	return cmd
    52  }
    53  
    54  // registerSpecialCommand registers a special command, such as publish, select, keys, flushAll
    55  func registerSpecialCommand(name string, arity int, flags int) *command {
    56  	name = strings.ToLower(name)
    57  	flags |= flagSpecial
    58  	cmd := &command{
    59  		name:  name,
    60  		arity: arity,
    61  		flags: flags,
    62  	}
    63  	cmdTable[name] = cmd
    64  	return cmd
    65  }
    66  
    67  func isReadOnlyCommand(name string) bool {
    68  	name = strings.ToLower(name)
    69  	cmd := cmdTable[name]
    70  	if cmd == nil {
    71  		return false
    72  	}
    73  	return cmd.flags&flagReadOnly > 0
    74  }
    75  
    76  func (cmd *command) toDescReply() redis.Reply {
    77  	args := make([]redis.Reply, 0, 6)
    78  	args = append(args,
    79  		protocol.MakeBulkReply([]byte(cmd.name)),
    80  		protocol.MakeIntReply(int64(cmd.arity)))
    81  	if cmd.extra != nil {
    82  		signs := make([][]byte, len(cmd.extra.signs))
    83  		for i, v := range cmd.extra.signs {
    84  			signs[i] = []byte(v)
    85  		}
    86  		args = append(args,
    87  			protocol.MakeMultiBulkReply(signs),
    88  			protocol.MakeIntReply(int64(cmd.extra.firstKey)),
    89  			protocol.MakeIntReply(int64(cmd.extra.lastKey)),
    90  			protocol.MakeIntReply(int64(cmd.extra.keyStep)),
    91  		)
    92  	}
    93  	return protocol.MakeMultiRawReply(args)
    94  }
    95  
    96  func (cmd *command) attachCommandExtra(signs []string, firstKey int, lastKey int, keyStep int) {
    97  	cmd.extra = &commandExtra{
    98  		signs:    signs,
    99  		firstKey: firstKey,
   100  		lastKey:  lastKey,
   101  		keyStep:  keyStep,
   102  	}
   103  }