-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Implement refactoring changes #1286
base: refactoring-wip
Are you sure you want to change the base?
Conversation
Qodana Community for JVM1 new problem were found
💡 Qodana analysis was run in the pull request mode: only the changed files were checked View the detailed Qodana reportTo be able to view the detailed Qodana report, you can either:
To get - name: 'Qodana Scan'
uses: JetBrains/[email protected]
with:
upload-result: true Contact Qodana teamContact us at [email protected]
|
@@ -283,9 +290,14 @@ protected void clusterIdChanged(final String oldClusterId) { | |||
} | |||
|
|||
protected ClusterSuggestedResult getSuggestedClusterId(final String url) { | |||
for (final Entry<String, List<HostSpec>> entry : topologyCache.getEntries().entrySet()) { | |||
Map<String, Topology> entries = storageService.getEntries(ItemCategory.TOPOLOGY); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once we remove the suggested ID functionality we can assess whether we want to remove the getEntries method as well
@@ -583,43 +600,6 @@ private void validateHostPatternSetting(final String hostPattern) { | |||
} | |||
} | |||
|
|||
public static void logCache() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed this because it is not being called anywhere and because I am using dependency injection to pass in a StorageService instance. Since the StorageService is an instance variable it cannot be accessed via a static context, so we cannot use it in this static method.
import software.amazon.jdbc.util.Messages; | ||
import software.amazon.jdbc.util.ShouldDisposeFunc; | ||
|
||
public class ExpirationCache<K, V> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class is similar to SlidingExpirationCacheWithCleanupThread except it takes in an expiration timeout in the constructor instead of with each get/set method. It can hold either items that do not have renewable expiration or items that do, so it can be used to replace both SlidingExpirationCacheWithCleanupThread or CacheMap. Alternatively we could implement a renewable expiration cache and a non-renewable expiration cache separately, at the expense of some code duplication.
wrapper/src/main/java/software/amazon/jdbc/util/storage/ItemCategory.java
Show resolved
Hide resolved
public @Nullable List<HostSpec> getCachedTopology() { | ||
return topologyCache.get(this.clusterId); | ||
public @Nullable List<HostSpec> getStoredTopology() { | ||
Topology topology = storageService.get(ItemCategory.TOPOLOGY, this.clusterId, Topology.class); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The get() method requires that you pass a Class specifying what the expected value is. This is needed inside the method to check if it matches what is in the cache and cast it for the caller. The limitation with this is that the caller cannot specify a generic class. For example, there is no way for the caller to specify specifically that they want a List. They can specify that they want a List.class but that still does not let us properly check if the List is a List. The solutions to this are:
- Use a non-generic class to wrap the generic object, which is what I've done here
- Remove the expected class as a parameter to get(), and return an Object without casting or checking an expected type. In this case the caller would have to check if the returned Object was the correct type and cast it, which is annoying
- Google Guava has a TypeToken dependency which may provide a way to specify and preserve the generic type info, but this requires adding it as a dependency which may not be acceptable
wrapper/src/main/java/software/amazon/jdbc/hostlistprovider/RdsHostListProvider.java
Outdated
Show resolved
Hide resolved
wrapper/src/main/java/software/amazon/jdbc/util/storage/StorageServiceImpl.java
Outdated
Show resolved
Hide resolved
wrapper/src/main/java/software/amazon/jdbc/wrapper/ConnectionWrapper.java
Outdated
Show resolved
Hide resolved
wrapper/src/main/java/software/amazon/jdbc/hostlistprovider/RdsHostListProvider.java
Show resolved
Hide resolved
wrapper/src/main/java/software/amazon/jdbc/util/storage/StorageServiceImpl.java
Outdated
Show resolved
Hide resolved
@@ -99,10 +103,19 @@ public ConnectionWrapper( | |||
effectiveConnectionProvider, | |||
this, | |||
telemetryFactory); | |||
ServiceContainer serviceContainer = new ServiceContainerImpl(storageService, pluginManager, telemetryFactory); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't love how we partially initialize the ServiceContainer here and then complete the initialization with the setters below. I wonder if we should consider a proper service locator to avoid this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's nothing wrong about partially initialize the object. By design this object is supposed to hold service references. Some of them could be missed, i.e. not yet initialized. I think we 're fine. We could improve it later.
wrapper/src/main/java/software/amazon/jdbc/util/monitoring/MonitorService.java
Outdated
Show resolved
Hide resolved
monitorClass, | ||
mc -> { | ||
monitorSettingsByType.putIfAbsent(monitorClass, new MonitorSettings(inactiveTimeoutNanos, errorResponses)); | ||
ShouldDisposeFunc<MonitorItem> wrappedShouldDisposeFunc = shouldDisposeFunc == null ? null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created the MonitorItem inner class so that monitors can be stored together with the suppliers used to create them. This allows us to re-create the monitor if it encounters an error or gets stuck. However, it makes things messy in this function. The caller passes in a shouldDisposeFunc for the monitor itself (eg ClusterTopologyMonitorImpl), but since we are actually storing MonitorItem's in the cache, we need to pass ShouldDisposeFunc<MonitorItem>. For now I resolved this by wrapping the passed in lambda, but this seems messy and I am getting a warning when I try to cast monitorItem.getMonitor() to T.
wrapper/src/main/java/software/amazon/jdbc/util/monitoring/MonitorService.java
Outdated
Show resolved
Hide resolved
@@ -67,6 +69,8 @@ public class AwsWrapperDataSource implements DataSource, Referenceable, Serializ | |||
private static final String SERVER_NAME = "serverName"; | |||
private static final String SERVER_PORT = "serverPort"; | |||
|
|||
private static final StorageService storageService = new StorageServiceImpl(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have another instance of the service in Driver class. We should use a single one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Driver and AwsWrapperDataSource are independent classes so there is not a way to pass the storage service from one to the other. The Driver class needs the storage service reference so that it can clear it when Driver.clearCaches is called. I think the only way we could make sure its a single instance is if we make it a singleton, do we want to do that? Keep in mind, even though AwsWrapperDataSource and Driver have different instances of StorageServiceImpl, the cache info is static so it will still be shared between both.
import java.util.logging.Logger; | ||
import software.amazon.jdbc.util.Messages; | ||
|
||
public abstract class AbstractMonitor implements Monitor, Runnable { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to add heartbeat functionality to this class? It'd be nice just to inherit it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would be nice, I'm not sure how to add that though. Each monitor type will have its own custom run loop that it needs to define, and the last updated timestamp needs to be updated somewhere in that custom loop. Not sure how to extract the heartbeat piece to the abstract monitor while leaving the custom loop implementation to the underlying monitor class.
Note: will be merged into the refactoring feature branch, not the main branch
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.