You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by be...@apache.org on 2011/06/05 07:43:01 UTC

svn commit: r1131871 - in /incubator/mesos/trunk: ./ src/ src/tests/ src/tests/external/LxcIsolation/

Author: benh
Date: Sun Jun  5 05:43:01 2011
New Revision: 1131871

URL: http://svn.apache.org/viewvc?rev=1131871&view=rev
Log:
Finished work on the scheduled_memhog and added some unit tests that use
it to test the LXC isolation module. Also fixed some build errors that
were introduced in a commit in master.

Added:
    incubator/mesos/trunk/src/tests/external/LxcIsolation/
    incubator/mesos/trunk/src/tests/external/LxcIsolation/HoldMoreMemThanRequested.sh   (with props)
    incubator/mesos/trunk/src/tests/external/LxcIsolation/ScaleUpAndDown.sh   (with props)
    incubator/mesos/trunk/src/tests/external/LxcIsolation/TwoSeparateTasks.sh   (with props)
    incubator/mesos/trunk/src/tests/external/LxcIsolation/run_scheduled_memhog_test.sh
    incubator/mesos/trunk/src/tests/test_lxc_isolation.cpp
Modified:
    incubator/mesos/trunk/.gitignore
    incubator/mesos/trunk/src/Makefile.in
    incubator/mesos/trunk/src/lxc_isolation_module.hpp
    incubator/mesos/trunk/src/memhog_executor.cpp
    incubator/mesos/trunk/src/scheduled_memhog.cpp
    incubator/mesos/trunk/src/tests/external_test.cpp

Modified: incubator/mesos/trunk/.gitignore
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/.gitignore?rev=1131871&r1=1131870&r2=1131871&view=diff
==============================================================================
--- incubator/mesos/trunk/.gitignore (original)
+++ incubator/mesos/trunk/.gitignore Sun Jun  5 05:43:01 2011
@@ -78,6 +78,7 @@ src/memhog
 src/memhog-executor
 src/test-framework
 src/test-executor
+src/scheduled-memhog
 src/swig/java/nexus
 src/swig/python/nexus.py
 src/test_output

Modified: incubator/mesos/trunk/src/Makefile.in
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/Makefile.in?rev=1131871&r1=1131870&r2=1131871&view=diff
==============================================================================
--- incubator/mesos/trunk/src/Makefile.in (original)
+++ incubator/mesos/trunk/src/Makefile.in Sun Jun  5 05:43:01 2011
@@ -93,7 +93,7 @@ LIBS += -lglog -lgtest -lprocess -lev -l
 
 NEXUS_EXES = nexus-master nexus-slave nexus-local nexus-launcher \
 	     test-framework test-executor cpp-test-framework cpp-test-executor \
-	     memhog memhog-executor
+	     memhog memhog-executor scheduled-memhog
 
 ifeq ($(OS_NAME),solaris)
   NEXUS_EXES += nexus-projd
@@ -108,15 +108,14 @@ NEXUS_LIB = libnexus++.a
 NEXUS_LIBS = $(SCHED_LIB) $(EXEC_LIB) $(NEXUS_LIB)
 
 MASTER_OBJ = master.o allocator_factory.o simple_allocator.o
-SLAVE_OBJ = slave.o launcher.o isolation_module_factory.o \
+SLAVE_OBJ = slave.o launcher.o isolation_module.o \
 	    process_based_isolation_module.o
-COMMON_OBJ = fatal.o hash_pid.o messages.o lock.o master_detector.o \
-	     url_processor.o zookeeper.o configuration.o
+COMMON_OBJ = fatal.o hash_pid.o messages.o lock.o master_detector.o url_processor.o zookeeper.o
 EXEC_LIB_OBJ = nexus_exec.o
 SCHED_LIB_OBJ = nexus_sched.o nexus_local.o params.o
 TEST_OBJ = tests/main.o tests/test_master.o tests/test_resources.o \
 	   tests/external_test.o tests/test_sample_frameworks.o \
