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

io.zeebe.broker.system.log.SystemPartitionManager Maven / Gradle / Ivy

There is a newer version: 0.21.0-alpha1
Show newest version
/*
 * Zeebe Broker Core
 * Copyright © 2017 camunda services GmbH ([email protected])
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see .
 */
package io.zeebe.broker.system.log;

import java.time.Duration;
import java.util.concurrent.atomic.AtomicReference;

import io.zeebe.broker.Loggers;
import io.zeebe.broker.clustering.management.PartitionManager;
import io.zeebe.broker.logstreams.LogStreamServiceNames;
import io.zeebe.broker.logstreams.processor.*;
import io.zeebe.broker.system.SystemConfiguration;
import io.zeebe.broker.system.SystemServiceNames;
import io.zeebe.broker.system.deployment.processor.PartitionCollector;
import io.zeebe.logstreams.log.LogStream;
import io.zeebe.protocol.clientapi.EventType;
import io.zeebe.servicecontainer.*;
import io.zeebe.transport.ServerOutput;
import io.zeebe.transport.ServerTransport;
import io.zeebe.util.sched.future.ActorFuture;
import io.zeebe.util.sched.future.CompletableActorFuture;

public class SystemPartitionManager implements Service
{
    public static final String CREATE_TOPICS_PROCESSOR = "create-topics";
    public static final String COLLECT_PARTITIONS_PROCESSOR = "collect-partitions";

    private ServiceStartContext serviceContext;

    private final Injector clientApiTransportInjector = new Injector<>();
    private final Injector partitionManagerInjector = new Injector<>();

    private final SystemConfiguration systemConfiguration;

    private PartitionManager partitionManager;
    private ServerTransport clientApiTransport;

    private final ServiceGroupReference logStreamsGroupReference = ServiceGroupReference.create()
        .onAdd((name, stream) -> addSystemPartition(stream, name))
        .onRemove((name, stream) -> removeSystemPartition())
        .build();

    private ResolvePendingPartitionsCommand resolvePendingPartitionsCommand;

    private AtomicReference partitionResponderRef = new AtomicReference<>();

    public SystemPartitionManager(SystemConfiguration systemConfiguration)
    {
        this.systemConfiguration = systemConfiguration;
    }

    public void addSystemPartition(LogStream logStream, ServiceName serviceName)
    {
        Loggers.SYSTEM_LOGGER.debug("Add system partiton");
        final ServerOutput serverOutput = clientApiTransport.getOutput();

        final TypedStreamEnvironment streamEnvironment = new TypedStreamEnvironment(logStream, serverOutput);

        installCreateTopicProcessor(serviceName, streamEnvironment);
        installPartitionCollectorProcessor(serviceName, serverOutput, streamEnvironment);
    }

    private void installPartitionCollectorProcessor(
            ServiceName logStreamName,
            final ServerOutput serverOutput,
            final TypedStreamEnvironment streamEnvironment)
    {
        final PartitionResponder partitionResponder = new PartitionResponder(serverOutput);
        final TypedStreamProcessor streamProcessor = buildPartitionResponseProcessor(streamEnvironment, partitionResponder);

        final StreamProcessorService streamProcessorService = new StreamProcessorService(
            COLLECT_PARTITIONS_PROCESSOR,
            StreamProcessorIds.SYSTEM_COLLECT_PARTITION_PROCESSOR_ID,
            streamProcessor)
            .eventFilter(streamProcessor.buildTypeFilter());

        serviceContext.createService(SystemServiceNames.systemProcessorName(streamProcessorService.getName()), streamProcessorService)
            .dependency(logStreamName, streamProcessorService.getLogStreamInjector())
            .dependency(LogStreamServiceNames.SNAPSHOT_STORAGE_SERVICE, streamProcessorService.getSnapshotStorageInjector())
            .install();


        partitionResponderRef.set(partitionResponder);
    }

