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.
- checksums.yaml +8 -8
- checksums.yaml.gz.asc +7 -7
- data.tar.gz.asc +7 -7
- data/CHANGELOG +15 -0
- data/CONTRIBUTORS +6 -0
- data/README.md +1 -1
- data/bin/passenger-install-apache2-module +24 -11
- data/bin/passenger-status +29 -14
- data/build/agents.rb +12 -10
- data/build/cxx_tests.rb +30 -30
- data/doc/Design and Architecture.html +1 -10
- data/doc/Design and Architecture.txt +1 -6
- data/doc/Users guide Apache.html +1 -19
- data/doc/Users guide Apache.txt +1 -1
- data/doc/Users guide Nginx.html +2 -20
- data/doc/Users guide Nginx.txt +2 -2
- data/doc/users_guide_snippets/tips.txt +0 -9
- data/ext/common/ApplicationPool2/ApiKey.h +158 -0
- data/ext/common/ApplicationPool2/BasicGroupInfo.h +81 -0
- data/ext/common/ApplicationPool2/BasicProcessInfo.h +106 -0
- data/ext/common/ApplicationPool2/Common.h +5 -44
- data/ext/common/ApplicationPool2/Context.h +94 -0
- data/ext/common/ApplicationPool2/Group.h +130 -1205
- data/ext/common/ApplicationPool2/Group/InitializationAndShutdown.cpp +190 -0
- data/ext/common/ApplicationPool2/Group/InternalUtils.cpp +329 -0
- data/ext/common/ApplicationPool2/Group/LifetimeAndBasics.cpp +103 -0
- data/ext/common/ApplicationPool2/{Pool/Debug.h → Group/Miscellaneous.cpp} +40 -38
- data/ext/common/ApplicationPool2/Group/OutOfBandWork.cpp +323 -0
- data/ext/common/ApplicationPool2/Group/ProcessListManagement.cpp +606 -0
- data/ext/common/ApplicationPool2/Group/SessionManagement.cpp +337 -0
- data/ext/common/ApplicationPool2/Group/SpawningAndRestarting.cpp +478 -0
- data/ext/common/ApplicationPool2/Group/StateInspection.cpp +197 -0
- data/ext/common/ApplicationPool2/Group/Verification.cpp +159 -0
- data/ext/common/ApplicationPool2/Implementation.cpp +19 -1401
- data/ext/common/ApplicationPool2/Options.h +5 -5
- data/ext/common/ApplicationPool2/Pool.h +260 -815
- data/ext/common/ApplicationPool2/Pool/{AnalyticsCollection.h → AnalyticsCollection.cpp} +55 -56
- data/ext/common/ApplicationPool2/Pool/{GarbageCollection.h → GarbageCollection.cpp} +49 -49
- data/ext/common/ApplicationPool2/Pool/GeneralUtils.cpp +241 -0
- data/ext/common/ApplicationPool2/Pool/GroupUtils.cpp +276 -0
- data/ext/common/ApplicationPool2/Pool/InitializationAndShutdown.cpp +145 -0
- data/ext/common/ApplicationPool2/Pool/Miscellaneous.cpp +244 -0
- data/ext/common/ApplicationPool2/Pool/ProcessUtils.cpp +330 -0
- data/ext/common/ApplicationPool2/Pool/StateInspection.cpp +299 -0
- data/ext/common/ApplicationPool2/Process.h +399 -205
- data/ext/common/ApplicationPool2/Session.h +70 -28
- data/ext/common/ApplicationPool2/Socket.h +1 -0
- data/ext/common/Constants.h +11 -3
- data/ext/common/Exceptions.h +1 -1
- data/ext/common/Logging.cpp +9 -4
- data/ext/common/Logging.h +6 -0
- data/ext/common/ServerKit/HttpServer.h +225 -215
- data/ext/common/ServerKit/Server.h +57 -57
- data/ext/common/SpawningKit/BackgroundIOCapturer.h +160 -0
- data/ext/common/SpawningKit/Config.h +107 -0
- data/ext/common/{ApplicationPool2 → SpawningKit}/DirectSpawner.h +17 -16
- data/ext/common/{ApplicationPool2 → SpawningKit}/DummySpawner.h +33 -33
- data/ext/common/{ApplicationPool2/SpawnerFactory.h → SpawningKit/Factory.h} +17 -17
- data/ext/common/{ApplicationPool2/ComponentInfo.h → SpawningKit/Options.h} +8 -21
- data/ext/common/SpawningKit/PipeWatcher.h +148 -0
- data/ext/common/{ApplicationPool2/PipeWatcher.h → SpawningKit/Result.h} +15 -33
- data/ext/common/{ApplicationPool2 → SpawningKit}/SmartSpawner.h +52 -57
- data/ext/common/{ApplicationPool2 → SpawningKit}/Spawner.h +83 -371
- data/ext/common/SpawningKit/UserSwitchingRules.h +265 -0
- data/ext/common/Utils/BufferedIO.h +24 -0
- data/ext/common/{ApplicationPool2/SpawnObject.h → Utils/ClassUtils.h} +24 -51
- data/ext/common/Utils/IOUtils.cpp +70 -0
- data/ext/common/Utils/IOUtils.h +19 -0
- data/ext/common/Utils/JsonUtils.h +113 -0
- data/ext/common/Utils/StrIntUtils.h +29 -0
- data/ext/common/Utils/json.h +1 -1
- data/ext/common/agents/ApiServerUtils.h +941 -0
- data/ext/common/agents/HelperAgent/{AdminServer.h → ApiServer.h} +163 -365
- data/ext/common/agents/HelperAgent/Main.cpp +86 -88
- data/ext/common/agents/HelperAgent/OptionParser.h +9 -10
- data/ext/common/agents/HelperAgent/RequestHandler/BufferBody.cpp +3 -0
- data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +2 -0
- data/ext/common/agents/HelperAgent/RequestHandler/Hooks.cpp +1 -1
- data/ext/common/agents/HelperAgent/RequestHandler/SendRequest.cpp +2 -2
- data/ext/common/agents/LoggingAgent/ApiServer.h +279 -0
- data/ext/common/agents/LoggingAgent/Main.cpp +41 -51
- data/ext/common/agents/LoggingAgent/OptionParser.h +11 -11
- data/ext/common/agents/Watchdog/ApiServer.h +311 -0
- data/ext/common/agents/Watchdog/Main.cpp +91 -65
- data/helper-scripts/prespawn +2 -0
- data/lib/phusion_passenger.rb +1 -1
- data/lib/phusion_passenger/admin_tools/instance.rb +1 -1
- data/lib/phusion_passenger/common_library.rb +27 -14
- data/lib/phusion_passenger/config/{admin_command_command.rb → api_call_command.rb} +19 -16
- data/lib/phusion_passenger/config/detach_process_command.rb +6 -3
- data/lib/phusion_passenger/config/main.rb +3 -5
- data/lib/phusion_passenger/config/reopen_logs_command.rb +29 -7
- data/lib/phusion_passenger/config/restart_app_command.rb +13 -4
- data/lib/phusion_passenger/config/utils.rb +15 -8
- data/lib/phusion_passenger/constants.rb +6 -2
- data/lib/phusion_passenger/platform_info/apache.rb +4 -0
- data/lib/phusion_passenger/platform_info/apache_detector.rb +18 -3
- data/resources/templates/apache2/mpm_unknown.txt.erb +20 -0
- metadata +42 -21
- metadata.gz.asc +7 -7
- data/ext/common/ApplicationPool2/Pool/GeneralUtils.h +0 -127
- data/ext/common/ApplicationPool2/Pool/Inspection.h +0 -219
- data/ext/common/ApplicationPool2/Pool/ProcessUtils.h +0 -85
- data/ext/common/ApplicationPool2/SuperGroup.h +0 -706
- data/ext/common/agents/LoggingAgent/AdminServer.h +0 -435
- 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_ */
|