Skip to content

Commit a3b40de

Browse files
guogermastersingh24
authored andcommitted
[FAB-5709] Infer LastOffsetPersisted correctly
The `LastOffsetPersisted` of block produced by Kafka orderer may be off by 1 in a corner case, see FAB-5709 for details. This is fixed by having `Ordered` method returning a boolean indicating if there's still message pending in the receiver. Also, a hacky way of calculating offset in subtests is removed in favor of querying sarama mock Consumer directly. Change-Id: I7f0384cd9df498b686d0971696fdcca102c52a59 Signed-off-by: Jay Guo <[email protected]>
1 parent ae4e37d commit a3b40de

File tree

7 files changed

+233
-245
lines changed

7 files changed

+233
-245
lines changed

orderer/common/blockcutter/blockcutter.go

+21-24
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ var logger = logging.MustGetLogger("orderer/common/blockcutter")
3030
type Receiver interface {
3131
// Ordered should be invoked sequentially as messages are ordered
3232
// If the current message valid, and no batches need to be cut:
33-
// - Ordered will return nil, nil, and true (indicating ok).
33+
// - Ordered will return nil, nil, and true (indicating valid Tx).
3434
// If the current message valid, and batches need to be cut:
35-
// - Ordered will return 1 or 2 batches of messages, 1 or 2 batches of committers, and true (indicating ok).
35+
// - Ordered will return 1 or 2 batches of messages, 1 or 2 batches of committers, and true (indicating valid Tx).
3636
// If the current message is invalid:
37-
// - Ordered will return nil, nil, and false (to indicate not ok).
37+
// - Ordered will return nil, nil, and false (to indicate invalid Tx).
3838
//
3939
// Given a valid message, if the current message needs to be isolated (as determined during filtering).
4040
// - Ordered will return:
@@ -45,7 +45,9 @@ type Receiver interface {
4545
// - The current message needs to be isolated (as determined during filtering).
4646
// - The current message will cause the pending batch size in bytes to exceed BatchSize.PreferredMaxBytes.
4747
// - After adding the current message to the pending batch, the message count has reached BatchSize.MaxMessageCount.
48-
Ordered(msg *cb.Envelope) ([][]*cb.Envelope, [][]filter.Committer, bool)
48+
//
49+
// In any case, `pending` is set to true if there are still messages pending in the receiver after cutting the block.
50+
Ordered(msg *cb.Envelope) (messageBatches [][]*cb.Envelope, committers [][]filter.Committer, validTx bool, pending bool)
4951

5052
// Cut returns the current batch and starts a new one
5153
Cut() ([]*cb.Envelope, []filter.Committer)
@@ -69,29 +71,34 @@ func NewReceiverImpl(sharedConfigManager config.Orderer, filters *filter.RuleSet
6971

7072
// Ordered should be invoked sequentially as messages are ordered
7173
// If the current message valid, and no batches need to be cut:
72-
// - Ordered will return nil, nil, and true (indicating ok).
74+
// - Ordered will return nil, nil, true (indicating valid tx) and true (indicating there are pending messages).
7375
// If the current message valid, and batches need to be cut:
74-
// - Ordered will return 1 or 2 batches of messages, 1 or 2 batches of committers, and true (indicating ok).
76+
// - Ordered will return 1 or 2 batches of messages, 1 or 2 batches of committers, and true (indicating valid tx).
7577
// If the current message is invalid:
76-
// - Ordered will return nil, nil, and false (to indicate not ok).
78+
// - Ordered will return nil, nil, and false (to indicate invalid tx).
7779
//
7880
// Given a valid message, if the current message needs to be isolated (as determined during filtering).
7981
// - Ordered will return:
8082
// * The pending batch of (if not empty), and a second batch containing only the isolated message.
8183
// * The corresponding batches of committers.
82-
// * true (indicating ok).
84+
// * true (indicating valid tx).
8385
// Otherwise, given a valid message, the pending batch, if not empty, will be cut and returned if:
8486
// - The current message needs to be isolated (as determined during filtering).
8587
// - The current message will cause the pending batch size in bytes to exceed BatchSize.PreferredMaxBytes.
8688
// - After adding the current message to the pending batch, the message count has reached BatchSize.MaxMessageCount.
87-
func (r *receiver) Ordered(msg *cb.Envelope) ([][]*cb.Envelope, [][]filter.Committer, bool) {
89+
//
90+
// In any case, `pending` is set to true if there are still messages pending in the receiver after cutting the block.
91+
func (r *receiver) Ordered(msg *cb.Envelope) (messageBatches [][]*cb.Envelope, committerBatches [][]filter.Committer, validTx bool, pending bool) {
8892
// The messages must be filtered a second time in case configuration has changed since the message was received
8993
committer, err := r.filters.Apply(msg)
9094
if err != nil {
9195
logger.Debugf("Rejecting message: %s", err)
92-
return nil, nil, false
96+
return // We don't bother to determine `pending` here as it's not processed in error case
9397
}
9498

99+
// message is valid
100+
validTx = true
101+
95102
messageSizeBytes := messageSizeBytes(msg)
96103

97104
if committer.Isolated() || messageSizeBytes > r.sharedConfigManager.BatchSize().PreferredMaxBytes {
@@ -102,9 +109,6 @@ func (r *receiver) Ordered(msg *cb.Envelope) ([][]*cb.Envelope, [][]filter.Commi
102109
logger.Debugf("The current message, with %v bytes, is larger than the preferred batch size of %v bytes and will be isolated.", messageSizeBytes, r.sharedConfigManager.BatchSize().PreferredMaxBytes)
103110
}
104111

105-
messageBatches := [][]*cb.Envelope{}
106-
committerBatches := [][]filter.Committer{}
107-
108112
// cut pending batch, if it has any messages
109113
if len(r.pendingBatch) > 0 {
110114
messageBatch, committerBatch := r.Cut()
@@ -116,12 +120,9 @@ func (r *receiver) Ordered(msg *cb.Envelope) ([][]*cb.Envelope, [][]filter.Commi
116120
messageBatches = append(messageBatches, []*cb.Envelope{msg})
117121
committerBatches = append(committerBatches, []filter.Committer{committer})
118122

119-
return messageBatches, committerBatches, true
123+
return
120124
}
121125

122-
messageBatches := [][]*cb.Envelope{}
123-
committerBatches := [][]filter.Committer{}
124-
125126
messageWillOverflowBatchSizeBytes := r.pendingBatchSizeBytes+messageSizeBytes > r.sharedConfigManager.BatchSize().PreferredMaxBytes
126127

127128
if messageWillOverflowBatchSizeBytes {
@@ -136,21 +137,17 @@ func (r *receiver) Ordered(msg *cb.Envelope) ([][]*cb.Envelope, [][]filter.Commi
136137
r.pendingBatch = append(r.pendingBatch, msg)
137138
r.pendingBatchSizeBytes += messageSizeBytes
138139
r.pendingCommitters = append(r.pendingCommitters, committer)
140+
pending = true
139141

140142
if uint32(len(r.pendingBatch)) >= r.sharedConfigManager.BatchSize().MaxMessageCount {
141143
logger.Debugf("Batch size met, cutting batch")
142144
messageBatch, committerBatch := r.Cut()
143145
messageBatches = append(messageBatches, messageBatch)
144146
committerBatches = append(committerBatches, committerBatch)
147+
pending = false
145148
}
146149

147-
// return nils instead of empty slices
148-
if len(messageBatches) == 0 {
149-
return nil, nil, true
150-
}
151-
152-
return messageBatches, committerBatches, true
153-
150+
return
154151
}
155152

156153
// Cut returns the current batch and starts a new one

0 commit comments

Comments
 (0)