passenger 4.0.27 → 4.0.28
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.
- data.tar.gz.asc +7 -7
- data/.gitignore +1 -0
- data/NEWS +22 -0
- data/build/preprocessor.rb +10 -0
- data/build/rpm.rb +74 -65
- data/debian.template/rules.template +8 -0
- data/dev/copy_boost_headers.rb +11 -2
- data/doc/Users guide Apache.idmap.txt +161 -145
- data/doc/Users guide Apache.txt +12 -1
- data/doc/Users guide Nginx.idmap.txt +142 -126
- data/doc/Users guide Nginx.txt +14 -1
- data/doc/Users guide Standalone.txt +1 -0
- data/doc/users_guide_snippets/environment_variables.txt +1 -1
- data/doc/users_guide_snippets/installation.txt +2 -0
- data/doc/users_guide_snippets/tips.txt +118 -0
- data/ext/apache2/Configuration.cpp +0 -6
- data/ext/apache2/Configuration.hpp +0 -5
- data/ext/apache2/ConfigurationCommands.cpp +7 -0
- data/ext/apache2/ConfigurationFields.hpp +2 -0
- data/ext/apache2/ConfigurationSetters.cpp +24 -0
- data/ext/apache2/CreateDirConfig.cpp +1 -0
- data/ext/apache2/Hooks.cpp +0 -1
- data/ext/apache2/MergeDirConfig.cpp +7 -0
- data/ext/apache2/SetHeaders.cpp +5 -1
- data/ext/boost/cregex.hpp +39 -0
- data/ext/boost/libs/regex/src/c_regex_traits.cpp +193 -0
- data/ext/boost/libs/regex/src/cpp_regex_traits.cpp +117 -0
- data/ext/boost/libs/regex/src/cregex.cpp +660 -0
- data/ext/boost/libs/regex/src/instances.cpp +32 -0
- data/ext/boost/libs/regex/src/internals.hpp +35 -0
- data/ext/boost/libs/regex/src/posix_api.cpp +296 -0
- data/ext/boost/libs/regex/src/regex.cpp +227 -0
- data/ext/boost/libs/regex/src/regex_debug.cpp +59 -0
- data/ext/boost/libs/regex/src/regex_raw_buffer.cpp +72 -0
- data/ext/boost/libs/regex/src/regex_traits_defaults.cpp +692 -0
- data/ext/boost/libs/regex/src/static_mutex.cpp +179 -0
- data/ext/boost/libs/regex/src/wc_regex_traits.cpp +301 -0
- data/ext/boost/libs/regex/src/wide_posix_api.cpp +315 -0
- data/ext/boost/libs/regex/src/winstances.cpp +35 -0
- data/ext/boost/regex.h +100 -0
- data/ext/boost/regex.hpp +37 -0
- data/ext/boost/regex/concepts.hpp +1128 -0
- data/ext/boost/regex/config.hpp +435 -0
- data/ext/boost/regex/config/borland.hpp +72 -0
- data/ext/boost/regex/config/cwchar.hpp +207 -0
- data/ext/boost/regex/mfc.hpp +190 -0
- data/ext/boost/regex/pattern_except.hpp +100 -0
- data/ext/boost/regex/pending/object_cache.hpp +165 -0
- data/ext/boost/regex/pending/static_mutex.hpp +179 -0
- data/ext/boost/regex/pending/unicode_iterator.hpp +776 -0
- data/ext/boost/regex/regex_traits.hpp +35 -0
- data/ext/boost/regex/user.hpp +93 -0
- data/ext/boost/regex/v4/basic_regex.hpp +782 -0
- data/ext/boost/regex/v4/basic_regex_creator.hpp +1571 -0
- data/ext/boost/regex/v4/basic_regex_parser.hpp +2874 -0
- data/ext/boost/regex/v4/c_regex_traits.hpp +211 -0
- data/ext/boost/regex/v4/char_regex_traits.hpp +81 -0
- data/ext/boost/regex/v4/cpp_regex_traits.hpp +1099 -0
- data/ext/boost/regex/v4/cregex.hpp +330 -0
- data/ext/boost/regex/v4/error_type.hpp +59 -0
- data/ext/boost/regex/v4/fileiter.hpp +455 -0
- data/ext/boost/regex/v4/instances.hpp +222 -0
- data/ext/boost/regex/v4/iterator_category.hpp +91 -0
- data/ext/boost/regex/v4/iterator_traits.hpp +135 -0
- data/ext/boost/regex/v4/match_flags.hpp +138 -0
- data/ext/boost/regex/v4/match_results.hpp +702 -0
- data/ext/boost/regex/v4/mem_block_cache.hpp +99 -0
- data/ext/boost/regex/v4/perl_matcher.hpp +587 -0
- data/ext/boost/regex/v4/perl_matcher_common.hpp +996 -0
- data/ext/boost/regex/v4/perl_matcher_non_recursive.hpp +1642 -0
- data/ext/boost/regex/v4/perl_matcher_recursive.hpp +991 -0
- data/ext/boost/regex/v4/primary_transform.hpp +146 -0
- data/ext/boost/regex/v4/protected_call.hpp +81 -0
- data/ext/boost/regex/v4/regbase.hpp +180 -0
- data/ext/boost/regex/v4/regex.hpp +202 -0
- data/ext/boost/regex/v4/regex_format.hpp +1156 -0
- data/ext/boost/regex/v4/regex_fwd.hpp +73 -0
- data/ext/boost/regex/v4/regex_grep.hpp +155 -0
- data/ext/boost/regex/v4/regex_iterator.hpp +201 -0
- data/ext/boost/regex/v4/regex_match.hpp +382 -0
- data/ext/boost/regex/v4/regex_merge.hpp +93 -0
- data/ext/boost/regex/v4/regex_raw_buffer.hpp +210 -0
- data/ext/boost/regex/v4/regex_replace.hpp +99 -0
- data/ext/boost/regex/v4/regex_search.hpp +217 -0
- data/ext/boost/regex/v4/regex_split.hpp +172 -0
- data/ext/boost/regex/v4/regex_token_iterator.hpp +342 -0
- data/ext/boost/regex/v4/regex_traits.hpp +189 -0
- data/ext/boost/regex/v4/regex_traits_defaults.hpp +371 -0
- data/ext/boost/regex/v4/regex_workaround.hpp +232 -0
- data/ext/boost/regex/v4/states.hpp +301 -0
- data/ext/boost/regex/v4/sub_match.hpp +512 -0
- data/ext/boost/regex/v4/syntax_type.hpp +105 -0
- data/ext/boost/regex/v4/u32regex_iterator.hpp +193 -0
- data/ext/boost/regex/v4/u32regex_token_iterator.hpp +377 -0
- data/ext/boost/regex/v4/w32_regex_traits.hpp +741 -0
- data/ext/boost/regex_fwd.hpp +33 -0
- data/ext/common/AgentsStarter.h +0 -11
- data/ext/common/ApplicationPool2/Common.h +1 -7
- data/ext/common/ApplicationPool2/DirectSpawner.h +3 -3
- data/ext/common/ApplicationPool2/Group.h +166 -69
- data/ext/common/ApplicationPool2/Implementation.cpp +55 -10
- data/ext/common/ApplicationPool2/Options.h +45 -10
- data/ext/common/ApplicationPool2/PipeWatcher.h +1 -2
- data/ext/common/ApplicationPool2/Pool.h +29 -7
- data/ext/common/ApplicationPool2/Process.h +22 -3
- data/ext/common/ApplicationPool2/Session.h +1 -0
- data/ext/common/ApplicationPool2/SmartSpawner.h +5 -10
- data/ext/common/ApplicationPool2/Spawner.h +10 -15
- data/ext/common/ApplicationPool2/SuperGroup.h +10 -9
- data/ext/common/Constants.h +1 -3
- data/ext/common/Hooks.h +193 -0
- data/ext/common/Logging.cpp +67 -2
- data/ext/common/Logging.h +23 -1
- data/ext/common/Utils.cpp +0 -21
- data/ext/common/Utils.h +0 -42
- data/ext/common/Utils/CachedFileStat.hpp +1 -1
- data/ext/common/Utils/StrIntUtils.h +61 -14
- data/ext/common/Utils/StringMap.h +4 -0
- data/ext/common/agents/HelperAgent/AgentOptions.h +4 -4
- data/ext/common/agents/HelperAgent/Main.cpp +2 -3
- data/ext/common/agents/HelperAgent/RequestHandler.h +65 -2
- data/ext/common/agents/LoggingAgent/FilterSupport.h +3 -1
- data/ext/common/agents/Watchdog/Main.cpp +8 -72
- data/ext/nginx/CacheLocationConfig.c +29 -1
- data/ext/nginx/Configuration.c +0 -12
- data/ext/nginx/Configuration.h +0 -1
- data/ext/nginx/ConfigurationCommands.c +10 -0
- data/ext/nginx/ConfigurationFields.h +2 -0
- data/ext/nginx/CreateLocationConfig.c +4 -0
- data/ext/nginx/MergeLocationConfig.c +6 -0
- data/ext/oxt/system_calls.cpp +7 -1
- data/ext/oxt/system_calls.hpp +7 -7
- data/helper-scripts/node-loader.js +6 -2
- data/helper-scripts/rack-loader.rb +5 -2
- data/helper-scripts/rack-preloader.rb +5 -2
- data/lib/phusion_passenger.rb +1 -1
- data/lib/phusion_passenger/apache2/config_options.rb +8 -0
- data/lib/phusion_passenger/constants.rb +0 -1
- data/lib/phusion_passenger/nginx/config_options.rb +9 -2
- data/lib/phusion_passenger/platform_info/apache.rb +2 -1
- data/lib/phusion_passenger/platform_info/compiler.rb +15 -1
- data/lib/phusion_passenger/platform_info/cxx_portability.rb +2 -0
- data/node_lib/phusion_passenger/httplib_emulation.js +85 -17
- data/node_lib/phusion_passenger/request_handler.js +10 -2
- data/rpm/Vagrantfile +32 -0
- data/rpm/get_distro_id.py +4 -0
- data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +2 -2
- data/test/cxx/ApplicationPool2/PoolTest.cpp +60 -9
- data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +2 -6
- data/test/cxx/CachedFileStatTest.cpp +5 -5
- data/test/cxx/RequestHandlerTest.cpp +3 -6
- data/test/cxx/UtilsTest.cpp +30 -0
- data/test/node/httplib_emulation_spec.js +491 -0
- data/test/node/spec_helper.js +25 -0
- metadata +78 -2
- metadata.gz.asc +7 -7
@@ -0,0 +1,33 @@
|
|
1
|
+
/*
|
2
|
+
*
|
3
|
+
* Copyright (c) 1998-2002
|
4
|
+
* John Maddock
|
5
|
+
*
|
6
|
+
* Use, modification and distribution are subject to the
|
7
|
+
* Boost Software License, Version 1.0. (See accompanying file
|
8
|
+
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
9
|
+
*
|
10
|
+
*/
|
11
|
+
|
12
|
+
/*
|
13
|
+
* LOCATION: see http://www.boost.org/libs/regex for documentation.
|
14
|
+
* FILE regex_fwd.cpp
|
15
|
+
* VERSION see <boost/version.hpp>
|
16
|
+
* DESCRIPTION: Forward declares boost::basic_regex<> and
|
17
|
+
* associated typedefs.
|
18
|
+
*/
|
19
|
+
|
20
|
+
#ifndef BOOST_REGEX_FWD_HPP
|
21
|
+
#define BOOST_REGEX_FWD_HPP
|
22
|
+
|
23
|
+
#ifndef BOOST_REGEX_CONFIG_HPP
|
24
|
+
#include <boost/regex/config.hpp>
|
25
|
+
#endif
|
26
|
+
|
27
|
+
#include <boost/regex/v4/regex_fwd.hpp>
|
28
|
+
|
29
|
+
#endif
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
|
data/ext/common/AgentsStarter.h
CHANGED
@@ -395,17 +395,6 @@ public:
|
|
395
395
|
.set ("temp_dir", getSystemTempDir());
|
396
396
|
extraParams.addTo(params);
|
397
397
|
|
398
|
-
// .setUid ("web_server_worker_uid", webServerWorkerUid)
|
399
|
-
// .setGid ("web_server_worker_gid", webServerWorkerGid)
|
400
|
-
// .set ("debug_log_file", debugLogFile)
|
401
|
-
// .set ("temp_dir", tempDir.empty() ? getSystemTempDir() : tempDir)
|
402
|
-
// .setBool("user_switching", userSwitching)
|
403
|
-
// .set ("default_user", defaultUser)
|
404
|
-
// .set ("default_group", defaultGroup)
|
405
|
-
// .set ("default_ruby", defaultRubyCommand)
|
406
|
-
// .setInt ("max_pool_size", maxPoolSize)
|
407
|
-
// .setInt ("max_instances_per_app", maxInstancesPerApp)
|
408
|
-
|
409
398
|
fds = createUnixSocketPair();
|
410
399
|
pid = syscalls::fork();
|
411
400
|
if (pid == 0) {
|
@@ -111,10 +111,6 @@ struct Ticket {
|
|
111
111
|
|
112
112
|
struct SpawnerConfig {
|
113
113
|
// Used by SmartSpawner and DirectSpawner.
|
114
|
-
/** Whether to print the preloader's and application's stdout. */
|
115
|
-
bool forwardStdout;
|
116
|
-
/** Whether to print the preloader's and application's stderr. */
|
117
|
-
bool forwardStderr;
|
118
114
|
/** A random generator to use. */
|
119
115
|
RandomGeneratorPtr randomGenerator;
|
120
116
|
|
@@ -124,9 +120,7 @@ struct SpawnerConfig {
|
|
124
120
|
unsigned int spawnTime;
|
125
121
|
|
126
122
|
SpawnerConfig(const RandomGeneratorPtr &randomGenerator = RandomGeneratorPtr())
|
127
|
-
:
|
128
|
-
forwardStderr(true),
|
129
|
-
concurrency(1),
|
123
|
+
: concurrency(1),
|
130
124
|
spawnerCreationSleepTime(0),
|
131
125
|
spawnTime(0)
|
132
126
|
{
|
@@ -222,15 +222,15 @@ public:
|
|
222
222
|
details.stderrCapturer =
|
223
223
|
make_shared<BackgroundIOCapturer>(
|
224
224
|
errorPipe.first,
|
225
|
-
|
226
|
-
|
225
|
+
pid,
|
226
|
+
// The cast works around a compilation problem in Clang.
|
227
|
+
(const char *) "stderr");
|
227
228
|
details.stderrCapturer->start();
|
228
229
|
details.pid = pid;
|
229
230
|
details.adminSocket = adminSocket.second;
|
230
231
|
details.io = BufferedIO(adminSocket.second);
|
231
232
|
details.errorPipe = errorPipe.first;
|
232
233
|
details.options = &options;
|
233
|
-
details.forwardStderr = config->forwardStderr;
|
234
234
|
details.debugDir = debugDir;
|
235
235
|
|
236
236
|
ProcessPtr process;
|
@@ -37,12 +37,14 @@
|
|
37
37
|
#include <oxt/macros.hpp>
|
38
38
|
#include <oxt/thread.hpp>
|
39
39
|
#include <oxt/dynamic_thread_group.hpp>
|
40
|
+
#include <cstdlib>
|
40
41
|
#include <cassert>
|
41
42
|
#include <ApplicationPool2/Common.h>
|
42
43
|
#include <ApplicationPool2/ComponentInfo.h>
|
43
44
|
#include <ApplicationPool2/SpawnerFactory.h>
|
44
45
|
#include <ApplicationPool2/Process.h>
|
45
46
|
#include <ApplicationPool2/Options.h>
|
47
|
+
#include <Hooks.h>
|
46
48
|
#include <Utils.h>
|
47
49
|
#include <Utils/CachedFileStat.hpp>
|
48
50
|
#include <Utils/FileChangeChecker.h>
|
@@ -79,6 +81,16 @@ private:
|
|
79
81
|
callback(_callback)
|
80
82
|
{ }
|
81
83
|
};
|
84
|
+
|
85
|
+
struct RouteResult {
|
86
|
+
Process *process;
|
87
|
+
bool finished;
|
88
|
+
|
89
|
+
RouteResult(Process *p, bool _finished = false)
|
90
|
+
: process(p),
|
91
|
+
finished(_finished)
|
92
|
+
{ }
|
93
|
+
};
|
82
94
|
|
83
95
|
/**
|
84
96
|
* Protects `m_shuttingDown`.
|
@@ -194,6 +206,9 @@ private:
|
|
194
206
|
bool anotherGroupIsWaitingForCapacity() const;
|
195
207
|
bool testOverflowRequestQueue() const;
|
196
208
|
const ResourceLocator &getResourceLocator() const;
|
209
|
+
void runAttachHooks(const ProcessPtr process) const;
|
210
|
+
void runDetachHooks(const ProcessPtr process) const;
|
211
|
+
void setupAttachOrDetachHook(const ProcessPtr process, HookScriptOptions &options) const;
|
197
212
|
|
198
213
|
void verifyInvariants() const {
|
199
214
|
// !a || b: logical equivalent of a IMPLIES b.
|
@@ -208,8 +223,7 @@ private:
|
|
208
223
|
assert((lifeStatus == ALIVE) == (spawner != NULL));
|
209
224
|
|
210
225
|
// Verify getWaitlist invariants.
|
211
|
-
assert(!( !getWaitlist.empty() ) || ( enabledProcesses.empty() ||
|
212
|
-
assert(!( !enabledProcesses.empty() && !pqueue.top()->atFullUtilization() ) || ( getWaitlist.empty() ));
|
226
|
+
assert(!( !getWaitlist.empty() ) || ( enabledProcesses.empty() || verifyNoRequestsOnGetWaitlistAreRoutable() ));
|
213
227
|
assert(!( enabledProcesses.empty() && !spawning() && !restarting() && !poolAtFullCapacity() ) || ( getWaitlist.empty() ));
|
214
228
|
assert(!( !getWaitlist.empty() ) || ( !enabledProcesses.empty() || spawning() || restarting() || poolAtFullCapacity() ));
|
215
229
|
|
@@ -272,6 +286,19 @@ private:
|
|
272
286
|
}
|
273
287
|
#endif
|
274
288
|
}
|
289
|
+
|
290
|
+
#ifndef NDEBUG
|
291
|
+
bool verifyNoRequestsOnGetWaitlistAreRoutable() const {
|
292
|
+
deque<GetWaiter>::const_iterator it, end = getWaitlist.end();
|
293
|
+
|
294
|
+
for (it = getWaitlist.begin(); it != end; it++) {
|
295
|
+
if (route(it->options).process != NULL) {
|
296
|
+
return false;
|
297
|
+
}
|
298
|
+
}
|
299
|
+
return true;
|
300
|
+
}
|
301
|
+
#endif
|
275
302
|
|
276
303
|
/**
|
277
304
|
* Sets options for this Group. Called at creation time and at restart time.
|
@@ -303,18 +330,71 @@ private:
|
|
303
330
|
static void doCleanupSpawner(SpawnerPtr spawner) {
|
304
331
|
spawner->cleanup();
|
305
332
|
}
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
333
|
+
|
334
|
+
unsigned int generateStickySessionId() {
|
335
|
+
unsigned int result;
|
336
|
+
|
337
|
+
while (true) {
|
338
|
+
result = (unsigned int) rand();
|
339
|
+
if (findProcessWithStickySessionId(result) == NULL) {
|
340
|
+
return result;
|
341
|
+
}
|
311
342
|
}
|
343
|
+
// Never reached; shut up compiler warning.
|
344
|
+
return 0;
|
345
|
+
}
|
346
|
+
|
347
|
+
/* Determines which process to route a get() action to. The returned process
|
348
|
+
* is guaranteed to be `canBeRoutedTo()`, i.e. not at full utilization.
|
349
|
+
*
|
350
|
+
* A request is routed to an enabled processes, or if there are none,
|
351
|
+
* from a disabling process. The rationale is as follows:
|
352
|
+
* If there are no enabled process, then waiting for one to spawn is too
|
353
|
+
* expensive. The next best thing is to route to disabling processes
|
354
|
+
* until more processes have been spawned.
|
355
|
+
*/
|
356
|
+
RouteResult route(const Options &options) const {
|
357
|
+
if (OXT_LIKELY(enabledCount > 0)) {
|
358
|
+
if (options.stickySessionId == 0) {
|
359
|
+
if (pqueue.top()->canBeRoutedTo()) {
|
360
|
+
return RouteResult(pqueue.top());
|
361
|
+
} else {
|
362
|
+
return RouteResult(NULL, true);
|
363
|
+
}
|
364
|
+
} else {
|
365
|
+
Process *process = findProcessWithStickySessionId(options.stickySessionId);
|
366
|
+
if (process != NULL) {
|
367
|
+
if (process->canBeRoutedTo()) {
|
368
|
+
return RouteResult(process);
|
369
|
+
} else {
|
370
|
+
return RouteResult(NULL, false);
|
371
|
+
}
|
372
|
+
} else if (pqueue.top()->canBeRoutedTo()) {
|
373
|
+
return RouteResult(pqueue.top());
|
374
|
+
} else {
|
375
|
+
return RouteResult(NULL, true);
|
376
|
+
}
|
377
|
+
}
|
378
|
+
} else {
|
379
|
+
Process *process = findProcessWithLowestUtilization(disablingProcesses);
|
380
|
+
if (process->canBeRoutedTo()) {
|
381
|
+
return RouteResult(process);
|
382
|
+
} else {
|
383
|
+
return RouteResult(NULL, true);
|
384
|
+
}
|
385
|
+
}
|
386
|
+
}
|
387
|
+
|
388
|
+
SessionPtr newSession(Process *process) {
|
312
389
|
SessionPtr session = process->newSession();
|
313
390
|
session->onInitiateFailure = _onSessionInitiateFailure;
|
314
391
|
session->onClose = _onSessionClose;
|
315
392
|
if (process->enabled == Process::ENABLED) {
|
316
|
-
|
317
|
-
|
393
|
+
if (process == pqueue.top()) {
|
394
|
+
pqueue.pop();
|
395
|
+
} else {
|
396
|
+
pqueue.erase(process->pqHandle);
|
397
|
+
}
|
318
398
|
process->pqHandle = pqueue.push(process, process->utilization());
|
319
399
|
}
|
320
400
|
return session;
|
@@ -325,7 +405,7 @@ private:
|
|
325
405
|
&& (newOptions.maxRequestQueueSize == 0
|
326
406
|
|| getWaitlist.size() < newOptions.maxRequestQueueSize)))
|
327
407
|
{
|
328
|
-
getWaitlist.
|
408
|
+
getWaitlist.push_back(GetWaiter(newOptions.copyAndPersist().clearLogger(), callback));
|
329
409
|
return true;
|
330
410
|
} else {
|
331
411
|
P_WARN("Request queue is full. Returning an error");
|
@@ -334,6 +414,17 @@ private:
|
|
334
414
|
}
|
335
415
|
}
|
336
416
|
|
417
|
+
Process *findProcessWithStickySessionId(unsigned int id) const {
|
418
|
+
ProcessList::const_iterator it, end = enabledProcesses.end();
|
419
|
+
for (it = enabledProcesses.begin(); it != end; it++) {
|
420
|
+
Process *process = it->get();
|
421
|
+
if (process->stickySessionId == id) {
|
422
|
+
return process;
|
423
|
+
}
|
424
|
+
}
|
425
|
+
return NULL;
|
426
|
+
}
|
427
|
+
|
337
428
|
Process *findProcessWithLowestUtilization(const ProcessList &processes) const {
|
338
429
|
Process *result = NULL;
|
339
430
|
ProcessList::const_iterator it, end = processes.end();
|
@@ -403,40 +494,38 @@ private:
|
|
403
494
|
P_BUG("Unknown destination list");
|
404
495
|
}
|
405
496
|
}
|
406
|
-
|
497
|
+
|
407
498
|
template<typename Lock>
|
408
499
|
void assignSessionsToGetWaitersQuickly(Lock &lock) {
|
500
|
+
if (getWaitlist.empty()) {
|
501
|
+
verifyInvariants();
|
502
|
+
lock.unlock();
|
503
|
+
return;
|
504
|
+
}
|
505
|
+
|
409
506
|
SmallVector<GetAction, 50> actions;
|
507
|
+
unsigned int i = 0;
|
508
|
+
bool done = false;
|
509
|
+
|
410
510
|
actions.reserve(getWaitlist.size());
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
511
|
+
|
512
|
+
while (!done && i < getWaitlist.size()) {
|
513
|
+
const GetWaiter &waiter = getWaitlist[i];
|
514
|
+
RouteResult result = route(waiter.options);
|
515
|
+
if (result.process != NULL) {
|
416
516
|
GetAction action;
|
417
|
-
action.callback =
|
418
|
-
action.session = newSession();
|
419
|
-
getWaitlist.
|
517
|
+
action.callback = waiter.callback;
|
518
|
+
action.session = newSession(result.process);
|
519
|
+
getWaitlist.erase(getWaitlist.begin() + i);
|
420
520
|
actions.push_back(action);
|
421
|
-
}
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
Process *process = findProcessWithLowestUtilization(
|
426
|
-
disablingProcesses);
|
427
|
-
assert(process != NULL);
|
428
|
-
if (process->atFullUtilization()) {
|
429
|
-
done = true;
|
430
|
-
} else {
|
431
|
-
GetAction action;
|
432
|
-
action.callback = getWaitlist.front().callback;
|
433
|
-
action.session = newSession(process);
|
434
|
-
getWaitlist.pop();
|
435
|
-
actions.push_back(action);
|
521
|
+
} else {
|
522
|
+
done = result.finished;
|
523
|
+
if (!result.finished) {
|
524
|
+
i++;
|
436
525
|
}
|
437
526
|
}
|
438
527
|
}
|
439
|
-
|
528
|
+
|
440
529
|
verifyInvariants();
|
441
530
|
lock.unlock();
|
442
531
|
SmallVector<GetAction, 50>::const_iterator it, end = actions.end();
|
@@ -446,26 +535,22 @@ private:
|
|
446
535
|
}
|
447
536
|
|
448
537
|
void assignSessionsToGetWaiters(vector<Callback> &postLockActions) {
|
449
|
-
|
450
|
-
|
538
|
+
unsigned int i = 0;
|
539
|
+
bool done = false;
|
540
|
+
|
541
|
+
while (!done && i < getWaitlist.size()) {
|
542
|
+
const GetWaiter &waiter = getWaitlist[i];
|
543
|
+
RouteResult result = route(waiter.options);
|
544
|
+
if (result.process != NULL) {
|
451
545
|
postLockActions.push_back(boost::bind(
|
452
|
-
|
546
|
+
waiter.callback,
|
547
|
+
newSession(result.process),
|
453
548
|
ExceptionPtr()));
|
454
|
-
getWaitlist.
|
455
|
-
}
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
Process *process = findProcessWithLowestUtilization(
|
460
|
-
disablingProcesses);
|
461
|
-
assert(process != NULL);
|
462
|
-
if (process->atFullUtilization()) {
|
463
|
-
done = true;
|
464
|
-
} else {
|
465
|
-
postLockActions.push_back(boost::bind(
|
466
|
-
getWaitlist.front().callback, newSession(process),
|
467
|
-
ExceptionPtr()));
|
468
|
-
getWaitlist.pop();
|
549
|
+
getWaitlist.erase(getWaitlist.begin() + i);
|
550
|
+
} else {
|
551
|
+
done = result.finished;
|
552
|
+
if (!result.finished) {
|
553
|
+
i++;
|
469
554
|
}
|
470
555
|
}
|
471
556
|
}
|
@@ -641,25 +726,33 @@ public:
|
|
641
726
|
* put on this wait list, which must be processed as soon as the necessary
|
642
727
|
* resources have become free.
|
643
728
|
*
|
644
|
-
*
|
645
|
-
*
|
646
|
-
*
|
647
|
-
*
|
648
|
-
*
|
729
|
+
* ### Invariant 1 (safety)
|
730
|
+
*
|
731
|
+
* If requests are queued in the getWaitlist, then that's because there are
|
732
|
+
* no processes that can serve them.
|
733
|
+
*
|
649
734
|
* if getWaitlist is non-empty:
|
650
|
-
* enabledProcesses.empty() || (
|
651
|
-
*
|
652
|
-
*
|
653
|
-
*
|
735
|
+
* enabledProcesses.empty() || (no request in getWaitlist is routeable)
|
736
|
+
*
|
737
|
+
* Here, "routeable" is defined as `route(options).process != NULL`.
|
738
|
+
*
|
739
|
+
* ### Invariant 2 (progress)
|
654
740
|
*
|
655
|
-
*
|
741
|
+
* The only reason why there are no enabled processes, while at the same time we're
|
742
|
+
* not spawning or waiting for pool capacity, is because there is nothing to do.
|
743
|
+
*
|
656
744
|
* if enabledProcesses.empty() && !spawning() && !restarting() && !poolAtFullCapacity():
|
657
745
|
* getWaitlist is empty
|
746
|
+
*
|
658
747
|
* Equivalently:
|
748
|
+
* If requests are queued in the getWaitlist, then either we have processes that can process
|
749
|
+
* them (some time in the future), or we're actively trying to spawn processes, unless we're
|
750
|
+
* unable to do that because of resource limits.
|
751
|
+
*
|
659
752
|
* if getWaitlist is non-empty:
|
660
753
|
* !enabledProcesses.empty() || spawning() || restarting() || poolAtFullCapacity()
|
661
754
|
*/
|
662
|
-
|
755
|
+
deque<GetWaiter> getWaitlist;
|
663
756
|
/**
|
664
757
|
* Disable() commands that couldn't finish immediately will put their callbacks
|
665
758
|
* in this queue. Note that there may be multiple DisableWaiters pointing to the
|
@@ -760,9 +853,8 @@ public:
|
|
760
853
|
}
|
761
854
|
return SessionPtr();
|
762
855
|
} else {
|
763
|
-
|
764
|
-
|
765
|
-
if (process->atFullUtilization()) {
|
856
|
+
RouteResult result = route(newOptions);
|
857
|
+
if (result.process == NULL) {
|
766
858
|
/* Looks like all processes are at full utilization.
|
767
859
|
* Wait until a new one has been spawned or until
|
768
860
|
* resources have become free.
|
@@ -772,8 +864,8 @@ public:
|
|
772
864
|
}
|
773
865
|
return SessionPtr();
|
774
866
|
} else {
|
775
|
-
P_DEBUG("Session checked out from process " << process->inspect());
|
776
|
-
return newSession();
|
867
|
+
P_DEBUG("Session checked out from process " << result.process->inspect());
|
868
|
+
return newSession(result.process);
|
777
869
|
}
|
778
870
|
}
|
779
871
|
}
|
@@ -825,6 +917,7 @@ public:
|
|
825
917
|
assert(isAlive());
|
826
918
|
|
827
919
|
process->setGroup(shared_from_this());
|
920
|
+
process->stickySessionId = generateStickySessionId();
|
828
921
|
P_DEBUG("Attaching process " << process->inspect());
|
829
922
|
addProcessToList(process, enabledProcesses);
|
830
923
|
|
@@ -858,6 +951,8 @@ public:
|
|
858
951
|
|
859
952
|
// Update GC sleep timer.
|
860
953
|
wakeUpGarbageCollector();
|
954
|
+
|
955
|
+
postLockActions.push_back(boost::bind(&Group::runAttachHooks, this, process));
|
861
956
|
}
|
862
957
|
|
863
958
|
/**
|
@@ -889,6 +984,8 @@ public:
|
|
889
984
|
|
890
985
|
addProcessToList(process, detachedProcesses);
|
891
986
|
startCheckingDetachedProcesses(false);
|
987
|
+
|
988
|
+
postLockActions.push_back(boost::bind(&Group::runDetachHooks, this, process));
|
892
989
|
}
|
893
990
|
|
894
991
|
/**
|