def _get_cached_solve(self):
if not (self.caching and self.memcached_servers):<EOL><INDENT>return None<EOL><DEDENT>variant_states = {}<EOL>last_release_times = {}<EOL>def _hit(data):<EOL><INDENT>solver_dict, _, _ = data<EOL>return solver_dict<EOL><DEDENT>def _miss():<EOL><INDENT>self._print("<STR_LIT>")<EOL>return None<EOL><DEDENT>def _delete_cache_entry(key):<EOL><INDENT>with self._memcached_client() as client:<EOL><INDENT>client.delete(key)<EOL><DEDENT>self._print("<STR_LIT>", key)<EOL><DEDENT>def _retrieve(timestamped):<EOL><INDENT>key = self._memcache_key(timestamped=timestamped)<EOL>self._print("<STR_LIT>", key)<EOL>with self._memcached_client() as client:<EOL><INDENT>data = client.get(key)<EOL><DEDENT>return key, data<EOL><DEDENT>def _packages_changed(key, data):<EOL><INDENT>solver_dict, _, variant_states_dict = data<EOL>for variant_handle in solver_dict.get("<STR_LIT>", []):<EOL><INDENT>variant = self._get_variant(variant_handle)<EOL>old_state = variant_states_dict.get(variant.name)<EOL>new_state = variant_states.get(variant)<EOL>if new_state is None:<EOL><INDENT>try:<EOL><INDENT>repo = variant.resource._repository<EOL>new_state = repo.get_variant_state_handle(variant.resource)<EOL><DEDENT>except (IOError, OSError) as e:<EOL><INDENT>self._print("<STR_LIT>"<EOL>"<STR_LIT>", variant.qualified_name,<EOL>e)<EOL>return True<EOL><DEDENT>variant_states[variant] = new_state<EOL><DEDENT>if old_state != new_state:<EOL><INDENT>self._print("<STR_LIT>", variant.qualified_name)<EOL>return True<EOL><DEDENT><DEDENT>return False<EOL><DEDENT>def _releases_since_solve(key, data):<EOL><INDENT>_, release_times_dict, _ = data<EOL>for package_name, release_time in release_times_dict.iteritems():<EOL><INDENT>time_ = last_release_times.get(package_name)<EOL>if time_ is None:<EOL><INDENT>time_ = get_last_release_time(package_name, self.package_paths)<EOL>last_release_times[package_name] = time_<EOL><DEDENT>if time_ != release_time:<EOL><INDENT>self._print(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>", package_name, time_, release_time, key)<EOL>return True<EOL><DEDENT><DEDENT>return False<EOL><DEDENT>def _timestamp_is_earlier(key, data):<EOL><INDENT>_, release_times_dict, _ = data<EOL>for package_name, release_time in release_times_dict.iteritems():<EOL><INDENT>if self.timestamp < release_time:<EOL><INDENT>self._print("<STR_LIT>"<EOL>"<STR_LIT>", self.timestamp,<EOL>package_name, release_time, key)<EOL>return True<EOL><DEDENT><DEDENT>return False<EOL><DEDENT>key, data = _retrieve(False)<EOL>if self.timestamp:<EOL><INDENT>if data:<EOL><INDENT>if _packages_changed(key, data) or _releases_since_solve(key, data):<EOL><INDENT>_delete_cache_entry(key)<EOL><DEDENT>elif not _timestamp_is_earlier(key, data):<EOL><INDENT>return _hit(data)<EOL><DEDENT><DEDENT>key, data = _retrieve(True)<EOL>if not data:<EOL><INDENT>return _miss()<EOL><DEDENT>if _packages_changed(key, data):<EOL><INDENT>_delete_cache_entry(key)<EOL>return _miss()<EOL><DEDENT>else:<EOL><INDENT>return _hit(data)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if not data:<EOL><INDENT>return _miss()<EOL><DEDENT>if _packages_changed(key, data) or _releases_since_solve(key, data):<EOL><INDENT>_delete_cache_entry(key)<EOL>return _miss()<EOL><DEDENT>else:<EOL><INDENT>return _hit(data)<EOL><DEDENT><DEDENT>
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).