command.go 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. package raft
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "reflect"
  8. )
  9. //------------------------------------------------------------------------------
  10. //
  11. // Globals
  12. //
  13. //------------------------------------------------------------------------------
  14. var commandTypes map[string]Command
  15. func init() {
  16. commandTypes = map[string]Command{}
  17. }
  18. //------------------------------------------------------------------------------
  19. //
  20. // Typedefs
  21. //
  22. //------------------------------------------------------------------------------
  23. // A command represents an action to be taken on the replicated state machine.
  24. type Command interface {
  25. CommandName() string
  26. Apply(server Server) (interface{}, error)
  27. }
  28. type CommandEncoder interface {
  29. Encode(w io.Writer) error
  30. Decode(r io.Reader) error
  31. }
  32. //------------------------------------------------------------------------------
  33. //
  34. // Functions
  35. //
  36. //------------------------------------------------------------------------------
  37. //--------------------------------------
  38. // Instantiation
  39. //--------------------------------------
  40. // Creates a new instance of a command by name.
  41. func newCommand(name string, data []byte) (Command, error) {
  42. // Find the registered command.
  43. command := commandTypes[name]
  44. if command == nil {
  45. return nil, fmt.Errorf("raft.Command: Unregistered command type: %s", name)
  46. }
  47. // Make a copy of the command.
  48. v := reflect.New(reflect.Indirect(reflect.ValueOf(command)).Type()).Interface()
  49. copy, ok := v.(Command)
  50. if !ok {
  51. panic(fmt.Sprintf("raft: Unable to copy command: %s (%v)", command.CommandName(), reflect.ValueOf(v).Kind().String()))
  52. }
  53. // If data for the command was passed in the decode it.
  54. if data != nil {
  55. if encoder, ok := copy.(CommandEncoder); ok {
  56. if err := encoder.Decode(bytes.NewReader(data)); err != nil {
  57. return nil, err
  58. }
  59. } else {
  60. json.NewDecoder(bytes.NewReader(data)).Decode(copy)
  61. }
  62. }
  63. return copy, nil
  64. }
  65. //--------------------------------------
  66. // Registration
  67. //--------------------------------------
  68. // Registers a command by storing a reference to an instance of it.
  69. func RegisterCommand(command Command) {
  70. if command == nil {
  71. panic(fmt.Sprintf("raft: Cannot register nil"))
  72. } else if commandTypes[command.CommandName()] != nil {
  73. panic(fmt.Sprintf("raft: Duplicate registration: %s", command.CommandName()))
  74. return
  75. }
  76. commandTypes[command.CommandName()] = command
  77. }