Commit e3c66f55 by Kevin Falcone

Optimize memory and CPU usage.

The print_out_all_courses() routine consumes a ton of memory (2G and
causes noticable mongo usage spikes).  This actually causes other
processes on production boxes to be memory starved and killed
(such as worker children on edge when this was run recently).

The behavior of this script on production is
* Print several hundred courses
* Ask if you want to delete the one you specified
* print several hundred courses minus one
On a sandbox with 5 courses, you could tell by eye that 1 is gone, but
not in production (or even in stage).

The original PLAT-619 ticket for this suggested printing a course
listing on error, but instead it always printed the course listing.
Even in the error case, hundreds of course ids is confusing and obscures
the error message saying that your course_id is invalid.

You should be getting the course id from the UI or from ./manage.py lms
dump_course_ids, not by searching a list.

Adjusted the test accordingly

Remove get_courses_keys
parent 035bf4fb
...@@ -233,4 +233,5 @@ Dongwook Yoon <dy252@cornell.edu> ...@@ -233,4 +233,5 @@ Dongwook Yoon <dy252@cornell.edu>
Awais Qureshi <awais.qureshi@arbisoft.com> Awais Qureshi <awais.qureshi@arbisoft.com>
Eric Fischer <efischer@edx.org> Eric Fischer <efischer@edx.org>
Brian Beggs <macdiesel@gmail.com> Brian Beggs <macdiesel@gmail.com>
Bill DeRusha <bill@edx.org> Bill DeRusha <bill@edx.org>
\ No newline at end of file Kevin Falcone <kevin@edx.org>
...@@ -18,18 +18,6 @@ from xmodule.modulestore import ModuleStoreEnum ...@@ -18,18 +18,6 @@ from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
def print_out_all_courses():
"""
Print out all the courses available in the course_key format so that
the user can correct any course_key mistakes
"""
courses = modulestore().get_courses_keys()
print 'Available courses:'
for course in courses:
print str(course)
print ''
class Command(BaseCommand): class Command(BaseCommand):
""" """
Delete a MongoDB backed course Delete a MongoDB backed course
...@@ -58,8 +46,6 @@ class Command(BaseCommand): ...@@ -58,8 +46,6 @@ class Command(BaseCommand):
elif len(args) > 2: elif len(args) > 2:
raise CommandError("Too many arguments! Expected <course_key> <commit>") raise CommandError("Too many arguments! Expected <course_key> <commit>")
print_out_all_courses()
if not modulestore().get_course(course_key): if not modulestore().get_course(course_key):
raise CommandError("Course with '%s' key not found." % args[0]) raise CommandError("Course with '%s' key not found." % args[0])
...@@ -67,4 +53,4 @@ class Command(BaseCommand): ...@@ -67,4 +53,4 @@ class Command(BaseCommand):
if query_yes_no("Deleting course {0}. Confirm?".format(course_key), default="no"): if query_yes_no("Deleting course {0}. Confirm?".format(course_key), default="no"):
if query_yes_no("Are you sure. This action cannot be undone!", default="no"): if query_yes_no("Are you sure. This action cannot be undone!", default="no"):
delete_course_and_groups(course_key, ModuleStoreEnum.UserID.mgmt_command) delete_course_and_groups(course_key, ModuleStoreEnum.UserID.mgmt_command)
print_out_all_courses() print "Deleted course {}".format(course_key)
...@@ -5,6 +5,7 @@ Unittests for deleting a course in an chosen modulestore ...@@ -5,6 +5,7 @@ Unittests for deleting a course in an chosen modulestore
import unittest import unittest
import mock import mock
from opaque_keys.edx.locations import SlashSeparatedCourseKey
from django.core.management import CommandError from django.core.management import CommandError
from contentstore.management.commands.delete_course import Command # pylint: disable=import-error from contentstore.management.commands.delete_course import Command # pylint: disable=import-error
from contentstore.tests.utils import CourseTestCase # pylint: disable=import-error from contentstore.tests.utils import CourseTestCase # pylint: disable=import-error
...@@ -94,27 +95,23 @@ class DeleteCourseTest(CourseTestCase): ...@@ -94,27 +95,23 @@ class DeleteCourseTest(CourseTestCase):
run=course_run run=course_run
) )
def test_courses_keys_listing(self):
"""
Test if the command lists out available course key courses
"""
courses = [str(key) for key in modulestore().get_courses_keys()]
self.assertIn("TestX/TS01/2015_Q1", courses)
def test_course_key_not_found(self): def test_course_key_not_found(self):
""" """
Test for when a non-existing course key is entered Test for when a non-existing course key is entered
""" """
errstring = "Course with 'TestX/TS01/2015_Q7' key not found." errstring = "Course with 'TestX/TS01/2015_Q7' key not found."
with self.assertRaisesRegexp(CommandError, errstring): with self.assertRaisesRegexp(CommandError, errstring):
self.command.handle("TestX/TS01/2015_Q7", "commit") self.command.handle('TestX/TS01/2015_Q7', "commit")
def test_course_deleted(self): def test_course_deleted(self):
""" """
Testing if the entered course was deleted Testing if the entered course was deleted
""" """
#Test if the course that is about to be deleted exists
self.assertIsNotNone(modulestore().get_course(SlashSeparatedCourseKey("TestX", "TS01", "2015_Q1")))
with mock.patch(self.YESNO_PATCH_LOCATION) as patched_yes_no: with mock.patch(self.YESNO_PATCH_LOCATION) as patched_yes_no:
patched_yes_no.return_value = True patched_yes_no.return_value = True
self.command.handle("TestX/TS01/2015_Q1", "commit") self.command.handle('TestX/TS01/2015_Q1', "commit")
courses = [unicode(key) for key in modulestore().get_courses_keys()] self.assertIsNone(modulestore().get_course(SlashSeparatedCourseKey("TestX", "TS01", "2015_Q1")))
self.assertNotIn("TestX/TS01/2015_Q1", courses)
...@@ -281,21 +281,6 @@ class MixedModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase): ...@@ -281,21 +281,6 @@ class MixedModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase):
return courses.values() return courses.values()
@strip_key @strip_key
def get_courses_keys(self, **kwargs):
'''
Returns a list containing the top level XModuleDescriptors keys of the courses in this modulestore.
'''
courses = {}
for store in self.modulestores:
# filter out ones which were fetched from earlier stores but locations may not be ==
for course in store.get_courses(**kwargs):
course_id = self._clean_locator_for_mapping(course.id)
if course_id not in courses:
# course is indeed unique. save it in result
courses[course_id] = course
return courses.keys()
@strip_key
def get_libraries(self, **kwargs): def get_libraries(self, **kwargs):
""" """
Returns a list containing the top level XBlock of the libraries (LibraryRoot) in this modulestore. Returns a list containing the top level XBlock of the libraries (LibraryRoot) in this modulestore.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment