Find a memcached resolve.

        If there is NOT a resolve timestamp:
            - fetch a non-timestamped memcache entry;
            - if no entry, then fail;
            - if packages have changed, then:
              - delete the entry;
              -  fail;
            - if no packages in the entry have been released since, then
              - use the entry and return;
            - else:
              - delete the entry;
              - fail.

        If there IS a resolve timestamp (let us call this T):
            - fetch a non-timestamped memcache entry;
            - if entry then:
              - if no packages have changed, then:
                - if no packages in the entry have been released since:
                  - if no packages in the entry were released after T, then
                    - use the entry and return;
                - else:
                  - delete the entry;
              - else:
                - delete the entry;
            - fetch a timestamped (T) memcache entry;
            - if no entry, then fail;
            - if packages have changed, then:
              - delete the entry;
              - fail;
            - else:
              - use the entry.

        This behaviour exists specifically so that resolves that use a
        timestamp but set that to the current time, can be reused by other
        resolves if nothing has changed. Older resolves however, can only be
        reused if the timestamp matches exactly (but this might happen a lot -
        consider a workflow where a work area is tied down to a particular
        timestamp in order to 'lock' it from any further software releases).

def _get_cached_solve(self):
        """Find a memcached resolve.

        If there is NOT a resolve timestamp:
            - fetch a non-timestamped memcache entry;
            - if no entry, then fail;
            - if packages have changed, then:
              - delete the entry;
              -  fail;
            - if no packages in the entry have been released since, then
              - use the entry and return;
            - else:
              - delete the entry;
              - fail.

        If there IS a resolve timestamp (let us call this T):
            - fetch a non-timestamped memcache entry;
            - if entry then:
              - if no packages have changed, then:
                - if no packages in the entry have been released since:
                  - if no packages in the entry were released after T, then
                    - use the entry and return;
                - else:
                  - delete the entry;
              - else:
                - delete the entry;
            - fetch a timestamped (T) memcache entry;
            - if no entry, then fail;
            - if packages have changed, then:
              - delete the entry;
              - fail;
            - else:
              - use the entry.

        This behaviour exists specifically so that resolves that use a
        timestamp but set that to the current time, can be reused by other
        resolves if nothing has changed. Older resolves however, can only be
        reused if the timestamp matches exactly (but this might happen a lot -
        consider a workflow where a work area is tied down to a particular
        timestamp in order to 'lock' it from any further software releases).
        """
        if not (self.caching and self.memcached_servers):
            return None

        # these caches avoids some potentially repeated file stats
        variant_states = {}
        last_release_times = {}

        def _hit(data):
            solver_dict, _, _ = data
            return solver_dict

        def _miss():
            self._print("No cache key retrieved")
            return None

        def _delete_cache_entry(key):
            with self._memcached_client() as client:
                client.delete(key)
            self._print("Discarded entry: %r", key)

        def _retrieve(timestamped):
            key = self._memcache_key(timestamped=timestamped)
            self._print("Retrieving memcache key: %r", key)
            with self._memcached_client() as client:
                data = client.get(key)
            return key, data

        def _packages_changed(key, data):
            solver_dict, _, variant_states_dict = data
            for variant_handle in solver_dict.get("variant_handles", []):
                variant = self._get_variant(variant_handle)
                old_state = variant_states_dict.get(variant.name)

                new_state = variant_states.get(variant)
                if new_state is None:
                    try:
                        repo = variant.resource._repository
                        new_state = repo.get_variant_state_handle(variant.resource)
                    except (IOError, OSError) as e:
                        # if, ie a package file was deleted on disk, then
                        # an IOError or OSError will be raised when we try to
                        # read from it - assume that the packages have changed!
                        self._print("Error loading %r (assuming cached state "
                                    "changed): %s", variant.qualified_name,
                                    e)
                        return True
                    variant_states[variant] = new_state

                if old_state != new_state:
                    self._print("%r has been modified", variant.qualified_name)
                    return True
            return False

        def _releases_since_solve(key, data):
            _, release_times_dict, _ = data
            for package_name, release_time in release_times_dict.iteritems():
                time_ = last_release_times.get(package_name)
                if time_ is None:
                    time_ = get_last_release_time(package_name, self.package_paths)
                    last_release_times[package_name] = time_

                if time_ != release_time:
                    self._print(
                        "A newer version of %r (%d) has been released since the "
                        "resolve was cached (latest release in cache was %d) "
                        "(entry: %r)", package_name, time_, release_time, key)
                    return True
            return False

        def _timestamp_is_earlier(key, data):
            _, release_times_dict, _ = data
            for package_name, release_time in release_times_dict.iteritems():
                if self.timestamp < release_time:
                    self._print("Resolve timestamp (%d) is earlier than %r in "
                                "solve (%d) (entry: %r)", self.timestamp,
                                package_name, release_time, key)
                    return True
            return False

        key, data = _retrieve(False)

        if self.timestamp:
            if data:
                if _packages_changed(key, data) or _releases_since_solve(key, data):
                    _delete_cache_entry(key)
                elif not _timestamp_is_earlier(key, data):
                    return _hit(data)

            key, data = _retrieve(True)
            if not data:
                return _miss()
            if _packages_changed(key, data):
                _delete_cache_entry(key)
                return _miss()
            else:
                return _hit(data)
        else:
            if not data:
                return _miss()
            if _packages_changed(key, data) or _releases_since_solve(key, data):
                _delete_cache_entry(key)
                return _miss()
            else:
                return _hit(data)