All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.scylladb.cdc.debezium.connector.ScyllaChangesConsumer Maven / Gradle / Ivy

package com.scylladb.cdc.debezium.connector;

import com.scylladb.cdc.model.TaskId;
import com.scylladb.cdc.model.worker.ChangeSchema;
import com.scylladb.cdc.model.worker.RawChange;
import com.scylladb.cdc.model.worker.Task;
import com.scylladb.cdc.model.worker.TaskAndRawChangeConsumer;
import io.debezium.pipeline.EventDispatcher;
import io.debezium.util.Clock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

public class ScyllaChangesConsumer implements TaskAndRawChangeConsumer {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    private final EventDispatcher dispatcher;
    private final ScyllaOffsetContext offsetContext;
    private final ScyllaSchema schema;
    private final Clock clock;
    private final boolean usePreimages;
    private final Map lastPreImage;

    public ScyllaChangesConsumer(EventDispatcher dispatcher, ScyllaOffsetContext offsetContext, ScyllaSchema schema, Clock clock, boolean usePreimages) {
        this.dispatcher = dispatcher;
        this.offsetContext = offsetContext;
        this.schema = schema;
        this.clock = clock;
        this.usePreimages = usePreimages;
        if (usePreimages) {
            this.lastPreImage = new HashMap<>();
        } else {
            this.lastPreImage = null;
        }
    }

    @Override
    public CompletableFuture consume(Task task, RawChange change) {
        try {
            logger.trace("Consuming RawChange of type {}", change.getOperationType());
            if (usePreimages && change.getOperationType() == RawChange.OperationType.PRE_IMAGE) {
                lastPreImage.put(task.id, change);
                return CompletableFuture.completedFuture(null);
            }

            Task updatedTask = task.updateState(change.getId());
            TaskStateOffsetContext taskStateOffsetContext = offsetContext.taskStateOffsetContext(task.id);
            taskStateOffsetContext.dataChangeEvent(updatedTask.state);

            RawChange.OperationType operationType = change.getOperationType();
            ChangeSchema changeSchema = change.getSchema();
            if (operationType == RawChange.OperationType.PARTITION_DELETE) {
                // The connector currently does not support partition deletes.
                //
                // However, there is a single exception to this:
                // If the (base) table's primary key consists only of
                // partition key, row DELETEs in such a table are represented as
                // partition deletes (even though they affect at most a single row).
                // In that case, we will interpret such a CDC operation
                // as a "standard" ROW_DELETE.
                boolean hasClusteringColumn = changeSchema.getNonCdcColumnDefinitions().stream()
                        .anyMatch(column -> column.getBaseTableColumnType() == ChangeSchema.ColumnType.CLUSTERING_KEY);
                if (hasClusteringColumn) {
                    return CompletableFuture.completedFuture(null);
                }
            } else if (operationType != RawChange.OperationType.ROW_INSERT
                    && operationType != RawChange.OperationType.ROW_UPDATE
                    && operationType != RawChange.OperationType.ROW_DELETE) {
                return CompletableFuture.completedFuture(null);
            }

            if (usePreimages && lastPreImage.containsKey(task.id)) {
                dispatcher.dispatchDataChangeEvent(new CollectionId(task.id.getTable()),
                    new ScyllaChangeRecordEmitter(lastPreImage.get(task.id), change, taskStateOffsetContext, schema, clock));
                lastPreImage.remove(task.id);
            }
            else {
                dispatcher.dispatchDataChangeEvent(new CollectionId(task.id.getTable()),
                    new ScyllaChangeRecordEmitter(change, taskStateOffsetContext, schema, clock));
            }
        } catch (InterruptedException e) {
            logger.error("Exception while dispatching change: {}", change.getId().toString());
            logger.error("Exception details: {}", e.getMessage());
        }
        return CompletableFuture.completedFuture(null);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy