// We do this last to ensure noone is cheating with dependency access private void satisfyDependencies(Object... modules) { for (Object module : modules) { for (Method method : module.getClass().getMethods()) { if (!method.getDeclaringClass().equals(Object.class)) { try { dependencies.satisfyDependency(method.invoke(module)); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } } } } }
private TransactionLogModule buildTransactionLogs( Config config, Logging logging, LabelScanStore labelScanStore, FileSystemAbstraction fileSystemAbstraction, NeoStore neoStore, CacheAccessBackDoor cacheAccess, IndexingService indexingService, Iterable<IndexImplementation> indexProviders) { File directory = config.get(GraphDatabaseSettings.store_dir); TransactionMetadataCache transactionMetadataCache = new TransactionMetadataCache(1000, 100_000); final PhysicalLogFiles logFiles = new PhysicalLogFiles(directory, PhysicalLogFile.DEFAULT_NAME, fileSystemAbstraction); IdOrderingQueue legacyIndexTransactionOrdering = new SynchronizedArrayIdOrderingQueue(20); final TransactionRepresentationStoreApplier storeApplier = dependencies.satisfyDependency( new TransactionRepresentationStoreApplier( indexingService, labelScanStore, neoStore, cacheAccess, lockService, legacyIndexProviderLookup, indexConfigStore, legacyIndexTransactionOrdering)); final PhysicalLogFile logFile = new PhysicalLogFile( fileSystemAbstraction, logFiles, config.get(GraphDatabaseSettings.logical_log_rotation_threshold), neoStore, neoStore, physicalLogMonitor, transactionMetadataCache); final PhysicalLogFileInformation.SPI logInformation = new PhysicalLogFileInformation.SPI() { @Override public long getTimestampForVersion(long version) throws IOException { LogPosition position = new LogPosition(version, LOG_HEADER_SIZE); try (ReadableVersionableLogChannel channel = logFile.getReader(position)) { final LogEntryReader<ReadableVersionableLogChannel> reader = new LogEntryReaderFactory().versionable(); LogEntry entry; while ((entry = reader.readLogEntry(channel)) != null) { if (entry instanceof LogEntryStart) { return entry.<LogEntryStart>as().getTimeWritten(); } } } return -1; } }; final LogFileInformation logFileInformation = new PhysicalLogFileInformation( logFiles, transactionMetadataCache, neoStore, logInformation); LogPruneStrategy logPruneStrategy = LogPruneStrategyFactory.fromConfigValue( fs, logFileInformation, logFiles, neoStore, config.get(GraphDatabaseSettings.keep_logical_logs)); monitors.addMonitorListener(new LogPruning(logPruneStrategy)); final LogRotationControl logRotationControl = new LogRotationControl(neoStore, indexingService, labelScanStore, indexProviders); final LogRotation logRotation = new LogRotationImpl( monitors.newMonitor(LogRotation.Monitor.class), logFile, logRotationControl); final LogicalTransactionStore logicalTransactionStore = new PhysicalLogicalTransactionStore( logFile, logRotation, transactionMetadataCache, neoStore, legacyIndexTransactionOrdering, config.get(GraphDatabaseSettings.batched_writes)); life.add(logFile); life.add(logicalTransactionStore); return new TransactionLogModule() { @Override public TransactionRepresentationStoreApplier storeApplier() { return storeApplier; } @Override public LogicalTransactionStore logicalTransactionStore() { return logicalTransactionStore; } @Override public LogFileInformation logFileInformation() { return logFileInformation; } @Override public PhysicalLogFiles logFiles() { return logFiles; } @Override public LogFile logFile() { return logFile; } @Override public LogRotationControl logRotationControl() { return logRotationControl; } @Override public LogRotation logRotation() { return logRotation; } }; }
@Override public void start() throws IOException { dependencies = new Dependencies(); life = new LifeSupport(); storeDir = config.get(Configuration.store_dir); File store = config.get(Configuration.neo_store); if (!storeFactory.storeExists()) { storeFactory.createNeoStore().close(); } indexProvider = dependencyResolver.resolveDependency( SchemaIndexProvider.class, SchemaIndexProvider.HIGHEST_PRIORITIZED_OR_NONE); // Monitor listeners LoggingLogFileMonitor loggingLogMonitor = new LoggingLogFileMonitor(logging.getMessagesLog(getClass())); monitors.addMonitorListener(loggingLogMonitor); monitors.addMonitorListener( new RecoveryVisitor.Monitor() { @Override public void transactionRecovered(long txId) { recoveredCount.incrementAndGet(); } }); // Upgrade the store before we begin upgradeStore(store, storeMigrationProcess, indexProvider); // Build all modules and their services try { final NeoStoreModule neoStoreModule = buildNeoStore(storeFactory, labelTokens, relationshipTypeTokens, propertyKeyTokenHolder); this.neoStoreModule = neoStoreModule; // TODO The only reason this is here is because of the provider-stuff for // DiskLayer. Remove when possible CacheModule cacheModule = buildCaches( neoStoreModule.neoStore(), cacheProvider, nodeManager, labelTokens, relationshipTypeTokens, propertyKeyTokenHolder); IndexingModule indexingModule = buildIndexing( config, scheduler, indexProvider, lockService, tokenNameLookup, logging, indexingServiceMonitor, neoStoreModule.neoStore(), cacheModule.updateableSchemaState()); StoreLayerModule storeLayerModule = buildStoreLayer( config, neoStoreModule.neoStore(), cacheModule.persistenceCache(), propertyKeyTokenHolder, labelTokens, relationshipTypeTokens, indexingModule.indexingService(), cacheModule.schemaCache()); TransactionLogModule transactionLogModule = buildTransactionLogs( config, logging, indexingModule.labelScanStore(), fs, neoStoreModule.neoStore(), cacheModule.cacheAccess(), indexingModule.indexingService(), indexProviders.values()); buildRecovery( fs, cacheModule.cacheAccess(), indexingModule.indexingService(), indexingModule.labelScanStore(), neoStoreModule.neoStore(), monitors.newMonitor(RecoveryVisitor.Monitor.class), monitors.newMonitor(Recovery.Monitor.class), transactionLogModule.logFiles(), transactionLogModule.logRotationControl(), startupStatistics); KernelModule kernelModule = buildKernel( indexingModule.integrityValidator(), transactionLogModule.logicalTransactionStore(), neoStoreModule.neoStore(), transactionLogModule.storeApplier(), indexingModule.indexingService(), storeLayerModule.storeLayer(), cacheModule.updateableSchemaState(), indexingModule.labelScanStore(), cacheModule.persistenceCache(), indexingModule.schemaIndexProviderMap()); // Do these assignments last so that we can ensure no cyclical dependencies exist this.cacheModule = cacheModule; this.indexingModule = indexingModule; this.storeLayerModule = storeLayerModule; this.transactionLogModule = transactionLogModule; this.kernelModule = kernelModule; dependencies.satisfyDependency(this); satisfyDependencies( neoStoreModule, cacheModule, indexingModule, storeLayerModule, transactionLogModule, kernelModule); } catch (Throwable e) { // Something unexpected happened during startup try { // Close the neostore, so that locks are released properly neoStoreModule.neoStore().close(); } catch (Exception closeException) { msgLog.logMessage("Couldn't close neostore after startup failure"); } throw Exceptions.launderedException(e); } try { life.start(); } catch (Throwable e) { // Something unexpected happened during startup try { // Close the neostore, so that locks are released properly neoStoreModule.neoStore().close(); } catch (Exception closeException) { msgLog.logMessage("Couldn't close neostore after startup failure"); } throw Exceptions.launderedException(e); } }
@Override public void start() throws IOException { life = new LifeSupport(); readOnly = config.get(Configuration.read_only); storeDir = config.get(Configuration.store_dir); File store = config.get(Configuration.neo_store); if (!storeFactory.storeExists()) { storeFactory.createNeoStore().close(); } indexProvider = dependencyResolver.resolveDependency( SchemaIndexProvider.class, SchemaIndexProvider.HIGHEST_PRIORITIZED_OR_NONE); storeMigrationProcess.addParticipant(indexProvider.storeMigrationParticipant()); // TODO: Build a real provider map final DefaultSchemaIndexProviderMap providerMap = new DefaultSchemaIndexProviderMap(indexProvider); storeMigrationProcess.migrateIfNeeded(store.getParentFile()); neoStore = dependencies.satisfyDependency(storeFactory.newNeoStore(false)); dependencies.satisfyDependency(TransactionIdStore.class, neoStore); schemaCache = new SchemaCache(Collections.<SchemaRule>emptyList()); nodeCache = new AutoLoadingCache<>(cacheProvider.node(), nodeLoader(neoStore.getNodeStore())); relationshipCache = new AutoLoadingCache<>( cacheProvider.relationship(), relationshipLoader(neoStore.getRelationshipStore())); RelationshipLoader relationshipLoader = new RelationshipLoader(relationshipCache, new RelationshipChainLoader(neoStore)); PersistenceCache persistenceCache = new PersistenceCache( nodeCache, relationshipCache, nodeManager, relationshipLoader, propertyKeyTokenHolder, relationshipTypeTokens, labelTokens); CacheAccessBackDoor cacheAccess = new BridgingCacheAccess(schemaCache, updateableSchemaState, persistenceCache); try { indexingService = new IndexingService( scheduler, providerMap, new NeoStoreIndexStoreView(lockService, neoStore), tokenNameLookup, updateableSchemaState, indexRuleLoader(), logging, indexingServiceMonitor); // TODO 2.2-future What index rules should be final IntegrityValidator integrityValidator = new IntegrityValidator(neoStore, indexingService); labelScanStore = dependencyResolver .resolveDependency( LabelScanStoreProvider.class, LabelScanStoreProvider.HIGHEST_PRIORITIZED) .getLabelScanStore(); fileListing = new NeoStoreFileListing( storeDir, labelScanStore, indexingService, legacyIndexProviderLookup); Provider<NeoStore> neoStoreProvider = new Provider<NeoStore>() { @Override public NeoStore instance() { return getNeoStore(); } }; if (config.get(GraphDatabaseSettings.cache_type).equals(CacheLayer.EXPERIMENTAL_OFF)) { storeLayer = new DiskLayer( propertyKeyTokenHolder, labelTokens, relationshipTypeTokens, new SchemaStorage(neoStore.getSchemaStore()), neoStoreProvider, indexingService); } else { storeLayer = new CacheLayer( new DiskLayer( propertyKeyTokenHolder, labelTokens, relationshipTypeTokens, new SchemaStorage(neoStore.getSchemaStore()), neoStoreProvider, indexingService), persistenceCache, indexingService, schemaCache); } LegacyPropertyTrackers legacyPropertyTrackers = new LegacyPropertyTrackers( propertyKeyTokenHolder, nodeManager.getNodePropertyTrackers(), nodeManager.getRelationshipPropertyTrackers(), nodeManager); StatisticsService statisticsService = new StatisticsServiceRepository(fs, config, storeLayer, scheduler).loadStatistics(); final NeoStoreTransactionContextSupplier neoStoreTransactionContextSupplier = new NeoStoreTransactionContextSupplier(neoStore); final TransactionHooks hooks = new TransactionHooks(); File directory = config.get(GraphDatabaseSettings.store_dir); TransactionMetadataCache transactionMetadataCache = new TransactionMetadataCache(1000, 100_000); PhysicalLogFiles logFiles = new PhysicalLogFiles(directory, PhysicalLogFile.DEFAULT_NAME, fs); LogFileInformation logFileInformation = dependencies.satisfyDependency( LogFileInformation.class, new PhysicalLogFileInformation( logFiles, transactionMetadataCache, neoStore, new PhysicalLogFileInformation.SPI() { @Override public long getTimestampForVersion(long version) throws IOException { LogPosition position = new LogPosition(version, LOG_HEADER_SIZE); try (ReadableLogChannel channel = logFile.getReader(position)) { LogEntryReader<ReadableLogChannel> reader = new VersionAwareLogEntryReader(); LogEntry entry; while ((entry = reader.readLogEntry(channel)) != null) { if (entry instanceof LogEntryStart) { return ((LogEntryStart) entry).getTimeWritten(); } } } return -1; } })); LogPruneStrategy logPruneStrategy = LogPruneStrategyFactory.fromConfigValue( fs, logFileInformation, logFiles, neoStore, config.get(GraphDatabaseSettings.keep_logical_logs)); final TransactionRepresentationStoreApplier storeApplier = dependencies.satisfyDependency( new TransactionRepresentationStoreApplier( indexingService, labelScanStore, neoStore, cacheAccess, lockService, legacyIndexProviderLookup, indexConfigStore, DEFAULT_HIGH_ID_TRACKING)); LoggingLogFileMonitor logMonitor = new LoggingLogFileMonitor(logging.getMessagesLog(getClass())); RecoveryVisitor recoveryVisitor = new RecoveryVisitor(neoStore, storeApplier, recoveredCount, logMonitor); Visitor<ReadableLogChannel, IOException> logFileRecoverer = new LogFileRecoverer(new VersionAwareLogEntryReader(), recoveryVisitor); logFile = dependencies.satisfyDependency( new PhysicalLogFile( fs, logFiles, config.get(GraphDatabaseSettings.logical_log_rotation_threshold), logPruneStrategy, neoStore, neoStore, logMonitor, this, transactionMetadataCache, logFileRecoverer)); final LogicalTransactionStore logicalTransactionStore = dependencies.satisfyDependency( LogicalTransactionStore.class, new PhysicalLogicalTransactionStore( logFile, txIdGenerator, transactionMetadataCache, neoStore, config.get(GraphDatabaseSettings.batched_writes))); TransactionCommitProcess transactionCommitProcess = dependencies.satisfyDependency( TransactionCommitProcess.class, commitProcessFactory.create( logicalTransactionStore, kernelHealth, neoStore, storeApplier, new NeoStoreInjectedTransactionValidator(integrityValidator), false)); /* * This is used by legacy indexes and constraint indexes whenever a transaction is to be spawned * from within an existing transaction. It smells, and we should look over alternatives when time permits. */ Provider<KernelAPI> kernelProvider = new Provider<KernelAPI>() { @Override public KernelAPI instance() { return kernel; } }; ConstraintIndexCreator constraintIndexCreator = new ConstraintIndexCreator(kernelProvider, indexingService); LegacyIndexStore legacyIndexStore = new LegacyIndexStore(config, indexConfigStore, kernelProvider, legacyIndexProviderLookup); StatementOperationParts statementOperations = buildStatementOperations( storeLayer, legacyPropertyTrackers, constraintIndexCreator, updateableSchemaState, guard, legacyIndexStore); kernelTransactions = life.add( new KernelTransactions( neoStoreTransactionContextSupplier, neoStore, locks, integrityValidator, constraintIndexCreator, indexingService, labelScanStore, statementOperations, updateableSchemaState, schemaWriteGuard, providerMap, transactionHeaderInformationFactory, persistenceCache, storeLayer, transactionCommitProcess, indexConfigStore, legacyIndexProviderLookup, hooks, transactionMonitor, life, readOnly)); kernel = new Kernel( statisticsService, kernelTransactions, hooks, kernelHealth, transactionMonitor); life.add(logFile); life.add(logicalTransactionStore); life.add( new LifecycleAdapter() { @Override public void start() throws Throwable { startupStatistics.setNumberOfRecoveredTransactions(recoveredCount.get()); recoveredCount.set(0); loadSchemaCache(); } }); life.add(statisticsService); life.add( new LifecycleAdapter() { @Override public void start() { neoStore.makeStoreOk(); } }); life.add(indexingService); life.add(labelScanStore); kernel.registerTransactionHook(transactionEventHandlers); neoStore.setRecoveredStatus(true); try { life.start(); } finally { neoStore.setRecoveredStatus(false); } propertyKeyTokenHolder.addTokens( neoStore.getPropertyKeyTokenStore().getTokens(Integer.MAX_VALUE)); relationshipTypeTokens.addTokens( neoStore.getRelationshipTypeTokenStore().getTokens(Integer.MAX_VALUE)); labelTokens.addTokens(neoStore.getLabelTokenStore().getTokens(Integer.MAX_VALUE)); } catch (Throwable e) { // Something unexpected happened during startup try { // Close the neostore, so that locks are released properly neoStore.close(); } catch (Exception closeException) { msgLog.logMessage("Couldn't close neostore after startup failure"); } throw Exceptions.launderedException(e); } }