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

org.neo4j.fabric.bootstrap.FabricServicesBootstrap Maven / Gradle / Ivy

There is a newer version: 5.25.1
Show newest version
/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [http://neo4j.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.fabric.bootstrap;

import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.function.Supplier;

import org.neo4j.bolt.dbapi.BoltGraphDatabaseManagementServiceSPI;
import org.neo4j.bolt.dbapi.BoltGraphDatabaseServiceSPI;
import org.neo4j.bolt.dbapi.CustomBookmarkFormatParser;
import org.neo4j.bolt.txtracking.TransactionIdTracker;
import org.neo4j.collection.Dependencies;
import org.neo4j.configuration.Config;
import org.neo4j.configuration.GraphDatabaseSettings;
import org.neo4j.cypher.internal.cache.ExecutorBasedCaffeineCacheFactory;
import org.neo4j.cypher.internal.config.CypherConfiguration;
import org.neo4j.dbms.api.DatabaseManagementService;
import org.neo4j.dbms.api.DatabaseNotFoundException;
import org.neo4j.dbms.database.DatabaseContext;
import org.neo4j.dbms.database.DatabaseManager;
import org.neo4j.fabric.FabricDatabaseManager;
import org.neo4j.fabric.bolt.BoltFabricDatabaseManagementService;
import org.neo4j.fabric.bookmark.LocalGraphTransactionIdTracker;
import org.neo4j.fabric.bookmark.TransactionBookmarkManagerFactory;
import org.neo4j.fabric.config.FabricConfig;
import org.neo4j.fabric.eval.CatalogManager;
import org.neo4j.fabric.eval.CommunityCatalogManager;
import org.neo4j.fabric.eval.DatabaseLookup;
import org.neo4j.fabric.eval.UseEvaluation;
import org.neo4j.fabric.executor.FabricDatabaseAccess;
import org.neo4j.fabric.executor.FabricExecutor;
import org.neo4j.fabric.executor.FabricLocalExecutor;
import org.neo4j.fabric.executor.FabricRemoteExecutor;
import org.neo4j.fabric.executor.FabricStatementLifecycles;
import org.neo4j.fabric.executor.ThrowingFabricRemoteExecutor;
import org.neo4j.fabric.pipeline.SignatureResolver;
import org.neo4j.fabric.planning.FabricPlanner;
import org.neo4j.fabric.transaction.ErrorReporter;
import org.neo4j.fabric.transaction.FabricTransactionMonitor;
import org.neo4j.fabric.transaction.TransactionManager;
import org.neo4j.internal.kernel.api.security.AbstractSecurityLog;
import org.neo4j.internal.kernel.api.security.CommunitySecurityLog;
import org.neo4j.kernel.api.procedure.GlobalProcedures;
import org.neo4j.kernel.availability.AvailabilityGuard;
import org.neo4j.kernel.availability.UnavailableException;
import org.neo4j.kernel.database.DatabaseReferenceRepository;
import org.neo4j.kernel.impl.api.transaction.monitor.TransactionMonitorScheduler;
import org.neo4j.kernel.internal.event.GlobalTransactionEventListeners;
import org.neo4j.kernel.lifecycle.LifeSupport;
import org.neo4j.kernel.lifecycle.LifecycleAdapter;
import org.neo4j.logging.LogProvider;
import org.neo4j.logging.internal.LogService;
import org.neo4j.memory.MemoryTracker;
import org.neo4j.monitoring.Monitors;
import org.neo4j.scheduler.JobScheduler;
import org.neo4j.time.SystemNanoClock;

import static org.neo4j.scheduler.Group.CYPHER_CACHE;
import static org.neo4j.scheduler.Group.FABRIC_WORKER;
import static org.neo4j.scheduler.JobMonitoringParams.systemJob;

public abstract class FabricServicesBootstrap
{

    private final FabricConfig fabricConfig;
    private final Dependencies dependencies;
    private final LogService logService;
    private final ServiceBootstrapper serviceBootstrapper;
    private final Config config;
    private final AvailabilityGuard availabilityGuard;
    protected final AbstractSecurityLog securityLog;
    protected final DatabaseManager databaseManager;
    protected final DatabaseReferenceRepository databaseReferenceRepo;

    public FabricServicesBootstrap( LifeSupport lifeSupport, Dependencies dependencies, LogService logService, AbstractSecurityLog securityLog,
            DatabaseManager databaseManager, DatabaseReferenceRepository databaseReferenceRepo )
    {
        this.dependencies = dependencies;
        this.logService = logService;
        this.securityLog = securityLog;
        this.databaseManager = databaseManager;
        this.databaseReferenceRepo = databaseReferenceRepo;

        serviceBootstrapper = new ServiceBootstrapper( lifeSupport, dependencies );

        config = dependencies.resolveDependency( Config.class );
        availabilityGuard = dependencies.resolveDependency( AvailabilityGuard.class );

        fabricConfig = bootstrapFabricConfig();
    }

    protected  T register( T dependency, Class dependencyType )
    {
        return serviceBootstrapper.registerService( dependency, dependencyType );
    }

    protected  T resolve( Class type )
    {
        return dependencies.resolveDependency( type );
    }

    public void bootstrapServices()
    {
        LogProvider internalLogProvider = logService.getInternalLogProvider();

        var fabricDatabaseManager = register( createFabricDatabaseManager( fabricConfig ), FabricDatabaseManager.class );

        var jobScheduler = resolve( JobScheduler.class );
        var monitors = resolve( Monitors.class );

        var databaseAccess = createFabricDatabaseAccess();
        var remoteExecutor = bootstrapRemoteStack();
        var localExecutor = register( new FabricLocalExecutor( fabricConfig, fabricDatabaseManager, databaseAccess ), FabricLocalExecutor.class );

        var systemNanoClock = resolve( SystemNanoClock.class );
        var transactionMonitor = register( new FabricTransactionMonitor( systemNanoClock, logService, fabricConfig ), FabricTransactionMonitor.class );

        var transactionCheckInterval = config.get( GraphDatabaseSettings.transaction_monitor_check_interval ).toMillis();
        register( new TransactionMonitorScheduler( transactionMonitor, jobScheduler, transactionCheckInterval, null ), TransactionMonitorScheduler.class );

        var errorReporter = new ErrorReporter( logService );
        var catalogManager = register( createCatalogManager( databaseReferenceRepo ), CatalogManager.class );
        register( new TransactionManager( remoteExecutor, localExecutor, catalogManager, fabricConfig, transactionMonitor, securityLog, systemNanoClock, config,
                availabilityGuard, errorReporter ), TransactionManager.class );

        var cypherConfig = CypherConfiguration.fromConfig( config );

        Supplier proceduresSupplier = () -> resolve( GlobalProcedures.class );
        var signatureResolver = new SignatureResolver( proceduresSupplier );
        var statementLifecycles = new FabricStatementLifecycles( databaseManager, monitors, config, systemNanoClock );
        var monitoredExecutor = jobScheduler.monitoredJobExecutor( CYPHER_CACHE );
        var cacheFactory = new ExecutorBasedCaffeineCacheFactory( job -> monitoredExecutor.execute( systemJob( "Query plan cache maintenance" ), job ) );
        var planner = register( new FabricPlanner( fabricConfig, cypherConfig, monitors, cacheFactory, signatureResolver ), FabricPlanner.class );
        var useEvaluation = register( new UseEvaluation( proceduresSupplier, signatureResolver ), UseEvaluation.class );

        register( new FabricReactorHooksService( errorReporter ), FabricReactorHooksService.class );

        Executor fabricWorkerExecutor = jobScheduler.executor( FABRIC_WORKER );
        var fabricExecutor = new FabricExecutor(
                fabricConfig, planner, useEvaluation, catalogManager, internalLogProvider, statementLifecycles, fabricWorkerExecutor );
        register( fabricExecutor, FabricExecutor.class );

        register( new TransactionBookmarkManagerFactory( fabricDatabaseManager ), TransactionBookmarkManagerFactory.class );
    }

    protected DatabaseLookup createDatabaseLookup( DatabaseReferenceRepository databaseReferenceRepository )
    {
        return new DatabaseLookup.Default( databaseReferenceRepository );
    }

    public BoltGraphDatabaseManagementServiceSPI createBoltDatabaseManagementServiceProvider(
            BoltGraphDatabaseManagementServiceSPI kernelDatabaseManagementService, DatabaseManagementService managementService, Monitors monitors,
            SystemNanoClock clock )
    {
        FabricExecutor fabricExecutor = dependencies.resolveDependency( FabricExecutor.class );
        TransactionManager transactionManager = dependencies.resolveDependency( TransactionManager.class );
        FabricDatabaseManager fabricDatabaseManager = dependencies.resolveDependency( FabricDatabaseManager.class );

        var serverConfig = dependencies.resolveDependency( Config.class );

        var transactionIdTracker = new TransactionIdTracker( managementService, monitors, clock );

        var databaseIdRepository = databaseManager.databaseIdRepository();
        var transactionBookmarkManagerFactory = dependencies.resolveDependency( TransactionBookmarkManagerFactory.class );

        var localGraphTransactionIdTracker = new LocalGraphTransactionIdTracker( transactionIdTracker, databaseIdRepository, serverConfig );
        var fabricDatabaseManagementService = dependencies.satisfyDependency(
                new BoltFabricDatabaseManagementService( fabricExecutor, fabricConfig, transactionManager, fabricDatabaseManager,
                                                         localGraphTransactionIdTracker, transactionBookmarkManagerFactory ) );

        return new BoltGraphDatabaseManagementServiceSPI()
        {

            @Override
            public BoltGraphDatabaseServiceSPI database( String databaseName, MemoryTracker memoryTracker )
                    throws UnavailableException, DatabaseNotFoundException
            {
                if ( fabricDatabaseManager.hasMultiGraphCapabilities( databaseName ) )
                {
                    return fabricDatabaseManagementService.database( databaseName, memoryTracker );
                }

                return kernelDatabaseManagementService.database( databaseName, memoryTracker );
            }

            @Override
            public Optional getCustomBookmarkFormatParser()
            {
                return fabricDatabaseManagementService.getCustomBookmarkFormatParser();
            }
        };
    }

    protected abstract FabricDatabaseManager createFabricDatabaseManager( FabricConfig fabricConfig );

    protected abstract CatalogManager createCatalogManager( DatabaseReferenceRepository databaseReferenceRepo );

    protected abstract FabricDatabaseAccess createFabricDatabaseAccess();

    protected abstract FabricRemoteExecutor bootstrapRemoteStack();

    protected abstract FabricConfig bootstrapFabricConfig();

    public static class Community extends FabricServicesBootstrap
    {
        public Community( LifeSupport lifeSupport, Dependencies dependencies, LogService logService,
                DatabaseManager databaseManager, DatabaseReferenceRepository databaseReferenceRepo )
        {
            super( lifeSupport, dependencies, logService, CommunitySecurityLog.NULL_LOG, databaseManager, databaseReferenceRepo );
        }

        @Override
        protected FabricDatabaseManager createFabricDatabaseManager( FabricConfig fabricConfig )
        {
            return new FabricDatabaseManager.Community( fabricConfig, databaseManager, databaseReferenceRepo );
        }

        @Override
        protected CatalogManager createCatalogManager( DatabaseReferenceRepository databaseReferenceRepo )
        {
            var txEventListeners = resolve( GlobalTransactionEventListeners.class );
            return new CommunityCatalogManager( createDatabaseLookup( databaseReferenceRepo ), txEventListeners );
        }

        @Override
        protected FabricDatabaseAccess createFabricDatabaseAccess()
        {
            return FabricDatabaseAccess.NO_RESTRICTION;
        }

        @Override
        protected FabricRemoteExecutor bootstrapRemoteStack()
        {
            return new ThrowingFabricRemoteExecutor();
        }

        @Override
        protected FabricConfig bootstrapFabricConfig()
        {
            var config = resolve( Config.class );
            return FabricConfig.from( config );
        }
    }

    private static class ServiceBootstrapper
    {
        private final LifeSupport lifeSupport;
        private final Dependencies dependencies;

        ServiceBootstrapper( LifeSupport lifeSupport, Dependencies dependencies )
        {
            this.lifeSupport = lifeSupport;
            this.dependencies = dependencies;
        }

         T registerService( T dependency, Class dependencyType )
        {
            dependencies.satisfyDependency( dependency );

            if ( LifecycleAdapter.class.isAssignableFrom( dependencyType ) )
            {
                lifeSupport.add( (LifecycleAdapter) dependency );
            }

            return dependencies.resolveDependency( dependencyType );
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy