|
25 | 25 | import org.apache.kafka.clients.consumer.ConsumerRecords; |
26 | 26 | import org.apache.kafka.clients.consumer.KafkaConsumer; |
27 | 27 | import org.apache.kafka.clients.consumer.OffsetAndMetadata; |
28 | | -import org.apache.kafka.clients.consumer.OffsetCommitCallback; |
29 | 28 | import org.apache.kafka.clients.producer.internals.BufferPool; |
30 | 29 | import org.apache.kafka.clients.producer.internals.BuiltInPartitioner; |
31 | 30 | import org.apache.kafka.clients.producer.internals.KafkaProducerMetrics; |
@@ -598,14 +597,17 @@ private TransactionManager configureTransactionState(ProducerConfig config, |
598 | 597 |
|
599 | 598 | if (config.getBoolean(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG)) { |
600 | 599 | final String transactionalId = config.getString(ProducerConfig.TRANSACTIONAL_ID_CONFIG); |
| 600 | + final boolean enable2PC = config.getBoolean(ProducerConfig.TRANSACTION_TWO_PHASE_COMMIT_ENABLE_CONFIG); |
601 | 601 | final int transactionTimeoutMs = config.getInt(ProducerConfig.TRANSACTION_TIMEOUT_CONFIG); |
602 | 602 | final long retryBackoffMs = config.getLong(ProducerConfig.RETRY_BACKOFF_MS_CONFIG); |
| 603 | + |
603 | 604 | transactionManager = new TransactionManager( |
604 | 605 | logContext, |
605 | 606 | transactionalId, |
606 | 607 | transactionTimeoutMs, |
607 | 608 | retryBackoffMs, |
608 | | - apiVersions |
| 609 | + apiVersions, |
| 610 | + enable2PC |
609 | 611 | ); |
610 | 612 |
|
611 | 613 | if (transactionManager.isTransactional()) |
@@ -656,6 +658,47 @@ public void initTransactions() { |
656 | 658 | transactionManager.maybeUpdateTransactionV2Enabled(true); |
657 | 659 | } |
658 | 660 |
|
| 661 | + /** |
| 662 | + * Performs initialization of transactions functionality in this producer instance. This method bootstraps |
| 663 | + * the producer with a {@code producerId} and also resets the internal state of the producer following a previous |
| 664 | + * fatal error. Additionally, it allows setting the {@code keepPreparedTxn} flag which, if set to true, puts the producer |
| 665 | + * into a restricted state that only allows transaction completion operations. |
| 666 | + * |
| 667 | + * <p> |
| 668 | + * When {@code keepPreparedTxn} is set to {@code true}, the producer will be able to complete in-flight prepared |
| 669 | + * transactions, but will only allow calling {@link #commitTransaction()}, {@link #abortTransaction()}, or |
| 670 | + * the to-be-added {@code completeTransaction()} methods. This is to support recovery of prepared transactions |
| 671 | + * after a producer restart. |
| 672 | + * |
| 673 | + * <p> |
| 674 | + * Note that this method should only be called once during the lifetime of a producer instance, and must be |
| 675 | + * called before any other methods which require a {@code transactionalId} to be specified. |
| 676 | + * |
| 677 | + * @param keepPreparedTxn whether to keep prepared transactions, restricting the producer to only support completion of |
| 678 | + * prepared transactions. When set to true, the producer will only allow transaction completion |
| 679 | + * operations after initialization. |
| 680 | + * |
| 681 | + * @throws IllegalStateException if no {@code transactional.id} has been configured for the producer |
| 682 | + * @throws org.apache.kafka.common.errors.UnsupportedVersionException fatal error indicating that the broker |
| 683 | + * does not support transactions (i.e. if its version is lower than 0.11.0.0). If this is encountered, |
| 684 | + * the producer cannot be used for transactional messaging. |
| 685 | + * @throws org.apache.kafka.common.errors.AuthorizationException fatal error indicating that the configured |
| 686 | + * {@code transactional.id} is not authorized. If this is encountered, the producer cannot be used for |
| 687 | + * transactional messaging. |
| 688 | + * @throws KafkaException if the producer has encountered a previous fatal error or for any other unexpected error |
| 689 | + * @see #initTransactions() |
| 690 | + */ |
| 691 | + public void initTransactions(boolean keepPreparedTxn) { |
| 692 | + throwIfNoTransactionManager(); |
| 693 | + throwIfProducerClosed(); |
| 694 | + long now = time.nanoseconds(); |
| 695 | + TransactionalRequestResult result = transactionManager.initializeTransactions(keepPreparedTxn); |
| 696 | + sender.wakeup(); |
| 697 | + result.await(maxBlockTimeMs, TimeUnit.MILLISECONDS); |
| 698 | + producerMetrics.recordInit(time.nanoseconds() - now); |
| 699 | + transactionManager.maybeUpdateTransactionV2Enabled(true); |
| 700 | + } |
| 701 | + |
659 | 702 | /** |
660 | 703 | * Should be called before the start of each new transaction. Note that prior to the first invocation |
661 | 704 | * of this method, you must invoke {@link #initTransactions()} exactly one time. |
@@ -703,7 +746,7 @@ public void beginTransaction() throws ProducerFencedException { |
703 | 746 | * <p> |
704 | 747 | * Note, that the consumer should have {@code enable.auto.commit=false} and should |
705 | 748 | * also not commit offsets manually (via {@link KafkaConsumer#commitSync(Map) sync} or |
706 | | - * {@link KafkaConsumer#commitAsync(Map, OffsetCommitCallback) async} commits). |
| 749 | + * {@link KafkaConsumer#commitAsync()} (Map, OffsetCommitCallback) async} commits). |
707 | 750 | * This method will raise {@link TimeoutException} if the producer cannot send offsets before expiration of {@code max.block.ms}. |
708 | 751 | * Additionally, it will raise {@link InterruptException} if interrupted. |
709 | 752 | * |
|
0 commit comments