    private void installCreateTopicProcessor(
            ServiceName logStreamName,
            final TypedStreamEnvironment streamEnvironment)
    {
        final PendingPartitionsIndex partitionsIndex = new PendingPartitionsIndex();
        final TopicsIndex topicsIndex = new TopicsIndex();

        resolvePendingPartitionsCommand = new ResolvePendingPartitionsCommand(
                partitionsIndex,
                partitionManager,
                streamEnvironment.buildStreamReader(),
                streamEnvironment.buildStreamWriter());

        final TypedStreamProcessor streamProcessor =
                buildTopicCreationProcessor(
                        streamEnvironment,
                        partitionManager,
                        topicsIndex,
                        partitionsIndex,
                        Duration.ofSeconds(systemConfiguration.getPartitionCreationTimeoutSeconds()), resolvePendingPartitionsCommand);

        final StreamProcessorService streamProcessorService = new StreamProcessorService(
            CREATE_TOPICS_PROCESSOR,
            StreamProcessorIds.SYSTEM_CREATE_TOPIC_PROCESSOR_ID,
            streamProcessor)
            .eventFilter(streamProcessor.buildTypeFilter());

        serviceContext.createService(SystemServiceNames.systemProcessorName(streamProcessorService.getName()), streamProcessorService)
            .dependency(logStreamName, streamProcessorService.getLogStreamInjector())
            .dependency(LogStreamServiceNames.SNAPSHOT_STORAGE_SERVICE, streamProcessorService.getSnapshotStorageInjector())
            .install();
    }

    private void removeSystemPartition()
    {
        Loggers.SYSTEM_LOGGER.debug("Remove");
        partitionResponderRef.set(null);
    }

    public static TypedStreamProcessor buildTopicCreationProcessor(
            TypedStreamEnvironment streamEnvironment,
            PartitionManager partitionManager,
            TopicsIndex topicsIndex,
            PendingPartitionsIndex partitionsIndex,
            Duration creationExpiration,
            Runnable onOpen)
    {
        final PartitionIdGenerator idGenerator = new PartitionIdGenerator();
        final PartitionCreatorSelectionStrategy creationStrategy = new RoundRobinSelectionStrategy(partitionManager);

        return streamEnvironment.newStreamProcessor()
            .onEvent(EventType.TOPIC_EVENT, TopicState.CREATE, new CreateTopicProcessor(topicsIndex, idGenerator, creationStrategy))
            .onEvent(EventType.PARTITION_EVENT, PartitionState.CREATE, new CreatePartitionProcessor(partitionManager, partitionsIndex, creationExpiration))
            .onEvent(EventType.PARTITION_EVENT, PartitionState.CREATE_COMPLETE, new CompletePartitionProcessor(partitionsIndex))
            .onEvent(EventType.PARTITION_EVENT, PartitionState.CREATED, new PartitionCreatedProcessor(topicsIndex, streamEnvironment.buildStreamReader()))
            .onEvent(EventType.PARTITION_EVENT, PartitionState.CREATE_EXPIRE, new ExpirePartitionCreationProcessor(partitionsIndex, idGenerator, creationStrategy))
            .withStateResource(topicsIndex.getRawMap())
            .withStateResource(partitionsIndex.getRawMap())
            .withStateResource(idGenerator)
            .withListener(new StreamProcessorLifecycleAware()
            {
                @Override
                public void onOpen(TypedStreamProcessor streamProcessor)
                {
                    // TODO check needs to be re-implemented
                    streamProcessor.getActor().runAtFixedRate(Duration.ofMillis(100), onOpen);
                }
            })
            .build();
    }

    public static TypedStreamProcessor buildPartitionResponseProcessor(
            TypedStreamEnvironment streamEnvironment,
            PartitionResponder partitionResponder)
    {
        final PartitionCollector partitionCollector = new PartitionCollector(partitionResponder);

        final TypedEventStreamProcessorBuilder streamProcessorBuilder = streamEnvironment.newStreamProcessor();
        partitionCollector.registerWith(streamProcessorBuilder);
        partitionResponder.registerWith(streamProcessorBuilder);

        return streamProcessorBuilder.build();
    }

    @Override
    public void start(ServiceStartContext startContext)
    {
        this.serviceContext = startContext;
        this.clientApiTransport = clientApiTransportInjector.getValue();
        this.partitionManager = getPartitionManagerInjector().getValue();
    }

    @Override
    public void stop(ServiceStopContext stopContext)
    {
        if (resolvePendingPartitionsCommand != null)
        {
            resolvePendingPartitionsCommand.close();
        }
        partitionResponderRef.set(null);
    }

    @Override
    public SystemPartitionManager get()
    {
        return this;
    }

    public ActorFuture sendPartitions(int requestStream, long request)
    {
        final PartitionResponder responder = partitionResponderRef.get();

        if (responder != null)
        {
            return responder.sendPartitions(requestStream, request);
        }
        else
        {
            return CompletableActorFuture.completedExceptionally(new IllegalStateException("No partition responder available."));
        }
    }


    public ServiceGroupReference getLogStreamsGroupReference()
    {
        return logStreamsGroupReference;
    }

    public Injector getClientApiTransportInjector()
    {
        return clientApiTransportInjector;
    }

    public Injector getPartitionManagerInjector()
    {
        return partitionManagerInjector;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy