passenger 5.0.25 → 5.0.26
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of passenger might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG +20 -0
- data/CONTRIBUTORS +1 -0
- data/build/cxx_dependency_map.rb +7338 -7104
- data/build/cxx_tests.rb +3 -3
- data/build/misc.rb +1 -0
- data/dev/index_cxx_dependencies.rb +3 -2
- data/resources/templates/standalone/config.erb +1 -1
- data/resources/templates/standalone/http.erb +1 -0
- data/resources/templates/standalone/server.erb +1 -0
- data/src/agent/Core/ApplicationPool/AbstractSession.h +83 -0
- data/src/agent/Core/ApplicationPool/Common.h +6 -4
- data/src/agent/Core/ApplicationPool/Options.h +4 -1
- data/src/agent/Core/ApplicationPool/Pool.h +2 -2
- data/src/agent/Core/ApplicationPool/Pool/AnalyticsCollection.cpp +3 -6
- data/src/agent/Core/ApplicationPool/Pool/GeneralUtils.cpp +3 -3
- data/src/agent/Core/ApplicationPool/Session.h +15 -27
- data/src/agent/Core/ApplicationPool/TestSession.h +188 -0
- data/src/agent/Core/Controller.h +15 -6
- data/src/agent/Core/Controller/CheckoutSession.cpp +13 -5
- data/src/agent/Core/Controller/ForwardResponse.cpp +20 -2
- data/src/agent/Core/Controller/Hooks.cpp +15 -2
- data/src/agent/Core/Controller/InitRequest.cpp +5 -1
- data/src/agent/Core/Controller/InitializationAndShutdown.cpp +1 -0
- data/src/agent/Core/Controller/Request.h +11 -4
- data/src/agent/Core/Controller/SendRequest.cpp +34 -13
- data/src/agent/Core/Controller/StateInspectionAndConfiguration.cpp +2 -2
- data/src/agent/Core/CoreMain.cpp +27 -1
- data/src/agent/Core/OptionParser.h +11 -1
- data/src/agent/Core/SpawningKit/DirectSpawner.h +1 -0
- data/src/agent/Core/SpawningKit/SmartSpawner.h +1 -0
- data/src/agent/Core/SpawningKit/Spawner.h +21 -1
- data/src/agent/SpawnPreparer/SpawnPreparerMain.cpp +1 -1
- data/src/agent/UstRouter/OptionParser.h +7 -1
- data/src/agent/UstRouter/UstRouterMain.cpp +27 -1
- data/src/cxx_supportlib/Algorithms/MovingAverage.h +223 -0
- data/src/cxx_supportlib/Constants.h +2 -2
- data/src/cxx_supportlib/DataStructures/StringKeyTable.h +96 -40
- data/src/cxx_supportlib/ResourceLocator.h +33 -14
- data/src/cxx_supportlib/ServerKit/Channel.h +198 -69
- data/src/cxx_supportlib/ServerKit/Errors.h +6 -1
- data/src/cxx_supportlib/ServerKit/HttpRequest.h +20 -1
- data/src/cxx_supportlib/ServerKit/HttpServer.h +124 -32
- data/src/cxx_supportlib/ServerKit/Server.h +65 -1
- data/src/cxx_supportlib/Utils/IOUtils.cpp +12 -22
- data/src/cxx_supportlib/Utils/JsonUtils.h +87 -1
- data/src/cxx_supportlib/Utils/StrIntUtils.cpp +16 -1
- data/src/cxx_supportlib/Utils/StrIntUtils.h +31 -1
- data/src/cxx_supportlib/Utils/VariantMap.h +6 -1
- data/src/cxx_supportlib/WatchdogLauncher.h +17 -9
- data/src/cxx_supportlib/vendor-copy/libuv/AUTHORS +43 -0
- data/src/cxx_supportlib/vendor-copy/libuv/ChangeLog +350 -1
- data/src/cxx_supportlib/vendor-copy/libuv/Makefile.am +9 -1
- data/src/cxx_supportlib/vendor-copy/libuv/README.md +48 -0
- data/src/cxx_supportlib/vendor-copy/libuv/checksparse.sh +1 -0
- data/src/cxx_supportlib/vendor-copy/libuv/common.gypi +5 -5
- data/src/cxx_supportlib/vendor-copy/libuv/configure.ac +2 -1
- data/src/cxx_supportlib/vendor-copy/libuv/gyp_uv.py +0 -3
- data/src/cxx_supportlib/vendor-copy/libuv/include/uv-version.h +5 -1
- data/src/cxx_supportlib/vendor-copy/libuv/include/uv.h +30 -3
- data/src/cxx_supportlib/vendor-copy/libuv/src/fs-poll.c +3 -3
- data/src/cxx_supportlib/vendor-copy/libuv/src/inet.c +0 -4
- data/src/cxx_supportlib/vendor-copy/libuv/src/queue.h +17 -1
- data/src/cxx_supportlib/vendor-copy/libuv/src/threadpool.c +10 -10
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/aix.c +84 -166
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/android-ifaddrs.c +11 -11
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/async.c +7 -1
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/atomic-ops.h +17 -0
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/core.c +140 -21
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/darwin.c +15 -11
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/dl.c +4 -7
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/freebsd.c +52 -37
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/fs.c +181 -60
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/fsevents.c +39 -34
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/getaddrinfo.c +4 -4
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/internal.h +3 -1
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/kqueue.c +12 -4
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-core.c +38 -15
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-inotify.c +36 -8
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-syscalls.c +4 -4
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-syscalls.h +2 -2
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/loop-watcher.c +6 -1
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/loop.c +28 -8
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/netbsd.c +18 -16
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/openbsd.c +18 -16
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/pipe.c +3 -3
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/process.c +18 -6
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/proctitle.c +2 -2
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/pthread-fixes.c +1 -0
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/signal.c +2 -0
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/stream.c +47 -30
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/sunos.c +13 -11
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/tcp.c +43 -8
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/thread.c +21 -15
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/tty.c +16 -2
- data/src/cxx_supportlib/vendor-copy/libuv/src/unix/udp.c +54 -14
- data/src/cxx_supportlib/vendor-copy/libuv/src/uv-common.c +104 -21
- data/src/cxx_supportlib/vendor-copy/libuv/src/uv-common.h +14 -1
- data/src/cxx_supportlib/vendor-copy/libuv/src/version.c +1 -5
- data/src/cxx_supportlib/vendor-copy/libuv/uv.gyp +22 -1
- data/src/nginx_module/CacheLocationConfig.c +52 -0
- data/src/nginx_module/CacheLocationConfig.c.erb +13 -1
- data/src/nginx_module/Configuration.c +1 -0
- data/src/nginx_module/Configuration.h +1 -0
- data/src/nginx_module/ConfigurationCommands.c +20 -0
- data/src/nginx_module/ConfigurationFields.h +4 -0
- data/src/nginx_module/CreateLocationConfig.c +8 -0
- data/src/nginx_module/MergeLocationConfig.c +12 -0
- data/src/nginx_module/config +31 -13
- data/src/nginx_module/ngx_http_passenger_module.c +4 -0
- data/src/ruby_supportlib/phusion_passenger.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/constants.rb +1 -1
- data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +11 -1
- data/src/ruby_supportlib/phusion_passenger/platform_info/apache.rb +6 -1
- data/src/ruby_supportlib/phusion_passenger/rack/thread_handler_extension.rb +32 -31
- data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +13 -2
- data/src/ruby_supportlib/phusion_passenger/standalone/config_utils.rb +1 -0
- data/src/ruby_supportlib/phusion_passenger/standalone/start_command/builtin_engine.rb +6 -1
- data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core.rb +6 -0
- data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/api.rb +29 -19
- data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/context.rb +2 -2
- data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter.rb +2 -3
- data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/simple_json.rb +2 -1
- data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/spec_helper.rb +2 -0
- data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/time_point.rb +3 -17
- data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/transaction.rb +7 -10
- data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/utils.rb +11 -9
- metadata +5 -2
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2011-
|
3
|
+
* Copyright (c) 2011-2016 Phusion Holding B.V.
|
4
4
|
*
|
5
5
|
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
6
|
* trademarks of Phusion Holding B.V.
|
@@ -971,6 +971,26 @@ protected:
|
|
971
971
|
}
|
972
972
|
}
|
973
973
|
|
974
|
+
void setUlimits(const Options &options) {
|
975
|
+
if (options.fileDescriptorUlimit != 0) {
|
976
|
+
struct rlimit limit;
|
977
|
+
int ret;
|
978
|
+
|
979
|
+
limit.rlim_cur = options.fileDescriptorUlimit;
|
980
|
+
limit.rlim_max = options.fileDescriptorUlimit;
|
981
|
+
do {
|
982
|
+
ret = setrlimit(RLIMIT_NOFILE, &limit);
|
983
|
+
} while (ret == -1 && errno == EINTR);
|
984
|
+
|
985
|
+
if (ret == -1) {
|
986
|
+
int e = errno;
|
987
|
+
fprintf(stderr, "Unable to set file descriptor ulimit to %u: %s (errno=%d)",
|
988
|
+
options.fileDescriptorUlimit, strerror(e), e);
|
989
|
+
fflush(stderr);
|
990
|
+
}
|
991
|
+
}
|
992
|
+
}
|
993
|
+
|
974
994
|
void setWorkingDirectory(const SpawnPreparationInfo &info) {
|
975
995
|
vector<string>::const_iterator it, end = info.appRootPathsInsideChroot.end();
|
976
996
|
int ret;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2012-
|
3
|
+
* Copyright (c) 2012-2016 Phusion Holding B.V.
|
4
4
|
*
|
5
5
|
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
6
|
* trademarks of Phusion Holding B.V.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2010-
|
3
|
+
* Copyright (c) 2010-2016 Phusion Holding B.V.
|
4
4
|
*
|
5
5
|
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
6
|
* trademarks of Phusion Holding B.V.
|
@@ -80,6 +80,9 @@ ustRouterUsage() {
|
|
80
80
|
printf(" --log-file PATH Log to the given file.\n");
|
81
81
|
printf(" --log-level LEVEL Logging level. Default: %d\n", DEFAULT_LOG_LEVEL);
|
82
82
|
printf("\n");
|
83
|
+
printf(" --core-file-descriptor-ulimit NUMBER\n");
|
84
|
+
printf(" Set custom file descriptor ulimit for the core\n");
|
85
|
+
printf("\n");
|
83
86
|
printf(" -h, --help Show this help\n");
|
84
87
|
printf("\n");
|
85
88
|
printf("API account privilege levels (ordered from most to least privileges):\n");
|
@@ -162,6 +165,9 @@ parseUstRouterOption(int argc, const char *argv[], int &i, VariantMap &options)
|
|
162
165
|
// the Watchdog, we don't want to affect the Watchdog's own log file.
|
163
166
|
options.set("ust_router_log_file", argv[i + 1]);
|
164
167
|
i += 2;
|
168
|
+
} else if (p.isValueFlag(argc, i, argv[i], '\0', "--core-file-descriptor-ulimit")) {
|
169
|
+
options.setUint("core_file_descriptor_ulimit", atoi(argv[i + 1]));
|
170
|
+
i += 2;
|
165
171
|
} else {
|
166
172
|
return false;
|
167
173
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
-
* Copyright (c) 2010-
|
3
|
+
* Copyright (c) 2010-2016 Phusion Holding B.V.
|
4
4
|
*
|
5
5
|
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
6
|
* trademarks of Phusion Holding B.V.
|
@@ -31,6 +31,7 @@
|
|
31
31
|
#include <oxt/thread.hpp>
|
32
32
|
|
33
33
|
#include <sys/types.h>
|
34
|
+
#include <sys/resource.h>
|
34
35
|
#include <unistd.h>
|
35
36
|
#include <pwd.h>
|
36
37
|
#include <grp.h>
|
@@ -188,6 +189,30 @@ initializePrivilegedWorkingObjects() {
|
|
188
189
|
wo->resourceLocator = new ResourceLocator(options.get("passenger_root"));
|
189
190
|
}
|
190
191
|
|
192
|
+
static void
|
193
|
+
setUlimits() {
|
194
|
+
TRACE_POINT();
|
195
|
+
VariantMap &options = *agentsOptions;
|
196
|
+
|
197
|
+
if (options.has("core_file_descriptor_ulimit")) {
|
198
|
+
unsigned int number = options.getUint("core_file_descriptor_ulimit");
|
199
|
+
struct rlimit limit;
|
200
|
+
int ret;
|
201
|
+
|
202
|
+
limit.rlim_cur = number;
|
203
|
+
limit.rlim_max = number;
|
204
|
+
do {
|
205
|
+
ret = setrlimit(RLIMIT_NOFILE, &limit);
|
206
|
+
} while (ret == -1 && errno == EINTR);
|
207
|
+
|
208
|
+
if (ret == -1) {
|
209
|
+
int e = errno;
|
210
|
+
P_ERROR("Unable to set file descriptor ulimit to " << number
|
211
|
+
<< ": " << strerror(e) << " (errno=" << e << ")");
|
212
|
+
}
|
213
|
+
}
|
214
|
+
}
|
215
|
+
|
191
216
|
static void
|
192
217
|
startListening() {
|
193
218
|
TRACE_POINT();
|
@@ -506,6 +531,7 @@ runUstRouter() {
|
|
506
531
|
try {
|
507
532
|
UPDATE_TRACE_POINT();
|
508
533
|
initializePrivilegedWorkingObjects();
|
534
|
+
setUlimits();
|
509
535
|
startListening();
|
510
536
|
lowerPrivilege();
|
511
537
|
initializeUnprivilegedWorkingObjects();
|
@@ -0,0 +1,223 @@
|
|
1
|
+
/*
|
2
|
+
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
+
* Copyright (c) 2016 Phusion Holding B.V.
|
4
|
+
*
|
5
|
+
* "Passenger", "Phusion Passenger" and "Union Station" are registered
|
6
|
+
* trademarks of Phusion Holding B.V.
|
7
|
+
*
|
8
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
|
+
* of this software and associated documentation files (the "Software"), to deal
|
10
|
+
* in the Software without restriction, including without limitation the rights
|
11
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12
|
+
* copies of the Software, and to permit persons to whom the Software is
|
13
|
+
* furnished to do so, subject to the following conditions:
|
14
|
+
*
|
15
|
+
* The above copyright notice and this permission notice shall be included in
|
16
|
+
* all copies or substantial portions of the Software.
|
17
|
+
*
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
21
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
24
|
+
* THE SOFTWARE.
|
25
|
+
*/
|
26
|
+
#ifndef _PASSENGER_ALGORITHMS_EXP_MOVING_AVERAGE_H_
|
27
|
+
#define _PASSENGER_ALGORITHMS_EXP_MOVING_AVERAGE_H_
|
28
|
+
|
29
|
+
#include <oxt/macros.hpp>
|
30
|
+
#include <boost/config.hpp>
|
31
|
+
#include <algorithm>
|
32
|
+
#include <utility>
|
33
|
+
#include <cmath>
|
34
|
+
|
35
|
+
namespace Passenger {
|
36
|
+
|
37
|
+
using namespace std;
|
38
|
+
|
39
|
+
|
40
|
+
/**
|
41
|
+
* Implements discontiguous exponential moving averaging, as described by John C. Gunther
|
42
|
+
* 1998. Can be used to compute moving exponentially decaying averages and standard
|
43
|
+
* deviations. Unlike normal exponential moving average, this algorithm also works when
|
44
|
+
* the data has gaps, and it also avoids initial value bias and postgap bias. See
|
45
|
+
* http://www.drdobbs.com/tools/discontiguous-exponential-averaging/184410671
|
46
|
+
*
|
47
|
+
* ## Template parameters
|
48
|
+
*
|
49
|
+
* ### alpha
|
50
|
+
*
|
51
|
+
* Specifies by what factor data should decay. Its range is [0, 1000]. Higher values
|
52
|
+
* cause the current value to have more weight (and thus the previous average
|
53
|
+
* to decay more quickly), lower values have the opposite effect.
|
54
|
+
*
|
55
|
+
* ### alphaTimeUnit
|
56
|
+
*
|
57
|
+
* Specifies the time, in microseconds, after which the data should decay
|
58
|
+
* by a factor of exactly `alpha`. For example, if `alpha = 0.5` and `alphaTimeUnit = 2000000`,
|
59
|
+
* then data decays by 0.5 per 2 seconds.
|
60
|
+
*
|
61
|
+
* The default value is 1 second.
|
62
|
+
*
|
63
|
+
* ### maxAge
|
64
|
+
*
|
65
|
+
* Represents an educational guess as to how long (in microseconds) it takes
|
66
|
+
* for the sampled data sequence to change significantly. If you don't expect large random
|
67
|
+
* variations then you should set this to a large value. For a data sequence dominated by
|
68
|
+
* large random variations, setting this to 1000000 (1 second) might be appropriate.
|
69
|
+
*
|
70
|
+
* If the time interval between updates is `dt`, using a `maxAge` of `N * dt` will cause
|
71
|
+
* each update to fill in up to `N - 1` of any preceeding skipped updates with the current
|
72
|
+
* data value.
|
73
|
+
*/
|
74
|
+
template<
|
75
|
+
unsigned int alpha,
|
76
|
+
unsigned long long alphaTimeUnit = 1000000,
|
77
|
+
unsigned long long maxAge = 1000000
|
78
|
+
>
|
79
|
+
class DiscExpMovingAverage {
|
80
|
+
private:
|
81
|
+
template<unsigned int, unsigned long long, unsigned long long>
|
82
|
+
friend class DiscExpMovingAverageWithStddev;
|
83
|
+
|
84
|
+
double sumOfWeights, sumOfData;
|
85
|
+
unsigned long long prevTime;
|
86
|
+
|
87
|
+
static BOOST_CONSTEXPR double floatingAlpha() {
|
88
|
+
return alpha / 1000.0;
|
89
|
+
}
|
90
|
+
|
91
|
+
static BOOST_CONSTEXPR double newDataWeightUpperBound() {
|
92
|
+
return pow(floatingAlpha(), maxAge / (double) alphaTimeUnit);
|
93
|
+
}
|
94
|
+
|
95
|
+
pair<double, double> internalUpdate(double value, unsigned long long now) {
|
96
|
+
double weightReductionFactor = pow(1 - floatingAlpha(),
|
97
|
+
(now - prevTime) / (double) alphaTimeUnit);
|
98
|
+
double newDataWeight = std::min(1 - weightReductionFactor,
|
99
|
+
newDataWeightUpperBound());
|
100
|
+
sumOfWeights = weightReductionFactor * sumOfWeights + newDataWeight;
|
101
|
+
sumOfData = weightReductionFactor * sumOfData + newDataWeight * value;
|
102
|
+
prevTime = now;
|
103
|
+
return make_pair(weightReductionFactor, newDataWeight);
|
104
|
+
}
|
105
|
+
|
106
|
+
public:
|
107
|
+
DiscExpMovingAverage(unsigned long long _prevTime = 0)
|
108
|
+
: sumOfWeights(0),
|
109
|
+
sumOfData(0),
|
110
|
+
prevTime(_prevTime)
|
111
|
+
{ }
|
112
|
+
|
113
|
+
void update(double value, unsigned long long now) {
|
114
|
+
if (OXT_LIKELY(now > prevTime)) {
|
115
|
+
internalUpdate(value, now);
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
bool available() const {
|
120
|
+
return sumOfWeights > 0;
|
121
|
+
}
|
122
|
+
|
123
|
+
double completeness(unsigned long long now) const {
|
124
|
+
return pow(floatingAlpha(), now - prevTime) * sumOfWeights;
|
125
|
+
}
|
126
|
+
|
127
|
+
double average() const {
|
128
|
+
return sumOfData / sumOfWeights;
|
129
|
+
}
|
130
|
+
|
131
|
+
double average(unsigned long long now) const {
|
132
|
+
DiscExpMovingAverage<alpha, alphaTimeUnit, maxAge> copy(*this);
|
133
|
+
copy.update(0, now);
|
134
|
+
return copy.average();
|
135
|
+
}
|
136
|
+
};
|
137
|
+
|
138
|
+
|
139
|
+
/**
|
140
|
+
* Like DescExpMovingAverage, but also keeps track of the standard deviation.
|
141
|
+
*/
|
142
|
+
template<
|
143
|
+
unsigned int alpha,
|
144
|
+
unsigned long long alphaTimeUnit = 1000000,
|
145
|
+
unsigned long long maxAge = 1
|
146
|
+
>
|
147
|
+
class DiscExpMovingAverageWithStddev {
|
148
|
+
private:
|
149
|
+
DiscExpMovingAverage<alpha, alphaTimeUnit, maxAge> dema;
|
150
|
+
double sumOfSquaredData;
|
151
|
+
|
152
|
+
public:
|
153
|
+
DiscExpMovingAverageWithStddev(unsigned long long prevTime = 0)
|
154
|
+
: dema(prevTime),
|
155
|
+
sumOfSquaredData(0)
|
156
|
+
{ }
|
157
|
+
|
158
|
+
void update(double value, unsigned long long now) {
|
159
|
+
if (OXT_UNLIKELY(now <= dema.prevTime)) {
|
160
|
+
return;
|
161
|
+
}
|
162
|
+
|
163
|
+
pair<double, double> p = dema.internalUpdate(value, now);
|
164
|
+
double weightReductionFactor = p.first;
|
165
|
+
double newDataWeight = p.second;
|
166
|
+
sumOfSquaredData = weightReductionFactor * sumOfSquaredData
|
167
|
+
+ newDataWeight * pow(value, 2.0);
|
168
|
+
}
|
169
|
+
|
170
|
+
bool available() const {
|
171
|
+
return dema.available();
|
172
|
+
}
|
173
|
+
|
174
|
+
double completeness(unsigned long long now) const {
|
175
|
+
return dema.completeness(now);
|
176
|
+
}
|
177
|
+
|
178
|
+
double average() const {
|
179
|
+
return dema.average();
|
180
|
+
}
|
181
|
+
|
182
|
+
double average(unsigned long long now) const {
|
183
|
+
return dema.average(now);
|
184
|
+
}
|
185
|
+
|
186
|
+
double stddev() const {
|
187
|
+
return sqrt(sumOfSquaredData / dema.sumOfWeights - pow(average(), 2));
|
188
|
+
}
|
189
|
+
|
190
|
+
double stddev(unsigned long long now) const {
|
191
|
+
DiscExpMovingAverageWithStddev<alpha, alphaTimeUnit, maxAge> copy(*this);
|
192
|
+
copy.update(0, now);
|
193
|
+
return sqrt(copy.sumOfSquaredData / copy.sumOfWeights - pow(copy.average(), 2));
|
194
|
+
}
|
195
|
+
};
|
196
|
+
|
197
|
+
|
198
|
+
/**
|
199
|
+
* Calculates an exponential moving average. `alpha` determines how much weight the
|
200
|
+
* current value has compared to the previous average. Higher values of `alpha`
|
201
|
+
* cause the current value to have more weight (and thus the previous average
|
202
|
+
* to decay more quickly), lower values have the opposite effect.
|
203
|
+
*
|
204
|
+
* This algorithm is not timing sensitive: it doesn't take into account gaps in the
|
205
|
+
* data over time, and treats all values equally regardless of when the value was
|
206
|
+
* collected. See also DiscExpMovingAverage.
|
207
|
+
*
|
208
|
+
* You should initialize the the average value with a value equal to `nullValue`.
|
209
|
+
* If `prevAverage` equals `nullValue` then this function simply returns `currentValue`.
|
210
|
+
*/
|
211
|
+
inline double
|
212
|
+
expMovingAverage(double prevAverage, double currentValue, double alpha, double nullValue = -1) {
|
213
|
+
if (OXT_UNLIKELY(prevAverage == nullValue)) {
|
214
|
+
return currentValue;
|
215
|
+
} else {
|
216
|
+
return alpha * currentValue + (1 - alpha) * prevAverage;
|
217
|
+
}
|
218
|
+
}
|
219
|
+
|
220
|
+
|
221
|
+
} // namespace Passenger
|
222
|
+
|
223
|
+
#endif /* _PASSENGER_ALGORITHMS_EXP_MOVING_AVERAGE_H_ */
|
@@ -83,7 +83,7 @@
|
|
83
83
|
|
84
84
|
#define DEFAULT_RUBY "ruby"
|
85
85
|
|
86
|
-
#define DEFAULT_SOCKET_BACKLOG
|
86
|
+
#define DEFAULT_SOCKET_BACKLOG 2048
|
87
87
|
|
88
88
|
#define DEFAULT_SPAWN_METHOD "smart"
|
89
89
|
|
@@ -121,7 +121,7 @@
|
|
121
121
|
|
122
122
|
#define PASSENGER_DEFAULT_USER "nobody"
|
123
123
|
|
124
|
-
#define PASSENGER_VERSION "5.0.
|
124
|
+
#define PASSENGER_VERSION "5.0.26"
|
125
125
|
|
126
126
|
#define POOL_HELPER_THREAD_STACK_SIZE 262144
|
127
127
|
|
@@ -26,6 +26,7 @@
|
|
26
26
|
#ifndef _PASSENGER_DATA_STRUCTURES_STRING_KEY_TABLE_H_
|
27
27
|
#define _PASSENGER_DATA_STRUCTURES_STRING_KEY_TABLE_H_
|
28
28
|
|
29
|
+
#include <boost/move/move.hpp>
|
29
30
|
#include <boost/cstdint.hpp>
|
30
31
|
#include <limits>
|
31
32
|
#include <cstring>
|
@@ -39,6 +40,11 @@ namespace Passenger {
|
|
39
40
|
|
40
41
|
using namespace std;
|
41
42
|
|
43
|
+
|
44
|
+
struct SKT_EnableMoveSupport { };
|
45
|
+
struct SKT_DisableMoveSupport { };
|
46
|
+
|
47
|
+
|
42
48
|
/**
|
43
49
|
* An optimized hash table that accepts string keys, optimized for the following workload:
|
44
50
|
*
|
@@ -63,7 +69,7 @@ using namespace std;
|
|
63
69
|
* This implementation is based on https://github.com/preshing/CompareIntegerMaps.
|
64
70
|
* See also http://preshing.com/20130107/this-hash-table-is-faster-than-a-judy-array
|
65
71
|
*/
|
66
|
-
template<typename T>
|
72
|
+
template<typename T, typename MoveSupport = SKT_DisableMoveSupport>
|
67
73
|
class StringKeyTable {
|
68
74
|
public:
|
69
75
|
#define SKT_FIRST_CELL(hash) (m_cells + ((hash) & (m_arraySize - 1)))
|
@@ -88,6 +94,16 @@ public:
|
|
88
94
|
Cell()
|
89
95
|
: keyOffset(EMPTY_CELL_KEY_OFFSET)
|
90
96
|
{ }
|
97
|
+
|
98
|
+
void move(Cell &target) {
|
99
|
+
target.keyOffset = keyOffset;
|
100
|
+
target.keyLength = keyLength;
|
101
|
+
target.hash = hash;
|
102
|
+
target.value = boost::move(value);
|
103
|
+
keyOffset = 0;
|
104
|
+
keyLength = 0;
|
105
|
+
hash = 0;
|
106
|
+
}
|
91
107
|
};
|
92
108
|
|
93
109
|
private:
|
@@ -181,7 +197,7 @@ private:
|
|
181
197
|
while (true) {
|
182
198
|
if (cellIsEmpty(newCell)) {
|
183
199
|
// Insert here
|
184
|
-
*newCell
|
200
|
+
copyOrMoveCell(*oldCell, *newCell, MoveSupport());
|
185
201
|
break;
|
186
202
|
} else {
|
187
203
|
newCell = SKT_CIRCULAR_NEXT(newCell);
|
@@ -194,7 +210,23 @@ private:
|
|
194
210
|
delete[] oldCells;
|
195
211
|
}
|
196
212
|
|
197
|
-
void
|
213
|
+
void copyOrMoveCell(Cell &source, Cell &target, const SKT_EnableMoveSupport &t) {
|
214
|
+
source.move(target);
|
215
|
+
}
|
216
|
+
|
217
|
+
void copyOrMoveCell(Cell &source, Cell &target, const SKT_DisableMoveSupport &t) {
|
218
|
+
target = source;
|
219
|
+
}
|
220
|
+
|
221
|
+
void copyOrMoveValue(T &source, T &target, const SKT_EnableMoveSupport &t) {
|
222
|
+
target = boost::move(source);
|
223
|
+
}
|
224
|
+
|
225
|
+
void copyOrMoveValue(const T &source, T &target, const SKT_DisableMoveSupport &t) {
|
226
|
+
target = source;
|
227
|
+
}
|
228
|
+
|
229
|
+
void copyTableFrom(const StringKeyTable &other) {
|
198
230
|
m_arraySize = other.m_arraySize;
|
199
231
|
m_population = other.m_population;
|
200
232
|
m_cells = new Cell[other.m_arraySize];
|
@@ -212,13 +244,54 @@ private:
|
|
212
244
|
}
|
213
245
|
}
|
214
246
|
|
247
|
+
template<typename ValueType, typename LocalMoveSupport>
|
248
|
+
void realInsert(const HashedStaticString &key, ValueType val, bool overwrite) {
|
249
|
+
assert(!key.empty());
|
250
|
+
assert(key.size() <= MAX_KEY_LENGTH);
|
251
|
+
assert(m_population < MAX_ITEMS);
|
252
|
+
|
253
|
+
if (OXT_UNLIKELY(m_cells == NULL)) {
|
254
|
+
init(DEFAULT_SIZE, DEFAULT_STORAGE_SIZE);
|
255
|
+
}
|
256
|
+
|
257
|
+
while (true) {
|
258
|
+
Cell *cell = SKT_FIRST_CELL(key.hash());
|
259
|
+
while (true) {
|
260
|
+
const char *cellKey = lookupCellKey(cell);
|
261
|
+
if (cellKey == NULL) {
|
262
|
+
// Cell is empty. Insert here.
|
263
|
+
if (shouldRepopulateOnInsert()) {
|
264
|
+
// Time to resize
|
265
|
+
repopulate(m_arraySize * 2);
|
266
|
+
break;
|
267
|
+
}
|
268
|
+
m_population++;
|
269
|
+
cell->keyOffset = appendToStorage(key);
|
270
|
+
cell->keyLength = key.size();
|
271
|
+
cell->hash = key.hash();
|
272
|
+
copyOrMoveValue(val, cell->value, LocalMoveSupport());
|
273
|
+
nonEmptyIndex = cell - &m_cells[0];
|
274
|
+
return;
|
275
|
+
} else if (compareKeys(cellKey, cell->keyLength, key)) {
|
276
|
+
// Cell matches.
|
277
|
+
if (overwrite) {
|
278
|
+
copyOrMoveValue(val, cell->value, LocalMoveSupport());
|
279
|
+
}
|
280
|
+
return;
|
281
|
+
} else {
|
282
|
+
cell = SKT_CIRCULAR_NEXT(cell);
|
283
|
+
}
|
284
|
+
}
|
285
|
+
}
|
286
|
+
}
|
287
|
+
|
215
288
|
public:
|
216
289
|
StringKeyTable(unsigned int initialSize = DEFAULT_SIZE, unsigned int initialStorageSize = DEFAULT_STORAGE_SIZE) {
|
217
290
|
init(initialSize, initialStorageSize);
|
218
291
|
}
|
219
292
|
|
220
293
|
StringKeyTable(const StringKeyTable &other) {
|
221
|
-
|
294
|
+
copyTableFrom(other);
|
222
295
|
}
|
223
296
|
|
224
297
|
~StringKeyTable() {
|
@@ -227,14 +300,17 @@ public:
|
|
227
300
|
}
|
228
301
|
|
229
302
|
StringKeyTable &operator=(const StringKeyTable &other) {
|
230
|
-
|
231
|
-
|
232
|
-
|
303
|
+
if (this != &other) {
|
304
|
+
delete[] m_cells;
|
305
|
+
free(m_storage);
|
306
|
+
copyTableFrom(other);
|
307
|
+
}
|
233
308
|
return *this;
|
234
309
|
}
|
235
310
|
|
236
311
|
void init(unsigned int initialSize, unsigned int initialStorageSize) {
|
237
312
|
assert((initialSize & (initialSize - 1)) == 0); // Must be a power of 2
|
313
|
+
assert((initialSize == 0) == (initialStorageSize == 0));
|
238
314
|
|
239
315
|
nonEmptyIndex = NON_EMPTY_INDEX_NONE;
|
240
316
|
|
@@ -314,7 +390,7 @@ public:
|
|
314
390
|
|
315
391
|
OXT_FORCE_INLINE
|
316
392
|
bool lookup(const HashedStaticString &key, T **result) {
|
317
|
-
return static_cast<const StringKeyTable<T> *>(this)->lookup(key,
|
393
|
+
return static_cast<const StringKeyTable<T, MoveSupport> *>(this)->lookup(key,
|
318
394
|
const_cast<const T **>(result));
|
319
395
|
}
|
320
396
|
|
@@ -355,45 +431,21 @@ public:
|
|
355
431
|
}
|
356
432
|
|
357
433
|
void insert(const HashedStaticString &key, const T &val, bool overwrite = true) {
|
358
|
-
|
359
|
-
|
360
|
-
assert(m_population < MAX_ITEMS);
|
434
|
+
realInsert<const T &, SKT_DisableMoveSupport>(key, val, overwrite);
|
435
|
+
}
|
361
436
|
|
362
|
-
|
363
|
-
|
364
|
-
while (true) {
|
365
|
-
const char *cellKey = lookupCellKey(cell);
|
366
|
-
if (cellKey == NULL) {
|
367
|
-
// Cell is empty. Insert here.
|
368
|
-
if (shouldRepopulateOnInsert()) {
|
369
|
-
// Time to resize
|
370
|
-
repopulate(m_arraySize * 2);
|
371
|
-
break;
|
372
|
-
}
|
373
|
-
m_population++;
|
374
|
-
cell->keyOffset = appendToStorage(key);
|
375
|
-
cell->keyLength = key.size();
|
376
|
-
cell->hash = key.hash();
|
377
|
-
cell->value = val;
|
378
|
-
nonEmptyIndex = cell - &m_cells[0];
|
379
|
-
return;
|
380
|
-
} else if (compareKeys(cellKey, cell->keyLength, key)) {
|
381
|
-
// Cell matches.
|
382
|
-
if (overwrite) {
|
383
|
-
cell->value = val;
|
384
|
-
}
|
385
|
-
return;
|
386
|
-
} else {
|
387
|
-
cell = SKT_CIRCULAR_NEXT(cell);
|
388
|
-
}
|
389
|
-
}
|
390
|
-
}
|
437
|
+
void insertByMoving(const HashedStaticString &key, BOOST_RV_REF(T) val, bool overwrite = true) {
|
438
|
+
realInsert<BOOST_RV_REF(T), SKT_EnableMoveSupport>(key, boost::move(val), overwrite);
|
391
439
|
}
|
392
440
|
|
393
441
|
void erase(Cell *cell) {
|
394
442
|
assert(cell >= m_cells && cell - m_cells < m_arraySize);
|
395
443
|
assert(!cellIsEmpty(cell));
|
396
444
|
|
445
|
+
if (OXT_UNLIKELY(m_cells == NULL)) {
|
446
|
+
return;
|
447
|
+
}
|
448
|
+
|
397
449
|
// Remove this cell by shuffling neighboring cells so there are no gaps in anyone's probe chain
|
398
450
|
Cell *neighbor = SKT_CIRCULAR_NEXT(cell);
|
399
451
|
while (true) {
|
@@ -433,6 +485,10 @@ public:
|
|
433
485
|
|
434
486
|
/** Does not resize the array. */
|
435
487
|
void clear() {
|
488
|
+
if (OXT_UNLIKELY(m_cells == NULL)) {
|
489
|
+
return;
|
490
|
+
}
|
491
|
+
|
436
492
|
for (unsigned int i = 0; i < m_arraySize; i++) {
|
437
493
|
m_cells[i].keyOffset = EMPTY_CELL_KEY_OFFSET;
|
438
494
|
m_cells[i].value = T();
|