Batch.java

package org.itsallcode.jdbc.batch;

import java.time.Duration;
import java.time.Instant;
import java.util.logging.Logger;

/**
 * A generic batch handler that takes care of maximum batch size and executing
 * the last batch before closing.
 */
class Batch implements AutoCloseable {
    private static final Logger LOG = Logger.getLogger(Batch.class.getName());

    private final Runnable batchExecutor;
    private final AutoCloseable resource;
    private final int maxBatchSize;
    private final Instant start;

    private int totalCount;
    private int currentBatchSize;

    Batch(final int maxBatchSize, final AutoCloseable resource, final Runnable batchExecutor) {
        this.maxBatchSize = maxBatchSize;
        this.resource = resource;
        this.batchExecutor = batchExecutor;
        this.start = Instant.now();
    }

    void addBatch() {
        this.currentBatchSize++;
        this.totalCount++;
        if (this.currentBatchSize >= this.maxBatchSize) {
            this.executeBatch();
        }
    }

    private void executeBatch() {
        if (currentBatchSize == 0) {
            LOG.finest("No items added to batch, skip");
            return;
        }
        final Instant batchStart = Instant.now();
        batchExecutor.run();
        final Duration duration = Duration.between(batchStart, Instant.now());
        LOG.finest(() -> "Execute batch of %d after %d took %d ms".formatted(currentBatchSize, totalCount,
                duration.toMillis()));
        currentBatchSize = 0;
    }

    @Override
    public void close() {
        executeBatch();
        closeResource();
        LOG.fine(() -> "Batch processing of %d items with batch size %d completed in %s".formatted(totalCount,
                maxBatchSize,
                Duration.between(start, Instant.now())));
    }

    private void closeResource() {
        try {
            resource.close();
        } catch (final Exception e) {
            throw new IllegalStateException("Failed to close resource: " + e.getMessage(), e);
        }
    }
}