-
Notifications
You must be signed in to change notification settings - Fork 0
/
command.go
133 lines (116 loc) · 3.06 KB
/
command.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
// Copyright (c) 2019 Meng Huang ([email protected])
// This package is licensed under a MIT license that can be found in the LICENSE file.
package raft
import (
"reflect"
"sync"
)
const (
noOperation = 0x1
addMemberOperation = 0x2
removeMemberOperation = 0x3
reconfigurationOperation = 0x4
)
// Command represents a command.
type Command interface {
// Type returns the command type. The type must be > 0.
Type() uint64
// Do executes the command with the context.
Do(context interface{}) (reply interface{}, err error)
}
type commands struct {
mu sync.RWMutex
types map[uint64]*sync.Pool
}
func (c *commands) register(cmd Command) error {
c.mu.Lock()
if _, ok := c.types[cmd.Type()]; ok {
c.mu.Unlock()
return ErrCommandTypeExisted
}
pool := &sync.Pool{New: func() interface{} {
return reflect.New(reflect.Indirect(reflect.ValueOf(cmd)).Type()).Interface()
}}
c.types[cmd.Type()] = pool
c.mu.Unlock()
pool.Put(pool.Get())
return nil
}
func (c *commands) clone(Type uint64) Command {
c.mu.RLock()
if commandPool, ok := c.types[Type]; ok {
c.mu.RUnlock()
return commandPool.Get().(Command)
}
c.mu.RUnlock()
return nil
}
func (c *commands) put(cmd Command) {
c.mu.RLock()
if commandPool, ok := c.types[cmd.Type()]; ok {
c.mu.RUnlock()
commandPool.Put(cmd)
} else {
c.mu.RUnlock()
}
}
func (c *commands) exists(cmd Command) bool {
c.mu.RLock()
_, ok := c.types[cmd.Type()]
c.mu.RUnlock()
return ok
}
// Type implements the Command Type method.
func (c *DefaultCommand) Type() uint64 {
return 0
}
// Do implements the Command Do method.
func (c *DefaultCommand) Do(context interface{}) (interface{}, error) {
switch c.Operation {
case noOperation:
return true, nil
case addMemberOperation:
n := context.(*node)
n.stateMachine.configuration.AddMember(c.Member)
n.stateMachine.configuration.load()
return nil, nil
case removeMemberOperation:
n := context.(*node)
n.stateMachine.configuration.RemoveMember(c.Member.Address)
n.stateMachine.configuration.load()
return nil, nil
case reconfigurationOperation:
n := context.(*node)
n.stateMachine.configuration.reconfiguration()
return nil, nil
}
return nil, nil
}
var noOperationCommand = newNoOperationCommand()
// NewNoOperationCommand returns a new NoOperationCommand.
func newNoOperationCommand() Command {
return &DefaultCommand{
Operation: noOperation,
}
}
var reconfigurationCommand = newReconfigurationCommand()
// NewReconfigurationCommand returns a new ReconfigurationCommand.
func newReconfigurationCommand() Command {
return &DefaultCommand{
Operation: reconfigurationOperation,
}
}
// NewAddMemberCommand returns a new AddMemberCommand.
func newAddMemberCommand(address string, nonVoting bool) Command {
return &DefaultCommand{
Operation: addMemberOperation,
Member: &Member{Address: address, NonVoting: nonVoting},
}
}
// NewRemoveMemberCommand returns a new RemoveMemberCommand.
func newRemoveMemberCommand(address string) Command {
return &DefaultCommand{
Operation: removeMemberOperation,
Member: &Member{Address: address},
}
}