-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Add a 'MixedModuleStore' which aggregates between XML and Mongo Modulestores #496
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6f11b98
b5253b5
8298897
2616d8f
cff93d3
5298f54
fa61bdf
54bd317
9f14f1e
aa8b054
e4eea6c
52928d1
7bdc4c5
7a80a9c
9cc796d
5ee5bea
0b8866e
6121916
c6cde6a
ed584a9
cf715cb
bca2018
ae6f97a
13ff461
d1ce55f
1128f36
bd71a2c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -100,6 +100,16 @@ def convert_legacy_static_url(path, course_namespace): | |
| loc = StaticContent.compute_location(course_namespace.org, course_namespace.course, path) | ||
| return StaticContent.get_url_path_from_location(loc) | ||
|
|
||
| @staticmethod | ||
| def convert_legacy_static_url_with_course_id(path, course_id): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pls unit test.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| """ | ||
| Returns a path to a piece of static content when we are provided with a filepath and | ||
| a course_id | ||
| """ | ||
| org, course_num, __ = course_id.split("/") | ||
| loc = StaticContent.compute_location(org, course_num, path) | ||
| return StaticContent.get_url_path_from_location(loc) | ||
|
|
||
| def stream_data(self): | ||
| yield self._data | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,8 @@ | |
|
|
||
| log = logging.getLogger('mitx.' + 'modulestore') | ||
|
|
||
| MONGO_MODULESTORE_TYPE = 'mongo' | ||
| XML_MODULESTORE_TYPE = 'xml' | ||
|
|
||
| URL_RE = re.compile(""" | ||
| (?P<tag>[^:]+)://? | ||
|
|
@@ -258,7 +260,7 @@ class ModuleStore(object): | |
| An abstract interface for a database backend that stores XModuleDescriptor | ||
| instances | ||
| """ | ||
| def has_item(self, location): | ||
| def has_item(self, course_id, location): | ||
| """ | ||
| Returns True if location exists in this ModuleStore. | ||
| """ | ||
|
|
@@ -384,6 +386,20 @@ def get_errored_courses(self): | |
| """ | ||
| raise NotImplementedError | ||
|
|
||
| def set_modulestore_configuration(self, config_dict): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pythonically, this would probably just be written as a I don't think this should block the PR, but it would be nice to capture it as a cleanup task (or, if someone has time, to clean it up now). |
||
| ''' | ||
| Allows for runtime configuration of the modulestore. In particular this is how the | ||
| application (LMS/CMS) can pass down Django related configuration information, e.g. caches, etc. | ||
| ''' | ||
| raise NotImplementedError | ||
|
|
||
| def get_modulestore_type(self, course_id): | ||
| """ | ||
| Returns a type which identifies which modulestore is servicing the given | ||
| course_id. The return can be either "xml" (for XML based courses) or "mongo" for MongoDB backed courses | ||
| """ | ||
| raise NotImplementedError | ||
|
|
||
|
|
||
| class ModuleStoreBase(ModuleStore): | ||
| ''' | ||
|
|
@@ -394,7 +410,7 @@ def __init__(self): | |
| Set up the error-tracking logic. | ||
| ''' | ||
| self._location_errors = {} # location -> ErrorLog | ||
| self.metadata_inheritance_cache = None | ||
| self.modulestore_configuration = {} | ||
| self.modulestore_update_signal = None # can be set by runtime to route notifications of datastore changes | ||
|
|
||
| def _get_errorlog(self, location): | ||
|
|
@@ -439,6 +455,27 @@ def get_course(self, course_id): | |
| return c | ||
| return None | ||
|
|
||
| @property | ||
| def metadata_inheritance_cache_subsystem(self): | ||
| """ | ||
| Exposes an accessor to the runtime configuration for the metadata inheritance cache | ||
| """ | ||
| return self.modulestore_configuration.get('metadata_inheritance_cache_subsystem', None) | ||
|
|
||
| @property | ||
| def request_cache(self): | ||
| """ | ||
| Exposes an accessor to the runtime configuration for the request cache | ||
| """ | ||
| return self.modulestore_configuration.get('request_cache', None) | ||
|
|
||
| def set_modulestore_configuration(self, config_dict): | ||
| """ | ||
| This is the base implementation of the interface, all we need to do is store | ||
| two possible configurations as attributes on the class | ||
| """ | ||
| self.modulestore_configuration = config_dict | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this method even necessary? |
||
|
|
||
|
|
||
| def namedtuple_to_son(namedtuple, prefix=''): | ||
| """ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,24 +25,31 @@ def load_function(path): | |
| return getattr(import_module(module_path), name) | ||
|
|
||
|
|
||
| def modulestore(name='default'): | ||
| if name not in _MODULESTORES: | ||
| class_ = load_function(settings.MODULESTORE[name]['ENGINE']) | ||
| def create_modulestore_instance(engine, options): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method isn't covered by unit tests.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| """ | ||
| This will return a new instance of a modulestore given an engine and options | ||
| """ | ||
| class_ = load_function(engine) | ||
|
|
||
| options = {} | ||
| _options = {} | ||
| _options.update(options) | ||
|
|
||
| options.update(settings.MODULESTORE[name]['OPTIONS']) | ||
| for key in FUNCTION_KEYS: | ||
| if key in options: | ||
| options[key] = load_function(options[key]) | ||
| for key in FUNCTION_KEYS: | ||
| if key in _options and isinstance(_options[key], basestring): | ||
| _options[key] = load_function(_options[key]) | ||
|
|
||
| _MODULESTORES[name] = class_( | ||
| **options | ||
| ) | ||
| return class_( | ||
| **_options | ||
| ) | ||
|
|
||
| return _MODULESTORES[name] | ||
|
|
||
| # if 'DJANGO_SETTINGS_MODULE' in environ: | ||
| # # Initialize the modulestores immediately | ||
| # for store_name in settings.MODULESTORE: | ||
| # modulestore(store_name) | ||
| def modulestore(name='default'): | ||
| """ | ||
| This returns an instance of a modulestore of given name. This will wither return an existing | ||
| modulestore or create a new one | ||
| """ | ||
| if name not in _MODULESTORES: | ||
| _MODULESTORES[name] = create_modulestore_instance(settings.MODULESTORE[name]['ENGINE'], | ||
| settings.MODULESTORE[name]['OPTIONS']) | ||
|
|
||
| return _MODULESTORES[name] | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like it would be better to write this line as
'"{}"'.format(mock_static_content.convert_legacy_static_url_with_course_id())