Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 512 lines (435 sloc) 18.055 kb
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
1 = ApplicationPool algorithm
2
3
4 == Introduction
5
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application conta...
FooBarWidget authored
6 For efficiency reasons, Passenger keeps a pool spawned Rails/Ruby applications.
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
7 Please read the C++ API documentation for the ApplicationPool class for a full
8eac99a @FooBarWidget Implement the 'PassengerMaxRequests' configuration option.
FooBarWidget authored
8 introduction. This document describes an algorithm for managing the pool, in a
9 high-level way.
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
10
11 The algorithm should strive to keep spawning to a minimum.
12
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing conditio...
FooBarWidget authored
13
14 == Definitions
15
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application conta...
FooBarWidget authored
16 === Vocabulary
17
18 - "Application root":
19 The toplevel directory in which an application is contained. For Rails
20 application, this is the same as RAILS_ROOT, i.e. the directory that contains
21 "app/", "public/", etc. For a Rack application, this is the directory that
22 contains "config.ru".
23
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
24 - "Active application process":
25 An application process that has more than 0 sessions.
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application conta...
FooBarWidget authored
26
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing conditio...
FooBarWidget authored
27 === Types
28
29 Most of the types that we use in this document are pretty standard. But we
30 explicitly define some special types:
31
32 - list<SomeType>
33 A doubly linked list which contains elements of type SomeType. It supports
34 all the usual list operations that one can expect from a linked list, like
35 add_to_back(), etc.
36
9c961e4 @FooBarWidget Some documentation updates.
FooBarWidget authored
37 We assume that operations that insert an element into the list return an
38 iterator object. An iterator object is an opaque object which represents a
39 specific position in the list; it probably contains the links to the previous
40 and the next iterator, as well as a reference to the actual list element,
41 depending on the list implementation.
42
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing conditio...
FooBarWidget authored
43 The following operations deserve special mention:
44 * remove(iterator)
9c961e4 @FooBarWidget Some documentation updates.
FooBarWidget authored
45 Removes the specified element from the list, as represented by the given
46 iterator. This operation can be done in O(1) time.
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing conditio...
FooBarWidget authored
47
48 * move_to_front(iterator)
9c961e4 @FooBarWidget Some documentation updates.
FooBarWidget authored
49 Moves the specified element - as represented by the given iterator - to
50 the front of the list. This operation can be done in O(1) time.
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing conditio...
FooBarWidget authored
51
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
52 - Group
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application conta...
FooBarWidget authored
53 A compound type (class) which contains information about an application root,
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
54 such as the application processes that have been spawned for this application
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application conta...
FooBarWidget authored
55 root.
56
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
57 A Group has the following members:
df9d8a8 @FooBarWidget Implement PassengerMinInstances for Apache and Nginx.
FooBarWidget authored
58 * processes (list<ProcessInfo>):
59 A list of ProcessInfo objects.
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application conta...
FooBarWidget authored
60
61 Invariant:
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
62 processes is non-empty.
63 for all 0 <= i < processes.size() - 1:
64 if processes[i].process is active:
65 processes[i + 1].process is active
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application conta...
FooBarWidget authored
66
df9d8a8 @FooBarWidget Implement PassengerMinInstances for Apache and Nginx.
FooBarWidget authored
67 * size (unsigned integer):
68 The number of items in _processes_.
69 Invariant:
70 if !detached:
71 size == processes.size()
8eac99a @FooBarWidget Implement the 'PassengerMaxRequests' configuration option.
FooBarWidget authored
72
df9d8a8 @FooBarWidget Implement PassengerMinInstances for Apache and Nginx.
FooBarWidget authored
73 * max_requests (unsigned integer):
74 The maximum number of requests that each application process in
75 this group may process. After having processed this
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
76 many requests, the application process will be shut down.
8eac99a @FooBarWidget Implement the 'PassengerMaxRequests' configuration option.
FooBarWidget authored
77 A value of 0 indicates that there is no maximum.
a1039bf @FooBarWidget Get rid of app_instance_count, that information is now stored in Domain.
FooBarWidget authored
78
df9d8a8 @FooBarWidget Implement PassengerMinInstances for Apache and Nginx.
FooBarWidget authored
79 * min_processes (unsigned integer):
80 The minimum number of processes that the cleaner thread should keep in
81 this group. Defaults to 0.
82
46c56e3 @FooBarWidget Minor changes to the application pool algorithm.
FooBarWidget authored
83 * detached (boolean): If true, then it indicates that this Group is
e55d098 @FooBarWidget Fix some errors in the application pool algorithm description.
FooBarWidget authored
84 no longer accessible via _groups_.
46c56e3 @FooBarWidget Minor changes to the application pool algorithm.
FooBarWidget authored
85 Set to false by the constructor.
86 Invariant:
e55d098 @FooBarWidget Fix some errors in the application pool algorithm description.
FooBarWidget authored
87 (detached) == (This Group is accessible via _groups_.)
46c56e3 @FooBarWidget Minor changes to the application pool algorithm.
FooBarWidget authored
88 if detached:
89 for all process_info objects p that have once been in this.processes:
90 p.detached
91
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
92 - ProcessInfo
93 A compound type (class) which contains a reference to an application process
94 object, as well as various metadata, such as iterators for various linked
95 lists. These iterators make it possible to perform actions on the linked
96 lists in O(1) time.
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing conditio...
FooBarWidget authored
97
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
98 A ProcessInfo has the following members:
99 * process - A process object, representing an application process.
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the connect...
FooBarWidget authored
100 * identifier (string) - A key that uniquely identifies this ProcessInfo in
101 this application pool. This key allows external processes to refer to a
102 specific ProcessInfo object without knowing its memory pointer. It's set
103 to a random string by ProcessInfo's constructor.
f569229 @FooBarWidget Fix some inconsistencies in the application pool algorithm description.
FooBarWidget authored
104 * start_time (timestamp with milisecond resolution) - The time at which this
d05bd9b @FooBarWidget Update the application pool algorithm description.
FooBarWidget authored
105 application process was started. It's set to the current time by the
106 constructor.
eb65c91 @FooBarWidget Display additional information in passenger-status: the number of reques...
FooBarWidget authored
107 * processed_requests (integer) - The number of requests processed by this
d05bd9b @FooBarWidget Update the application pool algorithm description.
FooBarWidget authored
108 application instance so far. Set to 0 by the constructor.
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
109 * last_used (time) - The last time a session for this application process
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing conditio...
FooBarWidget authored
110 was opened or closed.
111 * sessions (integer) - The number of open sessions for this application
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the connect...
FooBarWidget authored
112 process. It's set to 0 by the constructor.
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing conditio...
FooBarWidget authored
113 Invariant:
df9d8a8 @FooBarWidget Implement PassengerMinInstances for Apache and Nginx.
FooBarWidget authored
114 (sessions == 0 && !detached) == (This ProcessInfo is in inactive_apps.)
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
115 * iterator - The iterator for this ProcessInfo in the linked list
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
116 groups[process.app_root].processes
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
117 * ia_iterator - The iterator for this ProcessInfo in the linked list
118 inactive_apps. This iterator is only valid if this ProcessInfo really is
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing conditio...
FooBarWidget authored
119 in that list.
46c56e3 @FooBarWidget Minor changes to the application pool algorithm.
FooBarWidget authored
120 * detached (boolean) - If true, then it indicates that this ProcessInfo is
e55d098 @FooBarWidget Fix some errors in the application pool algorithm description.
FooBarWidget authored
121 no longer accessible via _groups_; this implies that it's no longer
46c56e3 @FooBarWidget Minor changes to the application pool algorithm.
FooBarWidget authored
122 contained in its associated Group's _processes_ member, a), and that
123 _iterator_ and _ia_iterator_ are no longer valid.
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the connect...
FooBarWidget authored
124 Set to false by the constructor.
125 Invariant:
e55d098 @FooBarWidget Fix some errors in the application pool algorithm description.
FooBarWidget authored
126 (detached) == (This ProcessInfo is accessible via _groups_.)
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing conditio...
FooBarWidget authored
127
4dacc10 @FooBarWidget Various refactorings and improvements.
FooBarWidget authored
128 - PoolOptions
129 A structure containing additional information used by the spawn manager's
130 spawning process, as well as by the get() function.
8eac99a @FooBarWidget Implement the 'PassengerMaxRequests' configuration option.
FooBarWidget authored
131
0bc257a @FooBarWidget Fix a bug which prevents ApplicationSpawner/FrameworkSpawner from being ...
FooBarWidget authored
132 A PoolOptions has at least the following members:
8eac99a @FooBarWidget Implement the 'PassengerMaxRequests' configuration option.
FooBarWidget authored
133 * max_requests (unsigned integer) - The maximum number of requests that the
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
134 application process may process. After having processed this many requests,
135 the application process will be shut down. A value of 0 indicates that there
8eac99a @FooBarWidget Implement the 'PassengerMaxRequests' configuration option.
FooBarWidget authored
136 is no maximum.
df9d8a8 @FooBarWidget Implement PassengerMinInstances for Apache and Nginx.
FooBarWidget authored
137 * min_processes (unsigned integer) - The minimum number of processes for the
138 current group that the cleaner thread should keep around.
4dacc10 @FooBarWidget Various refactorings and improvements.
FooBarWidget authored
139 * use_global_queue (boolean) - Whether to use a global queue for all
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
140 application processes, or a queue that's private to the application process.
4dacc10 @FooBarWidget Various refactorings and improvements.
FooBarWidget authored
141 The users guide explains this feature in more detail.
0bc257a @FooBarWidget Fix a bug which prevents ApplicationSpawner/FrameworkSpawner from being ...
FooBarWidget authored
142 * restart_dir (string) - The directory in which the algorithm should look for
143 restart.txt and always_restart.txt. The existance and modification times of
144 these files tell the algorithm whether an application should be restarted.
8eac99a @FooBarWidget Implement the 'PassengerMaxRequests' configuration option.
FooBarWidget authored
145
0e8110d @FooBarWidget Explicitly document locking in the ApplicationPool algorithm doucment. M...
FooBarWidget authored
146 === Special functions
147
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the connect...
FooBarWidget authored
148 - spawn(app_root, options)
149 Spawns a new application process at the given application root with the given
150 spawn options. Throws an exception if something went wrong. This function is
151 thread-safe. Note that application process initialization can take an arbitrary
152 amount of time.
0e8110d @FooBarWidget Explicitly document locking in the ApplicationPool algorithm doucment. M...
FooBarWidget authored
153
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing conditio...
FooBarWidget authored
154 === Instance variables
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
155
156 The algorithm requires the following instance variables for storing state
157 information:
158
0e8110d @FooBarWidget Explicitly document locking in the ApplicationPool algorithm doucment. M...
FooBarWidget authored
159 - lock: mutex
160 This lock is used for implementing thread-safetiness. We assume that it
161 is non-recursive, i.e. if a thread locks a mutex that it has already locked,
162 then it will result in a deadlock.
163
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
164 - groups: map[string => Group]
165 Maps an application root to its Group object. This map contains all
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
166 application processes in the pool.
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
167
a1039bf @FooBarWidget Get rid of app_instance_count, that information is now stored in Domain.
FooBarWidget authored
168 Invariant:
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
169 for all values g in groups:
46c56e3 @FooBarWidget Minor changes to the application pool algorithm.
FooBarWidget authored
170 !g.detached
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
171 g.size <= count
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the connect...
FooBarWidget authored
172 for all i in g.processes:
173 !i.detached
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
174 (sum of all g.size in groups) == count
a1039bf @FooBarWidget Get rid of app_instance_count, that information is now stored in Domain.
FooBarWidget authored
175
996ada0 @FooBarWidget Add some documentation
FooBarWidget authored
176 - max: integer
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
177 The maximum number of ProcessInfo objects that may exist in the pool.
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
178
7423478 @FooBarWidget Apply Jochen Tuchbreiter's RailsMaxInstancesPerApp patch. Doesn't pass u...
FooBarWidget authored
179 - max_per_app: integer
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
180 The maximum number of ProcessInfo objects that may be simultaneously alive
181 for a single Group.
7423478 @FooBarWidget Apply Jochen Tuchbreiter's RailsMaxInstancesPerApp patch. Doesn't pass u...
FooBarWidget authored
182
996ada0 @FooBarWidget Add some documentation
FooBarWidget authored
183 - count: integer
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
184 The current number of ProcessInfo objects in the pool.
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
185 Since 'max' can be set dynamically during the life time of an application
186 pool, 'count > max' is possible.
187
996ada0 @FooBarWidget Add some documentation
FooBarWidget authored
188 - active: integer
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
189 The number of application processes in the pool that are active.
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
190 Invariant:
191 active <= count
192
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
193 - inactive_apps: list<ProcessInfo>
194 A linked list of ProcessInfo objects. All application processes in this list
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing conditio...
FooBarWidget authored
195 are inactive.
196
197 Invariant:
198 inactive_apps.size() == count - active
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
199 for all x in inactive_apps:
e55d098 @FooBarWidget Fix some errors in the application pool algorithm description.
FooBarWidget authored
200 x can be accessed from _groups_.
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
201 x.sessions == 0
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing conditio...
FooBarWidget authored
202
64a39c0 @FooBarWidget Implement global queueing for ApplicationPool, to fight long-running req...
FooBarWidget authored
203 - waiting_on_global_queue: integer
204 If global queuing mode is enabled, then when get() is waiting for a backend
205 process to become idle, this variable will be incremented. When get() is done
206 waiting, this variable will be decremented.
207
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
208
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application conta...
FooBarWidget authored
209 == Class relations
210
211 Here's an UML diagram in ASCII art:
212
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
213 [ProcessInfo] 1..* --------+
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application conta...
FooBarWidget authored
214 |
215 |
216
217 1
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
218 [ApplicationPool] [Group]
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application conta...
FooBarWidget authored
219 1 0..*
220
221 | |
222 +-------------------+
223
224
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
225 == Algorithm in pseudo code
996ada0 @FooBarWidget Add some documentation
FooBarWidget authored
226
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing conditio...
FooBarWidget authored
227 # Thread-safetiness notes:
228 # - All wait commands are to unlock the lock during waiting.
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
229
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
230 # Connect to an existing application process, or spawn a new application process
231 # and connect to that if necessary.
232 # 'app_root' refers to an application root.
233 # 'options' is an object of type 'PoolOptions', which contains additional
234 # information which may be relevant for spawning.
8eac99a @FooBarWidget Implement the 'PassengerMaxRequests' configuration option.
FooBarWidget authored
235 function get(app_root, options):
542ea8c @FooBarWidget - Add invariant checks into the ApplicationPool code so that we can dete...
FooBarWidget authored
236 MAX_ATTEMPTS = 10
d0d8a84 @FooBarWidget ApplicationPool.get() now times out based on time instead of number of a...
FooBarWidget authored
237 attempt = 0
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the connect...
FooBarWidget authored
238 while (true):
239 attempt++
240 lock.synchronize:
dd80e55 @FooBarWidget Update ApplicationPool algorithm description: rename spawn_or_use_existi...
FooBarWidget authored
241 process_info, group = checkout_without_lock(app_root, options)
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the connect...
FooBarWidget authored
242 try:
243 return process_info.process.connect()
244 on exception:
245 # The app process seems to have crashed.
246 # So we remove this process from our data
247 # structures.
248 lock.synchronize:
249 detach_without_lock(process_info.identifier)
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
250 process_info.sessions--
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the connect...
FooBarWidget authored
251 if (attempt == MAX_ATTEMPTS):
252 propagate exception
253
254
dd80e55 @FooBarWidget Update ApplicationPool algorithm description: rename spawn_or_use_existi...
FooBarWidget authored
255 # Detach the process with the given identifier from the pool's data structures.
256 function detach(identifier):
257 lock.synchronize:
258 return detach_without_lock(identifier)
259
260
261 # Checkout a process from the application pool and mark it as being used.
262 # If there's no appropriate process in the pool, or if there are not
263 # enough processes, then one will be spawned.
264 #
265 # Returns a pair of [ProcessInfo, Group].
266 # All exceptions that occur are propagated.
267 private function checkout_without_lock(app_root, options):
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
268 group = groups[app_root]
ab0db05 @FooBarWidget Fixed the restart bug. :)
FooBarWidget authored
269
0bc257a @FooBarWidget Fix a bug which prevents ApplicationSpawner/FrameworkSpawner from being ...
FooBarWidget authored
270 if needs_restart(app_root, options):
2cd7e1f @FooBarWidget Various minor changes.
FooBarWidget authored
271 Tell spawn server to reload code for app_root.
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
272 if (group != nil):
273 for all process_info in group.processes:
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
274 if (process_info.sessions == 0):
275 inactive_apps.remove(process_info.ia_iterator)
0bc257a @FooBarWidget Fix a bug which prevents ApplicationSpawner/FrameworkSpawner from being ...
FooBarWidget authored
276 else:
277 active--
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
278 group.processes.remove(process_info.iterator)
85fc78c @FooBarWidget Reduce potential lock contention caused by the session close callback an...
FooBarWidget authored
279 process_info.detached = true
0bc257a @FooBarWidget Fix a bug which prevents ApplicationSpawner/FrameworkSpawner from being ...
FooBarWidget authored
280 count--
46c56e3 @FooBarWidget Minor changes to the application pool algorithm.
FooBarWidget authored
281 group.detached = true
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
282 groups.remove(app_root)
2cd7e1f @FooBarWidget Various minor changes.
FooBarWidget authored
283 group = nil
ab0db05 @FooBarWidget Fixed the restart bug. :)
FooBarWidget authored
284
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
285 if group != nil:
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
286 # There are existing processes for this app root.
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
287 processes = group.processes
5f3906d @FooBarWidget Update ApplicationPool algorithm description: wrap the application conta...
FooBarWidget authored
288
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
289 if (processes.front.sessions == 0):
290 # There is an inactive process, so we use it.
291 process_info = processes.front
292 processes.move_to_back(process_info.iterator)
293 inactive_apps.remove(process_info.ia_iterator)
ab0db05 @FooBarWidget Fixed the restart bug. :)
FooBarWidget authored
294 active++
542ea8c @FooBarWidget - Add invariant checks into the ApplicationPool code so that we can dete...
FooBarWidget authored
295 else if (count >= max) or (
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
296 (max_per_app != 0) and (group.size >= max_per_app)
542ea8c @FooBarWidget - Add invariant checks into the ApplicationPool code so that we can dete...
FooBarWidget authored
297 ):
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
298 # All processes are active, and the pool is full.
542ea8c @FooBarWidget - Add invariant checks into the ApplicationPool code so that we can dete...
FooBarWidget authored
299 # -OR-
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
300 # All processes are active and the maximum number of
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
301 # allowed processes for this application group has
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
302 # been reached.
542ea8c @FooBarWidget - Add invariant checks into the ApplicationPool code so that we can dete...
FooBarWidget authored
303 #
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
304 # We're not allowed to spawn a new application process.
d8d8cc9 @FooBarWidget Some code refactoring.
FooBarWidget authored
305 process_info = select_process(processes, options)
306 if process_info == null:
64a39c0 @FooBarWidget Implement global queueing for ApplicationPool, to fight long-running req...
FooBarWidget authored
307 goto beginning of function
ab0db05 @FooBarWidget Fixed the restart bug. :)
FooBarWidget authored
308 else:
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
309 # All processes are active, but the pool hasn't reached its
310 # maximum yet. So we spawn a new process.
d8d8cc9 @FooBarWidget Some code refactoring.
FooBarWidget authored
311 process = spawn(app_root, options)
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
312 process_info = new ProcessInfo
d8d8cc9 @FooBarWidget Some code refactoring.
FooBarWidget authored
313 process_info.process = process
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
314 iterator = processes.add_to_back(process_info)
315 process_info.iterator = iterator
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
316 group.size++
996ada0 @FooBarWidget Add some documentation
FooBarWidget authored
317 count++
318 active++
319 else:
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
320 # There are no processes for this app root.
f50d427 @FooBarWidget Fix a possible invariant violation in the application pool algorithm.
FooBarWidget authored
321 if (active >= max):
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
322 # Looks like the pool is full and all processes are busy.
323 # We wait until there's at least 1 idle process, or until
324 # there's an empty slot in the pool, then restart this
325 # function.
f50d427 @FooBarWidget Fix a possible invariant violation in the application pool algorithm.
FooBarWidget authored
326 wait until _active_ has changed
9848353 @FooBarWidget Fix a typo.
FooBarWidget authored
327 goto beginning of function
f50d427 @FooBarWidget Fix a possible invariant violation in the application pool algorithm.
FooBarWidget authored
328 elsif count == max:
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
329 # The pool is full, and not all processes are busy, but
330 # we're in a though situation nevertheless: there are
331 # several processes which are inactive, and none of them
332 # have application root _app_root_, so we must kill one
333 # of them in order to free a spot in the pool. But which
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing conditio...
FooBarWidget authored
334 # one do we kill? We want to minimize spawning.
335 #
336 # It's probably a good idea to keep some kind of
337 # statistics in order to decide this. We want the
338 # application root that gets the least traffic to be
339 # killed. But for now, we kill a random application
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
340 # process.
341 process_info = inactive_apps.pop_front
85fc78c @FooBarWidget Reduce potential lock contention caused by the session close callback an...
FooBarWidget authored
342 process_info.detached = true
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
343 group = groups[process_info.app.app_root]
344 processes = group.processes
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
345 processes.remove(process_info.iterator)
346 if processes.empty():
46c56e3 @FooBarWidget Minor changes to the application pool algorithm.
FooBarWidget authored
347 group.detached = true
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
348 groups.remove(process_info.process.app_root)
7423478 @FooBarWidget Apply Jochen Tuchbreiter's RailsMaxInstancesPerApp patch. Doesn't pass u...
FooBarWidget authored
349 else:
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
350 group.size--
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing conditio...
FooBarWidget authored
351 count--
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
352 process_info = new ProcessInfo
d05bd9b @FooBarWidget Update the application pool algorithm description.
FooBarWidget authored
353 process_info.process = spawn(app_root, options)
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
354 group = new Group
355 group.size = 1
356 group.max_requests = options.max_requests
df9d8a8 @FooBarWidget Implement PassengerMinInstances for Apache and Nginx.
FooBarWidget authored
357 group.min_processes = options.min_processes
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
358 groups[app_root] = group
359 iterator = group.processes.add_to_back(process_info)
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
360 process_info.iterator = iterator
996ada0 @FooBarWidget Add some documentation
FooBarWidget authored
361 count++
362 active++
ad57387 @FooBarWidget Refactor some code.
FooBarWidget authored
363
364 process_info.last_used = current_time()
365 process_info.sessions++
4263b80 @FooBarWidget Remove a dead code branch in the ApplicationPool algorithm and rename Do...
FooBarWidget authored
366 return [process_info, group]
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing conditio...
FooBarWidget authored
367
368
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the connect...
FooBarWidget authored
369 private function needs_restart(app_root, options):
0bc257a @FooBarWidget Fix a bug which prevents ApplicationSpawner/FrameworkSpawner from being ...
FooBarWidget authored
370 if (options.restart_dir is not set):
371 restart_dir = app_root + "/tmp"
372 else if (options.restart_dir is an absolute path):
373 restart_dir = options.restart_dir
374 else:
375 restart_dir = app_root + "/" + options.restart_dir
376
377 return (file_exists("$restart_dir/always_restart.txt")) or
378 (we haven't seen "$restart_dir/restart.txt" before) or
379 ("$restart_dir/restart.txt" changed since the last time we checked)
090e459 @FooBarWidget Improve ApplicationPool algorithm: better support for restarts, fix a fe...
FooBarWidget authored
380
381
d8d8cc9 @FooBarWidget Some code refactoring.
FooBarWidget authored
382 private function select_process(processes, options):
383 if options.use_global_queue:
384 # So we wait until _active_ has changed, then
385 # we restart this function and try again.
386 waiting_on_global_queue++
387 wait until _active_ has changed
388 waiting_on_global_queue--
389 return null
390 else:
391 # So we connect to an already active process.
392 # This connection will be put into that
393 # process's private queue.
394 process_info = an element in _processes_ with the smallest _session_ value
395 processes.move_to_back(process_info.iterator)
396 return process_info
397
398
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the connect...
FooBarWidget authored
399 private function detach_without_lock(identifier):
400 for group in groups:
401 processes = group.processes
402 for process_info in processes:
403 if process_info.identifier == identifier:
404 # Found a matching process.
405 process_info.detached = true
406 processes.remove(process_info.iterator)
407 group.size--
408 if processes.empty():
46c56e3 @FooBarWidget Minor changes to the application pool algorithm.
FooBarWidget authored
409 group.detached = true
1e6b245 @FooBarWidget Increase ApplicationPool::Interface::get() concurrency: move the connect...
FooBarWidget authored
410 groups.remove(process_info.process.app_root)
411 if process_info.sessions == 0:
412 inactive_apps.remove(process_info.ia_iterator)
413 else:
414 active--
415 count--
416 return true
417 return false
418
419
712efad @FooBarWidget Update ApplicationPool algorithm description: move some code pieces arou...
FooBarWidget authored
420 # The following function is to be called when a session has been closed.
85fc78c @FooBarWidget Reduce potential lock contention caused by the session close callback an...
FooBarWidget authored
421 # _process_info_ is a weak reference to the ProcessInfo that belongs to
422 # the process whose session has been closed; it evaluates to NULL if the
423 # ProcessInfo object that it belongs to has been destroyed.
712efad @FooBarWidget Update ApplicationPool algorithm description: move some code pieces arou...
FooBarWidget authored
424 callback session_has_been_closed(process_info):
395b9d8 @FooBarWidget Minor updates.
FooBarWidget authored
425 Convert process_info into a normal reference.
85fc78c @FooBarWidget Reduce potential lock contention caused by the session close callback an...
FooBarWidget authored
426
427 # We check process_info.detached without locking. This should be safe:
428 # even if a boolean update isn't atomic on the current CPU, a non-zero
395b9d8 @FooBarWidget Minor updates.
FooBarWidget authored
429 # value evaluates to true. Once true, _detached_ will never become false,
85fc78c @FooBarWidget Reduce potential lock contention caused by the session close callback an...
FooBarWidget authored
430 # so instruction reorderings by the compiler or CPU won't cause any
431 # damage.
432 if (process_info == null) or (process_info.detached):
433 return
434
712efad @FooBarWidget Update ApplicationPool algorithm description: move some code pieces arou...
FooBarWidget authored
435 lock.synchronize:
85fc78c @FooBarWidget Reduce potential lock contention caused by the session close callback an...
FooBarWidget authored
436 if process_info.detached:
437 return
438
712efad @FooBarWidget Update ApplicationPool algorithm description: move some code pieces arou...
FooBarWidget authored
439 group = groups[process_info.process.app_root]
85fc78c @FooBarWidget Reduce potential lock contention caused by the session close callback an...
FooBarWidget authored
440 processes = group.processes
441 process_info.processed++
442
443 if (group.max_requests > 0) and (process_info.processed >= group.max_requests):
444 # The application process has processed its maximum allowed
445 # number of requests, so we shut it down.
446 process_info.detached = true
447 processes.remove(process_info.iterator)
448 group.size--
449 if processes.empty():
46c56e3 @FooBarWidget Minor changes to the application pool algorithm.
FooBarWidget authored
450 group.detached = true
85fc78c @FooBarWidget Reduce potential lock contention caused by the session close callback an...
FooBarWidget authored
451 groups.remove(app_root)
452 count--
453 if (process_info.sessions == 0):
454 inactive_apps.remove(process_info.ia_iterator)
712efad @FooBarWidget Update ApplicationPool algorithm description: move some code pieces arou...
FooBarWidget authored
455 else:
85fc78c @FooBarWidget Reduce potential lock contention caused by the session close callback an...
FooBarWidget authored
456 active--
457 else:
458 process_info.last_used = current_time()
459 process_info.sessions--
460 process_info.processed++
461 if (process_info.sessions == 0):
462 processes.move_to_front(process_info.iterator)
463 process_info.ia_iterator = inactive_apps.add_to_back(process_info.process)
464 active--
712efad @FooBarWidget Update ApplicationPool algorithm description: move some code pieces arou...
FooBarWidget authored
465
466
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
467 # The following thread will be responsible for cleaning up idle application
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
468 # process, i.e. processes that haven't been used for a while.
49e3fd3 @redmar added docs about setting the PassengerPoolIdleTime to 0.
redmar authored
469 # This can be disabled per app when setting it's maxIdleTime to 0.
b2456b1 @FooBarWidget Improve documentation for the ApplicationPool algorithm.
FooBarWidget authored
470 thread cleaner:
0e8110d @FooBarWidget Explicitly document locking in the ApplicationPool algorithm doucment. M...
FooBarWidget authored
471 lock.synchronize:
38a2816 @FooBarWidget Make the pool cleaner thread more efficient.
FooBarWidget authored
472 while true:
473 # If MAX_IDLE_TIME is 0 we don't clean up any processes,
474 # giving us the option to persist the processes
475 # forever unless it's killed in order to free up space
476 # for another process.
477 if (MAX_IDLE_TIME == 0):
478 Wait until the thread has been signalled to quit
479 or until MAX_IDLE_TIME changed.
480 if thread has been signalled to quit:
481 return
482 else:
483 restart loop
484 else:
485 Wait until MAX_IDLE_TIME seconds have passed,
486 or until the thread has been signalled to quit,
487 or until MAX_IDLE_TIME changed.
488 if thread has been signalled to quit:
489 return
490 else if MAX_IDLE_TIME changed:
491 restart loop
492
493 # Invariant:
494 # From this point on, MAX_IDLE_TIME > 0
bb8d4a8 @FooBarWidget Get rid of the global queue in StandardApplicationPool:
FooBarWidget authored
495
0e8110d @FooBarWidget Explicitly document locking in the ApplicationPool algorithm doucment. M...
FooBarWidget authored
496 now = current_time()
9e10831 @FooBarWidget Change some terminology: Application -> Process.
FooBarWidget authored
497 for all process_info in inactive_apps:
f569229 @FooBarWidget Fix some inconsistencies in the application pool algorithm description.
FooBarWidget authored
498 if (now - process_info.last_used > MAX_IDLE_TIME):
df9d8a8 @FooBarWidget Implement PassengerMinInstances for Apache and Nginx.
FooBarWidget authored
499 process = process_info.process
38a2816 @FooBarWidget Make the pool cleaner thread more efficient.
FooBarWidget authored
500 group = groups[process.app_root]
f569229 @FooBarWidget Fix some inconsistencies in the application pool algorithm description.
FooBarWidget authored
501 if (group.size > group.min_processes):
df9d8a8 @FooBarWidget Implement PassengerMinInstances for Apache and Nginx.
FooBarWidget authored
502 processes = group.processes
503 processes.remove(process_info.iterator)
504 process_info.detached = true
505 inactive_apps.remove(process_info.ia_iterator)
506 group.size--
507 count--
508 if processes.empty():
509 group.detached = true
510 groups.remove(process.app_root)
5a01c90 @FooBarWidget Improve the ApplicationPool algorithm: fix some possible racing conditio...
FooBarWidget authored
511
Something went wrong with that request. Please try again.