Skip to content

Commit

Permalink
Add support for nested context manager use
Browse files Browse the repository at this point in the history
This commit adds support for nested use of the UsePrimaryDB context manager. If a new instance of the context manager was created at each level we could use instance variables to store the pinning state but the class object is generally used directly. Instead, we store a stack of pinning values locally in the thread and pop each value as we unwind the stack.
  • Loading branch information
bardiharborow committed Jun 28, 2022
1 parent f984772 commit 534d1e9
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 3 deletions.
7 changes: 4 additions & 3 deletions multidb/pinning.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def unpin_this_thread():


class UsePrimaryDB(object):
"""A contextmanager/decorator to use the master database."""
"""A contextmanager/decorator to use the primary database."""
def __call__(self, func):
@wraps(func)
def decorator(*args, **kw):
Expand All @@ -43,11 +43,12 @@ def decorator(*args, **kw):
return decorator

def __enter__(self):
_locals.old = this_thread_is_pinned()
_locals.old = getattr(_locals, 'old', [])
_locals.old.append(this_thread_is_pinned())
pin_this_thread()

def __exit__(self, type, value, tb):
if not _locals.old:
if not _locals.old.pop():
unpin_this_thread()


Expand Down
52 changes: 52 additions & 0 deletions multidb/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,22 @@ def check():
check()
assert not this_thread_is_pinned()

def test_decorator_nested(self):
@use_primary_db
def check_inner():
assert this_thread_is_pinned()

@use_primary_db
def check_outer():
assert this_thread_is_pinned()
check_inner()
assert this_thread_is_pinned()

unpin_this_thread()
assert not this_thread_is_pinned()
check_outer()
assert not this_thread_is_pinned()

def test_decorator_resets(self):
@use_primary_db
def check():
Expand All @@ -211,20 +227,56 @@ def check():
check()
assert this_thread_is_pinned()

def test_decorator_resets_nested(self):
@use_primary_db
def check_inner():
assert this_thread_is_pinned()

@use_primary_db
def check_outer():
assert this_thread_is_pinned()
check_inner()
assert this_thread_is_pinned()

pin_this_thread()
assert this_thread_is_pinned()
check_outer()
assert this_thread_is_pinned()

def test_context_manager(self):
unpin_this_thread()
assert not this_thread_is_pinned()
with use_primary_db:
assert this_thread_is_pinned()
assert not this_thread_is_pinned()

def test_context_manager_nested(self):
unpin_this_thread()
assert not this_thread_is_pinned()
with use_primary_db:
assert this_thread_is_pinned()
with use_primary_db:
assert this_thread_is_pinned()
assert this_thread_is_pinned()
assert not this_thread_is_pinned()

def test_context_manager_resets(self):
pin_this_thread()
assert this_thread_is_pinned()
with use_primary_db:
assert this_thread_is_pinned()
assert this_thread_is_pinned()

def test_context_manager_resets_nested(self):
pin_this_thread()
assert this_thread_is_pinned()
with use_primary_db:
assert this_thread_is_pinned()
with use_primary_db:
assert this_thread_is_pinned()
assert this_thread_is_pinned()
assert this_thread_is_pinned()

def test_context_manager_exception(self):
unpin_this_thread()
assert not this_thread_is_pinned()
Expand Down

0 comments on commit 534d1e9

Please sign in to comment.