@@ -175,9 +175,12 @@ public void testSelectLeastLoadedMlNodeForAnomalyDetectorJob_maxCapacityMemoryLi
175175 int currentlyRunningJobsPerNode = randomIntBetween (1 , 100 );
176176 int maxRunningJobsPerNode = currentlyRunningJobsPerNode + 1 ;
177177 // Be careful if changing this - in order for the error message to be exactly as expected
178- // the value here must divide exactly into (JOB_MEMORY_REQUIREMENT.getBytes() * 100)
179- int maxMachineMemoryPercent = 40 ;
180- long machineMemory = currentlyRunningJobsPerNode * JOB_MEMORY_REQUIREMENT .getBytes () * 100 / maxMachineMemoryPercent ;
178+ // the value here must divide exactly into both (JOB_MEMORY_REQUIREMENT.getBytes() * 100) and
179+ // MachineLearning.NATIVE_EXECUTABLE_CODE_OVERHEAD.getBytes()
180+ int maxMachineMemoryPercent = 20 ;
181+ long currentlyRunningJobMemory = MachineLearning .NATIVE_EXECUTABLE_CODE_OVERHEAD .getBytes () +
182+ currentlyRunningJobsPerNode * JOB_MEMORY_REQUIREMENT .getBytes ();
183+ long machineMemory = currentlyRunningJobMemory * 100 / maxMachineMemoryPercent ;
181184
182185 Map <String , String > nodeAttr = new HashMap <>();
183186 nodeAttr .put (MachineLearning .MAX_OPEN_JOBS_NODE_ATTR , Integer .toString (maxRunningJobsPerNode ));
@@ -193,19 +196,46 @@ public void testSelectLeastLoadedMlNodeForAnomalyDetectorJob_maxCapacityMemoryLi
193196 jobNodeSelector .selectNode (maxRunningJobsPerNode , 2 , maxMachineMemoryPercent , isMemoryTrackerRecentlyRefreshed );
194197 assertNull (result .getExecutorNode ());
195198 assertThat (result .getExplanation (), containsString ("because this node has insufficient available memory. "
196- + "Available memory for ML [" + (machineMemory * maxMachineMemoryPercent / 100 ) + "], memory required by existing jobs ["
197- + (JOB_MEMORY_REQUIREMENT .getBytes () * currentlyRunningJobsPerNode ) + "], estimated memory required for this job ["
198- + JOB_MEMORY_REQUIREMENT .getBytes () + "]" ));
199+ + "Available memory for ML [" + currentlyRunningJobMemory + "], memory required by existing jobs ["
200+ + currentlyRunningJobMemory + "], estimated memory required for this job [" + JOB_MEMORY_REQUIREMENT .getBytes () + "]" ));
201+ }
202+
203+ public void testSelectLeastLoadedMlNodeForAnomalyDetectorJob_firstJobTooBigMemoryLimiting () {
204+ int numNodes = randomIntBetween (1 , 10 );
205+ int maxRunningJobsPerNode = randomIntBetween (1 , 100 );
206+ int maxMachineMemoryPercent = 20 ;
207+ long firstJobTotalMemory = MachineLearning .NATIVE_EXECUTABLE_CODE_OVERHEAD .getBytes () + JOB_MEMORY_REQUIREMENT .getBytes ();
208+ long machineMemory = (firstJobTotalMemory - 1 ) * 100 / maxMachineMemoryPercent ;
209+
210+ Map <String , String > nodeAttr = new HashMap <>();
211+ nodeAttr .put (MachineLearning .MAX_OPEN_JOBS_NODE_ATTR , Integer .toString (maxRunningJobsPerNode ));
212+ nodeAttr .put (MachineLearning .MACHINE_MEMORY_NODE_ATTR , Long .toString (machineMemory ));
213+
214+ ClusterState .Builder cs = fillNodesWithRunningJobs (nodeAttr , numNodes , 0 );
215+
216+ Job job = BaseMlIntegTestCase .createFareQuoteJob ("job_id1000" , JOB_MEMORY_REQUIREMENT ).build (new Date ());
217+
218+ JobNodeSelector jobNodeSelector = new JobNodeSelector (cs .build (), job .getId (), MlTasks .JOB_TASK_NAME , memoryTracker ,
219+ 0 , node -> TransportOpenJobAction .nodeFilter (node , job ));
220+ PersistentTasksCustomMetaData .Assignment result =
221+ jobNodeSelector .selectNode (maxRunningJobsPerNode , 2 , maxMachineMemoryPercent , isMemoryTrackerRecentlyRefreshed );
222+ assertNull (result .getExecutorNode ());
223+ assertThat (result .getExplanation (), containsString ("because this node has insufficient available memory. "
224+ + "Available memory for ML [" + (firstJobTotalMemory - 1 )
225+ + "], memory required by existing jobs [0], estimated memory required for this job [" + firstJobTotalMemory + "]" ));
199226 }
200227
201228 public void testSelectLeastLoadedMlNodeForDataFrameAnalyticsJob_maxCapacityMemoryLimiting () {
202229 int numNodes = randomIntBetween (1 , 10 );
203230 int currentlyRunningJobsPerNode = randomIntBetween (1 , 100 );
204231 int maxRunningJobsPerNode = currentlyRunningJobsPerNode + 1 ;
205232 // Be careful if changing this - in order for the error message to be exactly as expected
206- // the value here must divide exactly into (JOB_MEMORY_REQUIREMENT.getBytes() * 100)
207- int maxMachineMemoryPercent = 40 ;
208- long machineMemory = currentlyRunningJobsPerNode * JOB_MEMORY_REQUIREMENT .getBytes () * 100 / maxMachineMemoryPercent ;
233+ // the value here must divide exactly into both (JOB_MEMORY_REQUIREMENT.getBytes() * 100) and
234+ // MachineLearning.NATIVE_EXECUTABLE_CODE_OVERHEAD.getBytes()
235+ int maxMachineMemoryPercent = 20 ;
236+ long currentlyRunningJobMemory = MachineLearning .NATIVE_EXECUTABLE_CODE_OVERHEAD .getBytes () +
237+ currentlyRunningJobsPerNode * JOB_MEMORY_REQUIREMENT .getBytes ();
238+ long machineMemory = currentlyRunningJobMemory * 100 / maxMachineMemoryPercent ;
209239
210240 Map <String , String > nodeAttr = new HashMap <>();
211241 nodeAttr .put (MachineLearning .MAX_OPEN_JOBS_NODE_ATTR , Integer .toString (maxRunningJobsPerNode ));
@@ -222,9 +252,34 @@ public void testSelectLeastLoadedMlNodeForDataFrameAnalyticsJob_maxCapacityMemor
222252 jobNodeSelector .selectNode (maxRunningJobsPerNode , 2 , maxMachineMemoryPercent , isMemoryTrackerRecentlyRefreshed );
223253 assertNull (result .getExecutorNode ());
224254 assertThat (result .getExplanation (), containsString ("because this node has insufficient available memory. "
225- + "Available memory for ML [" + (machineMemory * maxMachineMemoryPercent / 100 ) + "], memory required by existing jobs ["
226- + (JOB_MEMORY_REQUIREMENT .getBytes () * currentlyRunningJobsPerNode ) + "], estimated memory required for this job ["
227- + JOB_MEMORY_REQUIREMENT .getBytes () + "]" ));
255+ + "Available memory for ML [" + currentlyRunningJobMemory + "], memory required by existing jobs ["
256+ + currentlyRunningJobMemory + "], estimated memory required for this job [" + JOB_MEMORY_REQUIREMENT .getBytes () + "]" ));
257+ }
258+
259+ public void testSelectLeastLoadedMlNodeForDataFrameAnalyticsJob_firstJobTooBigMemoryLimiting () {
260+ int numNodes = randomIntBetween (1 , 10 );
261+ int maxRunningJobsPerNode = randomIntBetween (1 , 100 );
262+ int maxMachineMemoryPercent = 20 ;
263+ long firstJobTotalMemory = MachineLearning .NATIVE_EXECUTABLE_CODE_OVERHEAD .getBytes () + JOB_MEMORY_REQUIREMENT .getBytes ();
264+ long machineMemory = (firstJobTotalMemory - 1 ) * 100 / maxMachineMemoryPercent ;
265+
266+ Map <String , String > nodeAttr = new HashMap <>();
267+ nodeAttr .put (MachineLearning .MAX_OPEN_JOBS_NODE_ATTR , Integer .toString (maxRunningJobsPerNode ));
268+ nodeAttr .put (MachineLearning .MACHINE_MEMORY_NODE_ATTR , Long .toString (machineMemory ));
269+
270+ ClusterState .Builder cs = fillNodesWithRunningJobs (nodeAttr , numNodes , 0 );
271+
272+ String dataFrameAnalyticsId = "data_frame_analytics_id1000" ;
273+
274+ JobNodeSelector jobNodeSelector = new JobNodeSelector (cs .build (), dataFrameAnalyticsId ,
275+ MlTasks .DATA_FRAME_ANALYTICS_TASK_NAME , memoryTracker , 0 ,
276+ node -> TransportStartDataFrameAnalyticsAction .TaskExecutor .nodeFilter (node , dataFrameAnalyticsId ));
277+ PersistentTasksCustomMetaData .Assignment result =
278+ jobNodeSelector .selectNode (maxRunningJobsPerNode , 2 , maxMachineMemoryPercent , isMemoryTrackerRecentlyRefreshed );
279+ assertNull (result .getExecutorNode ());
280+ assertThat (result .getExplanation (), containsString ("because this node has insufficient available memory. "
281+ + "Available memory for ML [" + (firstJobTotalMemory - 1 )
282+ + "], memory required by existing jobs [0], estimated memory required for this job [" + firstJobTotalMemory + "]" ));
228283 }
229284
230285 public void testSelectLeastLoadedMlNode_noMlNodes () {
0 commit comments