From bf1e826d406e6434d6e1764a2c7dd5bffc2d2fae Mon Sep 17 00:00:00 2001 From: Andrei Koval Date: Wed, 9 Jan 2019 12:59:50 +0100 Subject: [PATCH] Throttle StoreFileBean calls to prevent excessive resources consumption --- .../org/neo4j/jmx/impl/StoreFileBean.java | 184 +++++++++++++----- .../org/neo4j/jmx/impl/StoreSizeBean.java | 20 +- 2 files changed, 144 insertions(+), 60 deletions(-) diff --git a/community/jmx/src/main/java/org/neo4j/jmx/impl/StoreFileBean.java b/community/jmx/src/main/java/org/neo4j/jmx/impl/StoreFileBean.java index ee700e803ecf0..d7a85549de028 100644 --- a/community/jmx/src/main/java/org/neo4j/jmx/impl/StoreFileBean.java +++ b/community/jmx/src/main/java/org/neo4j/jmx/impl/StoreFileBean.java @@ -20,8 +20,7 @@ package org.neo4j.jmx.impl; import java.io.File; -import java.io.IOException; -import javax.management.NotCompliantMBeanException; +import java.time.Clock; import org.neo4j.helpers.Service; import org.neo4j.io.fs.FileSystemAbstraction; @@ -32,6 +31,8 @@ import org.neo4j.kernel.impl.transaction.log.files.LogFiles; import org.neo4j.kernel.impl.transaction.state.DataSourceManager; +import static org.neo4j.jmx.impl.StoreSizeBean.resolveStorePath; +import static org.neo4j.jmx.impl.ThrottlingBeanSnapshotProxy.newThrottlingBeanSnapshotProxy; import static org.neo4j.kernel.impl.store.StoreFactory.NODE_STORE_NAME; import static org.neo4j.kernel.impl.store.StoreFactory.PROPERTY_ARRAYS_STORE_NAME; import static org.neo4j.kernel.impl.store.StoreFactory.PROPERTY_STORE_NAME; @@ -41,19 +42,137 @@ @Service.Implementation( ManagementBeanProvider.class ) public final class StoreFileBean extends ManagementBeanProvider { - @SuppressWarnings( "WeakerAccess" ) // Bean needs public constructor + private static final long UPDATE_INTERVAL = 60000; + private static final StoreFile NO_STORE_FILE = new StoreFile() + { + @Override + public long getLogicalLogSize() + { + return 0; + } + + @Override + public long getTotalStoreSize() + { + return 0; + } + + @Override + public long getNodeStoreSize() + { + return 0; + } + + @Override + public long getRelationshipStoreSize() + { + return 0; + } + + @Override + public long getPropertyStoreSize() + { + return 0; + } + + @Override + public long getStringStoreSize() + { + return 0; + } + + @Override + public long getArrayStoreSize() + { + return 0; + } + }; + public StoreFileBean() { super( StoreFile.class ); } @Override - protected Neo4jMBean createMBean( ManagementData management ) throws NotCompliantMBeanException + protected Neo4jMBean createMBean( ManagementData management ) { - return new StoreFileImpl( management ); + final StoreFileMBean bean = new StoreFileMBean( management ); + final DataSourceManager dataSourceManager = management.resolveDependency( DataSourceManager.class ); + dataSourceManager.addListener( bean ); + return bean; } - static class StoreFileImpl extends Neo4jMBean implements StoreFile + static class StoreFileMBean extends Neo4jMBean implements StoreFile, DataSourceManager.Listener + { + private final FileSystemAbstraction fs; + private final File storePath; + private volatile StoreFile delegate = NO_STORE_FILE; + + StoreFileMBean( ManagementData management ) + { + super( management, false ); + this.fs = management.getKernelData().getFilesystemAbstraction(); + this.storePath = resolveStorePath( management ); + } + + @Override + public void registered( NeoStoreDataSource ds ) + { + final LogFiles logFiles = ds.getDependencyResolver().resolveDependency( LogFiles.class ); + final StoreFileImpl dataProvider = new StoreFileImpl( fs, storePath, logFiles ); + this.delegate = newThrottlingBeanSnapshotProxy( StoreFile.class, dataProvider, UPDATE_INTERVAL, Clock.systemUTC() ); + } + + @Override + public void unregistered( NeoStoreDataSource ds ) + { + this.delegate = NO_STORE_FILE; + } + + @Override + public long getLogicalLogSize() + { + return delegate.getLogicalLogSize(); + } + + @Override + public long getTotalStoreSize() + { + return delegate.getTotalStoreSize(); + } + + @Override + public long getNodeStoreSize() + { + return delegate.getNodeStoreSize(); + } + + @Override + public long getRelationshipStoreSize() + { + return delegate.getRelationshipStoreSize(); + } + + @Override + public long getPropertyStoreSize() + { + return delegate.getPropertyStoreSize(); + } + + @Override + public long getStringStoreSize() + { + return delegate.getStringStoreSize(); + } + + @Override + public long getArrayStoreSize() + { + return delegate.getArrayStoreSize(); + } + } + + static class StoreFileImpl implements StoreFile { private static final String NODE_STORE = MetaDataStore.DEFAULT_NAME + NODE_STORE_NAME; private static final String RELATIONSHIP_STORE = MetaDataStore.DEFAULT_NAME + RELATIONSHIP_STORE_NAME; @@ -61,50 +180,15 @@ static class StoreFileImpl extends Neo4jMBean implements StoreFile private static final String ARRAY_STORE = MetaDataStore.DEFAULT_NAME + PROPERTY_ARRAYS_STORE_NAME; private static final String STRING_STORE = MetaDataStore.DEFAULT_NAME + PROPERTY_STRINGS_STORE_NAME; - private File storePath; - private LogFiles logFiles; - private FileSystemAbstraction fs; - - StoreFileImpl( ManagementData management ) throws NotCompliantMBeanException - { - super( management ); - - fs = management.getKernelData().getFilesystemAbstraction(); - - DataSourceManager dataSourceManager = management.resolveDependency( DataSourceManager.class ); - dataSourceManager.addListener( new DataSourceManager.Listener() - { - @Override - public void registered( NeoStoreDataSource ds ) - { - logFiles = resolveDependency( ds, LogFiles.class ); - storePath = resolvePath( ds ); - } - - private T resolveDependency( NeoStoreDataSource ds, Class clazz ) - { - return ds.getDependencyResolver().resolveDependency( clazz ); - } - - @Override - public void unregistered( NeoStoreDataSource ds ) - { - logFiles = null; - storePath = null; - } - - private File resolvePath( NeoStoreDataSource ds ) - { - try - { - return ds.getStoreDir().getCanonicalFile().getAbsoluteFile(); - } - catch ( IOException e ) - { - return ds.getStoreDir().getAbsoluteFile(); - } - } - } ); + private final File storePath; + private final LogFiles logFiles; + private final FileSystemAbstraction fs; + + StoreFileImpl( FileSystemAbstraction fs, File storePath, LogFiles logFiles ) + { + this.fs = fs; + this.storePath = storePath; + this.logFiles = logFiles; } @Override diff --git a/community/jmx/src/main/java/org/neo4j/jmx/impl/StoreSizeBean.java b/community/jmx/src/main/java/org/neo4j/jmx/impl/StoreSizeBean.java index c0d2f559d09d1..a765318252a76 100644 --- a/community/jmx/src/main/java/org/neo4j/jmx/impl/StoreSizeBean.java +++ b/community/jmx/src/main/java/org/neo4j/jmx/impl/StoreSizeBean.java @@ -257,18 +257,18 @@ public long getTotalStoreSize() { return delegate.getTotalStoreSize(); } + } - private static File resolveStorePath( ManagementData management ) + static File resolveStorePath( ManagementData management ) + { + File storeDir = management.getKernelData().getStoreDir(); + try { - File storeDir = management.getKernelData().getStoreDir(); - try - { - return storeDir.getCanonicalFile().getAbsoluteFile(); - } - catch ( IOException e ) - { - return storeDir.getAbsoluteFile(); - } + return storeDir.getCanonicalFile().getAbsoluteFile(); + } + catch ( IOException e ) + { + return storeDir.getAbsoluteFile(); } }