Commit 694520eb by Bridger Maxwell

StudentModuleCache now allows a list of descriptors. This speeds up grading significantly.

parent 854508b0
...@@ -501,11 +501,11 @@ class XModuleDescriptor(Plugin, HTMLSnippet): ...@@ -501,11 +501,11 @@ class XModuleDescriptor(Plugin, HTMLSnippet):
all(getattr(self, attr, None) == getattr(other, attr, None) all(getattr(self, attr, None) == getattr(other, attr, None)
for attr in self.equality_attributes)) for attr in self.equality_attributes))
if not eq: # if not eq:
for attr in self.equality_attributes: # for attr in self.equality_attributes:
print(getattr(self, attr, None), # print(getattr(self, attr, None),
getattr(other, attr, None), # getattr(other, attr, None),
getattr(self, attr, None) == getattr(other, attr, None)) # getattr(self, attr, None) == getattr(other, attr, None))
return eq return eq
......
...@@ -20,6 +20,7 @@ def get_graded_sections(course_descriptor): ...@@ -20,6 +20,7 @@ def get_graded_sections(course_descriptor):
"section_descriptor" : The section descriptor "section_descriptor" : The section descriptor
"xmoduledescriptors" : An array of xmoduledescriptors that could possibly be in the section, for any student "xmoduledescriptors" : An array of xmoduledescriptors that could possibly be in the section, for any student
""" """
all_descriptors = []
graded_sections = {} graded_sections = {}
for c in course_descriptor.get_children(): for c in course_descriptor.get_children():
...@@ -36,7 +37,10 @@ def get_graded_sections(course_descriptor): ...@@ -36,7 +37,10 @@ def get_graded_sections(course_descriptor):
section_format = s.metadata.get('format', "") section_format = s.metadata.get('format', "")
graded_sections[ section_format ] = graded_sections.get( section_format, [] ) + [section_description] graded_sections[ section_format ] = graded_sections.get( section_format, [] ) + [section_description]
return graded_sections all_descriptors.extend(xmoduledescriptors)
all_descriptors.append(s)
return graded_sections, all_descriptors
def yield_descriptor_descendents(module_descriptor): def yield_descriptor_descendents(module_descriptor):
for child in module_descriptor.get_children(): for child in module_descriptor.get_children():
......
...@@ -67,17 +67,30 @@ class StudentModuleCache(object): ...@@ -67,17 +67,30 @@ class StudentModuleCache(object):
""" """
A cache of StudentModules for a specific student A cache of StudentModules for a specific student
""" """
def __init__(self, user, descriptor, depth=None): def __init__(self, user, descriptor=None, depth=None, descriptors=None, descriptor_filter=lambda descriptor: True):
''' '''
Find any StudentModule objects that are needed by any child modules of the Find any StudentModule objects that are needed by any child modules of the
supplied descriptor. Avoids making multiple queries to the database supplied descriptor, or caches only the StudentModule objects specifically
for every descriptor in descriptors. Avoids making multiple queries to the
database.
There are two ways to init:
descriptor: An XModuleDescriptor descriptor: An XModuleDescriptor
depth is the number of levels of descendent modules to load StudentModules for, in addition to depth is the number of levels of descendent modules to load StudentModules for, in addition to
the supplied descriptor. If depth is None, load all descendent StudentModules the supplied descriptor. If depth is None, load all descendent StudentModules
OR
descriptors: An array of XModuleDescriptors.
descriptor_filter is a function that accepts a descriptor and return wether the StudentModule
should be cached
''' '''
if user.is_authenticated(): if user.is_authenticated():
module_ids = self._get_module_state_keys(descriptor, depth) if not (descriptor == None) != (descriptors == None): #An xor on the descriptor and descriptors parameters.
raise ValueError("Either the descriptor or descriptors must be supplied to StudentModuleCache.")
if descriptor != None:
descriptors = self._get_child_descriptors(descriptor, depth)
module_ids = self._get_module_state_keys(descriptors, descriptor_filter)
# This works around a limitation in sqlite3 on the number of parameters # This works around a limitation in sqlite3 on the number of parameters
# that can be put into a single query # that can be put into a single query
...@@ -92,27 +105,39 @@ class StudentModuleCache(object): ...@@ -92,27 +105,39 @@ class StudentModuleCache(object):
else: else:
self.cache = [] self.cache = []
def _get_module_state_keys(self, descriptor, depth): def _get_child_descriptors(self, descriptor, depth):
"""
descriptor: An XModuleDescriptor
depth is the number of levels of descendent modules to load StudentModules for, in addition to
the supplied descriptor. If depth is None, load all descendent StudentModules
"""
descriptors = [descriptor]
if depth is None or depth > 0:
new_depth = depth - 1 if depth is not None else depth
for child in descriptor.get_children():
descriptors.extend(self._get_child_descriptors(child, new_depth))
return descriptors
def _get_module_state_keys(self, descriptors, descriptor_filter):
''' '''
Get a list of the state_keys needed for StudentModules Get a list of the state_keys needed for StudentModules
required for this module descriptor required for this module descriptor
descriptor: An XModuleDescriptor descriptor_filter is a function that accepts a descriptor and return wether the StudentModule
depth is the number of levels of descendent modules to load StudentModules for, in addition to should be cached
the supplied descriptor. If depth is None, load all descendent StudentModules
''' '''
keys = [descriptor.location.url()] keys = []
for descriptor in descriptors:
if descriptor_filter(descriptor):
keys.append(descriptor.location.url())
shared_state_key = getattr(descriptor, 'shared_state_key', None) shared_state_key = getattr(descriptor, 'shared_state_key', None)
if shared_state_key is not None: if shared_state_key is not None:
keys.append(shared_state_key) keys.append(shared_state_key)
if depth is None or depth > 0:
new_depth = depth - 1 if depth is not None else depth
for child in descriptor.get_children():
keys.extend(self._get_module_state_keys(child, new_depth))
return keys return keys
def lookup(self, module_type, module_state_key): def lookup(self, module_type, module_state_key):
......
...@@ -38,9 +38,8 @@ template_imports = {'urllib': urllib} ...@@ -38,9 +38,8 @@ template_imports = {'urllib': urllib}
def test_grading(request, course_id): def test_grading(request, course_id):
course = check_course(course_id) course = check_course(course_id)
sections = grades.get_graded_sections(course) sections, all_descriptors = grades.get_graded_sections(course)
student_module_cache = StudentModuleCache(request.user, descriptors=all_descriptors)
student_module_cache = StudentModuleCache(request.user, course)
grade_result = grades.fast_grade(request.user, request, sections, course.grader, student_module_cache) grade_result = grades.fast_grade(request.user, request, sections, course.grader, student_module_cache)
......
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