Module: Mongoid::Threaded
| Relationships & Source Files | |
| Namespace Children | |
|
Modules:
| |
| Defined in: | lib/mongoid/threaded.rb, lib/mongoid/threaded/lifecycle.rb |
Overview
This module contains logic for easy access to objects that have a lifecycle on the current thread.
Constant Summary
-
ASSIGN =
# File 'lib/mongoid/threaded/lifecycle.rb', line 6'assign' -
AUTOSAVES_KEY =
# File 'lib/mongoid/threaded.rb', line 25'autosaves' -
BIND =
# File 'lib/mongoid/threaded/lifecycle.rb', line 5'bind' -
BUILD =
# File 'lib/mongoid/threaded/lifecycle.rb', line 7'build' -
CLIENT_OVERRIDE_KEY =
# File 'lib/mongoid/threaded.rb', line 20
The key to override the client.
'client-override' -
CREATE =
# File 'lib/mongoid/threaded/lifecycle.rb', line 9'create' -
CURRENT_SCOPE_KEY =
# File 'lib/mongoid/threaded.rb', line 23
The key for the current thread's scope stack.
'current-scope' -
DATABASE_OVERRIDE_KEY =
# File 'lib/mongoid/threaded.rb', line 17'db-override' -
EXECUTE_CALLBACKS =
# File 'lib/mongoid/threaded.rb', line 43
The key storing the default value for whether or not callbacks are executed on documents.
'execute-callbacks' -
LOAD =
# File 'lib/mongoid/threaded/lifecycle.rb', line 8'load' -
MODIFIED_DOCUMENTS_KEY =
# File 'lib/mongoid/threaded.rb', line 39
The key for storing documents modified inside transactions.
'modified-documents' -
SESSIONS_KEY =
# File 'lib/mongoid/threaded.rb', line 36
The key for the current thread's sessions.
'sessions' -
STACK_KEYS =
# File 'lib/mongoid/threaded.rb', line 31Hash.new do |hash, key| hash[key] = "#{key}-stack" end
-
STORAGE_KEY =
# File 'lib/mongoid/threaded.rb', line 11
The key for the shared thread- and fiber-local storage. It must be a symbol because keys for fiber-local storage must be symbols.
:'[mongoid]'
-
STORAGE_OWNER_KEY =
# File 'lib/mongoid/threaded.rb', line 15
Tracks which fiber owns the storage hash, to detect when a fiber has inherited (rather than created) its storage from a parent fiber.
:'[mongoid]:owner'
-
TOUCH_MERGED_KEY =
# File 'lib/mongoid/threaded.rb', line 29'touch-merged' -
VALIDATIONS_KEY =
# File 'lib/mongoid/threaded.rb', line 27'validations'
Instance Attribute Summary
-
#client_override ⇒ String | Symbol
rw
Get the global client override.
-
#client_override=(name) ⇒ String | Symbol
rw
::Setthe global client override. -
#database_override ⇒ String | Symbol
rw
Get the global database override.
-
#database_override=(name) ⇒ String | Symbol
rw
::Setthe global database override. -
#execute_callbacks=(flag)
rw
Indicates whether document callbacks should be invoked by default for the current thread.
-
#execute_callbacks? ⇒ true | false
rw
Queries whether document callbacks should be executed by default for the current thread.
Instance Method Summary
-
#add_modified_document(session, document)
Store a reference to the document that was modified inside a transaction associated with the session.
-
#autosaved?(document) ⇒ true | false
Is the document autosaved on the current thread?
-
#autosaves ⇒ Hash
Get all autosaves on the current thread.
-
#autosaves_for(klass) ⇒ Array
Get all autosaves on the current thread for the class.
-
#begin_autosave(document)
Begin autosaving a document on the current thread.
-
#begin_execution(name) ⇒ true
Begin entry into a named thread local stack.
-
#begin_touch_merged(document)
Mark that a document's touch updates have been merged into an atomic insert on the current thread.
-
#begin_validate(document)
Begin validating a document on the current thread.
-
#begin_without_default_scope(klass)
Internal use only
Internal use only
Begin suppressing default scopes for given model on the current thread.
-
#clear_modified_documents(session) ⇒ Set<Mongoid::Document>
Clears the set of modified documents for the given session, and return the content of the set before the clearance.
-
#clear_session(client: nil) ⇒ nil
Clear the cached session for this thread for a client.
-
#current_scope(klass = nil) ⇒ Criteria
Get the current
::Mongoidscope. - #current_scope=(scope) ⇒ Criteria
-
#delete(key)
Removes the named variable from local storage.
-
#executing?(name) ⇒ true
Are in the middle of executing the named stack.
-
#exit_autosave(document)
Exit autosaving a document on the current thread.
-
#exit_execution(name) ⇒ true
Exit from a named thread local stack.
-
#exit_touch_merged(document)
Clear the touch-merged flag for a document on the current thread.
-
#exit_validate(document)
Exit validating a document on the current thread.
-
#exit_without_default_scope(klass)
Internal use only
Internal use only
Exit suppressing default scopes for given model on the current thread.
-
#get(key, &default) ⇒ Object | nil
Queries the thread- or fiber-local variable with the given name.
-
#get_session(client: nil) ⇒ Mongo::Session | nil
Get the cached session for this thread for a client.
-
#has?(key) ⇒ true | false
Queries the presence of a named variable in local storage.
-
#modified_documents ⇒ Hash<Mongo::Session, Set<Mongoid::Document>>
Internal use only
Internal use only
Returns the thread store of modified documents.
-
#reset!
Resets the current thread- or fiber-local storage to its initial state.
-
#sessions ⇒ Hash<Integer, Set>
Internal use only
Internal use only
Returns the thread store of sessions.
-
#set(key, value)
Sets a variable in local storage with the given name to the given value.
- #set_current_scope(scope, klass) ⇒ Criteria
-
#set_session(session, client: nil)
Cache a session for this thread for a client.
-
#stack(name) ⇒ Array
Get the named stack.
-
#touch_merged ⇒ Hash
Get all touch-merged tracking on the current thread.
-
#touch_merged?(document) ⇒ true | false
Is the document flagged as having had its touch updates merged into an atomic insert?
-
#touch_merged_for(klass) ⇒ Array
Get all touch-merged document IDs on the current thread for the class.
-
#validated?(document) ⇒ true | false
Is the document validated on the current thread?
-
#validations ⇒ Hash
Get all validations on the current thread.
-
#validations_for(klass) ⇒ Array
Get all validations on the current thread for the class.
-
#without_default_scope?(klass) ⇒ Boolean
Internal use only
Internal use only
Is the given klass' default scope suppressed on the current thread?
-
#storage
private
Returns the current thread- or fiber-local storage as a
::Hash. -
#unset_current_scope(klass)
private
Removes the given klass from the current scope, and tidies the current scope list.
Instance Attribute Details
#client_override ⇒ String | Symbol (rw)
Get the global client override.
# File 'lib/mongoid/threaded.rb', line 283
def client_override get(CLIENT_OVERRIDE_KEY) end
#client_override=(name) ⇒ String | Symbol (rw)
::Set the global client override.
# File 'lib/mongoid/threaded.rb', line 295
def client_override=(name) set(CLIENT_OVERRIDE_KEY, name) end
#database_override ⇒ String | Symbol (rw)
Get the global database override.
# File 'lib/mongoid/threaded.rb', line 140
def database_override get(DATABASE_OVERRIDE_KEY) end
#database_override=(name) ⇒ String | Symbol (rw)
::Set the global database override.
# File 'lib/mongoid/threaded.rb', line 152
def database_override=(name) set(DATABASE_OVERRIDE_KEY, name) end
#execute_callbacks=(flag) (rw)
Indicates whether document callbacks should be invoked by default for the current thread. Individual documents may further override the callback behavior, but this will be used for the default behavior.
# File 'lib/mongoid/threaded.rb', line 543
def execute_callbacks=(flag) set(EXECUTE_CALLBACKS, flag) end
#execute_callbacks? ⇒ true | false (rw)
Queries whether document callbacks should be executed by default for the current thread.
Unless otherwise indicated (by #execute_callbacks=), this will return true.
# File 'lib/mongoid/threaded.rb', line 529
def execute_callbacks? if has?(EXECUTE_CALLBACKS) get(EXECUTE_CALLBACKS) else true end end
Instance Method Details
#add_modified_document(session, document)
Store a reference to the document that was modified inside a transaction associated with the session.
# File 'lib/mongoid/threaded.rb', line 504
def add_modified_document(session, document) return unless session&.in_transaction? modified_documents[session] << document end
#autosaved?(document) ⇒ true | false
Is the document autosaved on the current thread?
# File 'lib/mongoid/threaded.rb', line 368
def autosaved?(document) autosaves_for(document.class).include?(document._id) end
#autosaves ⇒ Hash
Get all autosaves on the current thread.
# File 'lib/mongoid/threaded.rb', line 403
def autosaves get(AUTOSAVES_KEY) { {} } end
#autosaves_for(klass) ⇒ Array
Get all autosaves on the current thread for the class.
# File 'lib/mongoid/threaded.rb', line 425
def autosaves_for(klass) autosaves[klass] ||= [] end
#begin_autosave(document)
Begin autosaving a document on the current thread.
# File 'lib/mongoid/threaded.rb', line 198
def begin_autosave(document) autosaves_for(document.class).push(document._id) end
#begin_execution(name) ⇒ true
Begin entry into a named thread local stack.
# File 'lib/mongoid/threaded.rb', line 130
def begin_execution(name) stack(name).push(true) end
#begin_touch_merged(document)
Mark that a document's touch updates have been merged into an atomic insert on the current thread.
# File 'lib/mongoid/threaded.rb', line 219
def begin_touch_merged(document) touch_merged_for(document.class).push(document._id) end
#begin_validate(document)
Begin validating a document on the current thread.
# File 'lib/mongoid/threaded.rb', line 208
def begin_validate(document) validations_for(document.class).push(document._id) end
#begin_without_default_scope(klass)
Begin suppressing default scopes for given model on the current thread.
# File 'lib/mongoid/threaded.rb', line 261
def begin_without_default_scope(klass) stack(:without_default_scope).push(klass) end
#clear_modified_documents(session) ⇒ Set<Mongoid::Document>
Clears the set of modified documents for the given session, and return the content of the set before the clearance.
# File 'lib/mongoid/threaded.rb', line 517
def clear_modified_documents(session) modified_documents.delete(session) || [] end
#clear_session(client: nil) ⇒ nil
For backward compatibility it is allowed to call this method without
Clear the cached session for this thread for a client.
specifying Mongoid#client parameter.
#current_scope(klass = nil) ⇒ Criteria
Get the current ::Mongoid scope.
# File 'lib/mongoid/threaded.rb', line 308
def current_scope(klass = nil) current_scope = get(CURRENT_SCOPE_KEY) if klass && current_scope.respond_to?(:keys) current_scope[current_scope.keys.find { |k| k <= klass }] else current_scope end end
#current_scope=(scope) ⇒ Criteria
[ GitHub ]# File 'lib/mongoid/threaded.rb', line 326
def current_scope=(scope) set(CURRENT_SCOPE_KEY, scope) end
#delete(key)
Removes the named variable from local storage.
# File 'lib/mongoid/threaded.rb', line 109
def delete(key) storage.delete(key) end
#executing?(name) ⇒ true
Are in the middle of executing the named stack
# File 'lib/mongoid/threaded.rb', line 164
def executing?(name) !stack(name).empty? end
#exit_autosave(document)
Exit autosaving a document on the current thread.
# File 'lib/mongoid/threaded.rb', line 229
def exit_autosave(document) autosaves_for(document.class).delete_one(document._id) end
#exit_execution(name) ⇒ true
Exit from a named thread local stack.
# File 'lib/mongoid/threaded.rb', line 176
def exit_execution(name) stack(name).pop end
#exit_touch_merged(document)
Clear the touch-merged flag for a document on the current thread.
# File 'lib/mongoid/threaded.rb', line 249
def exit_touch_merged(document) touch_merged_for(document.class).delete_one(document._id) end
#exit_validate(document)
Exit validating a document on the current thread.
# File 'lib/mongoid/threaded.rb', line 239
def exit_validate(document) validations_for(document.class).delete_one(document._id) end
#exit_without_default_scope(klass)
Exit suppressing default scopes for given model on the current thread.
#get(key, &default) ⇒ Object | nil
Queries the thread- or fiber-local variable with the given name. If a block is given, and the variable does not already exist, the return value of the block will be set as the value of the variable before returning it.
It is very important that applications (and especially ::Mongoid)
use this method instead of Thread#[], since Thread#[] is actually for
fiber-local variables, and ::Mongoid uses Fibers as an implementation
detail in some callbacks. Putting thread-local state in a fiber-local
store will result in the state being invisible when relevant callbacks are
run in a different fiber.
Affected callbacks are cascading callbacks on embedded children.
#get_session(client: nil) ⇒ Mongo::Session | nil
For backward compatibility it is allowed to call this method without
Get the cached session for this thread for a client.
specifying Mongoid#client parameter.
#has?(key) ⇒ true | false
Queries the presence of a named variable in local storage.
# File 'lib/mongoid/threaded.rb', line 118
def has?(key) storage.key?(key) end
#modified_documents ⇒ Hash<Mongo::Session, Set<Mongoid::Document>>
Returns the thread store of modified documents.
# File 'lib/mongoid/threaded.rb', line 562
def modified_documents get(MODIFIED_DOCUMENTS_KEY) { Hash.new { |h, k| h[k] = Set.new } } end
#reset!
Resets the current thread- or fiber-local storage to its initial state. This is useful for making sure the state is clean when starting a new thread or fiber.
The value of Config.real_isolation_level is used to determine
whether to reset the storage for the current thread or fiber.
# File 'lib/mongoid/threaded.rb', line 53
def reset! case Config.real_isolation_level when :thread Thread.current.thread_variable_set(STORAGE_KEY, nil) when :fiber Fiber[STORAGE_KEY] = {} Fiber[STORAGE_OWNER_KEY] = Fiber.current.object_id else raise "Unknown isolation level: #{Config.real_isolation_level.inspect}" end end
#sessions ⇒ Hash<Integer, Set>
Returns the thread store of sessions.
# File 'lib/mongoid/threaded.rb', line 552
def sessions get(SESSIONS_KEY) { {}.compare_by_identity } end
#set(key, value)
Sets a variable in local storage with the given name to the given value. See #get for a discussion of why this method is necessary, and why Thread#[]= should be avoided in cascading callbacks on embedded children.
# File 'lib/mongoid/threaded.rb', line 102
def set(key, value) storage[key] = value end
#set_current_scope(scope, klass) ⇒ Criteria
[ GitHub ]# File 'lib/mongoid/threaded.rb', line 339
def set_current_scope(scope, klass) if scope.nil? unset_current_scope(klass) else current_scope = get(CURRENT_SCOPE_KEY) { {} } current_scope[klass] = scope end end
#set_session(session, client: nil)
For backward compatibility it is allowed to call this method without
Cache a session for this thread for a client.
specifying Mongoid#client parameter.
#stack(name) ⇒ Array
Get the named stack.
# File 'lib/mongoid/threaded.rb', line 188
def stack(name) get(STACK_KEYS[name]) { [] } end
#storage (private)
Returns the current thread- or fiber-local storage as a ::Hash.
# File 'lib/mongoid/threaded.rb', line 582
def storage case Config.real_isolation_level when :thread storage_hash = Thread.current.thread_variable_get(STORAGE_KEY) unless storage_hash storage_hash = {} Thread.current.thread_variable_set(STORAGE_KEY, storage_hash) end storage_hash when :fiber # Fiber[] storage is inherited by child fibers, so multiple sibling # fibers would otherwise share a single mutable hash. We detect # inheritance by comparing the stored owner ID to the current fiber; # on first access by a new fiber we copy the inherited state so each # fiber starts with a snapshot of its parent's state rather than a # shared reference. if Fiber[STORAGE_OWNER_KEY] != Fiber.current.object_id Fiber[STORAGE_KEY] = (Fiber[STORAGE_KEY] || {}).dup Fiber[STORAGE_OWNER_KEY] = Fiber.current.object_id end Fiber[STORAGE_KEY] else raise "Unknown isolation level: #{Config.real_isolation_level.inspect}" end end
#touch_merged ⇒ Hash
Get all touch-merged tracking on the current thread.
# File 'lib/mongoid/threaded.rb', line 447
def touch_merged get(TOUCH_MERGED_KEY) { {} } end
#touch_merged?(document) ⇒ true | false
Is the document flagged as having had its touch updates merged into an atomic insert?
# File 'lib/mongoid/threaded.rb', line 393
def touch_merged?(document) touch_merged_for(document.class).include?(document._id) end
#touch_merged_for(klass) ⇒ Array
Get all touch-merged document IDs on the current thread for the class.
# File 'lib/mongoid/threaded.rb', line 459
def touch_merged_for(klass) touch_merged[klass] ||= [] end
#unset_current_scope(klass) (private)
Removes the given klass from the current scope, and tidies the current scope list.
# File 'lib/mongoid/threaded.rb', line 572
def unset_current_scope(klass) return unless has?(CURRENT_SCOPE_KEY) scope = get(CURRENT_SCOPE_KEY) scope.delete(klass) delete(CURRENT_SCOPE_KEY) if scope.empty? end
#validated?(document) ⇒ true | false
Is the document validated on the current thread?
# File 'lib/mongoid/threaded.rb', line 380
def validated?(document) validations_for(document.class).include?(document._id) end
#validations ⇒ Hash
Get all validations on the current thread.
# File 'lib/mongoid/threaded.rb', line 413
def validations get(VALIDATIONS_KEY) { {} } end
#validations_for(klass) ⇒ Array
Get all validations on the current thread for the class.
# File 'lib/mongoid/threaded.rb', line 437
def validations_for(klass) validations[klass] ||= [] end
#without_default_scope?(klass) ⇒ Boolean
Is the given klass' default scope suppressed on the current thread?
# File 'lib/mongoid/threaded.rb', line 356
def without_default_scope?(klass) stack(:without_default_scope).include?(klass) end