passenger 5.0.9 → 5.0.10

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (106) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/CHANGELOG +15 -0
  5. data/CONTRIBUTORS +6 -0
  6. data/README.md +1 -1
  7. data/bin/passenger-install-apache2-module +24 -11
  8. data/bin/passenger-status +29 -14
  9. data/build/agents.rb +12 -10
  10. data/build/cxx_tests.rb +30 -30
  11. data/doc/Design and Architecture.html +1 -10
  12. data/doc/Design and Architecture.txt +1 -6
  13. data/doc/Users guide Apache.html +1 -19
  14. data/doc/Users guide Apache.txt +1 -1
  15. data/doc/Users guide Nginx.html +2 -20
  16. data/doc/Users guide Nginx.txt +2 -2
  17. data/doc/users_guide_snippets/tips.txt +0 -9
  18. data/ext/common/ApplicationPool2/ApiKey.h +158 -0
  19. data/ext/common/ApplicationPool2/BasicGroupInfo.h +81 -0
  20. data/ext/common/ApplicationPool2/BasicProcessInfo.h +106 -0
  21. data/ext/common/ApplicationPool2/Common.h +5 -44
  22. data/ext/common/ApplicationPool2/Context.h +94 -0
  23. data/ext/common/ApplicationPool2/Group.h +130 -1205
  24. data/ext/common/ApplicationPool2/Group/InitializationAndShutdown.cpp +190 -0
  25. data/ext/common/ApplicationPool2/Group/InternalUtils.cpp +329 -0
  26. data/ext/common/ApplicationPool2/Group/LifetimeAndBasics.cpp +103 -0
  27. data/ext/common/ApplicationPool2/{Pool/Debug.h → Group/Miscellaneous.cpp} +40 -38
  28. data/ext/common/ApplicationPool2/Group/OutOfBandWork.cpp +323 -0
  29. data/ext/common/ApplicationPool2/Group/ProcessListManagement.cpp +606 -0
  30. data/ext/common/ApplicationPool2/Group/SessionManagement.cpp +337 -0
  31. data/ext/common/ApplicationPool2/Group/SpawningAndRestarting.cpp +478 -0
  32. data/ext/common/ApplicationPool2/Group/StateInspection.cpp +197 -0
  33. data/ext/common/ApplicationPool2/Group/Verification.cpp +159 -0
  34. data/ext/common/ApplicationPool2/Implementation.cpp +19 -1401
  35. data/ext/common/ApplicationPool2/Options.h +5 -5
  36. data/ext/common/ApplicationPool2/Pool.h +260 -815
  37. data/ext/common/ApplicationPool2/Pool/{AnalyticsCollection.h → AnalyticsCollection.cpp} +55 -56
  38. data/ext/common/ApplicationPool2/Pool/{GarbageCollection.h → GarbageCollection.cpp} +49 -49
  39. data/ext/common/ApplicationPool2/Pool/GeneralUtils.cpp +241 -0
  40. data/ext/common/ApplicationPool2/Pool/GroupUtils.cpp +276 -0
  41. data/ext/common/ApplicationPool2/Pool/InitializationAndShutdown.cpp +145 -0
  42. data/ext/common/ApplicationPool2/Pool/Miscellaneous.cpp +244 -0
  43. data/ext/common/ApplicationPool2/Pool/ProcessUtils.cpp +330 -0
  44. data/ext/common/ApplicationPool2/Pool/StateInspection.cpp +299 -0
  45. data/ext/common/ApplicationPool2/Process.h +399 -205
  46. data/ext/common/ApplicationPool2/Session.h +70 -28
  47. data/ext/common/ApplicationPool2/Socket.h +1 -0
  48. data/ext/common/Constants.h +11 -3
  49. data/ext/common/Exceptions.h +1 -1
  50. data/ext/common/Logging.cpp +9 -4
  51. data/ext/common/Logging.h +6 -0
  52. data/ext/common/ServerKit/HttpServer.h +225 -215
  53. data/ext/common/ServerKit/Server.h +57 -57
  54. data/ext/common/SpawningKit/BackgroundIOCapturer.h +160 -0
  55. data/ext/common/SpawningKit/Config.h +107 -0
  56. data/ext/common/{ApplicationPool2 → SpawningKit}/DirectSpawner.h +17 -16
  57. data/ext/common/{ApplicationPool2 → SpawningKit}/DummySpawner.h +33 -33
  58. data/ext/common/{ApplicationPool2/SpawnerFactory.h → SpawningKit/Factory.h} +17 -17
  59. data/ext/common/{ApplicationPool2/ComponentInfo.h → SpawningKit/Options.h} +8 -21
  60. data/ext/common/SpawningKit/PipeWatcher.h +148 -0
  61. data/ext/common/{ApplicationPool2/PipeWatcher.h → SpawningKit/Result.h} +15 -33
  62. data/ext/common/{ApplicationPool2 → SpawningKit}/SmartSpawner.h +52 -57
  63. data/ext/common/{ApplicationPool2 → SpawningKit}/Spawner.h +83 -371
  64. data/ext/common/SpawningKit/UserSwitchingRules.h +265 -0
  65. data/ext/common/Utils/BufferedIO.h +24 -0
  66. data/ext/common/{ApplicationPool2/SpawnObject.h → Utils/ClassUtils.h} +24 -51
  67. data/ext/common/Utils/IOUtils.cpp +70 -0
  68. data/ext/common/Utils/IOUtils.h +19 -0
  69. data/ext/common/Utils/JsonUtils.h +113 -0
  70. data/ext/common/Utils/StrIntUtils.h +29 -0
  71. data/ext/common/Utils/json.h +1 -1
  72. data/ext/common/agents/ApiServerUtils.h +941 -0
  73. data/ext/common/agents/HelperAgent/{AdminServer.h → ApiServer.h} +163 -365
  74. data/ext/common/agents/HelperAgent/Main.cpp +86 -88
  75. data/ext/common/agents/HelperAgent/OptionParser.h +9 -10
  76. data/ext/common/agents/HelperAgent/RequestHandler/BufferBody.cpp +3 -0
  77. data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +2 -0
  78. data/ext/common/agents/HelperAgent/RequestHandler/Hooks.cpp +1 -1
  79. data/ext/common/agents/HelperAgent/RequestHandler/SendRequest.cpp +2 -2
  80. data/ext/common/agents/LoggingAgent/ApiServer.h +279 -0
  81. data/ext/common/agents/LoggingAgent/Main.cpp +41 -51
  82. data/ext/common/agents/LoggingAgent/OptionParser.h +11 -11
  83. data/ext/common/agents/Watchdog/ApiServer.h +311 -0
  84. data/ext/common/agents/Watchdog/Main.cpp +91 -65
  85. data/helper-scripts/prespawn +2 -0
  86. data/lib/phusion_passenger.rb +1 -1
  87. data/lib/phusion_passenger/admin_tools/instance.rb +1 -1
  88. data/lib/phusion_passenger/common_library.rb +27 -14
  89. data/lib/phusion_passenger/config/{admin_command_command.rb → api_call_command.rb} +19 -16
  90. data/lib/phusion_passenger/config/detach_process_command.rb +6 -3
  91. data/lib/phusion_passenger/config/main.rb +3 -5
  92. data/lib/phusion_passenger/config/reopen_logs_command.rb +29 -7
  93. data/lib/phusion_passenger/config/restart_app_command.rb +13 -4
  94. data/lib/phusion_passenger/config/utils.rb +15 -8
  95. data/lib/phusion_passenger/constants.rb +6 -2
  96. data/lib/phusion_passenger/platform_info/apache.rb +4 -0
  97. data/lib/phusion_passenger/platform_info/apache_detector.rb +18 -3
  98. data/resources/templates/apache2/mpm_unknown.txt.erb +20 -0
  99. metadata +42 -21
  100. metadata.gz.asc +7 -7
  101. data/ext/common/ApplicationPool2/Pool/GeneralUtils.h +0 -127
  102. data/ext/common/ApplicationPool2/Pool/Inspection.h +0 -219
  103. data/ext/common/ApplicationPool2/Pool/ProcessUtils.h +0 -85
  104. data/ext/common/ApplicationPool2/SuperGroup.h +0 -706
  105. data/ext/common/agents/LoggingAgent/AdminServer.h +0 -435
  106. data/ext/common/agents/Watchdog/AdminServer.h +0 -432
