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
@@ -22,23 +22,32 @@
22
22
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
23
  * THE SOFTWARE.
24
24
  */
25
+ #include <ApplicationPool2/Pool.h>
25
26
 
26
- // This file is included inside the Pool class.
27
+ /*************************************************************************
28
+ *
29
+ * Analytics collection functions for ApplicationPool2::Pool
30
+ *
31
+ *************************************************************************/
27
32
 
28
- private:
33
+ namespace Passenger {
34
+ namespace ApplicationPool2 {
29
35
 
30
- struct UnionStationLogEntry {
31
- string groupName;
32
- const char *category;
33
- string key;
34
- string data;
35
- };
36
+ using namespace std;
37
+ using namespace boost;
36
38
 
37
- SystemMetricsCollector systemMetricsCollector;
38
- SystemMetrics systemMetrics;
39
39
 
40
+ void
41
+ Pool::initializeAnalyticsCollection() {
42
+ interruptableThreads.create_thread(
43
+ boost::bind(collectAnalytics, shared_from_this()),
44
+ "Pool analytics collector",
45
+ POOL_HELPER_THREAD_STACK_SIZE
46
+ );
47
+ }
40
48
 
41
- static void collectAnalytics(PoolPtr self) {
49
+ void
50
+ Pool::collectAnalytics(PoolPtr self) {
42
51
  TRACE_POINT();
43
52
  syscalls::usleep(3000000);
44
53
  while (!this_thread::interruption_requested()) {
@@ -70,25 +79,27 @@ static void collectAnalytics(PoolPtr self) {
70
79
  }
71
80
  }
72
81
 
73
- static void collectPids(const ProcessList &processes, vector<pid_t> &pids) {
82
+ void
83
+ Pool::collectPids(const ProcessList &processes, vector<pid_t> &pids) {
74
84
  foreach (const ProcessPtr &process, processes) {
75
- pids.push_back(process->pid);
85
+ pids.push_back(process->getPid());
76
86
  }
77
87
  }
78
88
 
79
- static void updateProcessMetrics(const ProcessList &processes,
89
+ void
90
+ Pool::updateProcessMetrics(const ProcessList &processes,
80
91
  const ProcessMetricMap &allMetrics,
81
92
  vector<ProcessPtr> &processesToDetach)
82
93
  {
83
94
  foreach (const ProcessPtr &process, processes) {
84
95
  ProcessMetricMap::const_iterator metrics_it =
85
- allMetrics.find(process->pid);
96
+ allMetrics.find(process->getPid());
86
97
  if (metrics_it != allMetrics.end()) {
87
98
  process->metrics = metrics_it->second;
88
99
  // If the process is missing from 'allMetrics' then either 'ps'
89
100
  // failed or the process really is gone. We double check by sending
90
101
  // it a signal.
91
- } else if (!process->dummy && !process->osProcessExists()) {
102
+ } else if (!process->isDummy() && !process->osProcessExists()) {
92
103
  P_WARN("Process " << process->inspect() << " no longer exists! "
93
104
  "Detaching it from the pool.");
94
105
  processesToDetach.push_back(process);
@@ -96,7 +107,8 @@ static void updateProcessMetrics(const ProcessList &processes,
96
107
  }
97
108
  }
98
109
 
99
- void prepareUnionStationProcessStateLogs(vector<UnionStationLogEntry> &logEntries,
110
+ void
111
+ Pool::prepareUnionStationProcessStateLogs(vector<UnionStationLogEntry> &logEntries,
100
112
  const GroupPtr &group) const
101
113
  {
102
114
  const UnionStation::CorePtr &unionStationCore = getUnionStationCore();
@@ -116,7 +128,8 @@ void prepareUnionStationProcessStateLogs(vector<UnionStationLogEntry> &logEntrie
116
128
  }
117
129
  }
118
130
 
119
- void prepareUnionStationSystemMetricsLogs(vector<UnionStationLogEntry> &logEntries,
131
+ void
132
+ Pool::prepareUnionStationSystemMetricsLogs(vector<UnionStationLogEntry> &logEntries,
120
133
  const GroupPtr &group) const
121
134
  {
122
135
  const UnionStation::CorePtr &unionStationCore = getUnionStationCore();
@@ -135,7 +148,8 @@ void prepareUnionStationSystemMetricsLogs(vector<UnionStationLogEntry> &logEntri
135
148
  }
136
149
  }
137
150
 
138
- void realCollectAnalytics() {
151
+ void
152
+ Pool::realCollectAnalytics() {
139
153
  TRACE_POINT();
140
154
  this_thread::disable_interruption di;
141
155
  this_thread::disable_syscall_interruption dsi;
@@ -153,19 +167,14 @@ void realCollectAnalytics() {
153
167
  {
154
168
  UPDATE_TRACE_POINT();
155
169
  LockGuard l(syncher);
156
- SuperGroupMap::ConstIterator sg_it(superGroups);
157
-
158
- while (*sg_it != NULL) {
159
- const SuperGroupPtr &superGroup = sg_it.getValue();
160
- SuperGroup::GroupList::const_iterator g_it, g_end = superGroup->groups.end();
161
-
162
- for (g_it = superGroup->groups.begin(); g_it != g_end; g_it++) {
163
- const GroupPtr &group = *g_it;
164
- collectPids(group->enabledProcesses, pids);
165
- collectPids(group->disablingProcesses, pids);
166
- collectPids(group->disabledProcesses, pids);
167
- }
168
- sg_it.next();
170
+ GroupMap::ConstIterator g_it(groups);
171
+
172
+ while (*g_it != NULL) {
173
+ const GroupPtr &group = g_it.getValue();
174
+ collectPids(group->enabledProcesses, pids);
175
+ collectPids(group->disablingProcesses, pids);
176
+ collectPids(group->disabledProcesses, pids);
177
+ g_it.next();
169
178
  }
170
179
  }
171
180
 
@@ -174,6 +183,7 @@ void realCollectAnalytics() {
174
183
  ProcessMetricMap processMetrics;
175
184
  try {
176
185
  UPDATE_TRACE_POINT();
186
+ P_DEBUG("Collecting process metrics");
177
187
  processMetrics = ProcessMetricsCollector().collect(pids);
178
188
  } catch (const ParseException &) {
179
189
  P_WARN("Unable to collect process metrics: cannot parse 'ps' output.");
@@ -181,6 +191,7 @@ void realCollectAnalytics() {
181
191
  }
182
192
  try {
183
193
  UPDATE_TRACE_POINT();
194
+ P_DEBUG("Collecting system metrics");
184
195
  systemMetricsCollector.collect(systemMetrics);
185
196
  } catch (const RuntimeException &e) {
186
197
  P_WARN("Unable to collect system metrics: " << e.what());
@@ -193,23 +204,17 @@ void realCollectAnalytics() {
193
204
  vector<ProcessPtr> processesToDetach;
194
205
  boost::container::vector<Callback> actions;
195
206
  ScopedLock l(syncher);
196
- SuperGroupMap::ConstIterator sg_it(superGroups);
207
+ GroupMap::ConstIterator g_it(groups);
197
208
 
198
209
  UPDATE_TRACE_POINT();
199
- while (*sg_it != NULL) {
200
- const SuperGroupPtr &superGroup = sg_it.getValue();
201
- SuperGroup::GroupList::iterator g_it, g_end = superGroup->groups.end();
202
-
203
- for (g_it = superGroup->groups.begin(); g_it != g_end; g_it++) {
204
- const GroupPtr &group = *g_it;
205
-
206
- updateProcessMetrics(group->enabledProcesses, processMetrics, processesToDetach);
207
- updateProcessMetrics(group->disablingProcesses, processMetrics, processesToDetach);
208
- updateProcessMetrics(group->disabledProcesses, processMetrics, processesToDetach);
209
- prepareUnionStationProcessStateLogs(logEntries, group);
210
- prepareUnionStationSystemMetricsLogs(logEntries, group);
211
- }
212
- sg_it.next();
210
+ while (*g_it != NULL) {
211
+ const GroupPtr &group = g_it.getValue();
212
+ updateProcessMetrics(group->enabledProcesses, processMetrics, processesToDetach);
213
+ updateProcessMetrics(group->disablingProcesses, processMetrics, processesToDetach);
214
+ updateProcessMetrics(group->disabledProcesses, processMetrics, processesToDetach);
215
+ prepareUnionStationProcessStateLogs(logEntries, group);
216
+ prepareUnionStationSystemMetricsLogs(logEntries, group);
217
+ g_it.next();
213
218
  }
214
219
 
215
220
  UPDATE_TRACE_POINT();
@@ -223,6 +228,7 @@ void realCollectAnalytics() {
223
228
  UPDATE_TRACE_POINT();
224
229
  if (!logEntries.empty()) {
225
230
  const UnionStation::CorePtr &unionStationCore = getUnionStationCore();
231
+ P_DEBUG("Sending process and system metrics to Union Station");
226
232
  while (!logEntries.empty()) {
227
233
  UnionStationLogEntry &entry = logEntries.back();
228
234
  UnionStation::TransactionPtr transaction =
@@ -244,12 +250,5 @@ void realCollectAnalytics() {
244
250
  }
245
251
 
246
252
 
247
- protected:
248
-
249
- void initializeAnalyticsCollection() {
250
- interruptableThreads.create_thread(
251
- boost::bind(collectAnalytics, shared_from_this()),
252
- "Pool analytics collector",
253
- POOL_HELPER_THREAD_STACK_SIZE
254
- );
255
- }
253
+ } // namespace ApplicationPool2
254
+ } // namespace Passenger
@@ -22,21 +22,32 @@
22
22
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
23
  * THE SOFTWARE.
24
24
  */
25
+ #include <ApplicationPool2/Pool.h>
25
26
 
26
- // This file is included inside the Pool class.
27
+ /*************************************************************************
28
+ *
29
+ * Garbage collection functions for ApplicationPool2::Pool
30
+ *
31
+ *************************************************************************/
27
32
 
28
- private:
33
+ namespace Passenger {
34
+ namespace ApplicationPool2 {
29
35
 
30
- struct GarbageCollectorState {
31
- unsigned long long now;
32
- unsigned long long nextGcRunTime;
33
- boost::container::vector<Callback> actions;
34
- };
36
+ using namespace std;
37
+ using namespace boost;
35
38
 
36
- boost::condition_variable garbageCollectionCond;
37
39
 
40
+ void
41
+ Pool::initializeGarbageCollection() {
42
+ interruptableThreads.create_thread(
43
+ boost::bind(garbageCollect, shared_from_this()),
44
+ "Pool garbage collector",
45
+ POOL_HELPER_THREAD_STACK_SIZE
46
+ );
47
+ }
38
48
 
39
- static void garbageCollect(PoolPtr self) {
49
+ void
50
+ Pool::garbageCollect(PoolPtr self) {
40
51
  TRACE_POINT();
41
52
  {
42
53
  ScopedLock lock(self->syncher);
@@ -59,13 +70,15 @@ static void garbageCollect(PoolPtr self) {
59
70
  }
60
71
  }
61
72
 
62
- void maybeUpdateNextGcRuntime(GarbageCollectorState &state, unsigned long candidate) {
73
+ void
74
+ Pool::maybeUpdateNextGcRuntime(GarbageCollectorState &state, unsigned long candidate) {
63
75
  if (state.nextGcRunTime == 0 || candidate < state.nextGcRunTime) {
64
76
  state.nextGcRunTime = candidate;
65
77
  }
66
78
  }
67
79
 
68
- void checkWhetherProcessCanBeGarbageCollected(GarbageCollectorState &state,
80
+ void
81
+ Pool::checkWhetherProcessCanBeGarbageCollected(GarbageCollectorState &state,
69
82
  const GroupPtr &group, const ProcessPtr &process, ProcessList &output)
70
83
  {
71
84
  assert(maxIdleTime > 0);
@@ -82,7 +95,8 @@ void checkWhetherProcessCanBeGarbageCollected(GarbageCollectorState &state,
82
95
  }
83
96
  }
84
97
 
85
- void garbageCollectProcessesInGroup(GarbageCollectorState &state,
98
+ void
99
+ Pool::garbageCollectProcessesInGroup(GarbageCollectorState &state,
86
100
  const GroupPtr &group)
87
101
  {
88
102
  ProcessList &processes = group->enabledProcesses;
@@ -102,19 +116,20 @@ void garbageCollectProcessesInGroup(GarbageCollectorState &state,
102
116
  {
103
117
  ProcessPtr process = *p_it;
104
118
  P_DEBUG("Garbage collect idle process: " << process->inspect() <<
105
- ", group=" << group->name);
119
+ ", group=" << group->getName());
106
120
  group->detach(process, state.actions);
107
121
  p_it++;
108
122
  }
109
123
  }
110
124
 
111
- void maybeCleanPreloader(GarbageCollectorState &state, const GroupPtr &group) {
125
+ void
126
+ Pool::maybeCleanPreloader(GarbageCollectorState &state, const GroupPtr &group) {
112
127
  if (group->spawner->cleanable() && group->options.getMaxPreloaderIdleTime() != 0) {
113
128
  unsigned long long spawnerGcTime =
114
129
  group->spawner->lastUsed() +
115
130
  group->options.getMaxPreloaderIdleTime() * 1000000;
116
131
  if (state.now >= spawnerGcTime) {
117
- P_DEBUG("Garbage collect idle spawner: group=" << group->name);
132
+ P_DEBUG("Garbage collect idle spawner: group=" << group->getName());
118
133
  group->cleanupSpawner(state.actions);
119
134
  } else {
120
135
  maybeUpdateNextGcRuntime(state, spawnerGcTime);
@@ -123,10 +138,10 @@ void maybeCleanPreloader(GarbageCollectorState &state, const GroupPtr &group) {
123
138
  }
124
139
 
125
140
  unsigned long long
126
- realGarbageCollect() {
141
+ Pool::realGarbageCollect() {
127
142
  TRACE_POINT();
128
143
  ScopedLock lock(syncher);
129
- SuperGroupMap::ConstIterator sg_it(superGroups);
144
+ GroupMap::ConstIterator g_it(groups);
130
145
  GarbageCollectorState state;
131
146
  state.now = SystemTime::getUsec();
132
147
  state.nextGcRunTime = 0;
@@ -134,30 +149,21 @@ realGarbageCollect() {
134
149
  P_DEBUG("Garbage collection time...");
135
150
  verifyInvariants();
136
151
 
137
- // For all supergroups and groups...
138
- while (*sg_it != NULL) {
139
- const SuperGroupPtr superGroup = sg_it.getValue();
140
- SuperGroup::GroupList &groups = superGroup->groups;
141
- SuperGroup::GroupList::iterator g_it, g_end = groups.end();
142
-
143
- superGroup->verifyInvariants();
152
+ // For all groups...
153
+ while (*g_it != NULL) {
154
+ const GroupPtr group = g_it.getValue();
144
155
 
145
- for (g_it = groups.begin(); g_it != g_end; g_it++) {
146
- GroupPtr group = *g_it;
147
-
148
- if (maxIdleTime > 0) {
149
- // ...detach processes that have been idle for more than maxIdleTime.
150
- garbageCollectProcessesInGroup(state, group);
151
- }
156
+ if (maxIdleTime > 0) {
157
+ // ...detach processes that have been idle for more than maxIdleTime.
158
+ garbageCollectProcessesInGroup(state, group);
159
+ }
152
160
 
153
- group->verifyInvariants();
161
+ group->verifyInvariants();
154
162
 
155
- // ...cleanup the spawner if it's been idle for more than preloaderIdleTime.
156
- maybeCleanPreloader(state, group);
157
- }
163
+ // ...cleanup the spawner if it's been idle for more than preloaderIdleTime.
164
+ maybeCleanPreloader(state, group);
158
165
 
159
- superGroup->verifyInvariants();
160
- sg_it.next();
166
+ g_it.next();
161
167
  }
162
168
 
163
169
  verifyInvariants();
@@ -184,17 +190,11 @@ realGarbageCollect() {
184
190
  return sleepTime;
185
191
  }
186
192
 
187
-
188
- protected:
189
-
190
- void initializeGarbageCollection() {
191
- interruptableThreads.create_thread(
192
- boost::bind(garbageCollect, shared_from_this()),
193
- "Pool garbage collector",
194
- POOL_HELPER_THREAD_STACK_SIZE
195
- );
196
- }
197
-
198
- void wakeupGarbageCollector() {
193
+ void
194
+ Pool::wakeupGarbageCollector() {
199
195
  garbageCollectionCond.notify_all();
200
196
  }
197
+
198
+
199
+ } // namespace ApplicationPool2
200
+ } // namespace Passenger
@@ -0,0 +1,241 @@
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
+ #include <ApplicationPool2/Pool.h>
26
+
27
+ /*************************************************************************
28
+ *
29
+ * General utility functions for ApplicationPool2::Pool
30
+ *
31
+ *************************************************************************/
32
+
33
+ namespace Passenger {
34
+ namespace ApplicationPool2 {
35
+
36
+ using namespace std;
37
+ using namespace boost;
38
+
39
+
40
+ /****************************
41
+ *
42
+ * Private methods
43
+ *
44
+ ****************************/
45
+
46
+
47
+ const char *
48
+ Pool::maybeColorize(const InspectOptions &options, const char *color) {
49
+ if (options.colorize) {
50
+ return color;
51
+ } else {
52
+ return "";
53
+ }
54
+ }
55
+
56
+ const char *
57
+ Pool::maybePluralize(unsigned int count, const char *singular, const char *plural) {
58
+ if (count == 1) {
59
+ return singular;
60
+ } else {
61
+ return plural;
62
+ }
63
+ }
64
+
65
+ void
66
+ Pool::runAllActions(const boost::container::vector<Callback> &actions) {
67
+ boost::container::vector<Callback>::const_iterator it, end = actions.end();
68
+ for (it = actions.begin(); it != end; it++) {
69
+ (*it)();
70
+ }
71
+ }
72
+
73
+ void
74
+ Pool::runAllActionsWithCopy(boost::container::vector<Callback> actions) {
75
+ runAllActions(actions);
76
+ }
77
+
78
+ bool
79
+ Pool::runHookScripts(const char *name,
80
+ const boost::function<void (HookScriptOptions &)> &setup) const
81
+ {
82
+ if (agentsOptions != NULL) {
83
+ string hookName = string("hook_") + name;
84
+ string spec = agentsOptions->get(hookName, false);
85
+ if (!spec.empty()) {
86
+ HookScriptOptions options;
87
+ options.agentsOptions = agentsOptions;
88
+ options.name = name;
89
+ options.spec = spec;
90
+ setup(options);
91
+ return Passenger::runHookScripts(options);
92
+ } else {
93
+ return true;
94
+ }
95
+ } else {
96
+ return true;
97
+ }
98
+ }
99
+
100
+ void
101
+ Pool::verifyInvariants() const {
102
+ // !a || b: logical equivalent of a IMPLIES b.
103
+ #ifndef NDEBUG
104
+ if (!selfchecking) {
105
+ return;
106
+ }
107
+ assert(!( !getWaitlist.empty() ) || ( atFullCapacityUnlocked() ));
108
+ assert(!( !atFullCapacityUnlocked() ) || ( getWaitlist.empty() ));
109
+ #endif
110
+ }
111
+
112
+ void
113
+ Pool::verifyExpensiveInvariants() const {
114
+ #ifndef NDEBUG
115
+ if (!selfchecking) {
116
+ return;
117
+ }
118
+ vector<GetWaiter>::const_iterator it, end = getWaitlist.end();
119
+ for (it = getWaitlist.begin(); it != end; it++) {
120
+ const GetWaiter &waiter = *it;
121
+ const GroupPtr *group;
122
+ assert(!groups.lookup(waiter.options.getAppGroupName(), &group));
123
+ }
124
+ #endif
125
+ }
126
+
127
+ void
128
+ Pool::fullVerifyInvariants() const {
129
+ TRACE_POINT();
130
+ verifyInvariants();
131
+ UPDATE_TRACE_POINT();
132
+ verifyExpensiveInvariants();
133
+ UPDATE_TRACE_POINT();
134
+
135
+ GroupMap::ConstIterator g_it(groups);
136
+ while (*g_it != NULL) {
137
+ const GroupPtr &group = g_it.getValue();
138
+ group->verifyInvariants();
139
+ group->verifyExpensiveInvariants();
140
+ g_it.next();
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Process all waiters on the getWaitlist. Call when capacity has become free.
146
+ * This function assigns sessions to them by calling get() on the corresponding
147
+ * Groups, or by creating more Groups, in so far the new capacity allows.
148
+ */
149
+ void
150
+ Pool::assignSessionsToGetWaiters(boost::container::vector<Callback> &postLockActions) {
151
+ bool done = false;
152
+ vector<GetWaiter>::iterator it, end = getWaitlist.end();
153
+ vector<GetWaiter> newWaitlist;
154
+
155
+ for (it = getWaitlist.begin(); it != end && !done; it++) {
156
+ GetWaiter &waiter = *it;
157
+
158
+ Group *group = findMatchingGroup(waiter.options);
159
+ if (group != NULL) {
160
+ SessionPtr session = group->get(waiter.options, waiter.callback,
161
+ postLockActions);
162
+ if (session != NULL) {
163
+ postLockActions.push_back(boost::bind(GetCallback::call,
164
+ waiter.callback, session, ExceptionPtr()));
165
+ }
166
+ /* else: the callback has now been put in
167
+ * the group's get wait list.
168
+ */
169
+ } else if (!atFullCapacityUnlocked()) {
170
+ createGroupAndAsyncGetFromIt(waiter.options, waiter.callback,
171
+ postLockActions);
172
+ } else {
173
+ /* Still cannot satisfy this get request. Keep it on the get
174
+ * wait list and try again later.
175
+ */
176
+ newWaitlist.push_back(waiter);
177
+ }
178
+ }
179
+
180
+ std::swap(getWaitlist, newWaitlist);
181
+ }
182
+
183
+ template<typename Queue>
184
+ void
185
+ Pool::assignExceptionToGetWaiters(Queue &getWaitlist,
186
+ const ExceptionPtr &exception,
187
+ boost::container::vector<Callback> &postLockActions)
188
+ {
189
+ while (!getWaitlist.empty()) {
190
+ postLockActions.push_back(boost::bind(GetCallback::call,
191
+ getWaitlist.front().callback, SessionPtr(),
192
+ exception));
193
+ getWaitlist.pop_front();
194
+ }
195
+ }
196
+
197
+ void
198
+ Pool::syncGetCallback(const SessionPtr &session, const ExceptionPtr &e,
199
+ void *userData)
200
+ {
201
+ Ticket *ticket = static_cast<Ticket *>(userData);
202
+ ScopedLock lock(ticket->syncher);
203
+ if (OXT_LIKELY(session != NULL)) {
204
+ ticket->session = session;
205
+ } else {
206
+ ticket->exception = e;
207
+ }
208
+ ticket->cond.notify_one();
209
+ }
210
+
211
+
212
+ /****************************
213
+ *
214
+ * Public methods
215
+ *
216
+ ****************************/
217
+
218
+
219
+ Context *
220
+ Pool::getContext() {
221
+ return &context;
222
+ }
223
+
224
+ const SpawningKit::ConfigPtr &
225
+ Pool::getSpawningKitConfig() const {
226
+ return context.getSpawningKitConfig();
227
+ }
228
+
229
+ const UnionStation::CorePtr &
230
+ Pool::getUnionStationCore() const {
231
+ return getSpawningKitConfig()->unionStationCore;
232
+ }
233
+
234
+ const RandomGeneratorPtr &
235
+ Pool::getRandomGenerator() const {
236
+ return getSpawningKitConfig()->randomGenerator;
237
+ }
238
+
239
+
240
+ } // namespace ApplicationPool2
241
+ } // namespace Passenger