@@ -6,38 +6,56 @@ module Mongoid
6
6
# This module contains logic for easy access to objects that have a lifecycle
7
7
# on the current thread.
8
8
module Threaded
9
- DATABASE_OVERRIDE_KEY = '[mongoid]:db-override'
9
+ # The key for the shared thread- and fiber-local storage. It must be a
10
+ # symbol because keys for fiber-local storage must be symbols.
11
+ STORAGE_KEY = :'[mongoid]'
10
12
11
- # Constant for the key to store clients.
12
- CLIENTS_KEY = '[mongoid]:clients'
13
+ DATABASE_OVERRIDE_KEY = 'db-override'
13
14
14
15
# The key to override the client.
15
- CLIENT_OVERRIDE_KEY = '[mongoid]: client-override'
16
+ CLIENT_OVERRIDE_KEY = 'client-override'
16
17
17
18
# The key for the current thread's scope stack.
18
- CURRENT_SCOPE_KEY = '[mongoid]: current-scope'
19
+ CURRENT_SCOPE_KEY = 'current-scope'
19
20
20
- AUTOSAVES_KEY = '[mongoid]: autosaves'
21
+ AUTOSAVES_KEY = 'autosaves'
21
22
22
- VALIDATIONS_KEY = '[mongoid]: validations'
23
+ VALIDATIONS_KEY = 'validations'
23
24
24
25
STACK_KEYS = Hash . new do |hash , key |
25
- hash [ key ] = "[mongoid]: #{ key } -stack"
26
+ hash [ key ] = "#{ key } -stack"
26
27
end
27
28
28
29
# The key for the current thread's sessions.
29
- SESSIONS_KEY = '[mongoid]: sessions'
30
+ SESSIONS_KEY = 'sessions'
30
31
31
32
# The key for storing documents modified inside transactions.
32
- MODIFIED_DOCUMENTS_KEY = '[mongoid]: modified-documents'
33
+ MODIFIED_DOCUMENTS_KEY = 'modified-documents'
33
34
34
35
# The key storing the default value for whether or not callbacks are
35
36
# executed on documents.
36
- EXECUTE_CALLBACKS = '[mongoid]: execute-callbacks'
37
+ EXECUTE_CALLBACKS = 'execute-callbacks'
37
38
38
39
extend self
39
40
40
- # Queries the thread-local variable with the given name. If a block is
41
+ # Resets the current thread- or fiber-local storage to its initial state.
42
+ # This is useful for making sure the state is clean when starting a new
43
+ # thread or fiber.
44
+ #
45
+ # The value of Mongoid::Config.isolation_level is used to determine
46
+ # whether to reset the storage for the current thread or fiber.
47
+ def reset!
48
+ case Config . isolation_level
49
+ when :thread
50
+ Thread . current . thread_variable_set ( STORAGE_KEY , nil )
51
+ when :fiber
52
+ Fiber [ STORAGE_KEY ] = nil
53
+ else
54
+ raise "Unknown isolation level: #{ Config . isolation_level . inspect } "
55
+ end
56
+ end
57
+
58
+ # Queries the thread- or fiber-local variable with the given name. If a block is
41
59
# given, and the variable does not already exist, the return value of the
42
60
# block will be set as the value of the variable before returning it.
43
61
#
@@ -57,7 +75,7 @@ module Threaded
57
75
# @return [ Object | nil ] the value of the queried variable, or nil if
58
76
# it is not set and no default was given.
59
77
def get ( key , &default )
60
- result = Thread . current . thread_variable_get ( key )
78
+ result = storage [ key ]
61
79
62
80
if result . nil? && default
63
81
result = yield
@@ -67,43 +85,31 @@ def get(key, &default)
67
85
result
68
86
end
69
87
70
- # Sets a thread- local variable with the given name to the given value.
88
+ # Sets a variable in local storage with the given name to the given value.
71
89
# See #get for a discussion of why this method is necessary, and why
72
90
# Thread#[]= should be avoided in cascading callbacks on embedded children.
73
91
#
74
92
# @param [ String | Symbol ] key the name of the variable to set.
75
93
# @param [ Object | nil ] value the value of the variable to set (or `nil`
76
94
# if you wish to unset the variable)
77
95
def set ( key , value )
78
- Thread . current . thread_variable_set ( key , value )
96
+ storage [ key ] = value
79
97
end
80
98
81
- # Removes the named variable from thread- local storage.
99
+ # Removes the named variable from local storage.
82
100
#
83
101
# @param [ String | Symbol ] key the name of the variable to remove.
84
102
def delete ( key )
85
- set ( key , nil )
103
+ storage . delete ( key )
86
104
end
87
105
88
- # Queries the presence of a named variable in thread- local storage.
106
+ # Queries the presence of a named variable in local storage.
89
107
#
90
108
# @param [ String | Symbol ] key the name of the variable to query.
91
109
#
92
110
# @return [ true | false ] whether the given variable is present or not.
93
111
def has? ( key )
94
- # Here we have a classic example of JRuby not behaving like MRI. In
95
- # MRI, if you set a thread variable to nil, it removes it from the list
96
- # and subsequent calls to thread_variable?(key) will return false. Not
97
- # so with JRuby. Once set, you cannot unset the thread variable.
98
- #
99
- # However, because setting a variable to nil is supposed to remove it,
100
- # we can assume a nil-valued variable doesn't actually exist.
101
-
102
- # So, instead of this:
103
- # Thread.current.thread_variable?(key)
104
-
105
- # We have to do this:
106
- !get ( key ) . nil?
112
+ storage . key? ( key )
107
113
end
108
114
109
115
# Begin entry into a named thread local stack.
@@ -508,5 +514,22 @@ def unset_current_scope(klass)
508
514
509
515
delete ( CURRENT_SCOPE_KEY ) if scope . empty?
510
516
end
517
+
518
+ # Returns the current thread- or fiber-local storage as a Hash.
519
+ def storage
520
+ case Config . isolation_level
521
+ when :thread
522
+ if !Thread . current . thread_variable? ( STORAGE_KEY )
523
+ Thread . current . thread_variable_set ( STORAGE_KEY , { } )
524
+ end
525
+
526
+ Thread . current . thread_variable_get ( STORAGE_KEY )
527
+ when :fiber
528
+ Fiber [ STORAGE_KEY ] ||= { }
529
+ else
530
+ raise "Unknown isolation level: #{ Config . isolation_level . inspect } "
531
+ end
532
+ end
533
+
511
534
end
512
535
end
0 commit comments