kelceydamage/raspi-rtl

View on GitHub
rtl/transport/cache.py

Summary

Maintainability
A
0 mins
Test Coverage
#!/usr/bin/env python
# ------------------------------------------------------------------------ 79->
# Author: ${name=Kelcey Damage}
# Python: 3.5+
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Doc
# ------------------------------------------------------------------------ 79->
"""
This module provides a cache interface for accessing LMDB.

Note:
    this is not intended for general cache use and is intended for job meta
    data caching.

Todo
    - Convert to cython

"""


# Imports
# ------------------------------------------------------------------------ 79->
import lmdb
from rtl.transport.conf.configuration import CACHE_MAP_SIZE
from rtl.transport.conf.configuration import CACHE_PATH
from rtl.transport.conf.configuration import TASK_WORKERS


# Classes
# ------------------------------------------------------------------------ 79->


class ExperimentalCache(object):
    """Experimental cache is an api abstraction for LMDB."""

    def __init__(self):
        """Initializer for the experimental cache class.

        There are non-passable paramaters used to open the cache. These are:
            * metasync=True
            * sync=True
            * writemap=True
            * readahead=True
            * subdir=True
            * Lock=True
            * max_dbs=true

        The following can be configured in :ref:`configuration`:
            * CACHE_PATH
            * CACHE_MAP_SIZE
            * TASK_WORKERS

        Note:
            Sets up the LMDB environment for use.

        """
        self.lmdb = lmdb.open(
            CACHE_PATH,
            metasync=True,
            sync=True,
            writemap=True,
            readahead=True,
            subdir=True,
            map_size=CACHE_MAP_SIZE,
            lock=True,
            max_readers=TASK_WORKERS+2,
            max_dbs=1,
            max_spare_txns=TASK_WORKERS+2
            )
        self.ndb = self.lmdb.open_db(b'raspi-rtl')

    def get(self, key):
        """Get method for retrieving a value from the cache based on a key.

        Example:
            .. code-block:: Python

                key, result = ExperimentalCache().get(my_key)

        Args:
            key (bytes): a key name encoded as bytes.

        Returns:
            tuple:
            - key (bytes): a key name encoded as bytes.
            - result (bool, bytes): a value encoded as bytes, or a boolean \
            false if not found.

        """
        with self.lmdb.begin() as txn:
            result = txn.get(key)
        if result is None:
            return (key, False)
        return (key, result)

    def put(self, key, value):
        """Put method for adding a value to the cache based on a key.

        Example:
            .. code-block:: Python

                key, result = ExperimentalCache().put(my_key, my_value)

        Args:
            key (bytes): a key name encoded as bytes.
            value (bytes): a value encoded as bytes.

        Returns:
            tuple:
            - key (bytes): a key name encoded as bytes.
            - result (bool): a boolean value for success.

        """
        with self.lmdb.begin(write=True) as txn:
            result = txn.put(
                key,
                value,
                overwrite=True
            )
        return (key, result)

    def delete(self, key):
        """Delete method for removing a value from the cache based on a key.

        Example:
            .. code-block:: Python

                key, result = ExperimentalCache().put(my_key)

        Args:
            key (bytes): a key name encoded as bytes.

        Returns:
            tuple:
            - key (bytes): a key name encoded as bytes.
            - result (bool): a boolean value for success.

        """
        with self.lmdb.begin(write=True) as txn:
            result = txn.delete(key)
        return (key, result)

    def status(self):
        """Status method for retrieving details on the makup of the cache.

        Example:
            .. code-block:: Python

                status = ExperimentalCache().status()

        Returns:
            dict:
            - psize (int)
            - depth (int)
            - branch_pages (int)
            - leaf_pages (int)
            - overflow_pages (int)
            - entries (int)

        """
        return self.lmdb.stat()

    def info(self):
        """Info method for retrieving details on the environment.

        Example:
            .. code-block:: Python

                info = ExperimentalCache().info()

        Returns:
            dict:
            - map_addr (int)
            - map_size (int)
            - last_pgno (int)
            - last_txnid (int)
            - max_readers (int)
            - num_readers (int)

        """
        return self.lmdb.info()

    def sync(self):
        """Sync the state of the cache

        Example:
            .. code-block:: Python

                ExperimentalCache().sync()

        """
        return self.lmdb.sync()


# Functions
# ------------------------------------------------------------------------ 79->

# Main
# ------------------------------------------------------------------------ 79->