Skip to content
This repository was archived by the owner on Sep 16, 2024. It is now read-only.

Commit 65f5522

Browse files
committed
DEVEXP-564 Using CMA to retrieve forest details
Allows for deploying databases much more quickly by getting all forest details in a single request as opposed to one request per forest via /manage/v2. Any issue results in /manage/v2 being used instead. A simple test was added for this, but the method is being tested by dozens of existing tests - i.e. any test that involves deploying a database is hitting this. There's no actual change in functionality too - it's purely a performance optimization.
1 parent 18768e2 commit 65f5522

File tree

4 files changed

+320
-187
lines changed

4 files changed

+320
-187
lines changed

src/main/java/com/marklogic/appdeployer/command/databases/DeployOtherDatabasesCommand.java

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,22 @@
3434
import com.marklogic.mgmt.mapper.DefaultResourceMapper;
3535
import com.marklogic.mgmt.mapper.ResourceMapper;
3636
import com.marklogic.mgmt.resource.databases.DatabaseManager;
37+
import com.marklogic.mgmt.resource.forests.ForestManager;
3738
import com.marklogic.mgmt.util.ObjectMapperFactory;
3839
import com.marklogic.rest.util.JsonNodeUtil;
3940

4041
import java.io.File;
4142
import java.io.FilenameFilter;
4243
import java.io.IOException;
43-
import java.util.*;
44+
import java.util.ArrayList;
45+
import java.util.Collections;
46+
import java.util.HashMap;
47+
import java.util.HashSet;
48+
import java.util.LinkedHashMap;
49+
import java.util.List;
50+
import java.util.Map;
51+
import java.util.Set;
52+
import java.util.stream.Collectors;
4453

4554
/**
4655
* As of release 3.14.0, this now handles all databases, not just "databases other than the default content database".
@@ -161,7 +170,7 @@ public void undo(CommandContext context) {
161170
/**
162171
* If no database files are found, may still need to delete the content database in case no file exists for it.
163172
* That's because the command for creating a REST API server will not delete the content database by default.
164-
*
173+
* <p>
165174
* Per ticket #404, this will now do a check to see if the default content database filename is ignored. If so,
166175
* and there are no database files found, then the content database will not be deleted.
167176
*
@@ -392,6 +401,8 @@ protected void buildDeployDatabaseCommands(CommandContext context, List<Database
392401
* @param databasePlans
393402
*/
394403
protected void deployDatabasesAndForestsViaCma(CommandContext context, List<DatabasePlan> databasePlans) {
404+
addForestMapToCommandContext(context, databasePlans);
405+
395406
Configuration dbConfig = new Configuration();
396407
// Forests must be included in a separate configuration object
397408
Configuration forestConfig = new Configuration();
@@ -415,6 +426,28 @@ protected void deployDatabasesAndForestsViaCma(CommandContext context, List<Data
415426
});
416427
}
417428

429+
/**
430+
* Added to greatly speed up performance when getting details about all the existing primary forests for each
431+
* database referenced by a plan. In the event that anything fails, the map won't be added to the command context
432+
* and any code expecting to use the map will just have to fall back to use /manage/v2.
433+
*
434+
* @param context
435+
* @param databasePlans
436+
*/
437+
private void addForestMapToCommandContext(CommandContext context, List<DatabasePlan> databasePlans) {
438+
try {
439+
Set<String> dbNames = databasePlans.stream().map(plan -> plan.getDatabaseName()).collect(Collectors.toSet());
440+
logger.info("Retrieving all forest details via CMA");
441+
long start = System.currentTimeMillis();
442+
Map<String, List<Forest>> forestMap = new ForestManager(context.getManageClient()).getPrimaryForestsForDatabases(dbNames.toArray(new String[]{}));
443+
logger.info("Finished retrieving all forests details via CMA; duration: " + (System.currentTimeMillis() - start));
444+
context.getContextMap().put("ml-app-deployer-forestMap", forestMap);
445+
} catch (Exception ex) {
446+
logger.warn("Unable to retrieve all forest details, cause: " + ex.getMessage() + "; will fall back to " +
447+
"using /manage/v2 when needed for getting details for a forest.");
448+
}
449+
}
450+
418451
/**
419452
* Each DatabasePlan is expected to have constructed a DeployForestCommand, but not executed it. Each
420453
* DeployForestCommand can then be used to build a list of forests. All of those forests can be combined into a

src/main/java/com/marklogic/appdeployer/command/forests/DeployForestsCommand.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,25 @@ protected void createForestsViaForestEndpoint(CommandContext context, List<Fores
128128
*/
129129
public List<Forest> buildForests(CommandContext context, boolean includeReplicas) {
130130
// Need to know what primary forests exist already in case more need to be added, or a new host has been added
131-
List<Forest> existingPrimaryForests = getExistingPrimaryForests(context, this.databaseName);
131+
List<Forest> existingPrimaryForests = null;
132+
133+
// As of 4.5.3, if CMA is enabled, then the context should contain a map of all the forests for each database
134+
// being deployed. If it's not there, then /manage/v2 will be used instead.
135+
if (context.getAppConfig().getCmaConfig().isDeployForests()) {
136+
Map<String, List<Forest>> map = (Map<String, List<Forest>>) context.getContextMap().get("ml-app-deployer-forestMap");
137+
if (map != null && map.containsKey(this.databaseName)) {
138+
existingPrimaryForests = map.get(this.databaseName);
139+
}
140+
}
141+
142+
if (existingPrimaryForests == null) {
143+
existingPrimaryForests = getExistingPrimaryForests(context, this.databaseName);
144+
}
145+
132146
return buildForests(context, includeReplicas, existingPrimaryForests);
133147
}
134148

135149
/**
136-
*
137150
* @param context
138151
* @param includeReplicas
139152
* @param existingPrimaryForests
@@ -163,6 +176,14 @@ protected List<Forest> buildForests(CommandContext context, boolean includeRepli
163176
return forestBuilder.buildForests(forestPlan, context.getAppConfig());
164177
}
165178

179+
/**
180+
* @param context
181+
* @param databaseName
182+
* @return
183+
* @deprecated in 4.5.3, as getting forest details one at a time can be very slow for applications with a large
184+
* number of forests.
185+
*/
186+
@Deprecated
166187
protected List<Forest> getExistingPrimaryForests(CommandContext context, String databaseName) {
167188
List<String> forestIds = new DatabaseManager(context.getManageClient()).getPrimaryForestIds(databaseName);
168189
ForestManager forestMgr = new ForestManager(context.getManageClient());
@@ -259,6 +280,7 @@ public boolean isCreateForestsOnEachHost() {
259280

260281
/**
261282
* Use appConfig.setDatabasesWithForestsOnOneHost
283+
*
262284
* @param createForestsOnEachHost
263285
*/
264286
@Deprecated

0 commit comments

Comments
 (0)