class NeoStoreDataSource extends LifecycleAdapter {

    @Override
    public void start() throws IOException
    {
        dataSourceDependencies = new Dependencies( dependencyResolver );
        dataSourceDependencies.satisfyDependency( this );
        dataSourceDependencies.satisfyDependency( monitors );
        dataSourceDependencies.satisfyDependency( tokenHolders );
        dataSourceDependencies.satisfyDependency( facade );
        dataSourceDependencies.satisfyDependency( indexConfigStore );
        dataSourceDependencies.satisfyDependency( explicitIndexProvider );
        dataSourceDependencies.satisfyDependency( databaseHealth );
        dataSourceDependencies.satisfyDependency( storeCopyCheckPointMutex );
        dataSourceDependencies.satisfyDependency( transactionMonitor );
        dataSourceDependencies.satisfyDependency( locks );
        dataSourceDependencies.satisfyDependency( databaseAvailabilityGuard );
        dataSourceDependencies.satisfyDependency( databaseAvailability );
        dataSourceDependencies.satisfyDependency( idGeneratorFactory );
        dataSourceDependencies.satisfyDependency( idController );
        dataSourceDependencies.satisfyDependency( new IdBasedStoreEntityCounters( this.idGeneratorFactory ) );
        dataSourceDependencies.satisfyDependency( auxTxStateManager );

        life = new LifeSupport();
        dataSourceDependencies.satisfyDependency( explicitIndexProvider );
        life.add( initializeExtensions( dataSourceDependencies ) );
        life.add( recoveryCleanupWorkCollector );
        dataSourceDependencies.satisfyDependency( lockService );
        life.add( indexConfigStore );

        FileSystemWatcherService watcherService = watcherServiceFactory.apply( databaseLayout.databaseDirectory() );
        life.add( watcherService );
        dataSourceDependencies.satisfyDependency( watcherService );

        life.add( Lifecycles.multiple( explicitIndexProvider.allIndexProviders() ) );

        // Check the tail of transaction logs and validate version
        final LogEntryReader<ReadableClosablePositionAwareChannel> logEntryReader = new VersionAwareLogEntryReader<>();

        LogFiles logFiles = LogFilesBuilder.builder( databaseLayout, fs )
                .withLogEntryReader( logEntryReader )
                .withLogFileMonitor( physicalLogMonitor )
                .withConfig( config )
                .withDependencies( dataSourceDependencies ).build();

        LoggingLogFileMonitor logFileMonitor = new LoggingLogFileMonitor( msgLog );
        LoggingLogTailScannerMonitor tailMonitor = new LoggingLogTailScannerMonitor( logService.getInternalLog( LogTailScanner.class ) );
        ReverseTransactionCursorLoggingMonitor reverseCursorMonitor =
                new ReverseTransactionCursorLoggingMonitor( logService.getInternalLog( ReversedSingleFileTransactionCursor.class ) );
        monitors.addMonitorListener( logFileMonitor );
        monitors.addMonitorListener( tailMonitor );
        monitors.addMonitorListener( reverseCursorMonitor );
        life.add( LifecycleAdapter.onShutdown( () ->
        {
            // We might be started and stopped multiple times, so make sure we clean up after ourselves when we're stopped.
            monitors.removeMonitorListener( logFileMonitor );
            monitors.removeMonitorListener( tailMonitor );
            monitors.removeMonitorListener( reverseCursorMonitor );
        } ) );

        LogTailScanner tailScanner = new LogTailScanner( logFiles, logEntryReader, monitors, failOnCorruptedLogFiles );
        LogVersionUpgradeChecker.check( tailScanner, config );

        // Upgrade the store before we begin
        RecordFormats formats = selectStoreFormats( config, databaseLayout, fs, pageCache, logService );
        upgradeStore( formats, tailScanner );

        // Build all modules and their services
        StorageEngine storageEngine = null;
        try
        {
            DatabaseSchemaState databaseSchemaState = new DatabaseSchemaState( logProvider );

            SynchronizedArrayIdOrderingQueue explicitIndexTransactionOrdering = new SynchronizedArrayIdOrderingQueue();

            Supplier<KernelTransactionsSnapshot> transactionsSnapshotSupplier = () -> kernelModule.kernelTransactions().get();
            idController.initialize( transactionsSnapshotSupplier );

            storageEngine = buildStorageEngine( explicitIndexProvider,
                    indexConfigStore, databaseSchemaState, explicitIndexTransactionOrdering, databaseInfo.operationalMode,
                    versionContextSupplier );
            life.add( logFiles );

            TransactionIdStore transactionIdStore = dataSourceDependencies.resolveDependency( TransactionIdStore.class );

            versionContextSupplier.init( transactionIdStore::getLastClosedTransactionId );

            LogVersionRepository logVersionRepository = dataSourceDependencies.resolveDependency( LogVersionRepository.class );
            NeoStoreTransactionLogModule transactionLogModule = buildTransactionLogs( logFiles, config, logProvider,
                    scheduler, storageEngine, logEntryReader, explicitIndexTransactionOrdering, transactionIdStore );
            transactionLogModule.satisfyDependencies( dataSourceDependencies );

            buildRecovery( fs,
                    transactionIdStore,
                    tailScanner,
                    monitors.newMonitor( RecoveryMonitor.class ),
                    monitors.newMonitor( RecoveryStartInformationProvider.Monitor.class ),
                    logFiles,
                    storageEngine, transactionLogModule.logicalTransactionStore(), logVersionRepository
            );

            // At the time of writing this comes from the storage engine (IndexStoreView)
            NodePropertyAccessor nodePropertyAccessor = dataSourceDependencies.resolveDependency( NodePropertyAccessor.class );

            final NeoStoreKernelModule kernelModule = buildKernel(
                    logFiles,
                    transactionLogModule.transactionAppender(),
                    dataSourceDependencies.resolveDependency( IndexingService.class ),
                    databaseSchemaState,
                    dataSourceDependencies.resolveDependency( LabelScanStore.class ),
                    storageEngine,
                    indexConfigStore,
                    transactionIdStore, databaseAvailabilityGuard,
                    clock, nodePropertyAccessor );

            kernelModule.satisfyDependencies( dataSourceDependencies );

            // Do these assignments last so that we can ensure no cyclical dependencies exist
            this.storageEngine = storageEngine;
            this.transactionLogModule = transactionLogModule;
            this.kernelModule = kernelModule;

            dataSourceDependencies.satisfyDependency( this );
            dataSourceDependencies.satisfyDependency( databaseSchemaState );
            dataSourceDependencies.satisfyDependency( logEntryReader );
            dataSourceDependencies.satisfyDependency( storageEngine );

            executionEngine = QueryEngineProvider.initialize( dataSourceDependencies, facade, engineProviders );
        }
        catch ( Throwable e )
        {
            // Something unexpected happened during startup
            msgLog.warn( "Exception occurred while setting up store modules. Attempting to close things down.", e );
            try
            {
                // Close the neostore, so that locks are released properly
                if ( storageEngine != null )
                {
                    storageEngine.forceClose();
                }
            }
            catch ( Exception closeException )
            {
                msgLog.error( "Couldn't close neostore after startup failure", closeException );
            }
            throwIfUnchecked( e );
            throw new RuntimeException( e );
        }

        life.add( new DatabaseDiagnostics( dataSourceDependencies.resolveDependency( DiagnosticsManager.class ), this, databaseInfo ) );
        life.add( databaseAvailability );
        life.setLast( lifecycleToTriggerCheckPointOnShutdown() );

        try
        {
            life.start();
        }
        catch ( Throwable e )
        {
            // Something unexpected happened during startup
            msgLog.warn( "Exception occurred while starting the datasource. Attempting to close things down.", e );
            try
            {
                life.shutdown();
                // Close the neostore, so that locks are released properly
                storageEngine.forceClose();
            }
            catch ( Exception closeException )
            {
                msgLog.error( "Couldn't close neostore after startup failure", closeException );
            }
            throw new RuntimeException( e );
        }
        /*
         * At this point recovery has completed and the datasource is ready for use. Whatever panic might have
         * happened before has been healed. So we can safely set the kernel health to ok.
         * This right now has any real effect only in the case of internal restarts (for example, after a store copy
         * in the case of HA). Standalone instances will have to be restarted by the user, as is proper for all
         * kernel panics.
         */
        databaseHealth.healed();
    }

    public  NeoStoreDataSource( DatabaseCreationContext context );

}