Skip to content

Commit 8f1e830

Browse files
committed
[FAB-1443] Extend sharedconfig with BatchTimeout
https://jira.hyperledger.org/browse/FAB-1443 As things stand right now, the solo consenter uses the local config file to load the batchTimeout value. This however belongs to the shared config. This changeset: 1. Defines a `BatchTimeout` proto message (and a `BatchTimeout` key). 2. Extends the `sharedconfig.Manager` interface with a `BatchTimeout` getter. 3. Modifies the solo consenter so that it fetches the value from the `sharedconfig.Manager` (via the `ConsenterSupport` object). 4. Modifies the mock `sharedconfig` implementation accordingly. Change-Id: Ibb5c73733febd0d27f5d7eebfd6b3208864e659e Signed-off-by: Kostas Christidis <[email protected]>
1 parent e757dbf commit 8f1e830

File tree

9 files changed

+169
-58
lines changed

9 files changed

+169
-58
lines changed

orderer/common/sharedconfig/sharedconfig.go

+31-9
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"regexp"
2222
"strconv"
2323
"strings"
24+
"time"
2425

2526
cb "github.com/hyperledger/fabric/protos/common"
2627
ab "github.com/hyperledger/fabric/protos/orderer"
@@ -36,6 +37,9 @@ const (
3637
// BatchSizeKey is the cb.ConfigurationItem type key name for the BatchSize message
3738
BatchSizeKey = "BatchSize"
3839

40+
// BatchTimeoutKey is the cb.ConfigurationItem type key name for the BatchTimeout message
41+
BatchTimeoutKey = "BatchTimeout"
42+
3943
// ChainCreatorsKey is the cb.ConfigurationItem type key name for the ChainCreators message
4044
ChainCreatorsKey = "ChainCreators"
4145

@@ -60,6 +64,9 @@ type Manager interface {
6064
// BatchSize returns the maximum number of messages to include in a block
6165
BatchSize() *ab.BatchSize
6266

67+
// BatchTimeout returns the amount of time to wait before creating a batch
68+
BatchTimeout() time.Duration
69+
6370
// ChainCreators returns the policy names which are allowed for chain creation
6471
// This field is only set for the system ordering chain
6572
ChainCreators() []string
@@ -73,6 +80,7 @@ type Manager interface {
7380
type ordererConfig struct {
7481
consensusType string
7582
batchSize *ab.BatchSize
83+
batchTimeout time.Duration
7684
chainCreators []string
7785
kafkaBrokers []string
7886
}
@@ -101,6 +109,11 @@ func (pm *ManagerImpl) BatchSize() *ab.BatchSize {
101109
return pm.config.batchSize
102110
}
103111

112+
// BatchTimeout returns the amount of time to wait before creating a batch
113+
func (pm *ManagerImpl) BatchTimeout() time.Duration {
114+
return pm.config.batchTimeout
115+
}
116+
104117
// ChainCreators returns the policy names which are allowed for chain creation
105118
// This field is only set for the system ordering chain
106119
func (pm *ManagerImpl) ChainCreators() []string {
@@ -145,8 +158,7 @@ func (pm *ManagerImpl) ProposeConfig(configItem *cb.ConfigurationItem) error {
145158
switch configItem.Key {
146159
case ConsensusTypeKey:
147160
consensusType := &ab.ConsensusType{}
148-
err := proto.Unmarshal(configItem.Value, consensusType)
149-
if err != nil {
161+
if err := proto.Unmarshal(configItem.Value, consensusType); err != nil {
150162
return fmt.Errorf("Unmarshaling error for ConsensusType: %s", err)
151163
}
152164
if pm.config.consensusType == "" {
@@ -159,26 +171,36 @@ func (pm *ManagerImpl) ProposeConfig(configItem *cb.ConfigurationItem) error {
159171
pm.pendingConfig.consensusType = consensusType.Type
160172
case BatchSizeKey:
161173
batchSize := &ab.BatchSize{}
162-
err := proto.Unmarshal(configItem.Value, batchSize)
163-
if err != nil {
174+
if err := proto.Unmarshal(configItem.Value, batchSize); err != nil {
164175
return fmt.Errorf("Unmarshaling error for BatchSize: %s", err)
165176
}
166-
167177
if batchSize.MaxMessageCount <= 0 {
168178
return fmt.Errorf("Attempted to set the batch size max message count to %d which is less than or equal to 0", batchSize.MaxMessageCount)
169179
}
170180
pm.pendingConfig.batchSize = batchSize
181+
case BatchTimeoutKey:
182+
var timeoutValue time.Duration
183+
var err error
184+
batchTimeout := &ab.BatchTimeout{}
185+
if err = proto.Unmarshal(configItem.Value, batchTimeout); err != nil {
186+
return fmt.Errorf("Unmarshaling error for BatchTimeout: %s", err)
187+
}
188+
if timeoutValue, err = time.ParseDuration(batchTimeout.Timeout); err != nil {
189+
return fmt.Errorf("Attempted to set the batch timeout to a invalid value: %s", err)
190+
}
191+
if timeoutValue <= 0 {
192+
return fmt.Errorf("Attempted to set the batch timeout to a non-positive value: %s", timeoutValue.String())
193+
}
194+
pm.pendingConfig.batchTimeout = timeoutValue
171195
case ChainCreatorsKey:
172196
chainCreators := &ab.ChainCreators{}
173-
err := proto.Unmarshal(configItem.Value, chainCreators)
174-
if err != nil {
197+
if err := proto.Unmarshal(configItem.Value, chainCreators); err != nil {
175198
return fmt.Errorf("Unmarshaling error for ChainCreator: %s", err)
176199
}
177200
pm.pendingConfig.chainCreators = chainCreators.Policies
178201
case KafkaBrokersKey:
179202
kafkaBrokers := &ab.KafkaBrokers{}
180-
err := proto.Unmarshal(configItem.Value, kafkaBrokers)
181-
if err != nil {
203+
if err := proto.Unmarshal(configItem.Value, kafkaBrokers); err != nil {
182204
return fmt.Errorf("Unmarshaling error for KafkaBrokers: %s", err)
183205
}
184206
if len(kafkaBrokers.Brokers) == 0 {

orderer/common/sharedconfig/sharedconfig_test.go

+53
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"os"
2121
"os/exec"
2222
"testing"
23+
"time"
2324

2425
cb "github.com/hyperledger/fabric/protos/common"
2526
ab "github.com/hyperledger/fabric/protos/orderer"
@@ -172,6 +173,58 @@ func TestBatchSize(t *testing.T) {
172173
}
173174
}
174175

176+
func TestBatchTimeout(t *testing.T) {
177+
endBatchTimeout, _ := time.ParseDuration("1s")
178+
invalidMessage := &cb.ConfigurationItem{
179+
Type: cb.ConfigurationItem_Orderer,
180+
Key: BatchTimeoutKey,
181+
Value: []byte("Garbage Data"),
182+
}
183+
negativeBatchTimeout := &cb.ConfigurationItem{
184+
Type: cb.ConfigurationItem_Orderer,
185+
Key: BatchTimeoutKey,
186+
Value: utils.MarshalOrPanic(&ab.BatchTimeout{Timeout: "-1s"}),
187+
}
188+
zeroBatchTimeout := &cb.ConfigurationItem{
189+
Type: cb.ConfigurationItem_Orderer,
190+
Key: BatchTimeoutKey,
191+
Value: utils.MarshalOrPanic(&ab.BatchTimeout{Timeout: "0s"}),
192+
}
193+
validMessage := &cb.ConfigurationItem{
194+
Type: cb.ConfigurationItem_Orderer,
195+
Key: BatchTimeoutKey,
196+
Value: utils.MarshalOrPanic(&ab.BatchTimeout{Timeout: endBatchTimeout.String()}),
197+
}
198+
m := NewManagerImpl()
199+
m.BeginConfig()
200+
201+
err := m.ProposeConfig(validMessage)
202+
if err != nil {
203+
t.Fatalf("Error applying valid config: %s", err)
204+
}
205+
206+
err = m.ProposeConfig(invalidMessage)
207+
if err == nil {
208+
t.Fatalf("Should have failed on invalid message")
209+
}
210+
211+
err = m.ProposeConfig(negativeBatchTimeout)
212+
if err == nil {
213+
t.Fatalf("Should have rejected negative batch timeout: %s", err)
214+
}
215+
216+
err = m.ProposeConfig(zeroBatchTimeout)
217+
if err == nil {
218+
t.Fatalf("Should have rejected batch timeout of 0")
219+
}
220+
221+
m.CommitConfig()
222+
223+
if nowBatchTimeout := m.BatchTimeout(); nowBatchTimeout != endBatchTimeout {
224+
t.Fatalf("Got batch timeout of %s when expecting batch size of %s", nowBatchTimeout.String(), endBatchTimeout.String())
225+
}
226+
}
227+
175228
func TestKafkaBrokers(t *testing.T) {
176229
endList := []string{"127.0.0.1:9092", "foo.bar:9092"}
177230

orderer/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func main() {
100100
}
101101

102102
consenters := make(map[string]multichain.Consenter)
103-
consenters["solo"] = solo.New(conf.General.BatchTimeout)
103+
consenters["solo"] = solo.New()
104104
consenters["kafka"] = kafka.New(conf.Kafka.Version, conf.Kafka.Retry)
105105

106106
manager := multichain.NewManagerImpl(lf, consenters)

orderer/mocks/sharedconfig/sharedconfig.go

+8
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@ limitations under the License.
1717
package sharedconfig
1818

1919
import ab "github.com/hyperledger/fabric/protos/orderer"
20+
import "time"
2021

2122
// Manager is a mock implementation of sharedconfig.Manager
2223
type Manager struct {
2324
// ConsensusTypeVal is returned as the result of ConsensusType()
2425
ConsensusTypeVal string
2526
// BatchSizeVal is returned as the result of BatchSize()
2627
BatchSizeVal *ab.BatchSize
28+
// BatchTimeoutVal is returned as the result of BatchTimeout()
29+
BatchTimeoutVal time.Duration
2730
// ChainCreatorsVal is returned as the result of ChainCreators()
2831
ChainCreatorsVal []string
2932
// KafkaBrokersVal is returned as the result of KafkaBrokers()
@@ -40,6 +43,11 @@ func (scm *Manager) BatchSize() *ab.BatchSize {
4043
return scm.BatchSizeVal
4144
}
4245

46+
// BatchTimeout returns the BatchTimeoutVal
47+
func (scm *Manager) BatchTimeout() time.Duration {
48+
return scm.BatchTimeoutVal
49+
}
50+
4351
// ChainCreators returns the ChainCreatorsVal
4452
func (scm *Manager) ChainCreators() []string {
4553
return scm.ChainCreatorsVal

orderer/multichain/systemchain_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package multichain
1919
import (
2020
"reflect"
2121
"testing"
22+
"time"
2223

2324
"github.com/hyperledger/fabric/common/policies"
2425
coreutil "github.com/hyperledger/fabric/core/util"
@@ -58,6 +59,10 @@ func (msc *mockSharedConfig) BatchSize() *ab.BatchSize {
5859
panic("Unimplemented")
5960
}
6061

62+
func (msc *mockSharedConfig) BatchTimeout() time.Duration {
63+
panic("Unimplemented")
64+
}
65+
6166
func (msc *mockSharedConfig) ChainCreators() []string {
6267
return msc.chainCreators
6368
}

orderer/solo/consensus.go

+6-11
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@ func init() {
3030
logging.SetLevel(logging.DEBUG, "")
3131
}
3232

33-
type consenter struct {
34-
batchTimeout time.Duration
35-
}
33+
type consenter struct{}
3634

3735
type chain struct {
3836
support multichain.ConsenterSupport
@@ -45,20 +43,17 @@ type chain struct {
4543
// The solo consensus scheme is very simple, and allows only one consenter for a given chain (this process).
4644
// It accepts messages being delivered via Enqueue, orders them, and then uses the blockcutter to form the messages
4745
// into blocks before writing to the given ledger
48-
func New(batchTimeout time.Duration) multichain.Consenter {
49-
return &consenter{
50-
// TODO, ultimately this should come from the configManager at HandleChain
51-
batchTimeout: batchTimeout,
52-
}
46+
func New() multichain.Consenter {
47+
return &consenter{}
5348
}
5449

5550
func (solo *consenter) HandleChain(support multichain.ConsenterSupport) (multichain.Chain, error) {
56-
return newChain(solo.batchTimeout, support), nil
51+
return newChain(support), nil
5752
}
5853

59-
func newChain(batchTimeout time.Duration, support multichain.ConsenterSupport) *chain {
54+
func newChain(support multichain.ConsenterSupport) *chain {
6055
return &chain{
61-
batchTimeout: batchTimeout,
56+
batchTimeout: support.SharedConfig().BatchTimeout(),
6257
support: support,
6358
sendChan: make(chan *cb.Envelope),
6459
exitChan: make(chan struct{}),

orderer/solo/consensus_test.go

+21-12
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222

2323
mockblockcutter "github.com/hyperledger/fabric/orderer/mocks/blockcutter"
2424
mockmultichain "github.com/hyperledger/fabric/orderer/mocks/multichain"
25+
mocksharedconfig "github.com/hyperledger/fabric/orderer/mocks/sharedconfig"
2526
cb "github.com/hyperledger/fabric/protos/common"
2627
)
2728

@@ -48,12 +49,14 @@ func goWithWait(target func()) *waitableGo {
4849
}
4950

5051
func TestEmptyBatch(t *testing.T) {
52+
batchTimeout, _ := time.ParseDuration("1ms")
5153
support := &mockmultichain.ConsenterSupport{
52-
Batches: make(chan []*cb.Envelope),
53-
BlockCutterVal: mockblockcutter.NewReceiver(),
54+
Batches: make(chan []*cb.Envelope),
55+
BlockCutterVal: mockblockcutter.NewReceiver(),
56+
SharedConfigVal: &mocksharedconfig.Manager{BatchTimeoutVal: batchTimeout},
5457
}
5558
defer close(support.BlockCutterVal.Block)
56-
bs := newChain(time.Millisecond, support)
59+
bs := newChain(support)
5760
wg := goWithWait(bs.main)
5861
defer bs.Halt()
5962

@@ -67,12 +70,14 @@ func TestEmptyBatch(t *testing.T) {
6770
}
6871

6972
func TestBatchTimer(t *testing.T) {
73+
batchTimeout, _ := time.ParseDuration("1ms")
7074
support := &mockmultichain.ConsenterSupport{
71-
Batches: make(chan []*cb.Envelope),
72-
BlockCutterVal: mockblockcutter.NewReceiver(),
75+
Batches: make(chan []*cb.Envelope),
76+
BlockCutterVal: mockblockcutter.NewReceiver(),
77+
SharedConfigVal: &mocksharedconfig.Manager{BatchTimeoutVal: batchTimeout},
7378
}
7479
defer close(support.BlockCutterVal.Block)
75-
bs := newChain(time.Millisecond, support)
80+
bs := newChain(support)
7681
wg := goWithWait(bs.main)
7782
defer bs.Halt()
7883

@@ -100,13 +105,15 @@ func TestBatchTimer(t *testing.T) {
100105
}
101106

102107
func TestBatchTimerHaltOnFilledBatch(t *testing.T) {
108+
batchTimeout, _ := time.ParseDuration("1h")
103109
support := &mockmultichain.ConsenterSupport{
104-
Batches: make(chan []*cb.Envelope),
105-
BlockCutterVal: mockblockcutter.NewReceiver(),
110+
Batches: make(chan []*cb.Envelope),
111+
BlockCutterVal: mockblockcutter.NewReceiver(),
112+
SharedConfigVal: &mocksharedconfig.Manager{BatchTimeoutVal: batchTimeout},
106113
}
107114
defer close(support.BlockCutterVal.Block)
108115

109-
bs := newChain(time.Hour, support)
116+
bs := newChain(support)
110117
wg := goWithWait(bs.main)
111118
defer bs.Halt()
112119

@@ -141,12 +148,14 @@ func TestBatchTimerHaltOnFilledBatch(t *testing.T) {
141148
}
142149

143150
func TestConfigStyleMultiBatch(t *testing.T) {
151+
batchTimeout, _ := time.ParseDuration("1h")
144152
support := &mockmultichain.ConsenterSupport{
145-
Batches: make(chan []*cb.Envelope),
146-
BlockCutterVal: mockblockcutter.NewReceiver(),
153+
Batches: make(chan []*cb.Envelope),
154+
BlockCutterVal: mockblockcutter.NewReceiver(),
155+
SharedConfigVal: &mocksharedconfig.Manager{BatchTimeoutVal: batchTimeout},
147156
}
148157
defer close(support.BlockCutterVal.Block)
149-
bs := newChain(time.Hour, support)
158+
bs := newChain(support)
150159
wg := goWithWait(bs.main)
151160
defer bs.Halt()
152161

0 commit comments

Comments
 (0)