Class: RightScale::CloudApi::CacheValidator

Inherits:
Routine show all
Defined in:
lib/base/routines/cache_validator.rb

Overview

The routine processes cache validations (when caching is enabled).

It takes a response from a cloud and tries to find a pre-defined caching pattern that would fit to this response and its request. If there is a pattern it extracts a previous response from the cache and compares it to the current one.

If both the responses match it raises RightScale::CloudApi::CacheHit exception.

The main point of the caching - it is performed before parsing a response. So if we get a 10M XML from Amazon it will take seconds to parse it but if the response did not change there is need to parse it.

The caching setting is per cloud specific ApiManager. For some of them it is on by default so you need to look at the ApiManager definition.

Examples:

ec2 = RightScale::CloudApi::AWS::EC2.new(key, secret_key, :cache => true)
ec2.DescribeInstances #=> a list of instances
ec2.DescribeInstances(:options => {:cache => false}) #=> the same list of instances
ec2.DescribeInstances #=> exception if the response did not change

Defined Under Namespace

Modules: ClassMethods Classes: Error

Instance Attribute Summary

Attributes inherited from Routine

#data

Instance Method Summary collapse

Methods inherited from Routine

#cloud_api_logger, #execute, #invoke_callback_method, #options, #reset, #with_timer

Instance Method Details

#log(message) ⇒ Object

Logs a message.



57
58
59
# File 'lib/base/routines/cache_validator.rb', line 57

def log(message)
  cloud_api_logger.log( "#{message}", :cache_validator)
end

#processObject

The main entry point.



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/base/routines/cache_validator.rb', line 98

def process
  # Do nothing if caching is off
  return nil unless data[:options][:cache]
  # There is nothing to cache if we stream things
  return nil if data[:response][:instance].is_io?

  cache_patterns = data[:options][:cache_patterns] || []
  opts = { :relative_path => data[:request][:relative_path],
           :request       => data[:request][:instance],
           :response      => data[:response][:instance],
           :verb          => data[:request][:verb],
           :params        => data[:request][:orig_params].dup }

  # Walk through all the cache patterns and find the first that matches
  cache_patterns.each do |pattern|
    # Try on the next pattern unless the current one matches.
    next unless Utils::pattern_matches?(pattern, opts)
    # Process the matching pattern.
    log("Request matches to cache pattern: #{pattern.inspect}")
    # Build a cache key and get a text to be signed
    cache_key, text_to_sign = build_cache_key(pattern, opts)
    cache_record = {
      :timestamp => Time::now.utc,
      :md5       => Digest::MD5::hexdigest(text_to_sign).to_s,
      :hits      => 0
    }
    log("Processing cache record: #{cache_key} => #{cache_record.inspect}")
    # Save current cache key for later use (by other Routines)
    data[:vars][:cache] ||= {}
    data[:vars][:cache][:key]    = cache_key
    data[:vars][:cache][:record] = cache_record
    # Get the cache storage
    storage = (data[:vars][:system][:storage][:cache] ||= {} )
    unless storage[cache_key]
      # Create a new record unless exists.
      storage[cache_key] = cache_record
      log("New cache record created")
    else
      # If the record is already there but the response changed the replace the old record.
      unless storage[cache_key][:md5] == cache_record[:md5]
        storage[cache_key] = cache_record
        log("Missed. Record is replaced")
      else
        # Raise if cache hits.
        storage[cache_key][:hits] += 1
        message = "Cache hit: #{cache_key.inspect} has not changed since " +
                  "#{storage[cache_key][:timestamp].strftime('%Y-%m-%d %H:%M:%S')}, "+
                  "hits: #{storage[cache_key][:hits]}."
        log(message)
        fail CacheHit::new("CacheValidator: #{message}")
      end
    end
    break
  end
  true
end