|
25 | 25 | import java.nio.ByteBuffer;
|
26 | 26 | import java.util.ArrayList;
|
27 | 27 | import java.util.HashMap;
|
| 28 | +import java.util.HashSet; |
28 | 29 | import java.util.List;
|
29 | 30 | import java.util.Map;
|
30 | 31 | import java.util.Optional;
|
|
40 | 41 | import lombok.extern.slf4j.Slf4j;
|
41 | 42 | import org.apache.bookkeeper.common.concurrent.FutureUtils;
|
42 | 43 | import org.apache.kafka.common.TopicPartition;
|
| 44 | +import org.apache.kafka.common.message.ListTransactionsResponseData; |
43 | 45 | import org.apache.kafka.common.protocol.Errors;
|
44 | 46 | import org.apache.kafka.common.protocol.types.SchemaException;
|
45 | 47 | import org.apache.kafka.common.requests.ProduceResponse;
|
@@ -245,6 +247,71 @@ private boolean shouldExpire(TransactionMetadata txnMetadata, Long currentTimeMs
|
245 | 247 | <= (currentTimeMs - transactionConfig.getTransactionalIdExpirationMs());
|
246 | 248 | }
|
247 | 249 |
|
| 250 | + private static boolean shouldInclude(TransactionMetadata txnMetadata, |
| 251 | + List<Long> filterProducerIds, Set<String> filterStateNames) { |
| 252 | + if (txnMetadata.getState() == TransactionState.DEAD) { |
| 253 | + // We filter the `Dead` state since it is a transient state which |
| 254 | + // indicates that the transactionalId and its metadata are in the |
| 255 | + // process of expiration and removal. |
| 256 | + return false; |
| 257 | + } else if (!filterProducerIds.isEmpty() && !filterProducerIds.contains(txnMetadata.getProducerId())) { |
| 258 | + return false; |
| 259 | + } else if (!filterStateNames.isEmpty() && !filterStateNames.contains( |
| 260 | + txnMetadata.getState().toAdminState().toString())) { |
| 261 | + return false; |
| 262 | + } else { |
| 263 | + return true; |
| 264 | + } |
| 265 | + } |
| 266 | + |
| 267 | + public ListTransactionsResponseData listTransactionStates(List<Long> filteredProducerIds, |
| 268 | + List<String> filteredStates) { |
| 269 | + return CoreUtils.inReadLock(stateLock, () -> { |
| 270 | + ListTransactionsResponseData response = new ListTransactionsResponseData(); |
| 271 | + if (!loadingPartitions.isEmpty()) { |
| 272 | + response.setErrorCode(Errors.COORDINATOR_LOAD_IN_PROGRESS.code()); |
| 273 | + } else { |
| 274 | + Set<String> filterStates = new HashSet<>(); |
| 275 | + for (TransactionState stateName : TransactionState.values()) { |
| 276 | + String nameForTheClient = stateName.toAdminState().toString(); |
| 277 | + if (filteredStates.contains(nameForTheClient)) { |
| 278 | + filterStates.add(nameForTheClient); |
| 279 | + } else { |
| 280 | + response.unknownStateFilters().add(nameForTheClient); |
| 281 | + } |
| 282 | + } |
| 283 | + List<ListTransactionsResponseData.TransactionState> states = new ArrayList<>(); |
| 284 | + transactionMetadataCache.forEach((__, cache) -> { |
| 285 | + cache.values().forEach(txnMetadata -> { |
| 286 | + txnMetadata.inLock(() -> { |
| 287 | + // use toString() to get the name of the state according to the protocol |
| 288 | + ListTransactionsResponseData.TransactionState transactionState = |
| 289 | + new ListTransactionsResponseData.TransactionState() |
| 290 | + .setTransactionalId(txnMetadata.getTransactionalId()) |
| 291 | + .setProducerId(txnMetadata.getProducerId()) |
| 292 | + .setTransactionState(txnMetadata.getState().toAdminState().toString()); |
| 293 | + |
| 294 | + if (shouldInclude(txnMetadata, filteredProducerIds, filterStates)) { |
| 295 | + if (log.isDebugEnabled()) { |
| 296 | + log.debug("add transaction state: {}", transactionState); |
| 297 | + } |
| 298 | + states.add(transactionState); |
| 299 | + } else { |
| 300 | + if (log.isDebugEnabled()) { |
| 301 | + log.debug("Skip transaction state: {}", transactionState); |
| 302 | + } |
| 303 | + } |
| 304 | + return null; |
| 305 | + }); |
| 306 | + }); |
| 307 | + }); |
| 308 | + response.setErrorCode(Errors.NONE.code()) |
| 309 | + .setTransactionStates(states); |
| 310 | + } |
| 311 | + return response; |
| 312 | + }); |
| 313 | + } |
| 314 | + |
248 | 315 | @Data
|
249 | 316 | @AllArgsConstructor
|
250 | 317 | private static class TransactionalIdCoordinatorEpochAndMetadata {
|
|
0 commit comments