passenger 5.0.0.rc2 → 5.0.1
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 +10 -0
- data/CONTRIBUTORS +1 -0
- data/build/agents.rb +6 -0
- data/build/cxx_tests.rb +6 -0
- data/build/misc.rb +22 -1
- data/doc/Users guide Nginx.txt +12 -0
- data/ext/common/ApplicationPool2/Options.h +2 -1
- data/ext/common/ApplicationPool2/Pool.h +15 -744
- data/ext/common/ApplicationPool2/Pool/AnalyticsCollection.h +255 -0
- data/ext/common/ApplicationPool2/Pool/Debug.h +63 -0
- data/ext/common/ApplicationPool2/Pool/GarbageCollection.h +197 -0
- data/ext/common/ApplicationPool2/Pool/GeneralUtils.h +127 -0
- data/ext/common/ApplicationPool2/Pool/Inspection.h +214 -0
- data/ext/common/ApplicationPool2/Pool/ProcessUtils.h +85 -0
- data/ext/common/ApplicationPool2/Process.h +5 -7
- data/ext/common/Constants.h +1 -1
- data/ext/common/Hooks.h +2 -1
- data/ext/common/Utils.cpp +1 -1
- data/ext/common/Utils/JsonUtils.h +37 -1
- data/ext/common/agents/Base.cpp +45 -40
- data/ext/common/agents/Base.h +3 -2
- data/ext/common/agents/HelperAgent/RequestHandler/InitRequest.cpp +12 -10
- data/ext/nginx/Configuration.c +4 -1
- data/lib/phusion_passenger.rb +1 -1
- data/lib/phusion_passenger/common_library.rb +7 -1
- data/lib/phusion_passenger/config/restart_app_command.rb +40 -2
- data/lib/phusion_passenger/config/utils.rb +3 -5
- data/lib/phusion_passenger/utils/ansi_colors.rb +28 -21
- data/lib/phusion_passenger/utils/terminal_choice_menu.rb +27 -10
- data/resources/templates/standalone/config.erb +4 -4
- data/test/cxx/CxxTestMain.cpp +10 -22
- metadata +10 -4
- metadata.gz.asc +7 -7
@@ -0,0 +1,127 @@
|
|
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
|
+
protected:
|
29
|
+
|
30
|
+
static void runAllActions(const boost::container::vector<Callback> &actions) {
|
31
|
+
boost::container::vector<Callback>::const_iterator it, end = actions.end();
|
32
|
+
for (it = actions.begin(); it != end; it++) {
|
33
|
+
(*it)();
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
static void runAllActionsWithCopy(boost::container::vector<Callback> actions) {
|
38
|
+
runAllActions(actions);
|
39
|
+
}
|
40
|
+
|
41
|
+
void verifyInvariants() const {
|
42
|
+
// !a || b: logical equivalent of a IMPLIES b.
|
43
|
+
#ifndef NDEBUG
|
44
|
+
if (!selfchecking) {
|
45
|
+
return;
|
46
|
+
}
|
47
|
+
assert(!( !getWaitlist.empty() ) || ( atFullCapacityUnlocked() ));
|
48
|
+
assert(!( !atFullCapacityUnlocked() ) || ( getWaitlist.empty() ));
|
49
|
+
#endif
|
50
|
+
}
|
51
|
+
|
52
|
+
void verifyExpensiveInvariants() const {
|
53
|
+
#ifndef NDEBUG
|
54
|
+
if (!selfchecking) {
|
55
|
+
return;
|
56
|
+
}
|
57
|
+
vector<GetWaiter>::const_iterator it, end = getWaitlist.end();
|
58
|
+
for (it = getWaitlist.begin(); it != end; it++) {
|
59
|
+
const GetWaiter &waiter = *it;
|
60
|
+
const SuperGroupPtr *superGroup;
|
61
|
+
assert(!superGroups.lookup(waiter.options.getAppGroupName(), &superGroup));
|
62
|
+
}
|
63
|
+
#endif
|
64
|
+
}
|
65
|
+
|
66
|
+
void fullVerifyInvariants() const {
|
67
|
+
TRACE_POINT();
|
68
|
+
verifyInvariants();
|
69
|
+
UPDATE_TRACE_POINT();
|
70
|
+
verifyExpensiveInvariants();
|
71
|
+
UPDATE_TRACE_POINT();
|
72
|
+
|
73
|
+
SuperGroupMap::ConstIterator sg_it(superGroups);
|
74
|
+
while (*sg_it != NULL) {
|
75
|
+
const SuperGroupPtr &superGroup = sg_it.getValue();
|
76
|
+
superGroup->verifyInvariants();
|
77
|
+
foreach (GroupPtr group, superGroup->groups) {
|
78
|
+
group->verifyInvariants();
|
79
|
+
group->verifyExpensiveInvariants();
|
80
|
+
}
|
81
|
+
sg_it.next();
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
bool runHookScripts(const char *name,
|
86
|
+
const boost::function<void (HookScriptOptions &)> &setup) const
|
87
|
+
{
|
88
|
+
if (agentsOptions != NULL) {
|
89
|
+
string hookName = string("hook_") + name;
|
90
|
+
string spec = agentsOptions->get(hookName, false);
|
91
|
+
if (!spec.empty()) {
|
92
|
+
HookScriptOptions options;
|
93
|
+
options.agentsOptions = agentsOptions;
|
94
|
+
options.name = name;
|
95
|
+
options.spec = spec;
|
96
|
+
setup(options);
|
97
|
+
return Passenger::runHookScripts(options);
|
98
|
+
} else {
|
99
|
+
return true;
|
100
|
+
}
|
101
|
+
} else {
|
102
|
+
return true;
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
static const char *maybePluralize(unsigned int count, const char *singular, const char *plural) {
|
107
|
+
if (count == 1) {
|
108
|
+
return singular;
|
109
|
+
} else {
|
110
|
+
return plural;
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
|
115
|
+
public:
|
116
|
+
|
117
|
+
const SpawnerConfigPtr &getSpawnerConfig() const {
|
118
|
+
return spawnerFactory->getConfig();
|
119
|
+
}
|
120
|
+
|
121
|
+
const UnionStation::CorePtr &getUnionStationCore() const {
|
122
|
+
return getSpawnerConfig()->unionStationCore;
|
123
|
+
}
|
124
|
+
|
125
|
+
const RandomGeneratorPtr &getRandomGenerator() const {
|
126
|
+
return getSpawnerConfig()->randomGenerator;
|
127
|
+
}
|
@@ -0,0 +1,214 @@
|
|
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
|
+
public:
|
29
|
+
|
30
|
+
struct InspectOptions {
|
31
|
+
bool colorize;
|
32
|
+
bool verbose;
|
33
|
+
|
34
|
+
InspectOptions()
|
35
|
+
: colorize(false),
|
36
|
+
verbose(false)
|
37
|
+
{ }
|
38
|
+
|
39
|
+
InspectOptions(const VariantMap &options)
|
40
|
+
: colorize(options.getBool("colorize", false, false)),
|
41
|
+
verbose(options.getBool("verbose", false, false))
|
42
|
+
{ }
|
43
|
+
};
|
44
|
+
|
45
|
+
|
46
|
+
private:
|
47
|
+
|
48
|
+
void inspectProcessList(const InspectOptions &options, stringstream &result,
|
49
|
+
const Group *group, const ProcessList &processes) const
|
50
|
+
{
|
51
|
+
ProcessList::const_iterator p_it;
|
52
|
+
for (p_it = processes.begin(); p_it != processes.end(); p_it++) {
|
53
|
+
const ProcessPtr &process = *p_it;
|
54
|
+
char buf[128];
|
55
|
+
char cpubuf[10];
|
56
|
+
char membuf[10];
|
57
|
+
|
58
|
+
snprintf(cpubuf, sizeof(cpubuf), "%d%%", (int) process->metrics.cpu);
|
59
|
+
snprintf(membuf, sizeof(membuf), "%ldM",
|
60
|
+
(unsigned long) (process->metrics.realMemory() / 1024));
|
61
|
+
snprintf(buf, sizeof(buf),
|
62
|
+
" * PID: %-5lu Sessions: %-2u Processed: %-5u Uptime: %s\n"
|
63
|
+
" CPU: %-5s Memory : %-5s Last used: %s ago",
|
64
|
+
(unsigned long) process->pid,
|
65
|
+
process->sessions,
|
66
|
+
process->processed,
|
67
|
+
process->uptime().c_str(),
|
68
|
+
cpubuf,
|
69
|
+
membuf,
|
70
|
+
distanceOfTimeInWords(process->lastUsed / 1000000).c_str());
|
71
|
+
result << buf << endl;
|
72
|
+
|
73
|
+
if (process->enabled == Process::DISABLING) {
|
74
|
+
result << " Disabling..." << endl;
|
75
|
+
} else if (process->enabled == Process::DISABLED) {
|
76
|
+
result << " DISABLED" << endl;
|
77
|
+
} else if (process->enabled == Process::DETACHED) {
|
78
|
+
result << " Shutting down..." << endl;
|
79
|
+
}
|
80
|
+
|
81
|
+
const Socket *socket;
|
82
|
+
if (options.verbose && (socket = process->sockets.findSocketWithName("http")) != NULL) {
|
83
|
+
result << " URL : http://" << replaceString(socket->address, "tcp://", "") << endl;
|
84
|
+
result << " Password: " << StaticString(group->secret, Group::SECRET_SIZE) << endl;
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
static const char *maybeColorize(const InspectOptions &options, const char *color) {
|
90
|
+
if (options.colorize) {
|
91
|
+
return color;
|
92
|
+
} else {
|
93
|
+
return "";
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
|
98
|
+
public:
|
99
|
+
|
100
|
+
string inspect(const InspectOptions &options = InspectOptions(), bool lock = true) const {
|
101
|
+
DynamicScopedLock l(syncher, lock);
|
102
|
+
stringstream result;
|
103
|
+
const char *headerColor = maybeColorize(options, ANSI_COLOR_YELLOW ANSI_COLOR_BLUE_BG ANSI_COLOR_BOLD);
|
104
|
+
const char *resetColor = maybeColorize(options, ANSI_COLOR_RESET);
|
105
|
+
|
106
|
+
result << headerColor << "----------- General information -----------" << resetColor << endl;
|
107
|
+
result << "Max pool size : " << max << endl;
|
108
|
+
result << "Processes : " << getProcessCount(false) << endl;
|
109
|
+
result << "Requests in top-level queue : " << getWaitlist.size() << endl;
|
110
|
+
if (options.verbose) {
|
111
|
+
unsigned int i = 0;
|
112
|
+
foreach (const GetWaiter &waiter, getWaitlist) {
|
113
|
+
result << " " << i << ": " << waiter.options.getAppGroupName() << endl;
|
114
|
+
i++;
|
115
|
+
}
|
116
|
+
}
|
117
|
+
result << endl;
|
118
|
+
|
119
|
+
result << headerColor << "----------- Application groups -----------" << resetColor << endl;
|
120
|
+
SuperGroupMap::ConstIterator sg_it(superGroups);
|
121
|
+
while (*sg_it != NULL) {
|
122
|
+
const SuperGroupPtr &superGroup = sg_it.getValue();
|
123
|
+
const Group *group = superGroup->defaultGroup;
|
124
|
+
ProcessList::const_iterator p_it;
|
125
|
+
|
126
|
+
if (group != NULL) {
|
127
|
+
result << group->name << ":" << endl;
|
128
|
+
result << " App root: " << group->options.appRoot << endl;
|
129
|
+
if (group->restarting()) {
|
130
|
+
result << " (restarting...)" << endl;
|
131
|
+
}
|
132
|
+
if (group->spawning()) {
|
133
|
+
if (group->processesBeingSpawned == 0) {
|
134
|
+
result << " (spawning...)" << endl;
|
135
|
+
} else {
|
136
|
+
result << " (spawning " << group->processesBeingSpawned << " new " <<
|
137
|
+
maybePluralize(group->processesBeingSpawned, "process", "processes") <<
|
138
|
+
"...)" << endl;
|
139
|
+
}
|
140
|
+
}
|
141
|
+
result << " Requests in queue: " << group->getWaitlist.size() << endl;
|
142
|
+
inspectProcessList(options, result, group, group->enabledProcesses);
|
143
|
+
inspectProcessList(options, result, group, group->disablingProcesses);
|
144
|
+
inspectProcessList(options, result, group, group->disabledProcesses);
|
145
|
+
inspectProcessList(options, result, group, group->detachedProcesses);
|
146
|
+
result << endl;
|
147
|
+
}
|
148
|
+
sg_it.next();
|
149
|
+
}
|
150
|
+
return result.str();
|
151
|
+
}
|
152
|
+
|
153
|
+
string toXml(bool includeSecrets = true, bool lock = true) const {
|
154
|
+
DynamicScopedLock l(syncher, lock);
|
155
|
+
stringstream result;
|
156
|
+
SuperGroupMap::ConstIterator sg_it(superGroups);
|
157
|
+
SuperGroup::GroupList::const_iterator g_it;
|
158
|
+
ProcessList::const_iterator p_it;
|
159
|
+
|
160
|
+
result << "<?xml version=\"1.0\" encoding=\"iso8859-1\" ?>\n";
|
161
|
+
result << "<info version=\"3\">";
|
162
|
+
|
163
|
+
result << "<passenger_version>" << PASSENGER_VERSION << "</passenger_version>";
|
164
|
+
result << "<process_count>" << getProcessCount(false) << "</process_count>";
|
165
|
+
result << "<max>" << max << "</max>";
|
166
|
+
result << "<capacity_used>" << capacityUsedUnlocked() << "</capacity_used>";
|
167
|
+
result << "<get_wait_list_size>" << getWaitlist.size() << "</get_wait_list_size>";
|
168
|
+
|
169
|
+
if (includeSecrets) {
|
170
|
+
vector<GetWaiter>::const_iterator w_it, w_end = getWaitlist.end();
|
171
|
+
|
172
|
+
result << "<get_wait_list>";
|
173
|
+
for (w_it = getWaitlist.begin(); w_it != w_end; w_it++) {
|
174
|
+
const GetWaiter &waiter = *w_it;
|
175
|
+
result << "<item>";
|
176
|
+
result << "<app_group_name>" << escapeForXml(waiter.options.getAppGroupName()) << "</app_group_name>";
|
177
|
+
result << "</item>";
|
178
|
+
}
|
179
|
+
result << "</get_wait_list>";
|
180
|
+
}
|
181
|
+
|
182
|
+
result << "<supergroups>";
|
183
|
+
while (*sg_it != NULL) {
|
184
|
+
const SuperGroupPtr &superGroup = sg_it.getValue();
|
185
|
+
|
186
|
+
result << "<supergroup>";
|
187
|
+
result << "<name>" << escapeForXml(superGroup->name) << "</name>";
|
188
|
+
result << "<state>" << superGroup->getStateName() << "</state>";
|
189
|
+
result << "<get_wait_list_size>" << superGroup->getWaitlist.size() << "</get_wait_list_size>";
|
190
|
+
result << "<capacity_used>" << superGroup->capacityUsed() << "</capacity_used>";
|
191
|
+
if (includeSecrets) {
|
192
|
+
result << "<secret>" << escapeForXml(superGroup->secret) << "</secret>";
|
193
|
+
}
|
194
|
+
|
195
|
+
for (g_it = superGroup->groups.begin(); g_it != superGroup->groups.end(); g_it++) {
|
196
|
+
const GroupPtr &group = *g_it;
|
197
|
+
|
198
|
+
if (group->componentInfo.isDefault) {
|
199
|
+
result << "<group default=\"true\">";
|
200
|
+
} else {
|
201
|
+
result << "<group>";
|
202
|
+
}
|
203
|
+
group->inspectXml(result, includeSecrets);
|
204
|
+
result << "</group>";
|
205
|
+
}
|
206
|
+
result << "</supergroup>";
|
207
|
+
|
208
|
+
sg_it.next();
|
209
|
+
}
|
210
|
+
result << "</supergroups>";
|
211
|
+
|
212
|
+
result << "</info>";
|
213
|
+
return result.str();
|
214
|
+
}
|
@@ -0,0 +1,85 @@
|
|
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,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2011-
|
3
|
+
* Copyright (c) 2011-2015 Phusion
|
4
4
|
*
|
5
5
|
* "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
|
6
6
|
*
|
@@ -86,13 +86,11 @@ typedef boost::container::vector<ProcessPtr> ProcessList;
|
|
86
86
|
* ## Life time
|
87
87
|
*
|
88
88
|
* A Process object lives until the containing Group calls `detach(process)`,
|
89
|
-
* which indicates that it wants this Process to shut down.
|
90
|
-
*
|
91
|
-
*
|
92
|
-
* `detachedProcesses` collection in the Group and are no longer eligible for
|
93
|
-
* receiving requests. Once all requests on this Process have finished,
|
89
|
+
* which indicates that it wants this Process to shut down. The Process object
|
90
|
+
* is stored in the `detachedProcesses` collection in the Group and is no longer
|
91
|
+
* eligible for receiving requests. Once all requests on this Process have finished,
|
94
92
|
* `triggerShutdown()` will be called, which will send a message to the
|
95
|
-
* process telling it to shut down. Once the process is gone, `cleanup()` is
|
93
|
+
* OS process telling it to shut down. Once the OS process is gone, `cleanup()` is
|
96
94
|
* called, and the Process object is removed from the collection.
|
97
95
|
*
|
98
96
|
* This means that a Group outlives all its Processes, a Process outlives all
|