-	   tests/testing_utils.o tests/test_configuration.o
+	   tests/test_lxc_isolation.o
 
 ifeq ($(OS_NAME),solaris)
   SLAVE_OBJ += solaris_project_isolation_module.o
@@ -226,6 +225,9 @@ memhog: memhog.cpp $(NEXUS_LIB) third_pa
 memhog-executor: memhog_executor.cpp $(NEXUS_LIB) third_party/libprocess/libprocess.a
 	$(CXX) $(CXXFLAGS) -o $@ $< -L. $(LDFLAGS) -lnexus++ $(LIBS) 
 
+scheduled-memhog: scheduled_memhog.cpp $(NEXUS_LIB) third_party/libprocess/libprocess.a
+	$(CXX) $(CXXFLAGS) -o $@ $< -L. $(LDFLAGS) -lnexus++ $(LIBS) 
+
 java: $(JAVA_LIB) swig/java/nexus.jar swig/java/TestFramework.class swig/java/TestExecutor.class swig/java/TestExceptionFramework.class swig/java/TestExceptionExecutor.class
 
 python: $(PYTHON_LIB)

Modified: incubator/mesos/trunk/src/lxc_isolation_module.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/lxc_isolation_module.hpp?rev=1131871&r1=1131870&r2=1131871&view=diff
==============================================================================
--- incubator/mesos/trunk/src/lxc_isolation_module.hpp (original)
+++ incubator/mesos/trunk/src/lxc_isolation_module.hpp Sun Jun  5 05:43:01 2011
@@ -6,6 +6,8 @@
 #include <boost/unordered_map.hpp>
 
 #include "isolation_module.hpp"
