From 3e1411f3f8486e4e803b7712549501f94ffea7fc Mon Sep 17 00:00:00 2001
From: Jeff Nelson
Date: Tue, 14 May 2024 10:53:57 -0400
Subject: [PATCH 1/4] Change default value of max_search_substring_length
configuration option to 40 (#517)
* Revert "Revert "update changelog""
This reverts commit 504d7bab6a50150a03f33034e669d96a8bbcf226.
* Revert "Revert "change default value of max_search_substring_length""
This reverts commit f0a6664beae558a13c1d29c2be6bd15da6498b45.
---
CHANGELOG.md | 1 +
concourse-server/conf/concourse.yaml | 4 +---
.../main/java/com/cinchapi/concourse/server/GlobalState.java | 2 +-
3 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 14759e02d..590507f8b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ We made several changes to improve search performance and accuracy:
* **Previous Configuration**: In earlier versions, Concourse Server could be configured using the `conf/stopwords.txt` file to exclude common stopwords from indexing and search operations. This approach was designed to reduce storage requirements and improve search performance by removing frequently occurring, but generally less significant words.
* **Rationale for Change**: Preserving stopwords is crucial for maintaining context, which can significantly enhance the accuracy of search results and the effectiveness of ranking algorithms. Since affordable storage and computational resources are more abundant, resource usage is no longer a concern and it makes more sense to prioritze better search accuracy and system robustness. Lastly, preserving stopwords eliminates corner case bugs that are inherent to the way Concourse's search algorithm interacts with the buffered storage system.
* **Upgrade Implications**: Upon upgrading to this version, an automatic reindexing task will be initiated to ensure that all previously indexed data conforms to the new no-stopword-removal policy. It's important to allocate downtime for this reindexing to occur. And, it is wise to anticipate more storage spaced being used due to stopwords being included in the search corpus.
+* Changed the default value of the `max_search_substring_length` configuration option to `40`. The previous default allowed unlimited substring lengths, which increased search index size and hurt performance. Existing explicit configurations for this option remain unchanged.
##### Locking Optimizations
We made several changes to improve the safety, scalability and operational efficiency of the Just-in-Time (JIT) locking protocol:
diff --git a/concourse-server/conf/concourse.yaml b/concourse-server/conf/concourse.yaml
index 3234feb39..aa611ccc9 100644
--- a/concourse-server/conf/concourse.yaml
+++ b/concourse-server/conf/concourse.yaml
@@ -175,9 +175,7 @@ log_level:
# length of the longest possible word in the search language. For example, the longest
# possible word in English is about 40 characters long.
#
-# By default, search substrings are not limited.
-#
-# DEFAULT: no limit
+# DEFAULT: 40
max_search_substring_length:
# The listener port (1-65535) for shutdown commands. Choose a port between
diff --git a/concourse-server/src/main/java/com/cinchapi/concourse/server/GlobalState.java b/concourse-server/src/main/java/com/cinchapi/concourse/server/GlobalState.java
index 24c0734b6..a74062bbc 100644
--- a/concourse-server/src/main/java/com/cinchapi/concourse/server/GlobalState.java
+++ b/concourse-server/src/main/java/com/cinchapi/concourse/server/GlobalState.java
@@ -276,7 +276,7 @@ public final class GlobalState extends Constants {
* is about 40 characters long.
*
*/
- public static int MAX_SEARCH_SUBSTRING_LENGTH = -1;
+ public static int MAX_SEARCH_SUBSTRING_LENGTH = 40;
/**
* The password that is assigned to the root administrator account when
From 5600bc32a4a91f54703a729ed1a1592853db5d9e Mon Sep 17 00:00:00 2001
From: Jeff Nelson
Date: Sun, 19 May 2024 09:18:22 -0400
Subject: [PATCH 2/4] pass default value correctly when getting
init_root_username and init_root_password
---
.../main/java/com/cinchapi/concourse/server/GlobalState.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/concourse-server/src/main/java/com/cinchapi/concourse/server/GlobalState.java b/concourse-server/src/main/java/com/cinchapi/concourse/server/GlobalState.java
index a74062bbc..42dd348e7 100644
--- a/concourse-server/src/main/java/com/cinchapi/concourse/server/GlobalState.java
+++ b/concourse-server/src/main/java/com/cinchapi/concourse/server/GlobalState.java
@@ -415,10 +415,10 @@ public final class GlobalState extends Constants {
ENABLE_VERIFY_BY_LOOKUP);
INIT_ROOT_PASSWORD = config.getOrDefault("init.root.password",
- config.getOrDefault("init_root_password", "admin"));
+ config.getOrDefault("init_root_password", INIT_ROOT_PASSWORD));
INIT_ROOT_USERNAME = config.getOrDefault("init.root.username",
- config.getOrDefault("init_root_username", "admin"));
+ config.getOrDefault("init_root_username", INIT_ROOT_USERNAME));
// =================== PREF READING BLOCK ====================
}
From ea07fa3fef7c7eeec637c826252714de1d3ec1f7 Mon Sep 17 00:00:00 2001
From: Jeff Nelson
Date: Sat, 29 Jun 2024 10:10:14 +0100
Subject: [PATCH 3/4] GH-509: Create connection pool by copying existing
connection (#521)
* Rely on Supplier constructor for all ConnectionPool factory methods
Remove references and usage of deprecated constructors
* Add factory methods to create connection pools that copy and existing connection
* update changelog
* doc update
* update changelog
---
CHANGELOG.md | 3 +
.../concourse/CachedConnectionPool.java | 27 +-
.../cinchapi/concourse/ConnectionPool.java | 264 ++++++++++++------
.../concourse/FixedConnectionPool.java | 27 +-
.../concourse/CachedConnectionPoolTest.java | 5 +
.../concourse/ConnectionPoolTest.java | 36 +++
.../concourse/CustomConnectionPoolTest.java | 15 +
.../concourse/FixedConnectionPoolTest.java | 5 +
8 files changed, 247 insertions(+), 135 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 590507f8b..4dd5d2f22 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -37,6 +37,9 @@ We made several changes to improve the safety, scalability and operational effic
* `ConcourseArtifacts` - Provides factory methods to retrieve local copies of Concourse artifacts for any version. Can be used to download the installer for a released version.
* `ManagedConcourseServer` - Provdes the ability to control an external Concourse Server process within another application.
+##### New Functionality
+* Added the ability to create `ConnectionPool`s that copy the credentials and connection information from an existing handler These copying connection pools can be created by using the respective "cached" or "fixed" factory methods in the `ConnectionPool` class that take a `Concourse` parameter.
+
##### Bug Fixes
* [GH-454](https://github.com/cinchapi/concourse/issues/454): Fixed an issue that caused JVM startup options overriden in a ".dev" configuration file to be ignored (e.g., `heap_size`).
* [GH-491](https://github.com/cinchapi/concourse/issues/491) Fixed a race condition that made it possible for a range bloked operation to spurriously be allowed to proceed if it was waiting to acquire a range lock whose intended scope of protection intersected the scope of a range lock that was concurrently released.
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/CachedConnectionPool.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/CachedConnectionPool.java
index a66e17045..7ef83df83 100644
--- a/concourse-driver-java/src/main/java/com/cinchapi/concourse/CachedConnectionPool.java
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/CachedConnectionPool.java
@@ -16,6 +16,7 @@
package com.cinchapi.concourse;
import java.util.Queue;
+import java.util.function.Supplier;
import com.cinchapi.concourse.util.ConcurrentLoadingQueue;
@@ -31,31 +32,11 @@ class CachedConnectionPool extends ConnectionPool {
/**
* Construct a new instance.
*
- * @param host
- * @param port
- * @param username
- * @param password
+ * @param supplier
* @param poolSize
*/
- protected CachedConnectionPool(String host, int port, String username,
- String password, int poolSize) {
- this(host, port, username, password, "", poolSize);
- }
-
- /**
- * Construct a new instance.
- *
- * @param host
- * @param port
- * @param username
- * @param password
- * @param environment
- * @param poolSize
- */
- protected CachedConnectionPool(String host, int port, String username,
- String password, String environment, int poolSize) {
- super(() -> Concourse.connect(host, port, username, password,
- environment), poolSize);
+ protected CachedConnectionPool(Supplier supplier, int poolSize) {
+ super(supplier, poolSize);
}
@Override
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/ConnectionPool.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/ConnectionPool.java
index 2bb118ad6..6d5e73508 100644
--- a/concourse-driver-java/src/main/java/com/cinchapi/concourse/ConnectionPool.java
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/ConnectionPool.java
@@ -60,18 +60,6 @@ public abstract class ConnectionPool implements AutoCloseable {
// NOTE: This class does not define #hashCode or #equals because the
// defaults are the desired behaviour
- /**
- * The default connection pool size.
- */
- protected static final int DEFAULT_POOL_SIZE = 10;
-
- /**
- * The default configuration files to use if none are specified.
- */
- private static final Path[] DEFAULT_CONFIG_FILES = new Path[] {
- Paths.get("concourse_client.prefs"),
- Paths.get("concourse_client.yaml") };
-
/**
* Return a {@link ConnectionPool} that has no limit on the number of
* connections it can manage to the Concourse instance described in the
@@ -87,17 +75,25 @@ public static ConnectionPool newCachedConnectionPool() {
}
/**
- * Return a {@link ConnectionPool} that has no limit on the number of
- * connections it can manage to the Concourse instance described in the
- * {@code config} on behalf of the user identified in the {@code config},
- * but will try to use previously created connections before establishing
- * new ones for any request.
- *
- * @param config
- * @return the ConnectionPool
- */
- public static ConnectionPool newCachedConnectionPool(String config) {
- return newCachedConnectionPool(Paths.get(config));
+ * Returns a {@link ConnectionPool} populated with handlers that
+ * {@link Concourse#copyExistingConnection(Concourse) copy} the connection
+ * information of the provided {@code concourse} instance. The pool has no
+ * limit on the number of connections it can manage, but will attempt to use
+ * previously created connections before establishing new ones on request.
+ *
+ *
+ * NOTE: The provided {@code concourse} connection will not
+ * be a member of the returned {@link ConnectionPool} and its status will
+ * not affect the status of any connections managed by the pool.
+ *
+ *
+ * @param concourse the {@link Concourse} connection to copy when populating
+ * the {@link ConnectionPool}
+ * @return the populated {@link ConnectionPool}
+ */
+ public static ConnectionPool newCachedConnectionPool(Concourse concourse) {
+ Supplier supplier = () -> concourse.copyConnection();
+ return new CachedConnectionPool(supplier, DEFAULT_POOL_SIZE);
}
/**
@@ -113,9 +109,24 @@ public static ConnectionPool newCachedConnectionPool(String config) {
public static ConnectionPool newCachedConnectionPool(Path... configFiles) {
ConcourseClientConfiguration config = ConcourseClientConfiguration
.from(configFiles);
- return new CachedConnectionPool(config.getHost(), config.getPort(),
- config.getUsername(), new String(config.getPassword()),
- config.getEnvironment(), DEFAULT_POOL_SIZE);
+ Supplier supplier = getConcourseSupplier(config.getHost(),
+ config.getPort(), config.getUsername(),
+ new String(config.getPassword()), config.getEnvironment());
+ return new CachedConnectionPool(supplier, DEFAULT_POOL_SIZE);
+ }
+
+ /**
+ * Return a {@link ConnectionPool} that has no limit on the number of
+ * connections it can manage to the Concourse instance described in the
+ * {@code config} on behalf of the user identified in the {@code config},
+ * but will try to use previously created connections before establishing
+ * new ones for any request.
+ *
+ * @param config
+ * @return the ConnectionPool
+ */
+ public static ConnectionPool newCachedConnectionPool(String config) {
+ return newCachedConnectionPool(Paths.get(config));
}
/**
@@ -133,8 +144,9 @@ public static ConnectionPool newCachedConnectionPool(Path... configFiles) {
*/
public static ConnectionPool newCachedConnectionPool(String host, int port,
String username, String password) {
- return new CachedConnectionPool(host, port, username, password,
- DEFAULT_POOL_SIZE);
+ Supplier supplier = getConcourseSupplier(host, port,
+ username, password, "");
+ return new CachedConnectionPool(supplier, DEFAULT_POOL_SIZE);
}
/**
@@ -153,8 +165,9 @@ public static ConnectionPool newCachedConnectionPool(String host, int port,
*/
public static ConnectionPool newCachedConnectionPool(String host, int port,
String username, String password, String environment) {
- return new CachedConnectionPool(host, port, username, password,
- environment, DEFAULT_POOL_SIZE);
+ Supplier supplier = getConcourseSupplier(host, port,
+ username, password, environment);
+ return new CachedConnectionPool(supplier, DEFAULT_POOL_SIZE);
}
/**
@@ -230,6 +243,30 @@ public static ConnectionPool newConnectionPool(String host, int port,
return newFixedConnectionPool(host, port, username, password, poolSize);
}
+ /**
+ * Returns a {@link ConnectionPool} populated with handlers that
+ * {@link Concourse#copyExistingConnection(Concourse) copy} the connection
+ * information of the provided {@code concourse} instance. The pool will
+ * contain {@code poolSize} connections. If all connections are active,
+ * subsequent requests will block until a connection is returned.
+ *
+ *
+ * NOTE: The provided {@code concourse} connection will not
+ * be a member of the returned {@link ConnectionPool} and its status will
+ * not affect the status of any connections managed by the pool.
+ *
+ *
+ * @param concourse the {@link Concourse} connection to copy when populating
+ * the {@link ConnectionPool}
+ * @param poolSize the number of connections in the pool
+ * @return the populated {@link ConnectionPool}
+ */
+ public static ConnectionPool newFixedConnectionPool(Concourse concourse,
+ int poolSize) {
+ Supplier supplier = () -> concourse.copyConnection();
+ return new FixedConnectionPool(supplier, poolSize);
+ }
+
/**
* Return a new {@link ConnectionPool} with a fixed number of connections to
* the Concourse instance defined in the {@code concourse_client.prefs} file
@@ -256,13 +293,18 @@ public static ConnectionPool newFixedConnectionPool(int poolSize) {
* attempts will block until a connection is returned.
*
*
- * @param config
* @param poolSize
+ * @param config
* @return the ConnectionPool
*/
- public static ConnectionPool newFixedConnectionPool(String config,
- int poolSize) {
- return newFixedConnectionPool(poolSize, Paths.get(config));
+ public static ConnectionPool newFixedConnectionPool(int poolSize,
+ Path... configFiles) {
+ ConcourseClientConfiguration config = ConcourseClientConfiguration
+ .from(configFiles);
+ Supplier supplier = getConcourseSupplier(config.getHost(),
+ config.getPort(), config.getUsername(),
+ new String(config.getPassword()), config.getEnvironment());
+ return new FixedConnectionPool(supplier, poolSize);
}
/**
@@ -274,17 +316,13 @@ public static ConnectionPool newFixedConnectionPool(String config,
* attempts will block until a connection is returned.
*
*
- * @param poolSize
* @param config
+ * @param poolSize
* @return the ConnectionPool
*/
- public static ConnectionPool newFixedConnectionPool(int poolSize,
- Path... configFiles) {
- ConcourseClientConfiguration config = ConcourseClientConfiguration
- .from(configFiles);
- return new FixedConnectionPool(config.getHost(), config.getPort(),
- config.getUsername(), new String(config.getPassword()),
- config.getEnvironment(), poolSize);
+ public static ConnectionPool newFixedConnectionPool(String config,
+ int poolSize) {
+ return newFixedConnectionPool(poolSize, Paths.get(config));
}
/**
@@ -306,8 +344,9 @@ public static ConnectionPool newFixedConnectionPool(int poolSize,
*/
public static ConnectionPool newFixedConnectionPool(String host, int port,
String username, String password, int poolSize) {
- return new FixedConnectionPool(host, port, username, password,
- poolSize);
+ Supplier supplier = getConcourseSupplier(host, port,
+ username, password, "");
+ return new FixedConnectionPool(supplier, poolSize);
}
/**
@@ -331,10 +370,40 @@ public static ConnectionPool newFixedConnectionPool(String host, int port,
public static ConnectionPool newFixedConnectionPool(String host, int port,
String username, String password, String environment,
int poolSize) {
- return new FixedConnectionPool(host, port, username, password,
- environment, poolSize);
+ Supplier supplier = getConcourseSupplier(host, port,
+ username, password, environment);
+ return new FixedConnectionPool(supplier, poolSize);
}
+ /**
+ * Return a {@link Supplier} that generates a new {@link Concourse}
+ * connection from the provided credentials and connection information.
+ *
+ * @param host
+ * @param port
+ * @param username
+ * @param password
+ * @param environment
+ * @return the {@link Supplier}
+ */
+ private static Supplier getConcourseSupplier(String host,
+ int port, String username, String password, String environment) {
+ return () -> Concourse.connect(host, port, username, password,
+ environment);
+ }
+
+ /**
+ * The default connection pool size.
+ */
+ protected static final int DEFAULT_POOL_SIZE = 10;
+
+ /**
+ * The default configuration files to use if none are specified.
+ */
+ private static final Path[] DEFAULT_CONFIG_FILES = new Path[] {
+ Paths.get("concourse_client.prefs"),
+ Paths.get("concourse_client.yaml") };
+
/**
* A FIFO queue of connections that are available to be leased.
*/
@@ -356,26 +425,25 @@ public static ConnectionPool newFixedConnectionPool(String host, int port,
protected final Supplier supplier;
/**
- * Construct a new instance.
+ * Construct a new instance that provides {@link Concourse} connections that
+ * copy the connection information from the provided {@code concourse}
+ * handler.
+ *
+ * NOTE:This constructor is provided for subclasses to
+ * conveniently implement connection copying while abstracting away the
+ * details of how to construct an appropriate {@link Supplier}.
+ *
*
- * @param supplier
+ * @param concourse
* @param poolSize
*/
- protected ConnectionPool(Supplier supplier, int poolSize) {
- this.supplier = supplier;
- this.available = buildQueue(poolSize);
- this.leased = Sets.newConcurrentHashSet();
- for (int i = 0; i < poolSize; ++i) {
- available.offer(supplier.get());
- }
- // Ensure that the client connections are forced closed when the JVM is
- // shutdown in case the user does not properly close the pool
- Runtime.getRuntime().addShutdownHook(new Thread(() -> forceClose()));
+ protected ConnectionPool(Concourse concourse, int poolSize) {
+ this(() -> concourse.copyConnection(), poolSize);
}
/**
* Construct a new instance.
- *
+ *
* @param host
* @param port
* @param username
@@ -391,7 +459,7 @@ protected ConnectionPool(String host, int port, String username,
/**
* Construct a new instance.
- *
+ *
* @param host
* @param port
* @param username
@@ -406,6 +474,24 @@ protected ConnectionPool(String host, int port, String username,
environment), poolSize);
}
+ /**
+ * Construct a new instance.
+ *
+ * @param supplier
+ * @param poolSize
+ */
+ protected ConnectionPool(Supplier supplier, int poolSize) {
+ this.supplier = supplier;
+ this.available = buildQueue(poolSize);
+ this.leased = Sets.newConcurrentHashSet();
+ for (int i = 0; i < poolSize; ++i) {
+ available.offer(supplier.get());
+ }
+ // Ensure that the client connections are forced closed when the JVM is
+ // shutdown in case the user does not properly close the pool
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> forceClose()));
+ }
+
@Override
public void close() throws Exception {
Preconditions.checkState(isClosable(),
@@ -464,6 +550,35 @@ public Concourse request() {
return connection;
}
+ /**
+ * Return the {@link Queue} that will hold the connections.
+ *
+ * @param size
+ *
+ * @return the connections cache
+ */
+ protected abstract Queue buildQueue(int size);
+
+ /**
+ * Force the connection pool to close regardless of whether it is or is not
+ * in a {@link #isClosable() closable} state.
+ */
+ protected void forceClose() {
+ if(open.compareAndSet(true, false)) {
+ exitConnections(available);
+ exitConnections(leased);
+ }
+ }
+
+ /**
+ * Get a connection from the queue of {@code available} ones. The subclass
+ * should use the correct method depending upon whether this method should
+ * block or not.
+ *
+ * @return the connection
+ */
+ protected abstract Concourse getConnection();
+
/**
* Exit all the connections managed of the pool that has a
* {@link #available}.
@@ -529,33 +644,4 @@ private void verifyValidOrigin(Concourse connection) {
+ "was not previously requested from this pool");
}
}
-
- /**
- * Return the {@link Queue} that will hold the connections.
- *
- * @param size
- *
- * @return the connections cache
- */
- protected abstract Queue buildQueue(int size);
-
- /**
- * Force the connection pool to close regardless of whether it is or is not
- * in a {@link #isClosable() closable} state.
- */
- protected void forceClose() {
- if(open.compareAndSet(true, false)) {
- exitConnections(available);
- exitConnections(leased);
- }
- }
-
- /**
- * Get a connection from the queue of {@code available} ones. The subclass
- * should use the correct method depending upon whether this method should
- * block or not.
- *
- * @return the connection
- */
- protected abstract Concourse getConnection();
}
diff --git a/concourse-driver-java/src/main/java/com/cinchapi/concourse/FixedConnectionPool.java b/concourse-driver-java/src/main/java/com/cinchapi/concourse/FixedConnectionPool.java
index 8e65323ff..75eb4c223 100644
--- a/concourse-driver-java/src/main/java/com/cinchapi/concourse/FixedConnectionPool.java
+++ b/concourse-driver-java/src/main/java/com/cinchapi/concourse/FixedConnectionPool.java
@@ -18,6 +18,7 @@
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
+import java.util.function.Supplier;
import com.cinchapi.common.base.CheckedExceptions;
@@ -33,31 +34,11 @@ class FixedConnectionPool extends ConnectionPool {
/**
* Construct a new instance.
*
- * @param host
- * @param port
- * @param username
- * @param password
+ * @param supplier
* @param poolSize
*/
- protected FixedConnectionPool(String host, int port, String username,
- String password, int poolSize) {
- this(host, port, username, password, "", poolSize);
- }
-
- /**
- * Construct a new instance.
- *
- * @param host
- * @param port
- * @param username
- * @param password
- * @param environment
- * @param poolSize
- */
- protected FixedConnectionPool(String host, int port, String username,
- String password, String environment, int poolSize) {
- super(() -> Concourse.connect(host, port, username, password,
- environment), poolSize);
+ protected FixedConnectionPool(Supplier supplier, int poolSize) {
+ super(supplier, poolSize);
}
@Override
diff --git a/concourse-integration-tests/src/test/java/com/cinchapi/concourse/CachedConnectionPoolTest.java b/concourse-integration-tests/src/test/java/com/cinchapi/concourse/CachedConnectionPoolTest.java
index 63747b969..f4ff5c638 100644
--- a/concourse-integration-tests/src/test/java/com/cinchapi/concourse/CachedConnectionPoolTest.java
+++ b/concourse-integration-tests/src/test/java/com/cinchapi/concourse/CachedConnectionPoolTest.java
@@ -56,4 +56,9 @@ protected ConnectionPool getConnectionPool(String env) {
USERNAME, PASSWORD, env);
}
+ @Override
+ protected ConnectionPool getConnectionPool(Concourse concourse) {
+ return ConnectionPool.newCachedConnectionPool(concourse);
+ }
+
}
diff --git a/concourse-integration-tests/src/test/java/com/cinchapi/concourse/ConnectionPoolTest.java b/concourse-integration-tests/src/test/java/com/cinchapi/concourse/ConnectionPoolTest.java
index d703366b3..d014ecac9 100644
--- a/concourse-integration-tests/src/test/java/com/cinchapi/concourse/ConnectionPoolTest.java
+++ b/concourse-integration-tests/src/test/java/com/cinchapi/concourse/ConnectionPoolTest.java
@@ -25,6 +25,7 @@
import com.cinchapi.concourse.server.concurrent.Threads;
import com.cinchapi.concourse.test.ConcourseIntegrationTest;
import com.cinchapi.concourse.util.Environments;
+import com.cinchapi.concourse.util.Random;
import com.cinchapi.concourse.util.TestData;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
@@ -193,6 +194,33 @@ public void testRequestReleaseRaceCondition() {
});
}
+ @Test
+ public void testCopyConnectionPoolIndependentOfCopiedHandler()
+ throws Exception {
+ Concourse concourse = Concourse.connect(SERVER_HOST, SERVER_PORT,
+ USERNAME, PASSWORD, Random.getSimpleString());
+ ConnectionPool pool = getConnectionPool(concourse);
+ try {
+ concourse.exit();
+ try {
+ concourse.inventory();
+ Assert.fail();
+ }
+ catch (Exception e) {
+ Assert.assertTrue(true);
+ }
+ for (int i = 0; i < TestData.getScaleCount(); ++i) {
+ Concourse connection = pool.request();
+ connection.inventory();
+ Assert.assertTrue(true);
+ pool.release(connection);
+ }
+ }
+ finally {
+ pool.close();
+ }
+ }
+
/**
* Return a {@link com.cinchapi.concourse.ConnectionPool} to use in a unit
* test.
@@ -211,4 +239,12 @@ public void testRequestReleaseRaceCondition() {
*/
protected abstract ConnectionPool getConnectionPool(String env);
+ /**
+ * Return a {@link ConnectionPool} to use in a unit test.
+ *
+ * @param concourse
+ * @return the {@link ConnectionPool}
+ */
+ protected abstract ConnectionPool getConnectionPool(Concourse concourse);
+
}
diff --git a/concourse-integration-tests/src/test/java/com/cinchapi/concourse/CustomConnectionPoolTest.java b/concourse-integration-tests/src/test/java/com/cinchapi/concourse/CustomConnectionPoolTest.java
index 63d507408..ecc7bd86d 100644
--- a/concourse-integration-tests/src/test/java/com/cinchapi/concourse/CustomConnectionPoolTest.java
+++ b/concourse-integration-tests/src/test/java/com/cinchapi/concourse/CustomConnectionPoolTest.java
@@ -73,6 +73,16 @@ public CustomConcourse(Concourse concourse) {
static class CustomConnectionPool extends ConnectionPool {
+ /**
+ * Construct a new instance.
+ *
+ * @param concourse
+ * @param poolSize
+ */
+ public CustomConnectionPool(Concourse concourse, int poolSize) {
+ super(concourse, poolSize);
+ }
+
/**
* Construct a new instance.
*
@@ -114,4 +124,9 @@ protected Concourse getConnection() {
}
+ @Override
+ protected ConnectionPool getConnectionPool(Concourse concourse) {
+ return new CustomConnectionPool(concourse, 10);
+ }
+
}
diff --git a/concourse-integration-tests/src/test/java/com/cinchapi/concourse/FixedConnectionPoolTest.java b/concourse-integration-tests/src/test/java/com/cinchapi/concourse/FixedConnectionPoolTest.java
index b23dd8712..534f46ca2 100644
--- a/concourse-integration-tests/src/test/java/com/cinchapi/concourse/FixedConnectionPoolTest.java
+++ b/concourse-integration-tests/src/test/java/com/cinchapi/concourse/FixedConnectionPoolTest.java
@@ -83,4 +83,9 @@ protected ConnectionPool getConnectionPool(String env) {
USERNAME, PASSWORD, env, POOL_SIZE);
}
+ @Override
+ protected ConnectionPool getConnectionPool(Concourse concourse) {
+ return ConnectionPool.newFixedConnectionPool(concourse, POOL_SIZE);
+ }
+
}
From c2ff869c1d0f7651572cf36b5a58689a591a6e14 Mon Sep 17 00:00:00 2001
From: Jeff Nelson
Date: Sun, 30 Jun 2024 04:35:34 -0700
Subject: [PATCH 4/4] Reduce Manifest Memory Consumption (#520)
* Reduce the amount of memory required for Manifests by optimizing heap layout and hashmap sizing
* update changelog
* further optimize hashmap sizing
* Use a custom hashmap from fastutil to further reduce Manifest memory by mapping byte[] to byte[]
* slight code change
* add feature flag
* rename from enable_minimized_metadata to enable_efficient_metadata
* rename HeapEntries to BinaryHashMap
* rename HeapEntries to BinaryHashMap
* rename HeapEntries to BinaryHashMap
* rename HeapEntries to BinaryHashMap
* rename HeapEntries to BinaryHashMap
* no temp object creation
* fix weird performance issue using getOrDefault...
* clean up some things
* fix up names
* doc update
* update changelog
* doc updates
* rename MutableRange to Span
* formatting
* fix up
* Get the naming right, I think
* get all the names right
* add getOrDefault impl just in case anyone tries to use it in the future
---
CHANGELOG.md | 2 +
concourse-server/build.gradle | 1 +
concourse-server/conf/concourse.yaml | 12 +
.../concourse/server/GlobalState.java | 19 +
.../server/storage/db/kernel/Chunk.java | 1 -
.../server/storage/db/kernel/Manifest.java | 542 +++++++++++++-----
.../server/storage/db/kernel/Range.java | 47 ++
.../storage/db/kernel/ManifestTest.java | 3 +-
licenses/fastutil-core-8.5.13.txt | 201 +++++++
9 files changed, 667 insertions(+), 161 deletions(-)
create mode 100644 concourse-server/src/main/java/com/cinchapi/concourse/server/storage/db/kernel/Range.java
create mode 100644 licenses/fastutil-core-8.5.13.txt
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4dd5d2f22..30784cc3b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -39,6 +39,8 @@ We made several changes to improve the safety, scalability and operational effic
##### New Functionality
* Added the ability to create `ConnectionPool`s that copy the credentials and connection information from an existing handler These copying connection pools can be created by using the respective "cached" or "fixed" factory methods in the `ConnectionPool` class that take a `Concourse` parameter.
+* Reduced the amount of heap space required for essential storage metadata.
+* Added the `enable_efficient_metadata` configuration option to further reduce the amount of heap space required for essential storage metadata. When this option is set to `true`, metadata will occupy approximately one-third less heap space and likely improve overall system performance due to a decrease in garbage collection pauses (although per-operation performance may be slightly affected by additional overhead).
##### Bug Fixes
* [GH-454](https://github.com/cinchapi/concourse/issues/454): Fixed an issue that caused JVM startup options overriden in a ".dev" configuration file to be ignored (e.g., `heap_size`).
diff --git a/concourse-server/build.gradle b/concourse-server/build.gradle
index 5c765e720..6be722c2e 100644
--- a/concourse-server/build.gradle
+++ b/concourse-server/build.gradle
@@ -43,6 +43,7 @@ dependencies {
compile 'com.github.davidmoten:bplustree:0.1.3'
compile group:'com.cinchapi', name: 'off-heap-memory', version: '1.1.0-SNAPSHOT', changing:true
compile group:'com.cinchapi', name: 'configctl-lib', version: '1.2.0', changing:true
+ compile 'it.unimi.dsi:fastutil-core:8.5.13'
testCompile 'com.carrotsearch:junit-benchmarks:0.7.2'
testCompile 'io.takari.junit:takari-cpsuite:1.2.7'
diff --git a/concourse-server/conf/concourse.yaml b/concourse-server/conf/concourse.yaml
index aa611ccc9..39ed7392e 100644
--- a/concourse-server/conf/concourse.yaml
+++ b/concourse-server/conf/concourse.yaml
@@ -209,6 +209,18 @@ remote_debugger_port:
# DEFAULT: false
enable_compaction:
+# Use a more memory-efficient representation for storage metadata.
+#
+# On average, enabling this setting will reduce the amount of heap space needed
+# for essential metadata by a third. As a result, overall system performance may
+# improve due to a reduction in garbage collection pauses.
+#
+# However, this setting may increase CPU usage and slightly reduce peak performance
+# on a per-operation basis due to weaker reference locality.
+#
+# DEFAULT: false
+enable_efficient_metadata:
+
# Maintain and in-memory cache of the data indexes used to respond to search commands.
# Search indexes tend to be much larger than those used for primary and secondary
# lookups, so enabling the search cache may cause memory issues (and overall
diff --git a/concourse-server/src/main/java/com/cinchapi/concourse/server/GlobalState.java b/concourse-server/src/main/java/com/cinchapi/concourse/server/GlobalState.java
index 42dd348e7..f6765f8a1 100644
--- a/concourse-server/src/main/java/com/cinchapi/concourse/server/GlobalState.java
+++ b/concourse-server/src/main/java/com/cinchapi/concourse/server/GlobalState.java
@@ -333,6 +333,22 @@ public final class GlobalState extends Constants {
@Experimental
public static boolean ENABLE_VERIFY_BY_LOOKUP = false;
+ /**
+ * Use a more memory-efficient representation for storage metadata.
+ *
+ * On average, enabling this setting will reduce the amount of heap space
+ * needed for essential metadata by 33%. As a result, overall system
+ * performance may improve due to a reduction in garbage collection pauses.
+ *
+ *
+ * However, this setting may increase CPU usage and slightly reduce
+ * peak performance on a per-operation basis due to weaker reference
+ * locality.
+ *
+ */
+ @Experimental
+ public static boolean ENABLE_EFFICIENT_METADATA = false;
+
static {
List files = ImmutableList.of(
"conf" + File.separator + "concourse.prefs",
@@ -419,6 +435,9 @@ public final class GlobalState extends Constants {
INIT_ROOT_USERNAME = config.getOrDefault("init.root.username",
config.getOrDefault("init_root_username", INIT_ROOT_USERNAME));
+
+ ENABLE_EFFICIENT_METADATA = config.getOrDefault(
+ "enable_efficient_metadata", ENABLE_EFFICIENT_METADATA);
// =================== PREF READING BLOCK ====================
}
diff --git a/concourse-server/src/main/java/com/cinchapi/concourse/server/storage/db/kernel/Chunk.java b/concourse-server/src/main/java/com/cinchapi/concourse/server/storage/db/kernel/Chunk.java
index 2aa564401..d5ffae1d0 100644
--- a/concourse-server/src/main/java/com/cinchapi/concourse/server/storage/db/kernel/Chunk.java
+++ b/concourse-server/src/main/java/com/cinchapi/concourse/server/storage/db/kernel/Chunk.java
@@ -47,7 +47,6 @@
import com.cinchapi.concourse.server.storage.cache.BloomFilter;
import com.cinchapi.concourse.server.storage.db.Record;
import com.cinchapi.concourse.server.storage.db.Revision;
-import com.cinchapi.concourse.server.storage.db.kernel.Manifest.Range;
import com.cinchapi.concourse.util.Logger;
import com.cinchapi.lib.offheap.collect.OffHeapSortedSet;
import com.cinchapi.lib.offheap.io.Serializer;
diff --git a/concourse-server/src/main/java/com/cinchapi/concourse/server/storage/db/kernel/Manifest.java b/concourse-server/src/main/java/com/cinchapi/concourse/server/storage/db/kernel/Manifest.java
index d51a14f19..3383645df 100644
--- a/concourse-server/src/main/java/com/cinchapi/concourse/server/storage/db/kernel/Manifest.java
+++ b/concourse-server/src/main/java/com/cinchapi/concourse/server/storage/db/kernel/Manifest.java
@@ -21,11 +21,12 @@
import java.nio.file.Path;
import java.util.AbstractMap;
import java.util.AbstractSet;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
-import java.util.Objects;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
@@ -35,7 +36,6 @@
import java.util.function.BiConsumer;
import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.NotThreadSafe;
import com.cinchapi.common.base.CheckedExceptions;
@@ -48,9 +48,13 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterators;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import it.unimi.dsi.fastutil.Hash;
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap;
+
/**
* A {@link Manifest} stores and provides the efficient lookup for the start and
* end position for sequences of bytes that relate to a key that is described by
@@ -136,7 +140,7 @@ public static Manifest load(Segment segment, long position, long length) {
* Returned from {@link #lookup(Composite)} when an associated entry does
* not exist.
*/
- private static final Range NULL_RANGE = new Range() {
+ private static final com.cinchapi.concourse.server.storage.db.kernel.Range NULL_RANGE = new com.cinchapi.concourse.server.storage.db.kernel.Range() {
@Override
public long end() {
@@ -151,8 +155,21 @@ public long start() {
};
/**
- * A {@link SoftReference} to the entries contained in the {@link Manifest}
- * that is used to reduce memory overhead.
+ * The estimated number of bytes required to store an entry. This
+ * calculation is based on the variable range of {@link Composite} lengths.
+ */
+ // @formatter:off
+ private static final int ESTIMATED_ENTRY_SIZE_IN_BYTES =
+ ((Range.CONSTANT_SIZE + 1) +
+ (Range.CONSTANT_SIZE + Composite.MAX_SIZE))
+ / 2;
+ //@formatter:on
+
+ /**
+ * A {@link SoftReference} to the entries contained in the {@link Manifest}.
+ * After the {@link Manifest}'s memory is {@link {@link #free() freed}, this
+ * reference is populated to opportunistically keep the entries in memory if
+ * there is room to do so.
*
*
* It is {@code null} until the {@link Manifest} is {@link #flush(ByteSink)
@@ -160,20 +177,29 @@ public long start() {
*
*/
@Nullable
- private SoftReference