Module: Mongoid::Threaded
- Extended by:
- Threaded
- Included in:
- Threaded
- 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.
Defined Under Namespace
Modules: Lifecycle
Constant Summary collapse
- STORAGE_KEY =
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 =
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'- DATABASE_OVERRIDE_KEY =
'db-override'- CLIENT_OVERRIDE_KEY =
The key to override the client.
'client-override'- CURRENT_SCOPE_KEY =
The key for the current thread's scope stack.
'current-scope'- AUTOSAVES_KEY =
'autosaves'- VALIDATIONS_KEY =
'validations'- TOUCH_MERGED_KEY =
'touch-merged'- STACK_KEYS =
Hash.new do |hash, key| hash[key] = "#{key}-stack" end
- COLLECTION_MANAGEMENT =
The name of the stack tracking collection and index management.
:collection_management- SESSIONS_KEY =
The key for the current thread's sessions.
'sessions'- MODIFIED_DOCUMENTS_KEY =
The key for storing documents modified inside transactions.
'modified-documents'- EXECUTE_CALLBACKS =
The key storing the default value for whether or not callbacks are executed on documents.
'execute-callbacks'- REGEXP_BUDGET_KEY =
The key for the time left in the current in-memory regexp budget.
'regexp-budget'- BIND =
'bind'- ASSIGN =
'assign'- BUILD =
'build'- LOAD =
'load'- CREATE =
'create'
Instance Method Summary collapse
-
#add_modified_document(session, document) ⇒ Object
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) ⇒ Object
Begin autosaving a document on the current thread.
-
#begin_execution(name) ⇒ true
Begin entry into a named thread local stack.
-
#begin_touch_merged(document) ⇒ Object
Mark that a document's touch updates have been merged into an atomic insert on the current thread.
-
#begin_validate(document) ⇒ Object
Begin validating a document on the current thread.
-
#begin_without_default_scope(klass) ⇒ Object
private
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.
-
#client_override ⇒ String | Symbol
Get the global client override.
-
#client_override=(name) ⇒ String | Symbol
Set the global client override.
-
#current_scope(klass = nil) ⇒ Criteria
Get the current Mongoid scope.
-
#current_scope=(scope) ⇒ Criteria
Set the current Mongoid scope.
-
#database_override ⇒ String | Symbol
Get the global database override.
-
#database_override=(name) ⇒ String | Symbol
Set the global database override.
-
#delete(key) ⇒ Object
Removes the named variable from local storage.
-
#execute_callbacks=(flag) ⇒ Object
Indicates whether document callbacks should be invoked by default for the current thread.
-
#execute_callbacks? ⇒ true | false
Queries whether document callbacks should be executed by default for the current thread.
-
#executing?(name) ⇒ true
Are in the middle of executing the named stack.
-
#exit_autosave(document) ⇒ Object
Exit autosaving a document on the current thread.
-
#exit_execution(name) ⇒ true
Exit from a named thread local stack.
-
#exit_touch_merged(document) ⇒ Object
Clear the touch-merged flag for a document on the current thread.
-
#exit_validate(document) ⇒ Object
Exit validating a document on the current thread.
-
#exit_without_default_scope(klass) ⇒ Object
private
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.
-
#managing_collection? ⇒ true | false
Is collection or index management being executed?.
-
#modified_documents ⇒ Hash<Mongo::Session, Set<Mongoid::Document>>
private
Returns the thread store of modified documents.
-
#reset! ⇒ Object
Resets the current thread- or fiber-local storage to its initial state.
-
#sessions ⇒ Hash<Integer, Set>
private
Returns the thread store of sessions.
-
#set(key, value) ⇒ Object
Sets a variable in local storage with the given name to the given value.
-
#set_current_scope(scope, klass) ⇒ Criteria
Set the current Mongoid scope.
-
#set_session(session, client: nil) ⇒ Object
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.
-
#with_collection_management ⇒ Object
Execute the block as collection or index management.
-
#without_default_scope?(klass) ⇒ Boolean
private
Is the given klass' default scope suppressed on the current thread?.
Instance Method Details
#add_modified_document(session, document) ⇒ Object
Store a reference to the document that was modified inside a transaction associated with the session.
540 541 542 543 544 |
# File 'lib/mongoid/threaded.rb', line 540 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?
404 405 406 |
# File 'lib/mongoid/threaded.rb', line 404 def autosaved?(document) autosaves_for(document.class).include?(document._id) end |
#autosaves ⇒ Hash
Get all autosaves on the current thread.
439 440 441 |
# File 'lib/mongoid/threaded.rb', line 439 def autosaves get(AUTOSAVES_KEY) { {} } end |
#autosaves_for(klass) ⇒ Array
Get all autosaves on the current thread for the class.
461 462 463 |
# File 'lib/mongoid/threaded.rb', line 461 def autosaves_for(klass) autosaves[klass] ||= [] end |
#begin_autosave(document) ⇒ Object
Begin autosaving a document on the current thread.
234 235 236 |
# File 'lib/mongoid/threaded.rb', line 234 def begin_autosave(document) autosaves_for(document.class).push(document._id) end |
#begin_execution(name) ⇒ true
Begin entry into a named thread local stack.
136 137 138 |
# File 'lib/mongoid/threaded.rb', line 136 def begin_execution(name) stack(name).push(true) end |
#begin_touch_merged(document) ⇒ Object
Mark that a document's touch updates have been merged into an atomic insert on the current thread.
255 256 257 |
# File 'lib/mongoid/threaded.rb', line 255 def begin_touch_merged(document) touch_merged_for(document.class).push(document._id) end |
#begin_validate(document) ⇒ Object
Begin validating a document on the current thread.
244 245 246 |
# File 'lib/mongoid/threaded.rb', line 244 def begin_validate(document) validations_for(document.class).push(document._id) end |
#begin_without_default_scope(klass) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Begin suppressing default scopes for given model on the current thread.
297 298 299 |
# File 'lib/mongoid/threaded.rb', line 297 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.
553 554 555 |
# File 'lib/mongoid/threaded.rb', line 553 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 client parameter.
530 531 532 |
# File 'lib/mongoid/threaded.rb', line 530 def clear_session(client: nil) sessions.delete(client)&.end_session end |
#client_override ⇒ String | Symbol
Get the global client override.
319 320 321 |
# File 'lib/mongoid/threaded.rb', line 319 def client_override get(CLIENT_OVERRIDE_KEY) end |
#client_override=(name) ⇒ String | Symbol
Set the global client override.
331 332 333 |
# File 'lib/mongoid/threaded.rb', line 331 def client_override=(name) set(CLIENT_OVERRIDE_KEY, name) end |
#current_scope(klass = nil) ⇒ Criteria
Get the current Mongoid scope.
344 345 346 347 348 349 350 351 352 |
# File 'lib/mongoid/threaded.rb', line 344 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
Set the current Mongoid scope.
362 363 364 |
# File 'lib/mongoid/threaded.rb', line 362 def current_scope=(scope) set(CURRENT_SCOPE_KEY, scope) end |
#database_override ⇒ String | Symbol
Get the global database override.
146 147 148 |
# File 'lib/mongoid/threaded.rb', line 146 def database_override get(DATABASE_OVERRIDE_KEY) end |
#database_override=(name) ⇒ String | Symbol
Set the global database override.
158 159 160 |
# File 'lib/mongoid/threaded.rb', line 158 def database_override=(name) set(DATABASE_OVERRIDE_KEY, name) end |
#delete(key) ⇒ Object
Removes the named variable from local storage.
115 116 117 |
# File 'lib/mongoid/threaded.rb', line 115 def delete(key) storage.delete(key) end |
#execute_callbacks=(flag) ⇒ Object
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.
579 580 581 |
# File 'lib/mongoid/threaded.rb', line 579 def execute_callbacks=(flag) set(EXECUTE_CALLBACKS, flag) end |
#execute_callbacks? ⇒ true | false
Queries whether document callbacks should be executed by default for the current thread.
Unless otherwise indicated (by #execute_callbacks=), this will return true.
565 566 567 568 569 570 571 |
# File 'lib/mongoid/threaded.rb', line 565 def execute_callbacks? if has?(EXECUTE_CALLBACKS) get(EXECUTE_CALLBACKS) else true end end |
#executing?(name) ⇒ true
Are in the middle of executing the named stack
170 171 172 |
# File 'lib/mongoid/threaded.rb', line 170 def executing?(name) !stack(name).empty? end |
#exit_autosave(document) ⇒ Object
Exit autosaving a document on the current thread.
265 266 267 |
# File 'lib/mongoid/threaded.rb', line 265 def exit_autosave(document) autosaves_for(document.class).delete_one(document._id) end |
#exit_execution(name) ⇒ true
Exit from a named thread local stack.
212 213 214 |
# File 'lib/mongoid/threaded.rb', line 212 def exit_execution(name) stack(name).pop end |
#exit_touch_merged(document) ⇒ Object
Clear the touch-merged flag for a document on the current thread.
285 286 287 |
# File 'lib/mongoid/threaded.rb', line 285 def exit_touch_merged(document) touch_merged_for(document.class).delete_one(document._id) end |
#exit_validate(document) ⇒ Object
Exit validating a document on the current thread.
275 276 277 |
# File 'lib/mongoid/threaded.rb', line 275 def exit_validate(document) validations_for(document.class).delete_one(document._id) end |
#exit_without_default_scope(klass) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Exit suppressing default scopes for given model on the current thread.
309 310 311 |
# File 'lib/mongoid/threaded.rb', line 309 def exit_without_default_scope(klass) stack(:without_default_scope).delete(klass) end |
#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.
90 91 92 93 94 95 96 97 98 99 |
# File 'lib/mongoid/threaded.rb', line 90 def get(key, &default) result = storage[key] if result.nil? && default result = yield set(key, result) end result end |
#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 client parameter.
518 519 520 |
# File 'lib/mongoid/threaded.rb', line 518 def get_session(client: nil) sessions[client] end |
#has?(key) ⇒ true | false
Queries the presence of a named variable in local storage.
124 125 126 |
# File 'lib/mongoid/threaded.rb', line 124 def has?(key) storage.key?(key) end |
#managing_collection? ⇒ true | false
Is collection or index management being executed?
200 201 202 |
# File 'lib/mongoid/threaded.rb', line 200 def managing_collection? executing?(COLLECTION_MANAGEMENT) end |
#modified_documents ⇒ Hash<Mongo::Session, Set<Mongoid::Document>>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the thread store of modified documents.
598 599 600 |
# File 'lib/mongoid/threaded.rb', line 598 def modified_documents get(MODIFIED_DOCUMENTS_KEY) { Hash.new { |h, k| h[k] = Set.new } } end |
#reset! ⇒ Object
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 Mongoid::Config.real_isolation_level is used to determine whether to reset the storage for the current thread or fiber.
59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/mongoid/threaded.rb', line 59 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>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the thread store of sessions.
588 589 590 |
# File 'lib/mongoid/threaded.rb', line 588 def sessions get(SESSIONS_KEY) { {}.compare_by_identity } end |
#set(key, value) ⇒ Object
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.
108 109 110 |
# File 'lib/mongoid/threaded.rb', line 108 def set(key, value) storage[key] = value end |
#set_current_scope(scope, klass) ⇒ Criteria
Set the current Mongoid scope. Safe for multi-model scope chaining.
375 376 377 378 379 380 381 382 |
# File 'lib/mongoid/threaded.rb', line 375 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) ⇒ Object
For backward compatibility it is allowed to call this method without
Cache a session for this thread for a client.
specifying client parameter.
506 507 508 |
# File 'lib/mongoid/threaded.rb', line 506 def set_session(session, client: nil) sessions[client] = session end |
#stack(name) ⇒ Array
Get the named stack.
224 225 226 |
# File 'lib/mongoid/threaded.rb', line 224 def stack(name) get(STACK_KEYS[name]) { [] } end |
#touch_merged ⇒ Hash
Get all touch-merged tracking on the current thread.
483 484 485 |
# File 'lib/mongoid/threaded.rb', line 483 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?
429 430 431 |
# File 'lib/mongoid/threaded.rb', line 429 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.
495 496 497 |
# File 'lib/mongoid/threaded.rb', line 495 def touch_merged_for(klass) touch_merged[klass] ||= [] end |
#validated?(document) ⇒ true | false
Is the document validated on the current thread?
416 417 418 |
# File 'lib/mongoid/threaded.rb', line 416 def validated?(document) validations_for(document.class).include?(document._id) end |
#validations ⇒ Hash
Get all validations on the current thread.
449 450 451 |
# File 'lib/mongoid/threaded.rb', line 449 def validations get(VALIDATIONS_KEY) { {} } end |
#validations_for(klass) ⇒ Array
Get all validations on the current thread for the class.
473 474 475 |
# File 'lib/mongoid/threaded.rb', line 473 def validations_for(klass) validations[klass] ||= [] end |
#with_collection_management ⇒ Object
Execute the block as collection or index management.
Creating, dropping and inspecting collections and indexes sends no document data, so these operations are exempt from the encryption schema check that PersistenceContext applies to reads and writes. Without the exemption, tasks such as db:mongoid:create_collections would need an encryption-capable client to run.
186 187 188 189 190 191 |
# File 'lib/mongoid/threaded.rb', line 186 def with_collection_management begin_execution(COLLECTION_MANAGEMENT) yield ensure exit_execution(COLLECTION_MANAGEMENT) end |
#without_default_scope?(klass) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Is the given klass' default scope suppressed on the current thread?
392 393 394 |
# File 'lib/mongoid/threaded.rb', line 392 def without_default_scope?(klass) stack(:without_default_scope).include?(klass) end |