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.

Files changed (36) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/CHANGELOG +10 -0
  5. data/CONTRIBUTORS +1 -0
  6. data/build/agents.rb +6 -0
  7. data/build/cxx_tests.rb +6 -0
  8. data/build/misc.rb +22 -1
  9. data/doc/Users guide Nginx.txt +12 -0
  10. data/ext/common/ApplicationPool2/Options.h +2 -1
  11. data/ext/common/ApplicationPool2/Pool.h +15 -744
  12. data/ext/common/ApplicationPool2/Pool/AnalyticsCollection.h +255 -0
  13. data/ext/common/ApplicationPool2/Pool/Debug.h +63 -0
  14. data/ext/common/ApplicationPool2/Pool/GarbageCollection.h +197 -0
  15. data/ext/common/ApplicationPool2/Pool/GeneralUtils.h +127 -0
  16. data/ext/common/ApplicationPool2/Pool/Inspection.h +214 -0
  17. data/ext/common/ApplicationPool2/Pool/ProcessUtils.h +85 -0
  18. data/ext/common/ApplicationPool2/Process.h +5 -7
  19. data/ext/common/Constants.h +1 -1
  20. data/ext/common/Hooks.h +2 -1
  21. data/ext/common/Utils.cpp +1 -1
  22. data/ext/common/Utils/JsonUtils.h +37 -1
  23. data/ext/common/agents/Base.cpp +45 -40
  24. data/ext/common/agents/Base.h +3 -2
  25. data/ext/common/agents/HelperAgent/RequestHandler/InitRequest.cpp +12 -10
  26. data/ext/nginx/Configuration.c +4 -1
  27. data/lib/phusion_passenger.rb +1 -1
  28. data/lib/phusion_passenger/common_library.rb +7 -1
  29. data/lib/phusion_passenger/config/restart_app_command.rb +40 -2
  30. data/lib/phusion_passenger/config/utils.rb +3 -5
  31. data/lib/phusion_passenger/utils/ansi_colors.rb +28 -21
  32. data/lib/phusion_passenger/utils/terminal_choice_menu.rb +27 -10
  33. data/resources/templates/standalone/config.erb +4 -4
  34. data/test/cxx/CxxTestMain.cpp +10 -22
  35. metadata +10 -4
  36. 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-2014 Phusion
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. This causes
90
- * `signalDetached()` to be called, which may or may not send a message
91
- * to the process. After this, the Process object is stored in the
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