@@ -1,85 +0,0 @@
1
- /*
2
- * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011-2015 Phusion
4
- *
5
- * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
- *
7
- * Permission is hereby granted, free of charge, to any person obtaining a copy
8
- * of this software and associated documentation files (the "Software"), to deal
9
- * in the Software without restriction, including without limitation the rights
10
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- * copies of the Software, and to permit persons to whom the Software is
12
- * furnished to do so, subject to the following conditions:
13
- *
14
- * The above copyright notice and this permission notice shall be included in
15
- * all copies or substantial portions of the Software.
16
- *
17
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
- * THE SOFTWARE.
24
- */
25
-
26
- // This file is included inside the Pool class.
27
-
28
- private:
29
-
30
- ProcessPtr findOldestIdleProcess(const Group *exclude = NULL) const {
31
- ProcessPtr oldestIdleProcess;
32
-
33
- SuperGroupMap::ConstIterator sg_it(superGroups);
34
- while (*sg_it != NULL) {
35
- const SuperGroupPtr &superGroup = sg_it.getValue();
36
- const SuperGroup::GroupList &groups = superGroup->groups;
37
- SuperGroup::GroupList::const_iterator g_it, g_end = groups.end();
38
- for (g_it = groups.begin(); g_it != g_end; g_it++) {
39
- const GroupPtr &group = *g_it;
40
- if (group.get() == exclude) {
41
- continue;
42
- }
43
- const ProcessList &processes = group->enabledProcesses;
44
- ProcessList::const_iterator p_it, p_end = processes.end();
45
- for (p_it = processes.begin(); p_it != p_end; p_it++) {
46
- const ProcessPtr process = *p_it;
47
- if (process->busyness() == 0
48
- && (oldestIdleProcess == NULL
49
- || process->lastUsed < oldestIdleProcess->lastUsed)
50
- ) {
51
- oldestIdleProcess = process;
52
- }
53
- }
54
- }
55
- sg_it.next();
56
- }
57
-
58
- return oldestIdleProcess;
59
- }
60
-
61
- ProcessPtr findBestProcessToTrash() const {
62
- ProcessPtr oldestProcess;
63
-
64
- SuperGroupMap::ConstIterator sg_it(superGroups);
65
- while (*sg_it != NULL) {
66
- const SuperGroupPtr &superGroup = sg_it.getValue();
67
- const SuperGroup::GroupList &groups = superGroup->groups;
68
- SuperGroup::GroupList::const_iterator g_it, g_end = groups.end();
69
- for (g_it = groups.begin(); g_it != g_end; g_it++) {
70
- const GroupPtr &group = *g_it;
71
- const ProcessList &processes = group->enabledProcesses;
72
- ProcessList::const_iterator p_it, p_end = processes.end();
73
- for (p_it = processes.begin(); p_it != p_end; p_it++) {
74
- const ProcessPtr process = *p_it;
75
- if (oldestProcess == NULL
76
- || process->lastUsed < oldestProcess->lastUsed) {
77
- oldestProcess = process;
78
- }
79
- }
80
- }
81
- sg_it.next();
82
- }
83
-
84
- return oldestProcess;
85
- }
@@ -1,706 +0,0 @@
1
- /*
2
- * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011-2013 Phusion
4
- *
5
- * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
- *
7
- * Permission is hereby granted, free of charge, to any person obtaining a copy
8
- * of this software and associated documentation files (the "Software"), to deal
9
- * in the Software without restriction, including without limitation the rights
10
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- * copies of the Software, and to permit persons to whom the Software is
12
- * furnished to do so, subject to the following conditions:
13
- *
14
- * The above copyright notice and this permission notice shall be included in
15
- * all copies or substantial portions of the Software.
16
- *
17
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
- * THE SOFTWARE.
24
- */
25
- #ifndef _PASSENGER_APPLICATION_POOL2_SUPER_GROUP_H_
26
- #define _PASSENGER_APPLICATION_POOL2_SUPER_GROUP_H_
27
-
28
- #include <boost/function.hpp>
29
- #include <boost/bind.hpp>
30
- #include <boost/shared_ptr.hpp>
31
- #include <boost/make_shared.hpp>
32
- #include <boost/container/vector.hpp>
33
- #include <oxt/thread.hpp>
34
- #include <vector>
35
- #include <utility>
36
- #include <Logging.h>
37
- #include <ApplicationPool2/Common.h>
38
- #include <ApplicationPool2/ComponentInfo.h>
39
- #include <ApplicationPool2/Group.h>
40
- #include <ApplicationPool2/Options.h>
41
- #include <Utils/SmallVector.h>
42
-
43
- namespace Passenger {
44
- namespace ApplicationPool2 {
45
-
46
- using namespace std;
47
- using namespace boost;
48
- using namespace oxt;
49
-
50
-
51
- /**
52
- * An abstract container for multiple Groups (applications). It is a support
53
- * structure for supporting application sets, multiple applications that can
54
- * closely work with each other as if they were a single entity. There's no
55
- * support for application sets yet in Phusion Passenger 4, but this class
56
- * lays the foundation to make it possible.
57
- *
58
- * An application set is backed by a directory that contains:
59
- *
60
- * - The files for the individual applications.
61
- * - An application set manifest file that:
62
- * * Describes the containing applications.
63
- * * Describes the application set itself.
64
- * * Describes instructions that must be first
65
- * followed before the application set is usable.
66
- * * Describes instructions that must be followed when the
67
- * application set is to be cleaned up.
68
- *
69
- * SuperGroup is designed to assume to that loading the manifest file
70
- * and following the instructions in them may be a blocking operation
71
- * that can take a while. Thus it makes use of background threads to
72
- * do most of initialization and destruction work (see `doInitialize()`
73
- * and `doDestroy()`). The `state` variable keeps track of things.
74
- *
75
- * A SuperGroup starts off in the `INITIALIZING` state. When it's done
76
- * initializing, it becomes `READY`. If a restart is necessary it will
77
- * transition to `RESTARTING` and then eventually back to `READY`.
78
- * At any time the SuperGroup may be instructed to destroy itself, in
79
- * which case it will first transition to `DESTROYING` and eventually
80
- * to `DESTROYED`. Once destroyed, the SuperGroup is reusable so it
81
- * can go back to `INITIALIZING` when needed.
82
- *
83
- *
84
- * ## Life time
85
- *
86
- * A SuperGroup, once created and added to the Pool, is normally not
87
- * supposed to be destroyed and removed from the Pool automatically.
88
- * This is because a SuperGroup may contain important spawning
89
- * parameters such as SuperGroup-specific environment variables.
90
- * However the system does not disallow the administrator from
91
- * manually removing a SuperGroup from the pool.
92
- *
93
- *
94
- * ## Multiple instances and initialization/destruction
95
- *
96
- * It is allowed to create multiple SuperGroups backed by the same
97
- * application set directory, e.g. to increase concurrency. The system
98
- * may destroy a SuperGroup in the background while creating a new
99
- * one while that is in progress. This could even happen across processes,
100
- * e.g. one process is busy destroying a SuperGroup while another
101
- * one is initializing it.
102
- *
103
- * Furthermore, it is possible for a SuperGroup to receive a get()
104
- * command during destruction.
105
- *
106
- * It is therefore important that `doInitialize()` and `doDestroy()`
107
- * do not interfere with other instances of the same code, and can
108
- * commit their work atomically.
109
- *
110
- *
111
- * ## Thread-safety
112
- *
113
- * Except for otherwise documented parts, this class is not thread-safe,
114
- * so only access it within the ApplicationPool lock.
115
- */
116
- class SuperGroup: public boost::enable_shared_from_this<SuperGroup> {
117
- public:
118
- enum State {
119
- /** This SuperGroup is being initialized. `groups` is empty and
120
- * `get()` actions cannot be immediately satisfied, so they
121
- * are placed in `getWaitlist`. Once the SuperGroup is done
122
- * loading the state it will transition to `READY`. Calling `destroy()`
123
- * will make it transition to `DESTROYING`. If initialization
124
- * failed it will transition to `DESTROYED`.
125
- */
126
- INITIALIZING,
127
-
128
- /** This SuperGroup is loaded and is ready for action. From
129
- * here the state can transition to `RESTARTING` or `DESTROYING`.
130
- */
131
- READY,
132
-
133
- /** This SuperGroup is being restarted. The SuperGroup
134
- * information is being reloaded from the data source
135
- * and processes are being restarted. In this state
136
- * `get()` actions can still be statisfied, and the data
137
- * structures still contain the old information. Once reloading
138
- * is done the data structures will be atomically swapped
139
- * with the newly reloaded ones. The old structures will be
140
- * destroyed in the background.
141
- * Once the restart is completed, the state will transition
142
- * to `READY`.
143
- * Re-restarting won't have any effect in this state.
144
- * `destroy()` will cause the restart to be aborted and will
145
- * cause a transition to `DESTROYING`.
146
- */
147
- RESTARTING,
148
-
149
- /** This SuperGroup is being destroyed. Processes are being shut
150
- * down and other resources are being cleaned up. In this state,
151
- * `groups` is empty.
152
- * Restarting won't have any effect, but `get()` will cause a
153
- * transition to `INITIALIZING`.
154
- */
155
- DESTROYING,
156
-
157
- /** This SuperGroup has been destroyed and all resources have been
158
- * freed. Restarting won't have any effect but calling `get()` will
159
- * make it transition to `INITIALIZING`.
160
- */
161
- DESTROYED
162
- };
163
-
164
- enum ShutdownResult {
165
- /** The SuperGroup has been successfully destroyed. */
166
- SUCCESS,
167
- /** The SuperGroup was not destroyed because a get or restart
168
- * request came in while destroying.
169
- */
170
- CANCELED
171
- };
172
-
173
- typedef boost::function<void (ShutdownResult result)> ShutdownCallback;
174
- typedef SmallVector<GroupPtr, 1> GroupList;
175
-
176
- private:
177
- friend class Pool;
178
- friend class Group;
179
-
180
- Options options;
181
-
182
-
183
- // Thread-safe.
184
- static boost::mutex &getPoolSyncher(Pool *pool);
185
- static void runAllActions(const boost::container::vector<Callback> &actions);
186
- const PoolPtr getPoolPtr();
187
- string generateSecret() const;
188
- bool selfCheckingEnabled() const;
189
- void runInitializationHooks() const;
190
- void runDestructionHooks() const;
191
- void setupInitializationOrDestructionHook(HookScriptOptions &options) const;
192
-
193
- void createInterruptableThread(const boost::function<void ()> &func, const string &name,
194
- unsigned int stackSize);
195
-
196
- void verifyInvariants() const {
197
- #ifndef NDEBUG
198
- // !a || b: logical equivalent of a IMPLIES b.
199
-
200
- if (!selfCheckingEnabled()) {
201
- return;
202
- }
203
-
204
- assert(groups.empty() ==
205
- (state == INITIALIZING || state == DESTROYING || state == DESTROYED));
206
- assert((defaultGroup == NULL) ==
207
- (state == INITIALIZING || state == DESTROYING || state == DESTROYED));
208
- assert(!( state == READY || state == RESTARTING || state == DESTROYING || state == DESTROYED ) ||
209
- ( getWaitlist.empty() ));
210
- assert(!( state == DESTROYED ) || ( detachedGroups.empty() ));
211
- #endif
212
- }
213
-
214
- void setState(State newState) {
215
- state = newState;
216
- generation++;
217
- }
218
-
219
- vector<ComponentInfo> loadComponentInfos(const Options &options) const {
220
- vector<ComponentInfo> infos;
221
- ComponentInfo info;
222
- info.name = "default";
223
- info.isDefault = true;
224
- infos.push_back(info);
225
- return infos;
226
- }
227
-
228
- Group *findDefaultGroup(const SuperGroup::GroupList &groups) const {
229
- SuperGroup::GroupList::const_iterator it;
230
-
231
- for (it = groups.begin(); it != groups.end(); it++) {
232
- const GroupPtr &group = *it;
233
- if (group->componentInfo.isDefault) {
234
- return group.get();
235
- }
236
- }
237
- return NULL;
238
- }
239
-
240
- pair<GroupPtr, unsigned int> findGroupCorrespondingToComponent(
241
- const SuperGroup::GroupList &groups, const ComponentInfo &info) const
242
- {
243
- unsigned int i;
244
- for (i = 0; i < groups.size(); i++) {
245
- const GroupPtr &group = groups[i];
246
- if (group->componentInfo.name == info.name) {
247
- return make_pair(const_cast<GroupPtr &>(group), i);
248
- }
249
- }
250
- return make_pair(GroupPtr(), 0);
251
- }
252
-
253
- static void oneGroupHasBeenShutDown(SuperGroupPtr self, GroupPtr group) {
254
- // This function is either called from the pool event loop or directly from
255
- // the detachAllGroups post lock actions. In both cases getPool() is never NULL.
256
- Pool *pool = self->getPool();
257
- boost::lock_guard<boost::mutex> lock(self->getPoolSyncher(pool));
258
-
259
- vector<GroupPtr>::iterator it, end = self->detachedGroups.end();
260
- for (it = self->detachedGroups.begin(); it != end; it++) {
261
- if (*it == group) {
262
- self->detachedGroups.erase(it);
263
- break;
264
- }
265
- }
266
- }
267
-
268
- /** One of the post lock actions can potentially perform a long-running
269
- * operation, so running them in a thread is advised.
270
- */
271
- void detachAllGroups(GroupList &groups,
272
- boost::container::vector<Callback> &postLockActions)
273
- {
274
- foreach (const GroupPtr &group, groups) {
275
- // doRestart() may temporarily nullify elements in 'groups'.
276
- if (group == NULL) {
277
- continue;
278
- }
279
-
280
- while (!group->getWaitlist.empty()) {
281
- getWaitlist.push_back(group->getWaitlist.front());
282
- group->getWaitlist.pop_front();
283
- }
284
- detachedGroups.push_back(group);
285
- group->shutdown(
286
- boost::bind(oneGroupHasBeenShutDown,
287
- shared_from_this(),
288
- group),
289
- postLockActions
290
- );
291
- }
292
-
293
- groups.clear();
294
- }
295
-
296
- void assignGetWaitlistToGroups(boost::container::vector<Callback> &postLockActions) {
297
- while (!getWaitlist.empty()) {
298
- GetWaiter &waiter = getWaitlist.front();
299
- Group *group = route(waiter.options);
300
- Options adjustedOptions = waiter.options;
301
- adjustOptions(adjustedOptions, group);
302
- SessionPtr session = group->get(adjustedOptions, waiter.callback,
303
- postLockActions);
304
- if (session != NULL) {
305
- postLockActions.push_back(boost::bind(GetCallback::call,
306
- waiter.callback, session, ExceptionPtr()));
307
- }
308
- getWaitlist.pop_front();
309
- }
310
- }
311
-
312
- void adjustOptions(Options &options, const Group *group) const {
313
- // No-op.
314
- }
315
-
316
- static void doInitialize(SuperGroupPtr self, Options options, unsigned int generation) {
317
- self->realDoInitialize(options, generation);
318
- }
319
-
320
- static void doRestart(SuperGroupPtr self, Options options, unsigned int generation) {
321
- self->realDoRestart(options, generation);
322
- }
323
-
324
- void realDoInitialize(const Options &options, unsigned int generation);
325
- void realDoRestart(const Options &options, unsigned int generation);
326
-
327
- void doDestroy(SuperGroupPtr self, unsigned int generation, ShutdownCallback callback) {
328
- TRACE_POINT();
329
-
330
- runDestructionHooks();
331
-
332
- // Wait until 'detachedGroups' is empty.
333
- UPDATE_TRACE_POINT();
334
- Pool *pool = getPool();
335
- boost::unique_lock<boost::mutex> lock(getPoolSyncher(pool));
336
- verifyInvariants();
337
- while (true) {
338
- if (OXT_UNLIKELY(this->generation != generation)) {
339
- UPDATE_TRACE_POINT();
340
- lock.unlock();
341
- if (callback) {
342
- callback(CANCELED);
343
- }
344
- return;
345
- } else if (detachedGroups.empty()) {
346
- break;
347
- } else {
348
- UPDATE_TRACE_POINT();
349
- lock.unlock();
350
- syscalls::usleep(10000);
351
- lock.lock();
352
- verifyInvariants();
353
- }
354
- }
355
-
356
- UPDATE_TRACE_POINT();
357
- assert(state == DESTROYING);
358
- state = DESTROYED;
359
- verifyInvariants();
360
-
361
- lock.unlock();
362
- if (callback) {
363
- callback(SUCCESS);
364
- }
365
- }
366
-
367
- /*********************/
368
-
369
- /*********************/
370
-
371
- public:
372
- mutable boost::mutex backrefSyncher;
373
- // Public, read-only
374
- Pool *pool;
375
-
376
- /** A number for concurrency control, incremented every time the state changes.
377
- * Every background thread that SuperGroup spawns knows the generation number
378
- * from when the thread was spawned. A thread generally does some work outside
379
- * the lock, then grabs the lock and updates the information in this SuperGroup
380
- * with the results of the work. But before updating happens it first checks
381
- * whether the generation number is as expected, so increasing this generation
382
- * number will prevent old threads from updating the information with possibly
383
- * now-stale information. It is a good way to prevent A-B-A concurrency
384
- * problems.
385
- *
386
- * Private.
387
- */
388
- unsigned int generation;
389
- // Private
390
- State state;
391
-
392
- // Public, read-only
393
- string name;
394
- string secret;
395
-
396
- /** Invariant:
397
- * (defaultGroup == NULL) == (state == INITIALIZING || state == DESTROYING || state == DESTROYED)
398
- */
399
- Group *defaultGroup;
400
-
401
- /** Invariant:
402
- * groups.empty() == (state == INITIALIZING || state == DESTROYING || state == DESTROYED)
403
- */
404
- GroupList groups;
405
-
406
- /**
407
- * get() requests for this super group that cannot be immediately satisfied
408
- * are put on this wait list, which must be processed as soon as the
409
- * necessary resources have become free. Requests must wait when a SuperGroup
410
- * is initializing.
411
- *
412
- * Invariant:
413
- * if state == READY || state == RESTARTING || state == DESTROYING || state == DESTROYED:
414
- * getWaitlist.empty()
415
- * Equivalently:
416
- * if state != INITIALIZING:
417
- * getWaitlist.empty()
418
- * Equivalently:
419
- * if !getWaitlist.empty():
420
- * state == INITIALIZING
421
- */
422
- deque<GetWaiter> getWaitlist;
423
-
424
- /**
425
- * Groups which are being shut down right now. These Groups contain a
426
- * reference to the containg SuperGroup so that the SuperGroup is not
427
- * actually destroyed until all Groups in this collection are done
428
- * shutting down.
429
- *
430
- * Invariant:
431
- * if state == DESTROYED:
432
- * detachedGroups.empty()
433
- */
434
- vector<GroupPtr> detachedGroups;
435
-
436
- /** One MUST call initialize() after construction because shared_from_this()
437
- * is not available in the constructor.
438
- */
439
- SuperGroup(Pool *_pool, const Options &options)
440
- : pool(_pool)
441
- {
442
- this->options = options.copyAndPersist().detachFromUnionStationTransaction();
443
- this->name = options.getAppGroupName();
444
- secret = generateSecret();
445
- state = INITIALIZING;
446
- defaultGroup = NULL;
447
- generation = 0;
448
- }
449
-
450
- ~SuperGroup() {
451
- if (OXT_UNLIKELY(state != DESTROYED)) {
452
- P_BUG("You must call Group::destroy(..., false) before "
453
- "actually destroying the SuperGroup.");
454
- }
455
- verifyInvariants();
456
- }
457
-
458
- void initialize() {
459
- createInterruptableThread(
460
- boost::bind(
461
- doInitialize,
462
- shared_from_this(),
463
- options.copyAndPersist(),
464
- generation),
465
- "SuperGroup initializer: " + name,
466
- POOL_HELPER_THREAD_STACK_SIZE);
467
- }
468
-
469
- /**
470
- * Thread-safe.
471
- *
472
- * As long as 'state' != DESTROYED, result != NULL.
473
- * But in thread callbacks in this file, getPool() is never NULL
474
- * because Pool::destroy() joins all threads, so Pool can never
475
- * be destroyed before all thread callbacks have finished.
476
- */
477
- OXT_FORCE_INLINE
478
- Pool *getPool() const {
479
- return pool;
480
- }
481
-
482
- bool isAlive() const {
483
- return state != DESTROYING && state != DESTROYED;
484
- }
485
-
486
- const char *getStateName() const {
487
- switch (state) {
488
- case INITIALIZING:
489
- return "INITIALIZING";
490
- case READY:
491
- return "READY";
492
- case RESTARTING:
493
- return "RESTARTING";
494
- case DESTROYING:
495
- return "DESTROYING";
496
- case DESTROYED:
497
- return "DESTROYED";
498
- default:
499
- P_BUG("Unknown SuperGroup state " << (int) state);
500
- return NULL; // Shut up compiler warning.
501
- }
502
- }
503
-
504
- /**
505
- * If `allowReinitialization` is true then destroying a SuperGroup that
506
- * has get waiters will make it reinitialize. Otherwise this SuperGroup
507
- * will be forcefully set to the `DESTROYING` state and `getWaitlist` will be
508
- * left untouched; in this case it is up to the caller to empty
509
- * the `getWaitlist` and do something with it, otherwise the invariant
510
- * will be broken.
511
- *
512
- * One of the post lock actions can potentially perform a long-running
513
- * operation, so running them in a thread is advised.
514
- */
515
- void destroy(bool allowReinitialization,
516
- boost::container::vector<Callback> &postLockActions,
517
- const ShutdownCallback &callback)
518
- {
519
- verifyInvariants();
520
- switch (state) {
521
- case INITIALIZING:
522
- case READY:
523
- case RESTARTING:
524
- detachAllGroups(groups, postLockActions);
525
- defaultGroup = NULL;
526
- if (getWaitlist.empty() || !allowReinitialization) {
527
- setState(DESTROYING);
528
- createInterruptableThread(
529
- boost::bind(
530
- &SuperGroup::doDestroy,
531
- this,
532
- // Keep reference to self to prevent destruction.
533
- shared_from_this(),
534
- generation,
535
- callback),
536
- "SuperGroup destroyer: " + name,
537
- POOL_HELPER_THREAD_STACK_SIZE + 1024 * 256);
538
- } else {
539
- // Spawning this thread before setState() so that
540
- // it doesn't change the state when done.
541
- createInterruptableThread(
542
- boost::bind(
543
- &SuperGroup::doDestroy,
544
- this,
545
- // Keep reference to self to prevent destruction.
546
- shared_from_this(),
547
- generation,
548
- ShutdownCallback()),
549
- "SuperGroup destroyer: " + name,
550
- POOL_HELPER_THREAD_STACK_SIZE + 1024 * 256);
551
- setState(INITIALIZING);
552
- createInterruptableThread(
553
- boost::bind(
554
- doInitialize,
555
- shared_from_this(),
556
- options.copyAndPersist(),
557
- generation),
558
- "SuperGroup initializer: " + name,
559
- POOL_HELPER_THREAD_STACK_SIZE + 1024 * 256);
560
- if (callback) {
561
- postLockActions.push_back(boost::bind(callback, CANCELED));
562
- }
563
- }
564
- break;
565
- case DESTROYING:
566
- case DESTROYED:
567
- break;
568
- default:
569
- P_BUG("Unknown SuperGroup state " << (int) state);
570
- }
571
- if (allowReinitialization) {
572
- verifyInvariants();
573
- }
574
- }
575
-
576
- /**
577
- * @post
578
- * if result:
579
- * getWaitlist.empty()
580
- */
581
- bool garbageCollectable(unsigned long long now = 0) const {
582
- /* if (state == READY) {
583
- vector<GroupPtr>::const_iterator it, end = groups.end();
584
- bool result = true;
585
-
586
- for (it = groups.begin(); result && it != end; it++) {
587
- result = result && (*it)->garbageCollectable(now);
588
- }
589
- assert(!result || getWaitlist.empty());
590
- return result;
591
- } else {
592
- assert(!(state == DESTROYED) || getWaitlist.empty());
593
- return state == DESTROYED;
594
- } */
595
- return false;
596
- }
597
-
598
- SessionPtr get(const Options &newOptions, const GetCallback &callback,
599
- boost::container::vector<Callback> &postLockActions)
600
- {
601
- switch (state) {
602
- case INITIALIZING:
603
- getWaitlist.push_back(GetWaiter(newOptions, callback));
604
- verifyInvariants();
605
- return SessionPtr();
606
- case READY:
607
- case RESTARTING:
608
- if (needsRestart()) {
609
- restart(newOptions);
610
- }
611
- if (groups.size() > 1) {
612
- Group *group = route(newOptions);
613
- Options adjustedOptions = newOptions;
614
- adjustOptions(adjustedOptions, group);
615
- verifyInvariants();
616
- return group->get(adjustedOptions, callback, postLockActions);
617
- } else {
618
- verifyInvariants();
619
- return defaultGroup->get(newOptions, callback, postLockActions);
620
- }
621
- case DESTROYING:
622
- case DESTROYED:
623
- getWaitlist.push_back(GetWaiter(newOptions, callback));
624
- setState(INITIALIZING);
625
- createInterruptableThread(
626
- boost::bind(
627
- doInitialize,
628
- shared_from_this(),
629
- newOptions.copyAndPersist().detachFromUnionStationTransaction(),
630
- generation),
631
- "SuperGroup initializer: " + name,
632
- POOL_HELPER_THREAD_STACK_SIZE);
633
- verifyInvariants();
634
- return SessionPtr();
635
- default:
636
- P_BUG("Unknown SuperGroup state " << (int) state);
637
- return SessionPtr(); // Shut up compiler warning.
638
- };
639
- }
640
-
641
- Group *route(const Options &options) const {
642
- return defaultGroup;
643
- }
644
-
645
- unsigned int capacityUsed() const {
646
- unsigned int result = 0;
647
-
648
- if (groups.size() == 1) {
649
- result += defaultGroup->capacityUsed();
650
- } else {
651
- GroupList::const_iterator it, end = groups.end();
652
- for (it = groups.begin(); it != end; it++) {
653
- result += (*it)->capacityUsed();
654
- }
655
- }
656
- if (state == INITIALIZING || state == RESTARTING) {
657
- result++;
658
- }
659
- return result;
660
- }
661
-
662
- unsigned int getProcessCount() const {
663
- if (groups.size() == 1) {
664
- return defaultGroup->getProcessCount();
665
- } else {
666
- unsigned int result = 0;
667
- GroupList::const_iterator g_it, g_end = groups.end();
668
- for (g_it = groups.begin(); g_it != g_end; g_it++) {
669
- const GroupPtr &group = *g_it;
670
- result += group->getProcessCount();
671
- }
672
- return result;
673
- }
674
- }
675
-
676
- bool needsRestart() const {
677
- return false;
678
- }
679
-
680
- void restart(const Options &options) {
681
- verifyInvariants();
682
- if (state == READY) {
683
- createInterruptableThread(
684
- boost::bind(
685
- doRestart,
686
- // Keep reference to self to prevent destruction.
687
- shared_from_this(),
688
- options.copyAndPersist().detachFromUnionStationTransaction(),
689
- generation),
690
- "SuperGroup restarter: " + name,
691
- POOL_HELPER_THREAD_STACK_SIZE);
692
- state = RESTARTING;
693
- }
694
- verifyInvariants();
695
- }
696
-
697
- string inspect() const {
698
- return name;
699
- }
700
- };
701
-
702
-
703
- } // namespace ApplicationPool2
704
- } // namespace Passenger
705
-
706
- #endif /* _PASSENGER_APPLICATION_POOL2_SUPER_GROUP_H_ */