Skip to content

Commit

Permalink
refactor: revert to LockSingleton
Browse files Browse the repository at this point in the history
  • Loading branch information
posterzh authored and marvinmarnold committed Nov 9, 2021
1 parent decc4b5 commit 0bb2517
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 206 deletions.
36 changes: 10 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,27 +89,17 @@ print(retry_get_region("", "/var/pktfwd/region"))
```

## LockSingleton
`LockSingleton` prevents the concurrent access to a resource.
`LockSingleton` prevents the concurrent access to a resource across threads.

### Methods

**InterprocessLock(name, initial_value=1)**
**LockSingleton()**

Creates a new `InterprocessLock` object.
- `name` uniquely identifies the `LockSingleton` across processes in the system
- `available_resources` the count of the available resources
- `reset` set `True` to reset the available_resources
Creates a new `LockSingleton` object.

Note:
The available_resources of a `InterprocessLock` get reset on every restart of the system or docker container.
It's tested in Ubuntu 20.04 desktop and diagnostics container in a Hotspot.
Resetting the available_resources by passing the `reset=True` should be used with a caution and it can be used
in a very specific scenarios such as in the development environment. It's designed for facilitating
the development. It's not recommended to be used in production.
**acquire(timeout = DEFAULT_TIMEOUT)**

**acquire([timeout = None])**

Waits until the resource is available and then returns, decrementing the available count.
Waits until the resource is available. DEFAULT_TIMEOUT = 2 seconds

**release()**

Expand All @@ -119,13 +109,9 @@ Release the resource.

Check if there is an available resource.

**value()**

Returns the count of available resources.

### Usage
```
lock = LockSingleton("some_resource")
lock = LockSingleton()
try:
# try to acquire the resource or may raise an exception
Expand All @@ -140,20 +126,18 @@ try:
lock.release()
except ResourceBusyError:
print("The resource is busy now.")
except CannotLockError:
print("Can't lock the resource for some internal issue.")
```

### `@ecc_lock` decorator
`@ecc_lock(timeout=DEFAULT_TIMEOUT, raise_exception=False):`
### `@lock_ecc` decorator
`@lock_ecc(timeout=DEFAULT_TIMEOUT, raise_exception=False):`

This is the convenient decorator wrapping around the `LockSingleton`.
- timeout: timeout value. DEFAULT_TIMEOUT = 2 seconds
- timeout: timeout value. DEFAULT_TIMEOUT = 2 seconds.
- raise_exception: set True to raise exception in case of timeout or some error, otherwise just log the error msg

Usage
```
@ecc_lock()
@lock_ecc()
def run_gateway_mfr():
return subprocess.run(
[gateway_mfr_path, "key", "0"],
Expand Down
129 changes: 0 additions & 129 deletions hm_pyhelper/interprocess_lock.py

This file was deleted.

68 changes: 68 additions & 0 deletions hm_pyhelper/lock_singleton.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import functools
import threading
from hm_pyhelper.logger import get_logger

LOGGER = get_logger(__name__)

DEFAULT_TIMEOUT = 2.0 # 2 seconds


class LockSingleton(object):
_instance = None
_lock = threading.Lock()

def __new__(cls, *args, **kwargs):
if not cls._instance:
with cls._lock:
if not cls._instance:
cls._instance = super(LockSingleton, cls).__new__(cls)
return cls._instance

def acquire(self, timeout=DEFAULT_TIMEOUT):
if not self._lock.acquire(blocking=True, timeout=timeout):
raise ResourceBusyError()

def release(self):
self._lock.release()

def locked(self):
return self._lock.locked()


class ResourceBusyError(Exception):
"""Raised when the resource is busy"""
pass


def lock_ecc(timeout=DEFAULT_TIMEOUT, raise_exception=False):
"""
Returns a decorator that locks the ECC.
timeout: timeout value. DEFAULT_TIMEOUT = 2 seconds.
raise_exception: set True to raise exception in case of timeout and error.
Otherwise just log the error msg
"""

def decorator_lock_ecc(func):
lock = LockSingleton()

@functools.wraps(func)
def wrapper_lock_ecc(*args, **kwargs):
try:
# try to acquire the ECC resource or may raise an exception
lock.acquire(timeout=timeout)

value = func(*args, **kwargs)

# release the resource
lock.release()

return value
except Exception as ex:
LOGGER.error("ECC is busy now.")
if raise_exception:
raise ex

return wrapper_lock_ecc

return decorator_lock_ecc
6 changes: 3 additions & 3 deletions hm_pyhelper/miner_param.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import subprocess
import json
from retry import retry
from hm_pyhelper.interprocess_lock import ecc_lock
from hm_pyhelper.lock_singleton import lock_ecc
from hm_pyhelper.logger import get_logger
from hm_pyhelper.exceptions import MalformedRegionException, \
SPIUnavailableException, ECCMalfunctionException
Expand All @@ -15,7 +15,7 @@
SPI_UNAVAILABLE_SLEEP_SECONDS = 60


@ecc_lock()
@lock_ecc()
def run_gateway_mfr(args):
direct_path = os.path.dirname(os.path.abspath(__file__))
gateway_mfr_path = os.path.join(direct_path, 'gateway_mfr')
Expand Down Expand Up @@ -83,7 +83,7 @@ def provision_key():
return True

try:
@ecc_lock()
@lock_ecc()
def run_gateway_mfr():
return subprocess.run(
[gateway_mfr_path, "provision"],
Expand Down
Loading

0 comments on commit 0bb2517

Please sign in to comment.