@@ -81,7 +81,7 @@ protected CompletableFuture<Void> prepareCreateProducer() {
81
81
}
82
82
83
83
@ Override
84
- protected boolean replicateEntries (List <Entry > entries ) {
84
+ protected boolean replicateEntries (List <Entry > entries , InFlightTask inFlightTask ) {
85
85
boolean atLeastOneMessageSentForReplication = false ;
86
86
boolean isEnableReplicatedSubscriptions =
87
87
brokerService .pulsar ().getConfiguration ().isEnableReplicatedSubscriptions ();
@@ -90,12 +90,13 @@ protected boolean replicateEntries(List<Entry> entries) {
90
90
// This flag is set to true when we skip at least one local message,
91
91
// in order to skip remaining local messages.
92
92
boolean isLocalMessageSkippedOnce = false ;
93
- boolean skipRemainingMessages = false ;
93
+ boolean skipRemainingMessages = inFlightTask . isSkipReadResultDueToCursorRewound () ;
94
94
for (int i = 0 ; i < entries .size (); i ++) {
95
95
Entry entry = entries .get (i );
96
96
// Skip the messages since the replicator need to fetch the schema info to replicate the schema to the
97
97
// remote cluster. Rewind the cursor first and continue the message read after fetched the schema.
98
98
if (skipRemainingMessages ) {
99
+ inFlightTask .incCompletedEntries ();
99
100
entry .release ();
100
101
continue ;
101
102
}
@@ -108,12 +109,14 @@ protected boolean replicateEntries(List<Entry> entries) {
108
109
log .error ("[{}] Failed to deserialize message at {} (buffer size: {}): {}" , replicatorId ,
109
110
entry .getPosition (), length , t .getMessage (), t );
110
111
cursor .asyncDelete (entry .getPosition (), this , entry .getPosition ());
112
+ inFlightTask .incCompletedEntries ();
111
113
entry .release ();
112
114
continue ;
113
115
}
114
116
115
117
if (Markers .isTxnMarker (msg .getMessageBuilder ())) {
116
118
cursor .asyncDelete (entry .getPosition (), this , entry .getPosition ());
119
+ inFlightTask .incCompletedEntries ();
117
120
entry .release ();
118
121
msg .recycle ();
119
122
continue ;
@@ -123,6 +126,7 @@ protected boolean replicateEntries(List<Entry> entries) {
123
126
msg .getMessageBuilder ().getTxnidLeastBits ());
124
127
if (topic .isTxnAborted (tx , entry .getPosition ())) {
125
128
cursor .asyncDelete (entry .getPosition (), this , entry .getPosition ());
129
+ inFlightTask .incCompletedEntries ();
126
130
entry .release ();
127
131
msg .recycle ();
128
132
continue ;
@@ -136,6 +140,7 @@ protected boolean replicateEntries(List<Entry> entries) {
136
140
if (msg .isReplicated ()) {
137
141
// Discard messages that were already replicated into this region
138
142
cursor .asyncDelete (entry .getPosition (), this , entry .getPosition ());
143
+ inFlightTask .incCompletedEntries ();
139
144
entry .release ();
140
145
msg .recycle ();
141
146
continue ;
@@ -147,6 +152,7 @@ protected boolean replicateEntries(List<Entry> entries) {
147
152
entry .getPosition (), msg .getReplicateTo ());
148
153
}
149
154
cursor .asyncDelete (entry .getPosition (), this , entry .getPosition ());
155
+ inFlightTask .incCompletedEntries ();
150
156
entry .release ();
151
157
msg .recycle ();
152
158
continue ;
@@ -159,19 +165,21 @@ protected boolean replicateEntries(List<Entry> entries) {
159
165
replicatorId , entry .getPosition (), msg .getReplicateTo ());
160
166
}
161
167
cursor .asyncDelete (entry .getPosition (), this , entry .getPosition ());
168
+ inFlightTask .incCompletedEntries ();
162
169
entry .release ();
163
170
msg .recycle ();
164
171
continue ;
165
172
}
166
173
167
174
if (STATE_UPDATER .get (this ) != State .Started || isLocalMessageSkippedOnce ) {
168
175
// The producer is not ready yet after having stopped/restarted. Drop the message because it will
169
- // recovered when the producer is ready
176
+ // recover when the producer is ready
170
177
if (log .isDebugEnabled ()) {
171
178
log .debug ("[{}] Dropping read message at {} because producer is not ready" ,
172
179
replicatorId , entry .getPosition ());
173
180
}
174
181
isLocalMessageSkippedOnce = true ;
182
+ inFlightTask .incCompletedEntries ();
175
183
entry .release ();
176
184
msg .recycle ();
177
185
continue ;
@@ -184,24 +192,31 @@ protected boolean replicateEntries(List<Entry> entries) {
184
192
185
193
CompletableFuture <SchemaInfo > schemaFuture = getSchemaInfo (msg );
186
194
if (!schemaFuture .isDone () || schemaFuture .isCompletedExceptionally ()) {
195
+ /**
196
+ * Skip in flight reading tasks.
197
+ * Explain the result of the race-condition between:
198
+ * - {@link #readMoreEntries}
199
+ * - {@link #beforeTerminateOrCursorRewinding(ReasonOfWaitForCursorRewinding)}
200
+ * Since {@link #acquirePermitsIfNotFetchingSchema} and
201
+ * {@link #beforeTerminateOrCursorRewinding(ReasonOfWaitForCursorRewinding)} acquire the
202
+ * same lock, it is safe.
203
+ */
204
+ beforeTerminateOrCursorRewinding (ReasonOfWaitForCursorRewinding .Fetching_Schema );
205
+ inFlightTask .incCompletedEntries ();
187
206
entry .release ();
188
207
headersAndPayload .release ();
189
208
msg .recycle ();
190
209
// Mark the replicator is fetching the schema for now and rewind the cursor
191
210
// and trigger the next read after complete the schema fetching.
192
- fetchSchemaInProgress = true ;
193
211
skipRemainingMessages = true ;
194
- cursor .cancelPendingReadRequest ();
195
212
log .info ("[{}] Pause the data replication due to new detected schema" , replicatorId );
196
213
schemaFuture .whenComplete ((__ , e ) -> {
197
214
if (e != null ) {
198
215
log .warn ("[{}] Failed to get schema from local cluster, will try in the next loop" ,
199
216
replicatorId , e );
200
217
}
201
218
log .info ("[{}] Resume the data replication after the schema fetching done" , replicatorId );
202
- cursor .rewind ();
203
- fetchSchemaInProgress = false ;
204
- readMoreEntries ();
219
+ doRewindCursor (true );
205
220
});
206
221
} else {
207
222
msg .setSchemaInfoForReplicator (schemaFuture .get ());
@@ -214,7 +229,6 @@ protected boolean replicateEntries(List<Entry> entries) {
214
229
stats .incrementMsgOutCounter ();
215
230
stats .incrementBytesOutCounter (headersAndPayload .readableBytes ());
216
231
// Increment pending messages for messages produced locally
217
- PENDING_MESSAGES_UPDATER .incrementAndGet (this );
218
232
if (log .isDebugEnabled ()) {
219
233
log .debug ("[{}] Publishing {}:{}" , replicatorId , entry .getLedgerId (), entry .getEntryId ());
220
234
}
0 commit comments