cache.py 4.48 KB
Newer Older
1 2 3 4 5 6 7 8
"""
Module for the Cache class for BlockStructure objects.
"""
# pylint: disable=protected-access
from logging import getLogger

from openedx.core.lib.cache_utils import zpickle, zunpickle

9 10
from .block_structure import BlockStructureBlockData
from .factory import BlockStructureFactory
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43


logger = getLogger(__name__)  # pylint: disable=C0103


class BlockStructureCache(object):
    """
    Cache for BlockStructure objects.
    """
    def __init__(self, cache):
        """
        Arguments:
            cache (django.core.cache.backends.base.BaseCache) - The
                cache into which cacheable data of the block structure
                is to be serialized.
        """
        self._cache = cache

    def add(self, block_structure):
        """
        Store a compressed and pickled serialization of the given
        block structure into the given cache.

        The key in the cache is 'root.key.<root_block_usage_key>'.
        The data stored in the cache includes the structure's
        block relations, transformer data, and block data.

        Arguments:
            block_structure (BlockStructure) - The block structure
                that is to be serialized to the given cache.
        """
        data_to_cache = (
            block_structure._block_relations,
44
            block_structure.transformer_data,
45
            block_structure._block_data_map,
46 47
        )
        zp_data_to_cache = zpickle(data_to_cache)
48

49 50 51
        # Set the timeout value for the cache to 1 day as a fail-safe
        # in case the signal to invalidate the cache doesn't come through.
        timeout_in_seconds = 60 * 60 * 24
52 53
        self._cache.set(
            self._encode_root_cache_key(block_structure.root_block_usage_key),
54
            zp_data_to_cache,
55
            timeout=timeout_in_seconds,
56
        )
57

58
        logger.info(
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
            "Wrote BlockStructure %s to cache, size: %s",
            block_structure.root_block_usage_key,
            len(zp_data_to_cache),
        )

    def get(self, root_block_usage_key):
        """
        Deserializes and returns the block structure starting at
        root_block_usage_key from the given cache, if it's found in the cache.

        The given root_block_usage_key must equate the root_block_usage_key
        previously passed to serialize_to_cache.

        Arguments:
            root_block_usage_key (UsageKey) - The usage_key for the root
                of the block structure that is to be deserialized from
                the given cache.

        Returns:
            BlockStructure - The deserialized block structure starting
            at root_block_usage_key, if found in the cache.

            NoneType - If the root_block_usage_key is not found in the cache.
        """

        # Find root_block_usage_key in the cache.
        zp_data_from_cache = self._cache.get(self._encode_root_cache_key(root_block_usage_key))
        if not zp_data_from_cache:
87
            logger.info(
88 89 90 91 92
                "Did not find BlockStructure %r in the cache.",
                root_block_usage_key,
            )
            return None
        else:
93
            logger.info(
94 95 96 97 98 99 100
                "Read BlockStructure %r from cache, size: %s",
                root_block_usage_key,
                len(zp_data_from_cache),
            )

        # Deserialize and construct the block structure.
        block_relations, transformer_data, block_data_map = zunpickle(zp_data_from_cache)
101 102 103 104 105 106
        return BlockStructureFactory.create_new(
            root_block_usage_key,
            block_relations,
            transformer_data,
            block_data_map,
        )
107 108 109 110 111 112 113 114 115 116 117 118

    def delete(self, root_block_usage_key):
        """
        Deletes the block structure for the given root_block_usage_key
        from the given cache.

        Arguments:
            root_block_usage_key (UsageKey) - The usage_key for the root
                of the block structure that is to be removed from
                the cache.
        """
        self._cache.delete(self._encode_root_cache_key(root_block_usage_key))
119
        logger.info(
120 121 122 123 124 125 126 127 128 129
            "Deleted BlockStructure %r from the cache.",
            root_block_usage_key,
        )

    @classmethod
    def _encode_root_cache_key(cls, root_block_usage_key):
        """
        Returns the cache key to use for storing the block structure
        for the given root_block_usage_key.
        """
130 131 132 133
        return "v{version}.root.key.{root_usage_key}".format(
            version=unicode(BlockStructureBlockData.VERSION),
            root_usage_key=unicode(root_block_usage_key),
        )