Skip to content

Commit 04d5247

Browse files
authored
[couchbase] Explicitly configure service quotas (and allow customization). (#4802)
This changeset explicitly configures the service memory quotas to their documented limits by default. This ensures that if a service is enabled, it does not consume more memory than absolutely needed. This is important because some services (like analytics) try to grab memory available which is good for production but of limited use in a testcontainers setting. A new API is also added which allows to customize the memory quota for each service should the test case require more than the minimum (which for most services is 256MB anyways).
1 parent f89dece commit 04d5247

File tree

2 files changed

+120
-34
lines changed

2 files changed

+120
-34
lines changed

modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@
3636
import java.util.ArrayList;
3737
import java.util.Arrays;
3838
import java.util.EnumSet;
39+
import java.util.HashMap;
3940
import java.util.Iterator;
4041
import java.util.List;
42+
import java.util.Map;
4143
import java.util.Optional;
4244
import java.util.Set;
4345
import java.util.concurrent.TimeUnit;
@@ -100,6 +102,11 @@ public class CouchbaseContainer extends GenericContainer<CouchbaseContainer> {
100102
CouchbaseService.INDEX
101103
);
102104

105+
/**
106+
* Holds the custom service quotas if configured by the user.
107+
*/
108+
private final Map<CouchbaseService, Integer> customServiceQuotas = new HashMap<>();
109+
103110
private final List<BucketDefinition> buckets = new ArrayList<>();
104111

105112
private boolean isEnterprise = false;
@@ -158,6 +165,26 @@ public CouchbaseContainer withEnabledServices(final CouchbaseService... enabled)
158165
return this;
159166
}
160167

168+
/**
169+
* Configures a custom memory quota for a given service.
170+
*
171+
* @param service the service to configure the quota for.
172+
* @param quotaMb the memory quota in MB.
173+
* @return this {@link CouchbaseContainer} for chaining purposes.
174+
*/
175+
public CouchbaseContainer withServiceQuota(final CouchbaseService service, final int quotaMb) {
176+
checkNotRunning();
177+
if (!service.hasQuota()) {
178+
throw new IllegalArgumentException("The provided service (" + service + ") has no quota to configure");
179+
}
180+
if (quotaMb < service.getMinimumQuotaMb()) {
181+
throw new IllegalArgumentException("The custom quota (" + quotaMb + ") must not be smaller than the " +
182+
"minimum quota for the service (" + service.getMinimumQuotaMb() + ")");
183+
}
184+
this.customServiceQuotas.put(service, quotaMb);
185+
return this;
186+
}
187+
161188
/**
162189
* Enables the analytics service which is not enabled by default.
163190
*
@@ -262,6 +289,7 @@ protected void containerIsStarting(final InspectContainerResponse containerInfo)
262289
timePhase("initializeIsEnterprise", this::initializeIsEnterprise);
263290
timePhase("renameNode", this::renameNode);
264291
timePhase("initializeServices", this::initializeServices);
292+
timePhase("setMemoryQuotas", this::setMemoryQuotas);
265293
timePhase("configureAdminUser", this::configureAdminUser);
266294
timePhase("configureExternalPorts", this::configureExternalPorts);
267295

@@ -341,6 +369,35 @@ private void initializeServices() {
341369
checkSuccessfulResponse(response, "Could not enable couchbase services");
342370
}
343371

372+
/**
373+
* Sets the memory quotas for each enabled service.
374+
* <p>
375+
* If there is no explicit custom quota defined, the default minimum quota will be used.
376+
*/
377+
private void setMemoryQuotas() {
378+
logger().debug("Custom service memory quotas: {}", customServiceQuotas);
379+
380+
final FormBody.Builder quotaBuilder = new FormBody.Builder();
381+
for (CouchbaseService service : enabledServices) {
382+
if (!service.hasQuota()) {
383+
continue;
384+
}
385+
386+
int quota = customServiceQuotas.getOrDefault(service, service.getMinimumQuotaMb());
387+
if (CouchbaseService.KV.equals(service)) {
388+
quotaBuilder.add("memoryQuota", Integer.toString(quota));
389+
} else {
390+
quotaBuilder.add(service.getIdentifier() + "MemoryQuota", Integer.toString(quota));
391+
}
392+
}
393+
394+
@Cleanup Response response = doHttpRequest(
395+
MGMT_PORT, "/pools/default", "POST", quotaBuilder.build(), false
396+
);
397+
398+
checkSuccessfulResponse(response, "Could not configure service memory quotas");
399+
}
400+
344401
/**
345402
* Configures the admin user on the couchbase node.
346403
* <p>

modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java

Lines changed: 63 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -21,38 +21,67 @@
2121
*/
2222
public enum CouchbaseService {
2323

24-
/**
25-
* Key-Value service.
26-
*/
27-
KV("kv"),
28-
29-
/**
30-
* Query (N1QL) service.
31-
*/
32-
QUERY("n1ql"),
33-
34-
/**
35-
* Search (FTS) service.
36-
*/
37-
SEARCH("fts"),
38-
39-
/**
40-
* Indexing service (needed if QUERY is also used!).
41-
*/
42-
INDEX("index"),
43-
44-
/**
45-
* Analytics service.
46-
*/
47-
ANALYTICS("cbas");
48-
49-
private final String identifier;
50-
51-
CouchbaseService(String identifier) {
52-
this.identifier = identifier;
53-
}
54-
55-
String getIdentifier() {
56-
return identifier;
57-
}
24+
/**
25+
* Key-Value service.
26+
*/
27+
KV("kv", 256),
28+
29+
/**
30+
* Query (N1QL) service.
31+
* <p>
32+
* Note that the query service has no memory quota, so it is set to 0.
33+
*/
34+
QUERY("n1ql", 0),
35+
36+
/**
37+
* Search (FTS) service.
38+
*/
39+
SEARCH("fts", 256),
40+
41+
/**
42+
* Indexing service (needed if QUERY is also used!).
43+
*/
44+
INDEX("index", 256),
45+
46+
/**
47+
* Analytics service.
48+
*/
49+
ANALYTICS("cbas", 1024);
50+
51+
private final String identifier;
52+
53+
private final int minimumQuotaMb;
54+
55+
CouchbaseService(final String identifier, final int minimumQuotaMb) {
56+
this.identifier = identifier;
57+
this.minimumQuotaMb = minimumQuotaMb;
58+
}
59+
60+
/**
61+
* Returns the internal service identifier.
62+
*
63+
* @return the internal service identifier.
64+
*/
65+
String getIdentifier() {
66+
return identifier;
67+
}
68+
69+
/**
70+
* Returns the minimum quota for the service in MB.
71+
*
72+
* @return the minimum quota in MB.
73+
*/
74+
int getMinimumQuotaMb() {
75+
return minimumQuotaMb;
76+
}
77+
78+
/**
79+
* Returns true if the service has a quota that needs to be applied.
80+
*
81+
* @return true if its quota needs to be applied.
82+
*/
83+
boolean hasQuota() {
84+
return minimumQuotaMb > 0;
85+
}
86+
5887
}

0 commit comments

Comments
 (0)