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
@@ -0,0 +1,190 @@
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/Group.h>
26
+
27
+ /*************************************************************************
28
+ *
29
+ * Initialization and shutdown functions for ApplicationPool2::Group
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
+ ApiKey
48
+ Group::generateApiKey(const Pool *pool) {
49
+ char value[ApiKey::SIZE];
50
+ pool->getRandomGenerator()->generateAsciiString(value, ApiKey::SIZE);
51
+ return ApiKey(StaticString(value, ApiKey::SIZE));
52
+ }
53
+
54
+ string
55
+ Group::generateUuid(const Pool *pool) {
56
+ return pool->getRandomGenerator()->generateAsciiString(20);
57
+ }
58
+
59
+ bool
60
+ Group::shutdownCanFinish() const {
61
+ LifeStatus lifeStatus = (LifeStatus) this->lifeStatus.load(boost::memory_order_relaxed);
62
+ return lifeStatus == SHUTTING_DOWN
63
+ && enabledCount == 0
64
+ && disablingCount == 0
65
+ && disabledCount == 0
66
+ && detachedProcesses.empty();
67
+ }
68
+
69
+ /** One of the post lock actions can potentially perform a long-running
70
+ * operation, so running them in a thread is advised.
71
+ */
72
+ void
73
+ Group::finishShutdown(boost::container::vector<Callback> &postLockActions) {
74
+ TRACE_POINT();
75
+ #ifndef NDEBUG
76
+ LifeStatus lifeStatus = (LifeStatus) this->lifeStatus.load(boost::memory_order_relaxed);
77
+ P_ASSERT_EQ(lifeStatus, SHUTTING_DOWN);
78
+ #endif
79
+ P_DEBUG("Finishing shutdown of group " << info.name);
80
+ if (shutdownCallback) {
81
+ postLockActions.push_back(shutdownCallback);
82
+ shutdownCallback = Callback();
83
+ }
84
+ postLockActions.push_back(boost::bind(interruptAndJoinAllThreads,
85
+ shared_from_this()));
86
+ this->lifeStatus.store(SHUT_DOWN, boost::memory_order_release);
87
+ selfPointer.reset();
88
+ }
89
+
90
+
91
+ /****************************
92
+ *
93
+ * Public methods
94
+ *
95
+ ****************************/
96
+
97
+
98
+ Group::Group(Pool *_pool, const Options &_options)
99
+ : pool(_pool),
100
+ uuid(generateUuid(_pool))
101
+ {
102
+ info.context = _pool->getContext();
103
+ info.group = this;
104
+ info.name = _options.getAppGroupName().toString();
105
+ info.apiKey = generateApiKey(_pool);
106
+ resetOptions(_options);
107
+ enabledCount = 0;
108
+ disablingCount = 0;
109
+ disabledCount = 0;
110
+ nEnabledProcessesTotallyBusy = 0;
111
+ spawner = getContext()->getSpawningKitFactory()->create(options);
112
+ restartsInitiated = 0;
113
+ processesBeingSpawned = 0;
114
+ m_spawning = false;
115
+ m_restarting = false;
116
+ lifeStatus.store(ALIVE, boost::memory_order_relaxed);
117
+ lastRestartFileMtime = 0;
118
+ lastRestartFileCheckTime = 0;
119
+ alwaysRestartFileExists = false;
120
+ if (options.restartDir.empty()) {
121
+ restartFile = options.appRoot + "/tmp/restart.txt";
122
+ alwaysRestartFile = options.appRoot + "/tmp/always_restart.txt";
123
+ } else if (options.restartDir[0] == '/') {
124
+ restartFile = options.restartDir + "/restart.txt";
125
+ alwaysRestartFile = options.restartDir + "/always_restart.txt";
126
+ } else {
127
+ restartFile = options.appRoot + "/" + options.restartDir + "/restart.txt";
128
+ alwaysRestartFile = options.appRoot + "/" + options.restartDir + "/always_restart.txt";
129
+ }
130
+
131
+ detachedProcessesCheckerActive = false;
132
+ }
133
+
134
+ Group::~Group() {
135
+ LifeStatus lifeStatus = getLifeStatus();
136
+ if (OXT_UNLIKELY(lifeStatus == ALIVE)) {
137
+ P_BUG("You must call Group::shutdown() before destroying a Group.");
138
+ }
139
+ assert(lifeStatus == SHUT_DOWN);
140
+ assert(!detachedProcessesCheckerActive);
141
+ assert(getWaitlist.empty());
142
+ }
143
+
144
+ bool
145
+ Group::initialize() {
146
+ Json::Value json;
147
+
148
+ json["type"] = "dummy";
149
+ json["pid"] = 0;
150
+ json["gupid"] = "0";
151
+ json["spawner_creation_time"] = 0;
152
+ json["spawn_start_time"] = 0;
153
+ json["sockets"] = Json::Value(Json::arrayValue);
154
+
155
+ nullProcess = createProcessObject(json);
156
+ nullProcess->shutdownNotRequired();
157
+ return true;
158
+ }
159
+
160
+ /**
161
+ * Must be called before destroying a Group. You can optionally provide a
162
+ * callback so that you are notified when shutdown has finished.
163
+ *
164
+ * The caller is responsible for migrating waiters on the getWaitlist.
165
+ *
166
+ * One of the post lock actions can potentially perform a long-running
167
+ * operation, so running them in a thread is advised.
168
+ */
169
+ void
170
+ Group::shutdown(const Callback &callback,
171
+ boost::container::vector<Callback> &postLockActions)
172
+ {
173
+ assert(isAlive());
174
+ assert(getWaitlist.empty());
175
+
176
+ P_DEBUG("Begin shutting down group " << info.name);
177
+ shutdownCallback = callback;
178
+ detachAll(postLockActions);
179
+ startCheckingDetachedProcesses(true);
180
+ interruptableThreads.interrupt_all();
181
+ postLockActions.push_back(boost::bind(doCleanupSpawner, spawner));
182
+ spawner.reset();
183
+ selfPointer = shared_from_this();
184
+ assert(disableWaitlist.empty());
185
+ lifeStatus.store(SHUTTING_DOWN, boost::memory_order_release);
186
+ }
187
+
188
+
189
+ } // namespace ApplicationPool2
190
+ } // namespace Passenger
@@ -0,0 +1,329 @@
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/Group.h>
26
+
27
+ /*************************************************************************
28
+ *
29
+ * Internal utility functions for ApplicationPool2::Group
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
+ void
48
+ Group::runAllActions(const boost::container::vector<Callback> &actions) {
49
+ boost::container::vector<Callback>::const_iterator it, end = actions.end();
50
+ for (it = actions.begin(); it != end; it++) {
51
+ (*it)();
52
+ }
53
+ }
54
+
55
+ void
56
+ Group::interruptAndJoinAllThreads(GroupPtr self) {
57
+ self->interruptableThreads.interrupt_and_join_all();
58
+ }
59
+
60
+ void
61
+ Group::doCleanupSpawner(SpawningKit::SpawnerPtr spawner) {
62
+ spawner->cleanup();
63
+ }
64
+
65
+ /**
66
+ * Persists options into this Group. Called at creation time and at restart time.
67
+ * Values will be persisted into `destination`. Or if it's NULL, into `this->options`.
68
+ */
69
+ void
70
+ Group::resetOptions(const Options &newOptions, Options *destination) {
71
+ if (destination == NULL) {
72
+ destination = &this->options;
73
+ }
74
+ *destination = newOptions;
75
+ destination->persist(newOptions);
76
+ destination->clearPerRequestFields();
77
+ destination->apiKey = getApiKey().toStaticString();
78
+ destination->groupUuid = uuid;
79
+ }
80
+
81
+ /**
82
+ * Merges some of the new options from the latest get() request into this Group.
83
+ */
84
+ void
85
+ Group::mergeOptions(const Options &other) {
86
+ options.maxRequests = other.maxRequests;
87
+ options.minProcesses = other.minProcesses;
88
+ options.statThrottleRate = other.statThrottleRate;
89
+ options.maxPreloaderIdleTime = other.maxPreloaderIdleTime;
90
+ }
91
+
92
+ /* Given a hook name like "queue_full_error", we return HookScriptOptions filled in with this name and a spec
93
+ * (user settings that can be queried from agentsOptions using the external hook name that is prefixed with "hook_")
94
+ *
95
+ * @return false if the user parameters (agentsOptions) are not available (e.g. during ApplicationPool2_PoolTest)
96
+ */
97
+ bool
98
+ Group::prepareHookScriptOptions(HookScriptOptions &hsOptions, const char *name) {
99
+ SpawningKit::ConfigPtr config = getPool()->getSpawningKitConfig();
100
+ if (config->agentsOptions == NULL) {
101
+ return false;
102
+ }
103
+
104
+ hsOptions.name = name;
105
+ string hookName = string("hook_") + name;
106
+ hsOptions.spec = config->agentsOptions->get(hookName, false);
107
+
108
+ return true;
109
+ }
110
+
111
+ // 'process' is not a reference so that bind(runAttachHooks, ...) causes the shared
112
+ // pointer reference to increment.
113
+ void
114
+ Group::runAttachHooks(const ProcessPtr process) const {
115
+ getPool()->runHookScripts("attached_process",
116
+ boost::bind(&Group::setupAttachOrDetachHook, this, process, _1));
117
+ }
118
+
119
+ void
120
+ Group::runDetachHooks(const ProcessPtr process) const {
121
+ getPool()->runHookScripts("detached_process",
122
+ boost::bind(&Group::setupAttachOrDetachHook, this, process, _1));
123
+ }
124
+
125
+ void
126
+ Group::setupAttachOrDetachHook(const ProcessPtr process, HookScriptOptions &options) const {
127
+ options.environment.push_back(make_pair("PASSENGER_PROCESS_PID", toString(process->getPid())));
128
+ options.environment.push_back(make_pair("PASSENGER_APP_ROOT", this->options.appRoot));
129
+ }
130
+
131
+ unsigned int
132
+ Group::generateStickySessionId() {
133
+ unsigned int result;
134
+
135
+ while (true) {
136
+ result = (unsigned int) rand();
137
+ if (result != 0 && findProcessWithStickySessionId(result) == NULL) {
138
+ return result;
139
+ }
140
+ }
141
+ // Never reached; shut up compiler warning.
142
+ return 0;
143
+ }
144
+
145
+ ProcessPtr
146
+ Group::createProcessObject(const Json::Value &json) {
147
+ struct Guard {
148
+ Context *context;
149
+ Process *process;
150
+
151
+ Guard(Context *c, Process *s)
152
+ : context(c),
153
+ process(s)
154
+ { }
155
+
156
+ ~Guard() {
157
+ if (process != NULL) {
158
+ context->getProcessObjectPool().free(process);
159
+ }
160
+ }
161
+
162
+ void clear() {
163
+ process = NULL;
164
+ }
165
+ };
166
+
167
+ Context *context = getContext();
168
+ LockGuard l(context->getMmSyncher());
169
+ Process *process = context->getProcessObjectPool().malloc();
170
+ Guard guard(context, process);
171
+ process = new (process) Process(&info, json);
172
+ guard.clear();
173
+ return ProcessPtr(process, false);
174
+ }
175
+
176
+ bool
177
+ Group::poolAtFullCapacity() const {
178
+ return getPool()->atFullCapacityUnlocked();
179
+ }
180
+
181
+ ProcessPtr
182
+ Group::poolForceFreeCapacity(const Group *exclude,
183
+ boost::container::vector<Callback> &postLockActions)
184
+ {
185
+ return getPool()->forceFreeCapacity(exclude, postLockActions);
186
+ }
187
+
188
+ void
189
+ Group::wakeUpGarbageCollector() {
190
+ getPool()->garbageCollectionCond.notify_all();
191
+ }
192
+
193
+ bool
194
+ Group::anotherGroupIsWaitingForCapacity() const {
195
+ return findOtherGroupWaitingForCapacity() != NULL;
196
+ }
197
+
198
+ Group *
199
+ Group::findOtherGroupWaitingForCapacity() const {
200
+ Pool *pool = getPool();
201
+ if (pool->groups.size() == 1) {
202
+ return NULL;
203
+ }
204
+
205
+ GroupMap::ConstIterator g_it(pool->groups);
206
+ while (*g_it != NULL) {
207
+ const GroupPtr &group = g_it.getValue();
208
+ if (group.get() != this && group->isWaitingForCapacity()) {
209
+ return group.get();
210
+ }
211
+ g_it.next();
212
+ }
213
+ return NULL;
214
+ }
215
+
216
+ bool
217
+ Group::pushGetWaiter(const Options &newOptions, const GetCallback &callback,
218
+ boost::container::vector<Callback> &postLockActions)
219
+ {
220
+ if (OXT_LIKELY(!testOverflowRequestQueue()
221
+ && (newOptions.maxRequestQueueSize == 0
222
+ || getWaitlist.size() < newOptions.maxRequestQueueSize)))
223
+ {
224
+ getWaitlist.push_back(GetWaiter(
225
+ newOptions.copyAndPersist().detachFromUnionStationTransaction(),
226
+ callback));
227
+ return true;
228
+ } else {
229
+ postLockActions.push_back(boost::bind(GetCallback::call,
230
+ callback, SessionPtr(), boost::make_shared<RequestQueueFullException>(newOptions.maxRequestQueueSize)));
231
+
232
+ HookScriptOptions hsOptions;
233
+ if (prepareHookScriptOptions(hsOptions, "queue_full_error")) {
234
+ // TODO <Feb 17, 2015] DK> should probably rate limit this, since we are already at heavy load
235
+ postLockActions.push_back(boost::bind(runHookScripts, hsOptions));
236
+ }
237
+
238
+ return false;
239
+ }
240
+ }
241
+
242
+ template<typename Lock>
243
+ void
244
+ Group::assignSessionsToGetWaitersQuickly(Lock &lock) {
245
+ if (getWaitlist.empty()) {
246
+ verifyInvariants();
247
+ lock.unlock();
248
+ return;
249
+ }
250
+
251
+ SmallVector<GetAction, 8> actions;
252
+ unsigned int i = 0;
253
+ bool done = false;
254
+
255
+ actions.reserve(getWaitlist.size());
256
+
257
+ while (!done && i < getWaitlist.size()) {
258
+ const GetWaiter &waiter = getWaitlist[i];
259
+ RouteResult result = route(waiter.options);
260
+ if (result.process != NULL) {
261
+ GetAction action;
262
+ action.callback = waiter.callback;
263
+ action.session = newSession(result.process);
264
+ getWaitlist.erase(getWaitlist.begin() + i);
265
+ actions.push_back(action);
266
+ } else {
267
+ done = result.finished;
268
+ if (!result.finished) {
269
+ i++;
270
+ }
271
+ }
272
+ }
273
+
274
+ verifyInvariants();
275
+ lock.unlock();
276
+ SmallVector<GetAction, 50>::const_iterator it, end = actions.end();
277
+ for (it = actions.begin(); it != end; it++) {
278
+ it->callback(it->session, ExceptionPtr());
279
+ }
280
+ }
281
+
282
+ void
283
+ Group::assignSessionsToGetWaiters(boost::container::vector<Callback> &postLockActions) {
284
+ unsigned int i = 0;
285
+ bool done = false;
286
+
287
+ while (!done && i < getWaitlist.size()) {
288
+ const GetWaiter &waiter = getWaitlist[i];
289
+ RouteResult result = route(waiter.options);
290
+ if (result.process != NULL) {
291
+ postLockActions.push_back(boost::bind(
292
+ GetCallback::call,
293
+ waiter.callback,
294
+ newSession(result.process),
295
+ ExceptionPtr()));
296
+ getWaitlist.erase(getWaitlist.begin() + i);
297
+ } else {
298
+ done = result.finished;
299
+ if (!result.finished) {
300
+ i++;
301
+ }
302
+ }
303
+ }
304
+ }
305
+
306
+ bool
307
+ Group::testOverflowRequestQueue() const {
308
+ // This has a performance penalty, although I'm not sure whether the penalty is
309
+ // any greater than a hash table lookup if I were to implement it in Options.
310
+ Pool::DebugSupportPtr debug = getPool()->debugSupport;
311
+ if (debug) {
312
+ return debug->testOverflowRequestQueue;
313
+ } else {
314
+ return false;
315
+ }
316
+ }
317
+
318
+ void
319
+ Group::callAbortLongRunningConnectionsCallback(const ProcessPtr &process) {
320
+ Pool::AbortLongRunningConnectionsCallback callback =
321
+ getPool()->abortLongRunningConnectionsCallback;
322
+ if (callback != NULL) {
323
+ callback(process);
324
+ }
325
+ }
326
+
327
+
328
+ } // namespace ApplicationPool2
329
+ } // namespace Passenger