Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
cb113dea
Commit
cb113dea
authored
Oct 11, 2013
by
Don Mitchell
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Separate all db ops from modulestore ops
parent
bc4ebfdc
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
170 additions
and
113 deletions
+170
-113
common/lib/xmodule/xmodule/modulestore/split_migrator.py
+1
-1
common/lib/xmodule/xmodule/modulestore/split_mongo/definition_lazy_loader.py
+1
-2
common/lib/xmodule/xmodule/modulestore/split_mongo/mongo_connection.py
+116
-0
common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
+38
-84
common/lib/xmodule/xmodule/modulestore/tests/test_split_migrator.py
+3
-3
common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py
+11
-23
No files found.
common/lib/xmodule/xmodule/modulestore/split_migrator.py
View file @
cb113dea
...
@@ -88,7 +88,7 @@ class SplitMigrator(object):
...
@@ -88,7 +88,7 @@ class SplitMigrator(object):
index_info
=
self
.
split_modulestore
.
get_course_index_info
(
course_version_locator
)
index_info
=
self
.
split_modulestore
.
get_course_index_info
(
course_version_locator
)
versions
=
index_info
[
'versions'
]
versions
=
index_info
[
'versions'
]
versions
[
'draft'
]
=
versions
[
'published'
]
versions
[
'draft'
]
=
versions
[
'published'
]
self
.
split_modulestore
.
update_course_index
(
course_version_locator
,
{
'versions'
:
versions
},
update_versions
=
True
)
self
.
split_modulestore
.
update_course_index
(
index_info
)
# clean up orphans in published version: in old mongo, parents pointed to the union of their published and draft
# clean up orphans in published version: in old mongo, parents pointed to the union of their published and draft
# children which meant some pointers were to non-existent locations in 'direct'
# children which meant some pointers were to non-existent locations in 'direct'
...
...
common/lib/xmodule/xmodule/modulestore/split_mongo/definition_lazy_loader.py
View file @
cb113dea
...
@@ -22,5 +22,4 @@ class DefinitionLazyLoader(object):
...
@@ -22,5 +22,4 @@ class DefinitionLazyLoader(object):
Fetch the definition. Note, the caller should replace this lazy
Fetch the definition. Note, the caller should replace this lazy
loader pointer with the result so as not to fetch more than once
loader pointer with the result so as not to fetch more than once
"""
"""
return
self
.
modulestore
.
definitions
.
find_one
(
return
self
.
modulestore
.
db_connection
.
get_definition
(
self
.
definition_locator
.
definition_id
)
{
'_id'
:
self
.
definition_locator
.
definition_id
})
common/lib/xmodule/xmodule/modulestore/split_mongo/mongo_connection.py
0 → 100644
View file @
cb113dea
"""
Segregation of pymongo functions from the data modeling mechanisms for split modulestore.
"""
import
pymongo
class
MongoConnection
(
object
):
"""
Segregation of pymongo functions from the data modeling mechanisms for split modulestore.
"""
def
__init__
(
self
,
db
,
collection
,
host
,
port
=
27017
,
tz_aware
=
True
,
user
=
None
,
password
=
None
,
**
kwargs
):
"""
Create & open the connection, authenticate, and provide pointers to the collections
"""
self
.
database
=
pymongo
.
database
.
Database
(
pymongo
.
MongoClient
(
host
=
host
,
port
=
port
,
tz_aware
=
tz_aware
,
**
kwargs
),
db
)
if
user
is
not
None
and
password
is
not
None
:
self
.
database
.
authenticate
(
user
,
password
)
self
.
course_index
=
self
.
database
[
collection
+
'.active_versions'
]
self
.
structures
=
self
.
database
[
collection
+
'.structures'
]
self
.
definitions
=
self
.
database
[
collection
+
'.definitions'
]
# every app has write access to the db (v having a flag to indicate r/o v write)
# Force mongo to report errors, at the expense of performance
# pymongo docs suck but explanation:
# http://api.mongodb.org/java/2.10.1/com/mongodb/WriteConcern.html
self
.
course_index
.
write_concern
=
{
'w'
:
1
}
self
.
structures
.
write_concern
=
{
'w'
:
1
}
self
.
definitions
.
write_concern
=
{
'w'
:
1
}
def
get_structure
(
self
,
key
):
"""
Get the structure from the persistence mechanism whose id is the given key
"""
return
self
.
structures
.
find_one
({
'_id'
:
key
})
def
find_matching_structures
(
self
,
query
):
"""
Find the structure matching the query. Right now the query must be a legal mongo query
:param query: a mongo-style query of {key: [value|{$in ..}|..], ..}
"""
return
self
.
structures
.
find
(
query
)
def
insert_structure
(
self
,
structure
):
"""
Create the structure in the db
"""
self
.
structures
.
insert
(
structure
)
def
update_structure
(
self
,
structure
):
"""
Update the db record for structure
"""
self
.
structures
.
update
({
'_id'
:
structure
[
'_id'
]},
structure
)
def
get_course_index
(
self
,
key
):
"""
Get the course_index from the persistence mechanism whose id is the given key
"""
return
self
.
course_index
.
find_one
({
'_id'
:
key
})
def
find_matching_course_indexes
(
self
,
query
):
"""
Find the course_index matching the query. Right now the query must be a legal mongo query
:param query: a mongo-style query of {key: [value|{$in ..}|..], ..}
"""
return
self
.
course_index
.
find
(
query
)
def
insert_course_index
(
self
,
course_index
):
"""
Create the course_index in the db
"""
self
.
course_index
.
insert
(
course_index
)
def
update_course_index
(
self
,
course_index
):
"""
Update the db record for course_index
"""
self
.
course_index
.
update
({
'_id'
:
course_index
[
'_id'
]},
course_index
)
def
delete_course_index
(
self
,
key
):
"""
Delete the course_index from the persistence mechanism whose id is the given key
"""
return
self
.
course_index
.
remove
({
'_id'
:
key
})
def
get_definition
(
self
,
key
):
"""
Get the definition from the persistence mechanism whose id is the given key
"""
return
self
.
definitions
.
find_one
({
'_id'
:
key
})
def
find_matching_definitions
(
self
,
query
):
"""
Find the definitions matching the query. Right now the query must be a legal mongo query
:param query: a mongo-style query of {key: [value|{$in ..}|..], ..}
"""
return
self
.
definitions
.
find
(
query
)
def
insert_definition
(
self
,
definition
):
"""
Create the definition in the db
"""
self
.
definitions
.
insert
(
definition
)
common/lib/xmodule/xmodule/modulestore/split_mongo/split.py
View file @
cb113dea
import
threading
import
threading
import
datetime
import
datetime
import
logging
import
logging
import
pymongo
import
re
import
re
from
importlib
import
import_module
from
importlib
import
import_module
from
path
import
path
from
path
import
path
...
@@ -21,6 +20,7 @@ from .caching_descriptor_system import CachingDescriptorSystem
...
@@ -21,6 +20,7 @@ from .caching_descriptor_system import CachingDescriptorSystem
from
xblock.fields
import
Scope
from
xblock.fields
import
Scope
from
xblock.runtime
import
Mixologist
from
xblock.runtime
import
Mixologist
from
bson.objectid
import
ObjectId
from
bson.objectid
import
ObjectId
from
xmodule.modulestore.split_mongo.mongo_connection
import
MongoConnection
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
#==============================================================================
#==============================================================================
...
@@ -49,7 +49,6 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -49,7 +49,6 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
A Mongodb backed ModuleStore supporting versions, inheritance,
A Mongodb backed ModuleStore supporting versions, inheritance,
and sharing.
and sharing.
"""
"""
# pylint: disable=W0201
def
__init__
(
self
,
doc_store_config
,
fs_root
,
render_template
,
def
__init__
(
self
,
doc_store_config
,
fs_root
,
render_template
,
default_class
=
None
,
default_class
=
None
,
error_tracker
=
null_error_tracker
,
error_tracker
=
null_error_tracker
,
...
@@ -62,44 +61,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -62,44 +61,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
super
(
SplitMongoModuleStore
,
self
)
.
__init__
(
**
kwargs
)
super
(
SplitMongoModuleStore
,
self
)
.
__init__
(
**
kwargs
)
self
.
loc_mapper
=
loc_mapper
self
.
loc_mapper
=
loc_mapper
def
do_connection
(
self
.
db_connection
=
MongoConnection
(
**
doc_store_config
)
db
,
collection
,
host
,
port
=
27017
,
tz_aware
=
True
,
user
=
None
,
password
=
None
,
**
kwargs
self
.
db
=
self
.
db_connection
.
database
):
"""
Create & open the connection, authenticate, and provide pointers to the collections
"""
self
.
db
=
pymongo
.
database
.
Database
(
pymongo
.
MongoClient
(
host
=
host
,
port
=
port
,
tz_aware
=
tz_aware
,
**
kwargs
),
db
)
if
user
is
not
None
and
password
is
not
None
:
self
.
db
.
authenticate
(
user
,
password
)
self
.
course_index
=
self
.
db
[
collection
+
'.active_versions'
]
self
.
structures
=
self
.
db
[
collection
+
'.structures'
]
self
.
definitions
=
self
.
db
[
collection
+
'.definitions'
]
do_connection
(
**
doc_store_config
)
# Code review question: How should I expire entries?
# Code review question: How should I expire entries?
# _add_cache could use a lru mechanism to control the cache size?
# _add_cache could use a lru mechanism to control the cache size?
self
.
thread_cache
=
threading
.
local
()
self
.
thread_cache
=
threading
.
local
()
# every app has write access to the db (v having a flag to indicate r/o v write)
# Force mongo to report errors, at the expense of performance
# pymongo docs suck but explanation:
# http://api.mongodb.org/java/2.10.1/com/mongodb/WriteConcern.html
self
.
course_index
.
write_concern
=
{
'w'
:
1
}
self
.
structures
.
write_concern
=
{
'w'
:
1
}
self
.
definitions
.
write_concern
=
{
'w'
:
1
}
if
default_class
is
not
None
:
if
default_class
is
not
None
:
module_path
,
_
,
class_name
=
default_class
.
rpartition
(
'.'
)
module_path
,
_
,
class_name
=
default_class
.
rpartition
(
'.'
)
class_
=
getattr
(
import_module
(
module_path
),
class_name
)
class_
=
getattr
(
import_module
(
module_path
),
class_name
)
...
@@ -138,7 +106,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -138,7 +106,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
block
[
'definition'
]
=
DefinitionLazyLoader
(
self
,
block
[
'definition'
])
block
[
'definition'
]
=
DefinitionLazyLoader
(
self
,
block
[
'definition'
])
else
:
else
:
# Load all descendants by id
# Load all descendants by id
descendent_definitions
=
self
.
d
efinitions
.
find
({
descendent_definitions
=
self
.
d
b_connection
.
find_matching_definitions
({
'_id'
:
{
'$in'
:
[
block
[
'definition'
]
'_id'
:
{
'$in'
:
[
block
[
'definition'
]
for
block
in
new_module_data
.
itervalues
()]}})
for
block
in
new_module_data
.
itervalues
()]}})
# turn into a map
# turn into a map
...
@@ -226,7 +194,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -226,7 +194,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
if
course_locator
.
course_id
is
not
None
and
course_locator
.
branch
is
not
None
:
if
course_locator
.
course_id
is
not
None
and
course_locator
.
branch
is
not
None
:
# use the course_id
# use the course_id
index
=
self
.
course_index
.
find_one
({
'_id'
:
course_locator
.
course_id
}
)
index
=
self
.
db_connection
.
get_course_index
(
course_locator
.
course_id
)
if
index
is
None
:
if
index
is
None
:
raise
ItemNotFoundError
(
course_locator
)
raise
ItemNotFoundError
(
course_locator
)
if
course_locator
.
branch
not
in
index
[
'versions'
]:
if
course_locator
.
branch
not
in
index
[
'versions'
]:
...
@@ -241,7 +209,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -241,7 +209,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
# cast string to ObjectId if necessary
# cast string to ObjectId if necessary
version_guid
=
course_locator
.
as_object_id
(
version_guid
)
version_guid
=
course_locator
.
as_object_id
(
version_guid
)
entry
=
self
.
structures
.
find_one
({
'_id'
:
version_guid
}
)
entry
=
self
.
db_connection
.
get_structure
(
version_guid
)
# b/c more than one course can use same structure, the 'course_id' and 'branch' are not intrinsic to structure
# b/c more than one course can use same structure, the 'course_id' and 'branch' are not intrinsic to structure
# and the one assoc'd w/ it by another fetch may not be the one relevant to this fetch; so,
# and the one assoc'd w/ it by another fetch may not be the one relevant to this fetch; so,
...
@@ -269,7 +237,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -269,7 +237,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
if
qualifiers
is
None
:
if
qualifiers
is
None
:
qualifiers
=
{}
qualifiers
=
{}
qualifiers
.
update
({
"versions.{}"
.
format
(
branch
):
{
"$exists"
:
True
}})
qualifiers
.
update
({
"versions.{}"
.
format
(
branch
):
{
"$exists"
:
True
}})
matching
=
self
.
course_index
.
find
(
qualifiers
)
matching
=
self
.
db_connection
.
find_matching_course_indexes
(
qualifiers
)
# collect ids and then query for those
# collect ids and then query for those
version_guids
=
[]
version_guids
=
[]
...
@@ -279,7 +247,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -279,7 +247,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
version_guids
.
append
(
version_guid
)
version_guids
.
append
(
version_guid
)
id_version_map
[
version_guid
]
=
structure
[
'_id'
]
id_version_map
[
version_guid
]
=
structure
[
'_id'
]
course_entries
=
self
.
structures
.
find
({
'_id'
:
{
'$in'
:
version_guids
}})
course_entries
=
self
.
db_connection
.
find_matching_structures
({
'_id'
:
{
'$in'
:
version_guids
}})
# get the block for the course element (s/b the root)
# get the block for the course element (s/b the root)
result
=
[]
result
=
[]
...
@@ -455,7 +423,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -455,7 +423,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
"""
"""
if
course_locator
.
course_id
is
None
:
if
course_locator
.
course_id
is
None
:
return
None
return
None
index
=
self
.
course_index
.
find_one
({
'_id'
:
course_locator
.
course_id
}
)
index
=
self
.
db_connection
.
get_course_index
(
course_locator
.
course_id
)
return
index
return
index
# TODO figure out a way to make this info accessible from the course descriptor
# TODO figure out a way to make this info accessible from the course descriptor
...
@@ -487,7 +455,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -487,7 +455,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
'edited_on': when the change was made
'edited_on': when the change was made
}
}
"""
"""
definition
=
self
.
d
efinitions
.
find_one
({
'_id'
:
definition_locator
.
definition_id
}
)
definition
=
self
.
d
b_connection
.
get_definition
(
definition_locator
.
definition_id
)
if
definition
is
None
:
if
definition
is
None
:
return
None
return
None
return
definition
[
'edit_info'
]
return
definition
[
'edit_info'
]
...
@@ -509,14 +477,14 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -509,14 +477,14 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
# TODO if depth is significant, it may make sense to get all that have the same original_version
# TODO if depth is significant, it may make sense to get all that have the same original_version
# and reconstruct the subtree from version_guid
# and reconstruct the subtree from version_guid
next_entries
=
self
.
structures
.
find
({
'previous_version'
:
version_guid
})
next_entries
=
self
.
db_connection
.
find_matching_structures
({
'previous_version'
:
version_guid
})
# must only scan cursor's once
# must only scan cursor's once
next_versions
=
[
struct
for
struct
in
next_entries
]
next_versions
=
[
struct
for
struct
in
next_entries
]
result
=
{
version_guid
:
[
CourseLocator
(
version_guid
=
struct
[
'_id'
])
for
struct
in
next_versions
]}
result
=
{
version_guid
:
[
CourseLocator
(
version_guid
=
struct
[
'_id'
])
for
struct
in
next_versions
]}
depth
=
1
depth
=
1
while
depth
<
version_history_depth
and
len
(
next_versions
)
>
0
:
while
depth
<
version_history_depth
and
len
(
next_versions
)
>
0
:
depth
+=
1
depth
+=
1
next_entries
=
self
.
structures
.
find
({
'previous_version'
:
next_entries
=
self
.
db_connection
.
find_matching_structures
({
'previous_version'
:
{
'$in'
:
[
struct
[
'_id'
]
for
struct
in
next_versions
]}})
{
'$in'
:
[
struct
[
'_id'
]
for
struct
in
next_versions
]}})
next_versions
=
[
struct
for
struct
in
next_entries
]
next_versions
=
[
struct
for
struct
in
next_entries
]
for
course_structure
in
next_versions
:
for
course_structure
in
next_versions
:
...
@@ -537,7 +505,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -537,7 +505,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
course_struct
=
self
.
_lookup_course
(
block_locator
.
version_agnostic
())[
'structure'
]
course_struct
=
self
.
_lookup_course
(
block_locator
.
version_agnostic
())[
'structure'
]
usage_id
=
block_locator
.
usage_id
usage_id
=
block_locator
.
usage_id
update_version_field
=
'blocks.{}.edit_info.update_version'
.
format
(
usage_id
)
update_version_field
=
'blocks.{}.edit_info.update_version'
.
format
(
usage_id
)
all_versions_with_block
=
self
.
structures
.
find
({
'original_version'
:
course_struct
[
'original_version'
],
all_versions_with_block
=
self
.
db_connection
.
find_matching_structures
({
'original_version'
:
course_struct
[
'original_version'
],
update_version_field
:
{
'$exists'
:
True
}})
update_version_field
:
{
'$exists'
:
True
}})
# find (all) root versions and build map previous: [successors]
# find (all) root versions and build map previous: [successors]
possible_roots
=
[]
possible_roots
=
[]
...
@@ -596,7 +564,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -596,7 +564,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
"original_version"
:
new_id
,
"original_version"
:
new_id
,
}
}
}
}
self
.
d
efinitions
.
insert
(
document
)
self
.
d
b_connection
.
insert_definition
(
document
)
definition_locator
=
DefinitionLocator
(
new_id
)
definition_locator
=
DefinitionLocator
(
new_id
)
return
definition_locator
return
definition_locator
...
@@ -618,7 +586,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -618,7 +586,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
# if this looks in cache rather than fresh fetches, then it will probably not detect
# if this looks in cache rather than fresh fetches, then it will probably not detect
# actual change b/c the descriptor and cache probably point to the same objects
# actual change b/c the descriptor and cache probably point to the same objects
old_definition
=
self
.
d
efinitions
.
find_one
({
'_id'
:
definition_locator
.
definition_id
}
)
old_definition
=
self
.
d
b_connection
.
get_definition
(
definition_locator
.
definition_id
)
if
old_definition
is
None
:
if
old_definition
is
None
:
raise
ItemNotFoundError
(
definition_locator
.
url
())
raise
ItemNotFoundError
(
definition_locator
.
url
())
...
@@ -630,7 +598,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -630,7 +598,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
old_definition
[
'edit_info'
][
'edited_on'
]
=
datetime
.
datetime
.
now
(
UTC
)
old_definition
[
'edit_info'
][
'edited_on'
]
=
datetime
.
datetime
.
now
(
UTC
)
# previous version id
# previous version id
old_definition
[
'edit_info'
][
'previous_version'
]
=
definition_locator
.
definition_id
old_definition
[
'edit_info'
][
'previous_version'
]
=
definition_locator
.
definition_id
self
.
d
efinitions
.
insert
(
old_definition
)
self
.
d
b_connection
.
insert_definition
(
old_definition
)
return
DefinitionLocator
(
old_definition
[
'_id'
]),
True
return
DefinitionLocator
(
old_definition
[
'_id'
]),
True
else
:
else
:
return
definition_locator
,
False
return
definition_locator
,
False
...
@@ -657,7 +625,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -657,7 +625,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
:param course_blocks: the current list of blocks.
:param course_blocks: the current list of blocks.
:param category:
:param category:
"""
"""
existing_uses
=
self
.
course_index
.
find
({
"_id"
:
{
"$regex"
:
id_root
}})
existing_uses
=
self
.
db_connection
.
find_matching_course_indexes
({
"_id"
:
{
"$regex"
:
id_root
}})
if
existing_uses
.
count
()
>
0
:
if
existing_uses
.
count
()
>
0
:
max_found
=
0
max_found
=
0
matcher
=
re
.
compile
(
id_root
+
r'(\d+)'
)
matcher
=
re
.
compile
(
id_root
+
r'(\d+)'
)
...
@@ -779,11 +747,11 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -779,11 +747,11 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
parent
[
'edit_info'
][
'update_version'
]
=
new_id
parent
[
'edit_info'
][
'update_version'
]
=
new_id
if
continue_version
:
if
continue_version
:
# db update
# db update
self
.
structures
.
update
({
'_id'
:
new_id
},
new_structure
)
self
.
db_connection
.
update_structure
(
new_structure
)
# clear cache so things get refetched and inheritance recomputed
# clear cache so things get refetched and inheritance recomputed
self
.
_clear_cache
(
new_id
)
self
.
_clear_cache
(
new_id
)
else
:
else
:
self
.
structures
.
insert
(
new_structure
)
self
.
db_connection
.
insert_structure
(
new_structure
)
# update the index entry if appropriate
# update the index entry if appropriate
if
index_entry
is
not
None
:
if
index_entry
is
not
None
:
...
@@ -856,7 +824,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -856,7 +824,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
'original_version'
:
definition_id
,
'original_version'
:
definition_id
,
}
}
}
}
self
.
d
efinitions
.
insert
(
definition_entry
)
self
.
d
b_connection
.
insert_definition
(
definition_entry
)
new_id
=
ObjectId
()
new_id
=
ObjectId
()
draft_structure
=
{
draft_structure
=
{
...
@@ -880,7 +848,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -880,7 +848,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
}
}
}
}
}
}
self
.
structures
.
insert
(
draft_structure
)
self
.
db_connection
.
insert_structure
(
draft_structure
)
if
versions_dict
is
None
:
if
versions_dict
is
None
:
versions_dict
=
{
master_branch
:
new_id
}
versions_dict
=
{
master_branch
:
new_id
}
...
@@ -898,20 +866,20 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -898,20 +866,20 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
if
block_fields
is
not
None
:
if
block_fields
is
not
None
:
root_block
[
'fields'
]
.
update
(
block_fields
)
root_block
[
'fields'
]
.
update
(
block_fields
)
if
definition_fields
is
not
None
:
if
definition_fields
is
not
None
:
definition
=
self
.
d
efinitions
.
find_one
({
'_id'
:
root_block
[
'definition'
]}
)
definition
=
self
.
d
b_connection
.
get_definition
(
root_block
[
'definition'
]
)
definition
[
'fields'
]
.
update
(
definition_fields
)
definition
[
'fields'
]
.
update
(
definition_fields
)
definition
[
'edit_info'
][
'previous_version'
]
=
definition
[
'_id'
]
definition
[
'edit_info'
][
'previous_version'
]
=
definition
[
'_id'
]
definition
[
'edit_info'
][
'edited_by'
]
=
user_id
definition
[
'edit_info'
][
'edited_by'
]
=
user_id
definition
[
'edit_info'
][
'edited_on'
]
=
datetime
.
datetime
.
now
(
UTC
)
definition
[
'edit_info'
][
'edited_on'
]
=
datetime
.
datetime
.
now
(
UTC
)
definition
[
'_id'
]
=
ObjectId
()
definition
[
'_id'
]
=
ObjectId
()
self
.
d
efinitions
.
insert
(
definition
)
self
.
d
b_connection
.
insert_definition
(
definition
)
root_block
[
'definition'
]
=
definition
[
'_id'
]
root_block
[
'definition'
]
=
definition
[
'_id'
]
root_block
[
'edit_info'
][
'edited_on'
]
=
datetime
.
datetime
.
now
(
UTC
)
root_block
[
'edit_info'
][
'edited_on'
]
=
datetime
.
datetime
.
now
(
UTC
)
root_block
[
'edit_info'
][
'edited_by'
]
=
user_id
root_block
[
'edit_info'
][
'edited_by'
]
=
user_id
root_block
[
'edit_info'
][
'previous_version'
]
=
root_block
[
'edit_info'
]
.
get
(
'update_version'
)
root_block
[
'edit_info'
][
'previous_version'
]
=
root_block
[
'edit_info'
]
.
get
(
'update_version'
)
root_block
[
'edit_info'
][
'update_version'
]
=
new_id
root_block
[
'edit_info'
][
'update_version'
]
=
new_id
self
.
structures
.
insert
(
draft_structure
)
self
.
db_connection
.
insert_structure
(
draft_structure
)
versions_dict
[
master_branch
]
=
new_id
versions_dict
[
master_branch
]
=
new_id
# create the index entry
# create the index entry
...
@@ -926,7 +894,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -926,7 +894,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
'edited_by'
:
user_id
,
'edited_by'
:
user_id
,
'edited_on'
:
datetime
.
datetime
.
now
(
UTC
),
'edited_on'
:
datetime
.
datetime
.
now
(
UTC
),
'versions'
:
versions_dict
}
'versions'
:
versions_dict
}
self
.
course_index
.
insert
(
index_entry
)
self
.
db_connection
.
insert_course_index
(
index_entry
)
return
self
.
get_course
(
CourseLocator
(
course_id
=
new_id
,
branch
=
master_branch
))
return
self
.
get_course
(
CourseLocator
(
course_id
=
new_id
,
branch
=
master_branch
))
def
update_item
(
self
,
descriptor
,
user_id
,
force
=
False
):
def
update_item
(
self
,
descriptor
,
user_id
,
force
=
False
):
...
@@ -978,7 +946,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -978,7 +946,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
'previous_version'
:
block_data
[
'edit_info'
][
'update_version'
],
'previous_version'
:
block_data
[
'edit_info'
][
'update_version'
],
'update_version'
:
new_id
,
'update_version'
:
new_id
,
}
}
self
.
structures
.
insert
(
new_structure
)
self
.
db_connection
.
insert_structure
(
new_structure
)
# update the index entry if appropriate
# update the index entry if appropriate
if
index_entry
is
not
None
:
if
index_entry
is
not
None
:
self
.
_update_head
(
index_entry
,
descriptor
.
location
.
branch
,
new_id
)
self
.
_update_head
(
index_entry
,
descriptor
.
location
.
branch
,
new_id
)
...
@@ -1016,7 +984,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1016,7 +984,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
is_updated
=
self
.
_persist_subdag
(
xblock
,
user_id
,
new_structure
[
'blocks'
],
new_id
)
is_updated
=
self
.
_persist_subdag
(
xblock
,
user_id
,
new_structure
[
'blocks'
],
new_id
)
if
is_updated
:
if
is_updated
:
self
.
structures
.
insert
(
new_structure
)
self
.
db_connection
.
insert_structure
(
new_structure
)
# update the index entry if appropriate
# update the index entry if appropriate
if
index_entry
is
not
None
:
if
index_entry
is
not
None
:
...
@@ -1115,31 +1083,18 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1115,31 +1083,18 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
'''Deprecated, use update_item.'''
'''Deprecated, use update_item.'''
raise
NotImplementedError
(
'use update_item'
)
raise
NotImplementedError
(
'use update_item'
)
def
update_course_index
(
self
,
course_locator
,
new_values_dict
,
update_versions
=
False
):
def
update_course_index
(
self
,
updated_index_entry
):
"""
"""
Change the given course's index entry for the given fields. new_values_dict
Change the given course's index entry.
should be a subset of the dict returned by get_course_index_info.
It cannot include '_id' (will raise IllegalArgument).
Provide update_versions=True if you intend this to replace the versions hash.
Note, this operation can be dangerous and break running courses.
If the dict includes versions and not update_versions, it will raise an exception.
If the dict includes edited_on or edited_by, it will raise an exception
Note, this operation can be dangerous and break running courses.
Does not return anything useful.
Does not return anything useful.
"""
"""
# TODO how should this log the change? edited_on and edited_by for this entry
# TODO how should this log the change? edited_on and edited_by for this entry
# has the semantic of who created the course and when; so, changing those will lose
# has the semantic of who created the course and when; so, changing those will lose
# that information.
# that information.
if
'_id'
in
new_values_dict
:
self
.
db_connection
.
update_course_index
(
updated_index_entry
)
raise
ValueError
(
"Cannot override _id"
)
if
'edited_on'
in
new_values_dict
or
'edited_by'
in
new_values_dict
:
raise
ValueError
(
"Cannot set edited_on or edited_by"
)
if
not
update_versions
and
'versions'
in
new_values_dict
:
raise
ValueError
(
"Cannot override versions without setting update_versions"
)
self
.
course_index
.
update
({
'_id'
:
course_locator
.
course_id
},
{
'$set'
:
new_values_dict
})
def
delete_item
(
self
,
usage_locator
,
user_id
,
delete_children
=
False
,
force
=
False
):
def
delete_item
(
self
,
usage_locator
,
user_id
,
delete_children
=
False
,
force
=
False
):
"""
"""
...
@@ -1182,7 +1137,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1182,7 +1137,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
remove_subtree
(
usage_locator
.
usage_id
)
remove_subtree
(
usage_locator
.
usage_id
)
# update index if appropriate and structures
# update index if appropriate and structures
self
.
structures
.
insert
(
new_structure
)
self
.
db_connection
.
insert_structure
(
new_structure
)
result
=
CourseLocator
(
version_guid
=
new_id
)
result
=
CourseLocator
(
version_guid
=
new_id
)
...
@@ -1204,11 +1159,11 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1204,11 +1159,11 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
:param course_id: uses course_id rather than locator to emphasize its global effect
:param course_id: uses course_id rather than locator to emphasize its global effect
"""
"""
index
=
self
.
course_index
.
find_one
({
'_id'
:
course_id
}
)
index
=
self
.
db_connection
.
get_course_index
(
course_id
)
if
index
is
None
:
if
index
is
None
:
raise
ItemNotFoundError
(
course_id
)
raise
ItemNotFoundError
(
course_id
)
# this is the only real delete in the system. should it do something else?
# this is the only real delete in the system. should it do something else?
self
.
course_index
.
remove
(
index
[
'_id'
])
self
.
db_connection
.
delete_course_index
(
index
[
'_id'
])
def
get_errored_courses
(
self
):
def
get_errored_courses
(
self
):
"""
"""
...
@@ -1296,7 +1251,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1296,7 +1251,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
block
[
'fields'
][
"children"
]
=
[
block
[
'fields'
][
"children"
]
=
[
usage_id
for
usage_id
in
block
[
'fields'
][
"children"
]
if
usage_id
in
original_structure
[
'blocks'
]
usage_id
for
usage_id
in
block
[
'fields'
][
"children"
]
if
usage_id
in
original_structure
[
'blocks'
]
]
]
self
.
structures
.
update
({
'_id'
:
original_structure
[
'_id'
]},
original_structure
)
self
.
db_connection
.
update_structure
(
original_structure
)
# clear cache again b/c inheritance may be wrong over orphans
# clear cache again b/c inheritance may be wrong over orphans
self
.
_clear_cache
(
original_structure
[
'_id'
])
self
.
_clear_cache
(
original_structure
[
'_id'
])
...
@@ -1379,7 +1334,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1379,7 +1334,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
else
:
else
:
return
None
return
None
else
:
else
:
index_entry
=
self
.
course_index
.
find_one
({
'_id'
:
locator
.
course_id
}
)
index_entry
=
self
.
db_connection
.
get_course_index
(
locator
.
course_id
)
is_head
=
(
is_head
=
(
locator
.
version_guid
is
None
or
locator
.
version_guid
is
None
or
index_entry
[
'versions'
][
locator
.
branch
]
==
locator
.
version_guid
index_entry
[
'versions'
][
locator
.
branch
]
==
locator
.
version_guid
...
@@ -1424,9 +1379,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
...
@@ -1424,9 +1379,8 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
:param course_locator:
:param course_locator:
:param new_id:
:param new_id:
"""
"""
self
.
course_index
.
update
(
index_entry
[
'versions'
][
branch
]
=
new_id
{
"_id"
:
index_entry
[
"_id"
]},
self
.
db_connection
.
update_course_index
(
index_entry
)
{
"$set"
:
{
"versions.{}"
.
format
(
branch
):
new_id
}})
def
_partition_fields_by_scope
(
self
,
category
,
fields
):
def
_partition_fields_by_scope
(
self
,
category
,
fields
):
"""
"""
...
...
common/lib/xmodule/xmodule/modulestore/tests/test_split_migrator.py
View file @
cb113dea
...
@@ -59,9 +59,9 @@ class TestMigration(unittest.TestCase):
...
@@ -59,9 +59,9 @@ class TestMigration(unittest.TestCase):
dbref
=
self
.
loc_mapper
.
db
dbref
=
self
.
loc_mapper
.
db
dbref
.
drop_collection
(
self
.
loc_mapper
.
location_map
)
dbref
.
drop_collection
(
self
.
loc_mapper
.
location_map
)
split_db
=
self
.
split_mongo
.
db
split_db
=
self
.
split_mongo
.
db
split_db
.
drop_collection
(
s
plit_db
.
course_index
)
split_db
.
drop_collection
(
s
elf
.
split_mongo
.
db_connection
.
course_index
)
split_db
.
drop_collection
(
s
plit_db
.
structures
)
split_db
.
drop_collection
(
s
elf
.
split_mongo
.
db_connection
.
structures
)
split_db
.
drop_collection
(
s
plit_db
.
definitions
)
split_db
.
drop_collection
(
s
elf
.
split_mongo
.
db_connection
.
definitions
)
# old_mongo doesn't give a db attr, but all of the dbs are the same
# old_mongo doesn't give a db attr, but all of the dbs are the same
dbref
.
drop_collection
(
self
.
old_mongo
.
collection
)
dbref
.
drop_collection
(
self
.
old_mongo
.
collection
)
...
...
common/lib/xmodule/xmodule/modulestore/tests/test_split_modulestore.py
View file @
cb113dea
...
@@ -1018,41 +1018,29 @@ class TestCourseCreation(SplitModuleTest):
...
@@ -1018,41 +1018,29 @@ class TestCourseCreation(SplitModuleTest):
Test changing the org, pretty id, etc of a course. Test that it doesn't allow changing the id, etc.
Test changing the org, pretty id, etc of a course. Test that it doesn't allow changing the id, etc.
"""
"""
locator
=
CourseLocator
(
course_id
=
"GreekHero"
,
branch
=
'draft'
)
locator
=
CourseLocator
(
course_id
=
"GreekHero"
,
branch
=
'draft'
)
modulestore
()
.
update_course_index
(
locator
,
{
'org'
:
'funkyU'
})
course_info
=
modulestore
()
.
get_course_index_info
(
locator
)
course_info
[
'org'
]
=
'funkyU'
modulestore
()
.
update_course_index
(
course_info
)
course_info
=
modulestore
()
.
get_course_index_info
(
locator
)
course_info
=
modulestore
()
.
get_course_index_info
(
locator
)
self
.
assertEqual
(
course_info
[
'org'
],
'funkyU'
)
self
.
assertEqual
(
course_info
[
'org'
],
'funkyU'
)
modulestore
()
.
update_course_index
(
locator
,
{
'org'
:
'moreFunky'
,
'prettyid'
:
'Ancient Greek Demagods'
})
course_info
[
'org'
]
=
'moreFunky'
course_info
[
'prettyid'
]
=
'Ancient Greek Demagods'
modulestore
()
.
update_course_index
(
course_info
)
course_info
=
modulestore
()
.
get_course_index_info
(
locator
)
course_info
=
modulestore
()
.
get_course_index_info
(
locator
)
self
.
assertEqual
(
course_info
[
'org'
],
'moreFunky'
)
self
.
assertEqual
(
course_info
[
'org'
],
'moreFunky'
)
self
.
assertEqual
(
course_info
[
'prettyid'
],
'Ancient Greek Demagods'
)
self
.
assertEqual
(
course_info
[
'prettyid'
],
'Ancient Greek Demagods'
)
self
.
assertRaises
(
ValueError
,
modulestore
()
.
update_course_index
,
locator
,
{
'_id'
:
'funkygreeks'
})
with
self
.
assertRaises
(
ValueError
):
modulestore
()
.
update_course_index
(
locator
,
{
'edited_on'
:
datetime
.
datetime
.
now
(
UTC
)}
)
with
self
.
assertRaises
(
ValueError
):
modulestore
()
.
update_course_index
(
locator
,
{
'edited_by'
:
'sneak'
}
)
self
.
assertRaises
(
ValueError
,
modulestore
()
.
update_course_index
,
locator
,
{
'versions'
:
{
'draft'
:
self
.
GUID_D1
}})
# an allowed but not necessarily recommended way to revert the draft version
# an allowed but not necessarily recommended way to revert the draft version
versions
=
course_info
[
'versions'
]
versions
=
course_info
[
'versions'
]
versions
[
'draft'
]
=
self
.
GUID_D1
versions
[
'draft'
]
=
self
.
GUID_D1
modulestore
()
.
update_course_index
(
locator
,
{
'versions'
:
versions
},
update_versions
=
True
)
modulestore
()
.
update_course_index
(
course_info
)
course
=
modulestore
()
.
get_course
(
locator
)
course
=
modulestore
()
.
get_course
(
locator
)
self
.
assertEqual
(
str
(
course
.
location
.
version_guid
),
self
.
GUID_D1
)
self
.
assertEqual
(
str
(
course
.
location
.
version_guid
),
self
.
GUID_D1
)
# an allowed but not recommended way to publish a course
# an allowed but not recommended way to publish a course
versions
[
'published'
]
=
self
.
GUID_D1
versions
[
'published'
]
=
self
.
GUID_D1
modulestore
()
.
update_course_index
(
locator
,
{
'versions'
:
versions
},
update_versions
=
True
)
modulestore
()
.
update_course_index
(
course_info
)
course
=
modulestore
()
.
get_course
(
CourseLocator
(
course_id
=
locator
.
course_id
,
branch
=
"published"
))
course
=
modulestore
()
.
get_course
(
CourseLocator
(
course_id
=
locator
.
course_id
,
branch
=
"published"
))
self
.
assertEqual
(
str
(
course
.
location
.
version_guid
),
self
.
GUID_D1
)
self
.
assertEqual
(
str
(
course
.
location
.
version_guid
),
self
.
GUID_D1
)
...
@@ -1068,9 +1056,9 @@ class TestCourseCreation(SplitModuleTest):
...
@@ -1068,9 +1056,9 @@ class TestCourseCreation(SplitModuleTest):
self
.
assertEqual
(
new_course
.
location
.
usage_id
,
'top'
)
self
.
assertEqual
(
new_course
.
location
.
usage_id
,
'top'
)
self
.
assertEqual
(
new_course
.
category
,
'chapter'
)
self
.
assertEqual
(
new_course
.
category
,
'chapter'
)
# look at db to verify
# look at db to verify
db_structure
=
modulestore
()
.
structures
.
find_one
({
db_structure
=
modulestore
()
.
db_connection
.
get_structure
(
'_id'
:
new_course
.
location
.
as_object_id
(
new_course
.
location
.
version_guid
)
new_course
.
location
.
as_object_id
(
new_course
.
location
.
version_guid
)
}
)
)
self
.
assertIsNotNone
(
db_structure
,
"Didn't find course"
)
self
.
assertIsNotNone
(
db_structure
,
"Didn't find course"
)
self
.
assertNotIn
(
'course'
,
db_structure
[
'blocks'
])
self
.
assertNotIn
(
'course'
,
db_structure
[
'blocks'
])
self
.
assertIn
(
'top'
,
db_structure
[
'blocks'
])
self
.
assertIn
(
'top'
,
db_structure
[
'blocks'
])
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment