123456789_123456789_123456789_123456789_123456789_

Module: Mongo::QueryCache

Relationships & Source Files
Namespace Children
Classes:
Defined in: lib/mongo/query_cache.rb

Class Attribute Summary

Class Method Summary

Class Attribute Details

.enabled=(value) (rw)

Set whether the cache is enabled.

Examples:

Set if the cache is enabled.

QueryCache.enabled = true

Parameters:

  • value (true, false)

    The enabled value.

[ GitHub ]

  
# File 'lib/mongo/query_cache.rb', line 28

def enabled=(value)
  Thread.current["[mongo]:query_cache:enabled"] = value
end

.enabled?true, false (rw)

Is the query cache enabled on the current thread?

Examples:

Is the query cache enabled?

QueryCache.enabled?

Returns:

  • (true, false)

    If the cache is enabled.

[ GitHub ]

  
# File 'lib/mongo/query_cache.rb', line 38

def enabled?
  !!Thread.current["[mongo]:query_cache:enabled"]
end

Class Method Details

.cacheObject

Execute the block while using the query cache.

Examples:

Execute with the cache.

QueryCache.cache { collection.find }

Returns:

  • (Object)

    The result of the block.

[ GitHub ]

  
# File 'lib/mongo/query_cache.rb', line 48

def cache
  enabled = enabled?
  self.enabled = true
  begin
    yield
  ensure
    self.enabled = enabled
  end
end

.cache_key(**opts) (private)

[ GitHub ]

  
# File 'lib/mongo/query_cache.rb', line 223

def cache_key(**opts)
  unless opts[:namespace]
    raise ArgumentError.new("Cannot generate cache key without namespace")
  end
  unless opts[:selector]
    raise ArgumentError.new("Cannot generate cache key without selector")
  end

  [
    opts[:namespace],
    opts[:selector],
    opts[:skip],
    opts[:sort],
    opts[:projection],
    opts[:collation],
    opts[:read_concern],
    opts[:read_preference]
  ]
end

.cache_table

[ GitHub ]

  
# File 'lib/mongo/query_cache.rb', line 80

private def cache_table
  Thread.current["[mongo]:query_cache"] ||= {}
end

.clearnil

Clear the query cache.

Examples:

Clear the cache.

QueryCache.clear

Returns:

  • (nil)

    Always nil.

[ GitHub ]

  
# File 'lib/mongo/query_cache.rb', line 90

def clear
  Thread.current["[mongo]:query_cache"] = nil
end

.clear_namespace(namespace) ⇒ nil

This method is for internal use only.

Clear the section of the query cache storing cursors with results from this namespace.

Parameters:

  • namespace (String)

    The namespace to be cleared, in the format “database.collection”.

Returns:

  • (nil)

    Always nil.

[ GitHub ]

  
# File 'lib/mongo/query_cache.rb', line 103

def clear_namespace(namespace)
  cache_table.delete(namespace)
  # The nil key is where cursors are stored that could potentially read from
  # multiple collections. This key should be cleared on every write operation
  # to prevent returning stale data.
  cache_table.delete(nil)
  nil
end

.get(**opts) ⇒ Mongo::CachingCursor | nil

This method is for internal use only.

For the given query options, retrieve a cached cursor that can be used to obtain the correct query results, if one exists in the cache.

Parameters:

  • opts (Hash)

    a customizable set of options

Options Hash (**opts):

  • :namespace (String | nil)

    The namespace of the query, in the format “database_name.collection_name”.

  • :selector (Array, Hash)

    The selector passed to the query. For most queries, this will be a Hash, but for aggregations, this will be an Array representing the aggregation pipeline. May not be nil.

  • :skip (Integer | nil)

    The skip value of the query.

  • :sort (Hash | nil)

    The order of the query results (e.g. { name: -1 }).

  • :limit (Integer | nil)

    The limit value of the query.

  • :projection (Hash | nil)

    The projection of the query results (e.g. { name: 1 }).

  • :collation (Hash | nil)

    The collation of the query (e.g. { “locale” => “fr_CA” }).

  • :read_concern (Hash | nil)

    The read concern of the query (e.g. { level: :majority }).

  • :read_preference (Hash | nil)

    The read preference of the query (e.g. { mode: :secondary }).

  • :multi_collection (Boolean | nil)

    Whether the query results could potentially come from multiple collections. When true, these results will be stored under the nil namespace key and cleared on every write command.

Returns:

[ GitHub ]

  
# File 'lib/mongo/query_cache.rb', line 181

def get(**opts)
  limit = normalized_limit(opts[:limit])

  _namespace_key = namespace_key(**opts)
  _cache_key = cache_key(**opts)

  namespace_hash = cache_table[_namespace_key]
  return nil unless namespace_hash

  caching_cursor = namespace_hash[_cache_key]
  return nil unless caching_cursor

  caching_cursor_limit = normalized_limit(caching_cursor.view.limit)

  # There are two scenarios in which a caching cursor could fulfill the
  # query:
  # 1. The query has a limit, and the stored cursor has no limit or
  #    a larger limit.
  # 2. The query has no limit and the stored cursor has no limit.
  #
  # Otherwise, return nil because the stored cursor will not satisfy
  # the query.

  if limit && (caching_cursor_limit.nil? || caching_cursor_limit >= limit)
    caching_cursor
  elsif limit.nil? && caching_cursor_limit.nil?
    caching_cursor
  else
    nil
  end
end

.namespace_key(**opts) (private)

If the cached results can come from multiple collections, store this cursor under the nil namespace to be cleared on every write operation. Otherwise, store it under the specified namespace.

[ GitHub ]

  
# File 'lib/mongo/query_cache.rb', line 246

def namespace_key(**opts)
  if opts[:multi_collection]
    nil
  else
    opts[:namespace]
  end
end

.normalized_limit(limit)

[ GitHub ]

  
# File 'lib/mongo/query_cache.rb', line 213

def normalized_limit(limit)
  return nil unless limit
  # For the purposes of caching, a limit of 0 means no limit, as mongo treats it as such.
  return nil if limit == 0
  # For the purposes of caching, a negative limit is the same as as a positive limit.
  limit.abs
end

.set(cursor, **opts) ⇒ true

This method is for internal use only.

Store a CachingCursor instance in the query cache associated with the specified query options.

Parameters:

  • cursor (Mongo::CachingCursor)

    The CachingCursor instance to store.

  • opts (Hash)

    a customizable set of options

Options Hash (**opts):

  • :namespace (String | nil)

    The namespace of the query, in the format “database_name.collection_name”.

  • :selector (Array, Hash)

    The selector passed to the query. For most queries, this will be a Hash, but for aggregations, this will be an Array representing the aggregation pipeline. May not be nil.

  • :skip (Integer | nil)

    The skip value of the query.

  • :sort (Hash | nil)

    The order of the query results (e.g. { name: -1 }).

  • :limit (Integer | nil)

    The limit value of the query.

  • :projection (Hash | nil)

    The projection of the query results (e.g. { name: 1 }).

  • :collation (Hash | nil)

    The collation of the query (e.g. { “locale” => “fr_CA” }).

  • :read_concern (Hash | nil)

    The read concern of the query (e.g. { level: :majority }).

  • :read_preference (Hash | nil)

    The read preference of the query (e.g. { mode: :secondary }).

  • :multi_collection (Boolean | nil)

    Whether the query results could potentially come from multiple collections. When true, these results will be stored under the nil namespace key and cleared on every write command.

Returns:

  • (true)

    Always true.

[ GitHub ]

  
# File 'lib/mongo/query_cache.rb', line 142

def set(cursor, **opts)
  _cache_key = cache_key(**opts)
  _namespace_key = namespace_key(**opts)

  cache_table[_namespace_key] ||= {}
  cache_table[_namespace_key][_cache_key] = cursor

  true
end

.uncachedObject

Execute the block with the query cache disabled.

Examples:

Execute without the cache.

QueryCache.uncached { collection.find }

Returns:

  • (Object)

    The result of the block.

[ GitHub ]

  
# File 'lib/mongo/query_cache.rb', line 64

def uncached
  enabled = enabled?
  self.enabled = false
  begin
    yield
  ensure
    self.enabled = enabled
  end
end