+#include "messages.hpp"
+#include "slave.hpp"
 
 namespace nexus { namespace internal { namespace slave {
 

Modified: incubator/mesos/trunk/src/memhog_executor.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/memhog_executor.cpp?rev=1131871&r1=1131870&r2=1131871&view=diff
==============================================================================
--- incubator/mesos/trunk/src/memhog_executor.cpp (original)
+++ incubator/mesos/trunk/src/memhog_executor.cpp Sun Jun  5 05:43:01 2011
@@ -83,7 +83,7 @@ void* runTask(void* threadArg)
     pos = nextRand(pos);
     data[pos % arg->memToHog] = pos;
     count++;
-    if (count == 5000) {
+    if (count == 2000) {
       // Check whether enough time has elapsed to end the task
       count = 0;
       time_t now = time(0);

Modified: incubator/mesos/trunk/src/scheduled_memhog.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/scheduled_memhog.cpp?rev=1131871&r1=1131870&r2=1131871&view=diff
==============================================================================
--- incubator/mesos/trunk/src/scheduled_memhog.cpp (original)
+++ incubator/mesos/trunk/src/scheduled_memhog.cpp Sun Jun  5 05:43:01 2011
@@ -1,5 +1,9 @@
 #include <nexus_sched.hpp>
 
+#include <libgen.h>
+#include <stdlib.h>
+#include <unistd.h>
+
 #include <algorithm>
 #include <cstdlib>
 #include <iostream>
@@ -9,6 +13,8 @@
 #include <boost/lexical_cast.hpp>
 #include <boost/unordered_map.hpp>
 
+#include <glog/logging.h>
+
 #include "foreach.hpp"
 
 using namespace std;
@@ -22,9 +28,13 @@ struct Task {
   double duration;
   bool launched;
   bool finished;
+  int64_t memToRequest;
+  int64_t memToHog;
 
-  Task(double launchTime_, double duration_)
+  Task(double launchTime_, double duration_,
+       int64_t memToRequest_, int64_t memToHog_)
     : launchTime(launchTime_), duration(duration_),
+      memToRequest(memToRequest_), memToHog(memToHog_),
       launched(0), finished(0) {}
 };
 
@@ -39,32 +49,40 @@ struct TaskComparator
 
 class MyScheduler : public Scheduler
 {
+public:
   string executor;
   double taskLen;
   int threadsPerTask;
-  int64_t memToRequest;
-  int64_t memToHog;
   string scheduleFile;
   vector<Task> tasks;
   time_t startTime;
   int tasksLaunched;
   int tasksFinished;
+  int successfulTasks;
 
-public:
   MyScheduler(const string& executor_, const string& scheduleFile_,
-      int threadsPerTask_, int64_t memToRequest_, int64_t memToHog_)
+              int threadsPerTask_)
     : executor(executor_), scheduleFile(scheduleFile_),
       threadsPerTask(threadsPerTask_),
-      memToRequest(memToRequest_), memToHog(memToHog_),
-      tasksLaunched(0), tasksFinished(0)
+      tasksLaunched(0), tasksFinished(0), successfulTasks(0)
   {
     ifstream in(scheduleFile.c_str());
     double launchTime;
     double duration;
-    while (in >> launchTime >> duration) {
-      tasks.push_back(Task(launchTime, duration));
+    int64_t memToRequest;
+    int64_t memToHog;
+    while (in >> launchTime >> duration >> memToRequest >> memToHog) {
+      memToRequest *= (1024 * 1024);
+      memToHog *= (1024 * 1024);
+      tasks.push_back(Task(launchTime, duration, memToRequest, memToHog));
     }
     in.close();
+    LOG(INFO) << "Loaded " << tasks.size() << " tasks";
+    if (tasks.size() == 0) {
+      cerr << "Schedule file contained no tasks!" << endl;
+      exit(1);
+    }
+    // Sort tasks by start time
     TaskComparator comp;
     sort(tasks.begin(), tasks.end(), comp);
   }
@@ -80,7 +98,7 @@ public:
   }
 
   virtual void registered(SchedulerDriver*, FrameworkID fid) {
-    cout << "Registered!" << endl;
+    LOG(INFO) << "Registered!";
     startTime = time(0);
   }
 
@@ -94,15 +112,19 @@ public:
       // This is kind of ugly because operator[] isn't a const function
       int32_t cpus = lexical_cast<int32_t>(offer.params.find("cpus")->second);
       int64_t mem = lexical_cast<int64_t>(offer.params.find("mem")->second);
-      if ((tasksLaunched < tasks.size()) && (cpus >= 1 && mem >= memToRequest) &&
-          curTime >= tasks[tasksLaunched].launchTime) {
+      if (tasksLaunched < tasks.size() &&
+          cpus >= 1 &&
+          curTime >= tasks[tasksLaunched].launchTime &&
+          mem >= tasks[tasksLaunched].memToRequest)
+      {
         TaskID tid = tasksLaunched++;
-        cout << "Launcing task " << tid << " on " << offer.host << endl;
+        LOG(INFO) << "Launcing task " << tid << " on " << offer.host;
         map<string, string> params;
         params["cpus"] = "1";
-        params["mem"] = lexical_cast<string>(memToRequest);
+        params["mem"] = lexical_cast<string>(tasks[tid].memToRequest);
         ostringstream arg;
-        arg << memToHog << " " << tasks[tid].duration << " " << threadsPerTask;
+        arg << tasks[tid].memToHog << " " << tasks[tid].duration
+            << " " << threadsPerTask;
         TaskDescription desc(tid, offer.slaveId, "task", params, arg.str());
         toLaunch.push_back(desc);
       }
@@ -112,11 +134,14 @@ public:
   }
 
   virtual void statusUpdate(SchedulerDriver* d, const TaskStatus& status) {
-    cout << "Task " << status.taskId << " is in state " << status.state << endl;
+    LOG(INFO) << "Task " << status.taskId << " is in state " << status.state;
     if (status.state == TASK_FINISHED || status.state == TASK_FAILED ||
         status.state == TASK_KILLED || status.state == TASK_LOST) {
       tasks[status.taskId].finished = true;
       tasksFinished++;
+      if (status.state == TASK_FINISHED) {
+        successfulTasks++;
+      }
       if (tasksFinished == tasks.size()) {
         d->stop();
       }
@@ -126,21 +151,15 @@ public:
 
 
 int main(int argc, char ** argv) {
-  if (argc != 6) {
-    cerr << "Usage: " << argv[0]
-         << " <master> <schedule_file> <threads_per_task>"
-         << " <MB_to_request> <MB_per_task>" << endl;
+  if (argc != 3) {
+    cerr << "Usage: " << argv[0] << " <master> <schedule_file>";
     return -1;
   }
-  char cwd[512];
-  getcwd(cwd, sizeof(cwd));
-  string executor = string(cwd) + "/memhog-executor";
-  MyScheduler sched(executor,
-                    argv[2],
-                    lexical_cast<int>(argv[3]),
-                    lexical_cast<int64_t>(argv[4]) * 1024 * 1024,
-                    lexical_cast<int64_t>(argv[5]) * 1024 * 1024);
+  char buf[4096];
+  realpath(dirname(argv[0]), buf);
+  string executor = string(buf) + "/memhog-executor";
+  MyScheduler sched(executor, argv[2], 1);
   NexusSchedulerDriver driver(&sched, argv[1]);
   driver.run();
-  return 0;
+  return (sched.successfulTasks == sched.tasks.size()) ? 0 : 1;
 }

Added: incubator/mesos/trunk/src/tests/external/LxcIsolation/HoldMoreMemThanRequested.sh
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/external/LxcIsolation/HoldMoreMemThanRequested.sh?rev=1131871&view=auto
==============================================================================
--- incubator/mesos/trunk/src/tests/external/LxcIsolation/HoldMoreMemThanRequested.sh (added)
+++ incubator/mesos/trunk/src/tests/external/LxcIsolation/HoldMoreMemThanRequested.sh Sun Jun  5 05:43:01 2011
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# Create scheduled-memhog's schedule file. In this schedule, we launch two
+# tasks that each claim to require 200 MB, but the first task only uses 50 MB
+# while the second uses 350. While both tasks are running, this is fine, but
+# once the first task finishes, the framework's memory can't be scaled down
+# below 350 and so the LXC isolation module should kill it.
+echo "
+0 10 200 50
+0 30 200 350
+" > schedule
+
+# Expect exit code 1 (returned by scheduled-memhog if some of its tasks fail)
+export DESIRED_MEMHOG_EXIT_CODE=1
+
+# Exec run_scheduled_memhog_test.sh, which actually runs the test and reports
+# whether memhog gave the desired exit status through its exit status
+exec $MESOS_HOME/tests/external/LxcIsolation/run_scheduled_memhog_test.sh

Propchange: incubator/mesos/trunk/src/tests/external/LxcIsolation/HoldMoreMemThanRequested.sh
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/mesos/trunk/src/tests/external/LxcIsolation/ScaleUpAndDown.sh
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/external/LxcIsolation/ScaleUpAndDown.sh?rev=1131871&view=auto
==============================================================================
--- incubator/mesos/trunk/src/tests/external/LxcIsolation/ScaleUpAndDown.sh (added)
+++ incubator/mesos/trunk/src/tests/external/LxcIsolation/ScaleUpAndDown.sh Sun Jun  5 05:43:01 2011
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# Create scheduled-memhog's schedule file
+echo "
+0 30 200 200
+10 10 200 200
+" > schedule
+
+export DESIRED_MEMHOG_EXIT_CODE=0
+
+# Exec run_scheduled_memhog_test.sh, which actually runs the test and reports
+# whether memhog gave the desired exit status through its exit status
+exec $MESOS_HOME/tests/external/LxcIsolation/run_scheduled_memhog_test.sh

Propchange: incubator/mesos/trunk/src/tests/external/LxcIsolation/ScaleUpAndDown.sh
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/mesos/trunk/src/tests/external/LxcIsolation/TwoSeparateTasks.sh
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/external/LxcIsolation/TwoSeparateTasks.sh?rev=1131871&view=auto
==============================================================================
--- incubator/mesos/trunk/src/tests/external/LxcIsolation/TwoSeparateTasks.sh (added)
+++ incubator/mesos/trunk/src/tests/external/LxcIsolation/TwoSeparateTasks.sh Sun Jun  5 05:43:01 2011
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# Create scheduled-memhog's schedule file
+echo "
+0 5 200 200
+10 5 200 200
+" > schedule
+
+export DESIRED_MEMHOG_EXIT_CODE=0
+
+# Exec run_scheduled_memhog_test.sh, which actually runs the test and reports
+# whether memhog gave the desired exit status through its exit status
+exec $MESOS_HOME/tests/external/LxcIsolation/run_scheduled_memhog_test.sh

Propchange: incubator/mesos/trunk/src/tests/external/LxcIsolation/TwoSeparateTasks.sh
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/mesos/trunk/src/tests/external/LxcIsolation/run_scheduled_memhog_test.sh
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/external/LxcIsolation/run_scheduled_memhog_test.sh?rev=1131871&view=auto
==============================================================================
--- incubator/mesos/trunk/src/tests/external/LxcIsolation/run_scheduled_memhog_test.sh (added)
+++ incubator/mesos/trunk/src/tests/external/LxcIsolation/run_scheduled_memhog_test.sh Sun Jun  5 05:43:01 2011
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+# This script runs scheduled-memhog with the schedule file in ./schedule on a
+# cluster using Linux Containers isolation, and checks if it returns
+# $DESIRED_MEMHOG_EXIT_CODE (set through the # environment).
+# It is invoked by the actual tests (TwoSeparateTasks.sh, etc) after creating
+# the schedule file and setting DESIRED_MEMHOG_EXIT_CODE.
+
+# Check that we're running as root
+if [[ $EUID -ne 0 ]]; then
+  echo "This test must be run as root because it uses Linux Containers." >&2
+  exit 2
+fi
+
+# Launch master
+$MESOS_HOME/nexus-master -p 5432 > master.log 2>&1 &
+MASTER_PID=$!
+echo "Launched master, PID = $MASTER_PID"
+sleep 2
+
+# Check if it's still running after 2 seconds
+kill -0 $MASTER_PID
+KILL_EXIT_CODE=$?
+if [[ $KILL_EXIT_CODE -ne 0 ]]; then
+  echo "Master crashed; failing test"
+  exit 2
+fi
+
+# Launch slave
+$MESOS_HOME/nexus-slave -u 1@$HOSTNAME:5432 -i lxc \
+                        -c 2 -m $[512*1024*1024] > slave.log 2>&1 &
+SLAVE_PID=$!
+echo "Launched slave, PID = $SLAVE_PID"
+sleep 2
+
+# Check if it's still running after 2 seconds
+kill -0 $SLAVE_PID
+KILL_EXIT_CODE=$?
+if [[ $KILL_EXIT_CODE -ne 0 ]]; then
+  echo "Slave crashed; failing test"
+  kill $MASTER_PID
+  exit 2
+fi
+
+# Launch memhog
+echo "Running scheduled-memhog"
+$MESOS_HOME/scheduled-memhog 1@$HOSTNAME:5432 schedule > memhog.log 2>&1
+EXIT_CODE=$?
+echo "Memhog exit code: $?"
+sleep 2
+
+# Kill everything once memhog exited
+echo "Killing slave: $SLAVE_PID"
+kill $SLAVE_PID
+sleep 2
+echo "Killing master: $MASTER_PID"
+kill $MASTER_PID
+sleep 2
+
+echo "Exiting"
+# Check whether memhog returned the right code
+if [[ $EXIT_CODE -eq $DESIRED_MEMHOG_EXIT_CODE ]]; then
+  exit 0
+else
+  exit 1
+fi

Modified: incubator/mesos/trunk/src/tests/external_test.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/external_test.cpp?rev=1131871&r1=1131870&r2=1131871&view=diff
==============================================================================
--- incubator/mesos/trunk/src/tests/external_test.cpp (original)
+++ incubator/mesos/trunk/src/tests/external_test.cpp Sun Jun  5 05:43:01 2011
@@ -1,5 +1,6 @@
 #include <gtest/gtest.h>
 
+#include <ctype.h>
 #include <stdlib.h>
 
 #include <string>
@@ -11,7 +12,21 @@
 #include "testing_utils.hpp"
 
 using std::string;
-using namespace nexus::internal::test;
+
+namespace {
+
+// Check that a test name contains only letters, numbers and underscores, to
+// prevent messing with directories outside test_output in runExternalTest.
+bool isValidTestName(const char* name) {
+  for (const char* p = name; *p != 0; p++) {
+    if (!isalnum(*p) && *p != '_') {
+      return false;
+    }
+  }
+  return true;
+}
+
+}
 
 
 /**
@@ -21,14 +36,25 @@ using namespace nexus::internal::test;
  * piping its output to files called stdout and stderr, and the test
  * passes if the script returns 0.
  */
-void nexus::internal::test::runExternalTest(const char* testCase,
-                                            const char* testName)
+void nexus::test::runExternalTest(const char* testCase, const char* testName)
 {
-  // Create and go into the test's work directory
-  enterTestDirectory(testCase, testName);
+  // Remove DISABLED_ prefix from test name if this is a disabled test
+  if (strncmp(testName, "DISABLED_", strlen("DISABLED_")) == 0)
+    testName += strlen("DISABLED_");
+  // Check that the test name is valid
+  if (!isValidTestName(testCase) || !isValidTestName(testName)) {
+    FAIL() << "Invalid test name for external test (name should " 
+           << "only contain alphanumeric and underscore characters)";
+  }
   // Figure out the absolute path to the test script
-  string script = mesosHome + "/tests/external/" + testCase
+  string script = MESOS_HOME + "/tests/external/" + testCase
                              + "/" + testName + ".sh";
+  // Make the work directory for this test
+  string workDir = MESOS_HOME + "/test_output/" + testCase + "/" + testName;
+  string command = "rm -fr '" + workDir + "'";
+  ASSERT_EQ(0, system(command.c_str())) << "Command failed: " << command;
+  command = "mkdir -p '" + workDir + "'";
+  ASSERT_EQ(0, system(command.c_str())) << "Command failed: " << command;
   // Fork a process to change directory and run the test
   pid_t pid;
   if ((pid = fork()) == -1) {
@@ -40,13 +66,14 @@ void nexus::internal::test::runExternalT
     wait(&exitCode);
     ASSERT_EQ(0, exitCode) << "External test " << testName << " failed";
   } else {
-    // In child process. Redirect standard output and error to files,
+    // In child process. Go into to the work directory, redirect IO to files,
     // set MESOS_HOME environment variable, and exec the test script.
+    chdir(workDir.c_str());
     if (freopen("stdout", "w", stdout) == NULL)
       fatalerror("freopen failed");
     if (freopen("stderr", "w", stderr) == NULL)
       fatalerror("freopen failed");
-    setenv("MESOS_HOME", mesosHome.c_str(), 1);
+    setenv("MESOS_HOME", MESOS_HOME.c_str(), 1);
     execl(script.c_str(), script.c_str(), (char*) NULL);
     // If we get here, execl failed; report the error
     fatalerror("Could not execute %s", script.c_str());

Added: incubator/mesos/trunk/src/tests/test_lxc_isolation.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/test_lxc_isolation.cpp?rev=1131871&view=auto
==============================================================================
--- incubator/mesos/trunk/src/tests/test_lxc_isolation.cpp (added)
+++ incubator/mesos/trunk/src/tests/test_lxc_isolation.cpp Sun Jun  5 05:43:01 2011
@@ -0,0 +1,12 @@
+#include <gtest/gtest.h>
+
+#include "external_test.hpp"
+
+// Run a number of tests for the LXC isolation module.
+// These tests are disabled by default since they require alltests to be run
+// with sudo for Linux Container commands to be usable (and of course, they
+// also require a Linux version with LXC support).
+// You can enable them using ./alltests --gtest_also_run_disabled_tests.
+TEST_EXTERNAL(LxcIsolation, DISABLED_TwoSeparateTasks)
+TEST_EXTERNAL(LxcIsolation, DISABLED_ScaleUpAndDown)
+TEST_EXTERNAL(LxcIsolation, DISABLED_HoldMoreMemThanRequested)