mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-06 06:18:12 +08:00
Refactor czi_hosted and server into backend directory, pull common code into backend/common, refactor tests (#2102)
* move local_server -> backend/server server-> backend/czi_hosted, pull common code into backend/common update imports, tests and make commands
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" rwlock.py
|
||||
|
||||
A class to implement read-write locks on top of the standard threading
|
||||
library.
|
||||
|
||||
This is implemented with two mutexes (threading.Lock instances) as per this
|
||||
wikipedia pseudocode:
|
||||
|
||||
https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock#Using_two_mutexes
|
||||
|
||||
Code written by Tyler Neylon at Unbox Research.
|
||||
|
||||
This file is public domain.
|
||||
|
||||
Modified to add a w_demote function to convert a writer lock to a reader lock
|
||||
"""
|
||||
|
||||
|
||||
# _______________________________________________________________________
|
||||
# Imports
|
||||
|
||||
from contextlib import contextmanager
|
||||
from threading import Lock
|
||||
|
||||
|
||||
# _______________________________________________________________________
|
||||
# Class
|
||||
|
||||
|
||||
class RWLock(object):
|
||||
""" RWLock class; this is meant to allow an object to be read from by
|
||||
multiple threads, but only written to by a single thread at a time. See:
|
||||
https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock
|
||||
|
||||
Usage:
|
||||
|
||||
from rwlock import RWLock
|
||||
|
||||
my_obj_rwlock = RWLock()
|
||||
|
||||
# When reading from my_obj:
|
||||
with my_obj_rwlock.r_locked():
|
||||
do_read_only_things_with(my_obj)
|
||||
|
||||
# When writing to my_obj:
|
||||
with my_obj_rwlock.w_locked():
|
||||
mutate(my_obj)
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.w_lock = Lock()
|
||||
self.num_r_lock = Lock()
|
||||
self.num_r = 0
|
||||
|
||||
# The d_lock is needed to handle the demotion case,
|
||||
# so that the writer can become a reader without releasing the w_lock.
|
||||
# the d_lock is held by the writer, and prevents any other thread from taking the
|
||||
# num_r_lock during that time, which means the writer thread is able to take the
|
||||
# num_r_lock to update the num_r.
|
||||
self.d_lock = Lock()
|
||||
|
||||
# ___________________________________________________________________
|
||||
# Reading methods.
|
||||
|
||||
def r_acquire(self):
|
||||
self.d_lock.acquire()
|
||||
self.num_r_lock.acquire()
|
||||
self.num_r += 1
|
||||
|
||||
if self.num_r == 1:
|
||||
self.w_lock.acquire()
|
||||
|
||||
self.num_r_lock.release()
|
||||
self.d_lock.release()
|
||||
|
||||
def r_release(self):
|
||||
assert self.num_r > 0
|
||||
self.num_r_lock.acquire()
|
||||
self.num_r -= 1
|
||||
if self.num_r == 0:
|
||||
self.w_lock.release()
|
||||
|
||||
self.num_r_lock.release()
|
||||
|
||||
@contextmanager
|
||||
def r_locked(self):
|
||||
""" This method is designed to be used via the `with` statement. """
|
||||
try:
|
||||
self.r_acquire()
|
||||
yield
|
||||
finally:
|
||||
self.r_release()
|
||||
|
||||
# ___________________________________________________________________
|
||||
# Writing methods.
|
||||
|
||||
def w_acquire(self):
|
||||
self.d_lock.acquire()
|
||||
self.w_lock.acquire()
|
||||
|
||||
def w_acquire_non_blocking(self):
|
||||
# if d_lock and w_lock can be acquired without blocking, acquire and return True,
|
||||
# else immediately return False.
|
||||
if self.d_lock.acquire(blocking=False):
|
||||
if self.w_lock.acquire(blocking=False):
|
||||
return True
|
||||
else:
|
||||
self.d_lock.release()
|
||||
return False
|
||||
|
||||
def w_release(self):
|
||||
self.w_lock.release()
|
||||
self.d_lock.release()
|
||||
|
||||
def w_demote(self):
|
||||
"""demote a writer lock to a reader lock"""
|
||||
|
||||
# the d_lock is already held from w_acquire.
|
||||
# releasing the d_lock at the end of this function allows multiple readers.
|
||||
# incrementing num_r makes this thread one of those readers.
|
||||
self.num_r_lock.acquire()
|
||||
self.num_r += 1
|
||||
self.num_r_lock.release()
|
||||
self.d_lock.release()
|
||||
|
||||
@contextmanager
|
||||
def w_locked(self):
|
||||
""" This method is designed to be used via the `with` statement. """
|
||||
try:
|
||||
self.w_acquire()
|
||||
yield
|
||||
finally:
|
||||
self.w_release()
|
||||
Reference in New Issue
Block a user