¡@

Home 

OpenStack Study: memory.py

OpenStack Index

**** CubicPower OpenStack Study ****

# Copyright 2013 Red Hat, Inc.

#

# 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.

import collections

from neutron.openstack.common.cache import backends

from neutron.openstack.common import lockutils

from neutron.openstack.common import timeutils

**** CubicPower OpenStack Study ****

class MemoryBackend(backends.BaseCache):

**** CubicPower OpenStack Study ****

    def __init__(self, parsed_url, options=None):

        super(MemoryBackend, self).__init__(parsed_url, options)

        self._clear()

**** CubicPower OpenStack Study ****

    def _set_unlocked(self, key, value, ttl=0):

        expires_at = 0

        if ttl != 0:

            expires_at = timeutils.utcnow_ts() + ttl

        self._cache[key] = (expires_at, value)

        if expires_at:

            self._keys_expires[expires_at].add(key)

**** CubicPower OpenStack Study ****

    def _set(self, key, value, ttl=0, not_exists=False):

        with lockutils.lock(key):

            # NOTE(flaper87): This is needed just in `set`

            # calls, hence it's not in `_set_unlocked`

            if not_exists and self._exists_unlocked(key):

                return False

            self._set_unlocked(key, value, ttl)

            return True

**** CubicPower OpenStack Study ****

    def _get_unlocked(self, key, default=None):

        now = timeutils.utcnow_ts()

        try:

            timeout, value = self._cache[key]

        except KeyError:

            return (0, default)

        if timeout and now >= timeout:

            # NOTE(flaper87): Record expired,

            # remove it from the cache but catch

            # KeyError and ValueError in case

            # _purge_expired removed this key already.

            try:

                del self._cache[key]

            except KeyError:

                pass

            try:

                # NOTE(flaper87): Keys with ttl == 0

                # don't exist in the _keys_expires dict

                self._keys_expires[timeout].remove(key)

            except (KeyError, ValueError):

                pass

            return (0, default)

        return (timeout, value)

**** CubicPower OpenStack Study ****

    def _get(self, key, default=None):

        with lockutils.lock(key):

            return self._get_unlocked(key, default)[1]

**** CubicPower OpenStack Study ****

    def _exists_unlocked(self, key):

        now = timeutils.utcnow_ts()

        try:

            timeout = self._cache[key][0]

            return not timeout or now <= timeout

        except KeyError:

            return False

**** CubicPower OpenStack Study ****

    def __contains__(self, key):

        with lockutils.lock(key):

            return self._exists_unlocked(key)

**** CubicPower OpenStack Study ****

    def _incr_append(self, key, other):

        with lockutils.lock(key):

            timeout, value = self._get_unlocked(key)

            if value is None:

                return None

            ttl = timeutils.utcnow_ts() - timeout

            new_value = value + other

            self._set_unlocked(key, new_value, ttl)

            return new_value

**** CubicPower OpenStack Study ****

    def _incr(self, key, delta):

        if not isinstance(delta, int):

            raise TypeError('delta must be an int instance')

        return self._incr_append(key, delta)

**** CubicPower OpenStack Study ****

    def _append_tail(self, key, tail):

        return self._incr_append(key, tail)

**** CubicPower OpenStack Study ****

    def _purge_expired(self):

        """Removes expired keys from the cache."""

        now = timeutils.utcnow_ts()

        for timeout in sorted(self._keys_expires.keys()):

            # NOTE(flaper87): If timeout is greater

            # than `now`, stop the iteration, remaining

            # keys have not expired.

            if now < timeout:

                break

            # NOTE(flaper87): Unset every key in

            # this set from the cache if its timeout

            # is equal to `timeout`. (The key might

            # have been updated)

            for subkey in self._keys_expires.pop(timeout):

                try:

                    if self._cache[subkey][0] == timeout:

                        del self._cache[subkey]

                except KeyError:

                    continue

**** CubicPower OpenStack Study ****

    def __delitem__(self, key):

        self._purge_expired()

        # NOTE(flaper87): Delete the key. Using pop

        # since it could have been deleted already

        value = self._cache.pop(key, None)

        if value:

            try:

                # NOTE(flaper87): Keys with ttl == 0

                # don't exist in the _keys_expires dict

                self._keys_expires[value[0]].remove(value[1])

            except (KeyError, ValueError):

                pass

**** CubicPower OpenStack Study ****

    def _clear(self):

        self._cache = {}

        self._keys_expires = collections.defaultdict(set)

**** CubicPower OpenStack Study ****

    def _get_many(self, keys, default):

        return super(MemoryBackend, self)._get_many(keys, default)

**** CubicPower OpenStack Study ****

    def _set_many(self, data, ttl=0):

        return super(MemoryBackend, self)._set_many(data, ttl)

**** CubicPower OpenStack Study ****

    def _unset_many(self, keys):

        return super(MemoryBackend, self)._unset_many(keys)