19
19
import com .marklogic .appdeployer .command .CommandContext ;
20
20
import com .marklogic .appdeployer .command .SortOrderConstants ;
21
21
import com .marklogic .mgmt .api .API ;
22
+ import com .marklogic .mgmt .api .configuration .Configuration ;
23
+ import com .marklogic .mgmt .api .configuration .Configurations ;
22
24
import com .marklogic .mgmt .api .forest .Forest ;
23
25
import com .marklogic .mgmt .mapper .DefaultResourceMapper ;
24
26
import com .marklogic .mgmt .mapper .ResourceMapper ;
28
30
import com .marklogic .mgmt .resource .groups .GroupManager ;
29
31
import com .marklogic .mgmt .resource .hosts .HostManager ;
30
32
31
- import java .util .*;
33
+ import java .util .ArrayList ;
34
+ import java .util .HashMap ;
35
+ import java .util .List ;
36
+ import java .util .Map ;
37
+ import java .util .stream .Collectors ;
32
38
33
39
/**
34
40
* Command for configuring - i.e. creating and setting - replica forests for existing databases.
@@ -131,19 +137,37 @@ protected void configureDatabaseReplicaForests(String databaseName, int replicaC
131
137
List <String > dataDirectories = forestBuilder .determineDataDirectories (databaseName , context .getAppConfig ());
132
138
forestBuilder .addReplicasToForests (forestsNeedingReplicas , forestPlan , context .getAppConfig (), dataDirectories );
133
139
134
- // TODO Use CMA here in the future? Need to test to see if a forest name + replicas are allowable
135
- ForestManager forestManager = new ForestManager (context .getManageClient ());
136
- for (Forest forest : forestsNeedingReplicas ) {
137
- final String forestName = forest .getForestName ();
138
-
140
+ List <Forest > forestsWithOnlyReplicas = forestsNeedingReplicas .stream ().map (forest -> {
139
141
Forest forestWithOnlyReplicas = new Forest ();
142
+ forestWithOnlyReplicas .setForestName (forest .getForestName ());
140
143
forestWithOnlyReplicas .setForestReplica (forest .getForestReplica ());
141
- String json = forestWithOnlyReplicas .getJson ();
144
+ return forestWithOnlyReplicas ;
145
+ }).collect (Collectors .toList ());
146
+
147
+ // As of 4.5.3, try CMA first so that this can be done in a single request instead of one request per forest.
148
+ if (context .getAppConfig ().getCmaConfig ().isDeployForests ()) {
149
+ try {
150
+ Configuration config = new Configuration ();
151
+ forestsWithOnlyReplicas .forEach (forest -> {
152
+ config .addForest (forest .toObjectNode ());
153
+ });
154
+ new Configurations (config ).submit (context .getManageClient ());
155
+ return ;
156
+ } catch (Exception ex ) {
157
+ logger .warn ("Unable to create forest replicas via CMA; cause: " + ex .getMessage () + "; will " +
158
+ "fall back to using /manage/v2." );
159
+ }
160
+ }
142
161
162
+ // If we get here, either CMA usage is disabled or an error occurred with CMA. Just use /manage/v2 to submit
163
+ // each forest one-by-one.
164
+ ForestManager forestManager = new ForestManager (context .getManageClient ());
165
+ forestsWithOnlyReplicas .forEach (forest -> {
166
+ String forestName = forest .getForestName ();
143
167
logger .info (format ("Creating forest replicas for primary forest %s" , forestName ));
144
- context .getManageClient ().putJson (forestManager .getPropertiesPath (forestName ), json );
168
+ context .getManageClient ().putJson (forestManager .getPropertiesPath (forestName ), forest . getJson () );
145
169
logger .info (format ("Finished creating forest replicas for primary forest %s" , forestName ));
146
- }
170
+ });
147
171
}
148
172
149
173
/**
@@ -161,22 +185,41 @@ protected List<Forest> determineForestsNeedingReplicas(String databaseName, Comm
161
185
ResourceMapper resourceMapper = new DefaultResourceMapper (api );
162
186
163
187
List <Forest > forestsNeedingReplicas = new ArrayList <>();
188
+ Map <String , List <Forest >> mapOfPrimaryForests = context .getMapOfPrimaryForests ();
164
189
165
- for (String forestName : dbMgr .getForestNames (databaseName )) {
166
- logger .info (format ("Checking the status of forest %s to determine if it is a primary forest and whether or not it has replicas already." , forestName ));
167
- ForestStatus status = forestManager .getForestStatus (forestName );
168
- if (!status .isPrimary ()) {
169
- logger .info (format ("Forest %s is not a primary forest, so not configuring replica forests" , forestName ));
170
- continue ;
171
- }
172
- if (status .hasReplicas ()) {
173
- logger .info (format ("Forest %s already has replicas, so not configuring replica forests" , forestName ));
174
- continue ;
175
- }
190
+ /**
191
+ * In both blocks below, a forest is not included if it already has replicas. This logic dates back to 2015,
192
+ * and is likely due to uncertainty over the various scenarios that can occur if a forest does already have
193
+ * replicas. At least as of August 2023, MarkLogic recommends a single replica per forest. Given that no users
194
+ * have asked for this check to not be performed and based on MarkLogic's recommendation, it seems reasonable
195
+ * to leave this check in for now. However, some ad hoc testing has indicated that this check is unnecessary
196
+ * and that it appears to safe to vary the number of replicas per forest. So it likely would be beneficial to
197
+ * remove this check at some point.
198
+ */
199
+ if (mapOfPrimaryForests != null && mapOfPrimaryForests .containsKey (databaseName )) {
200
+ mapOfPrimaryForests .get (databaseName ).forEach (forest -> {
201
+ boolean forestHasReplicasAlready = forest .getForestReplica () != null && !forest .getForestReplica ().isEmpty ();
202
+ if (!forestHasReplicasAlready ) {
203
+ forestsNeedingReplicas .add (forest );
204
+ }
205
+ });
206
+ } else {
207
+ for (String forestName : dbMgr .getForestNames (databaseName )) {
208
+ logger .info (format ("Checking the status of forest %s to determine if it is a primary forest and whether or not it has replicas already." , forestName ));
209
+ ForestStatus status = forestManager .getForestStatus (forestName );
210
+ if (!status .isPrimary ()) {
211
+ logger .info (format ("Forest %s is not a primary forest, so not configuring replica forests" , forestName ));
212
+ continue ;
213
+ }
214
+ if (status .hasReplicas ()) {
215
+ logger .info (format ("Forest %s already has replicas, so not configuring replica forests" , forestName ));
216
+ continue ;
217
+ }
176
218
177
- String forestJson = forestManager .getPropertiesAsJson (forestName );
178
- Forest forest = resourceMapper .readResource (forestJson , Forest .class );
179
- forestsNeedingReplicas .add (forest );
219
+ String forestJson = forestManager .getPropertiesAsJson (forestName );
220
+ Forest forest = resourceMapper .readResource (forestJson , Forest .class );
221
+ forestsNeedingReplicas .add (forest );
222
+ }
180
223
}
181
224
182
225
return forestsNeedingReplicas ;
0 commit comments