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.

Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +20 -0
  3. data/CONTRIBUTORS +1 -0
  4. data/build/cxx_dependency_map.rb +7338 -7104
  5. data/build/cxx_tests.rb +3 -3
  6. data/build/misc.rb +1 -0
  7. data/dev/index_cxx_dependencies.rb +3 -2
  8. data/resources/templates/standalone/config.erb +1 -1
  9. data/resources/templates/standalone/http.erb +1 -0
  10. data/resources/templates/standalone/server.erb +1 -0
  11. data/src/agent/Core/ApplicationPool/AbstractSession.h +83 -0
  12. data/src/agent/Core/ApplicationPool/Common.h +6 -4
  13. data/src/agent/Core/ApplicationPool/Options.h +4 -1
  14. data/src/agent/Core/ApplicationPool/Pool.h +2 -2
  15. data/src/agent/Core/ApplicationPool/Pool/AnalyticsCollection.cpp +3 -6
  16. data/src/agent/Core/ApplicationPool/Pool/GeneralUtils.cpp +3 -3
  17. data/src/agent/Core/ApplicationPool/Session.h +15 -27
  18. data/src/agent/Core/ApplicationPool/TestSession.h +188 -0
  19. data/src/agent/Core/Controller.h +15 -6
  20. data/src/agent/Core/Controller/CheckoutSession.cpp +13 -5
  21. data/src/agent/Core/Controller/ForwardResponse.cpp +20 -2
  22. data/src/agent/Core/Controller/Hooks.cpp +15 -2
  23. data/src/agent/Core/Controller/InitRequest.cpp +5 -1
  24. data/src/agent/Core/Controller/InitializationAndShutdown.cpp +1 -0
  25. data/src/agent/Core/Controller/Request.h +11 -4
  26. data/src/agent/Core/Controller/SendRequest.cpp +34 -13
  27. data/src/agent/Core/Controller/StateInspectionAndConfiguration.cpp +2 -2
  28. data/src/agent/Core/CoreMain.cpp +27 -1
  29. data/src/agent/Core/OptionParser.h +11 -1
  30. data/src/agent/Core/SpawningKit/DirectSpawner.h +1 -0
  31. data/src/agent/Core/SpawningKit/SmartSpawner.h +1 -0
  32. data/src/agent/Core/SpawningKit/Spawner.h +21 -1
  33. data/src/agent/SpawnPreparer/SpawnPreparerMain.cpp +1 -1
  34. data/src/agent/UstRouter/OptionParser.h +7 -1
  35. data/src/agent/UstRouter/UstRouterMain.cpp +27 -1
  36. data/src/cxx_supportlib/Algorithms/MovingAverage.h +223 -0
  37. data/src/cxx_supportlib/Constants.h +2 -2
  38. data/src/cxx_supportlib/DataStructures/StringKeyTable.h +96 -40
  39. data/src/cxx_supportlib/ResourceLocator.h +33 -14
  40. data/src/cxx_supportlib/ServerKit/Channel.h +198 -69
  41. data/src/cxx_supportlib/ServerKit/Errors.h +6 -1
  42. data/src/cxx_supportlib/ServerKit/HttpRequest.h +20 -1
  43. data/src/cxx_supportlib/ServerKit/HttpServer.h +124 -32
  44. data/src/cxx_supportlib/ServerKit/Server.h +65 -1
  45. data/src/cxx_supportlib/Utils/IOUtils.cpp +12 -22
  46. data/src/cxx_supportlib/Utils/JsonUtils.h +87 -1
  47. data/src/cxx_supportlib/Utils/StrIntUtils.cpp +16 -1
  48. data/src/cxx_supportlib/Utils/StrIntUtils.h +31 -1
  49. data/src/cxx_supportlib/Utils/VariantMap.h +6 -1
  50. data/src/cxx_supportlib/WatchdogLauncher.h +17 -9
  51. data/src/cxx_supportlib/vendor-copy/libuv/AUTHORS +43 -0
  52. data/src/cxx_supportlib/vendor-copy/libuv/ChangeLog +350 -1
  53. data/src/cxx_supportlib/vendor-copy/libuv/Makefile.am +9 -1
  54. data/src/cxx_supportlib/vendor-copy/libuv/README.md +48 -0
  55. data/src/cxx_supportlib/vendor-copy/libuv/checksparse.sh +1 -0
  56. data/src/cxx_supportlib/vendor-copy/libuv/common.gypi +5 -5
  57. data/src/cxx_supportlib/vendor-copy/libuv/configure.ac +2 -1
  58. data/src/cxx_supportlib/vendor-copy/libuv/gyp_uv.py +0 -3
  59. data/src/cxx_supportlib/vendor-copy/libuv/include/uv-version.h +5 -1
  60. data/src/cxx_supportlib/vendor-copy/libuv/include/uv.h +30 -3
  61. data/src/cxx_supportlib/vendor-copy/libuv/src/fs-poll.c +3 -3
  62. data/src/cxx_supportlib/vendor-copy/libuv/src/inet.c +0 -4
  63. data/src/cxx_supportlib/vendor-copy/libuv/src/queue.h +17 -1
  64. data/src/cxx_supportlib/vendor-copy/libuv/src/threadpool.c +10 -10
  65. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/aix.c +84 -166
  66. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/android-ifaddrs.c +11 -11
  67. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/async.c +7 -1
  68. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/atomic-ops.h +17 -0
  69. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/core.c +140 -21
  70. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/darwin.c +15 -11
  71. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/dl.c +4 -7
  72. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/freebsd.c +52 -37
  73. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/fs.c +181 -60
  74. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/fsevents.c +39 -34
  75. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/getaddrinfo.c +4 -4
  76. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/internal.h +3 -1
  77. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/kqueue.c +12 -4
  78. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-core.c +38 -15
  79. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-inotify.c +36 -8
  80. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-syscalls.c +4 -4
  81. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/linux-syscalls.h +2 -2
  82. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/loop-watcher.c +6 -1
  83. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/loop.c +28 -8
  84. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/netbsd.c +18 -16
  85. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/openbsd.c +18 -16
  86. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/pipe.c +3 -3
  87. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/process.c +18 -6
  88. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/proctitle.c +2 -2
  89. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/pthread-fixes.c +1 -0
  90. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/signal.c +2 -0
  91. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/stream.c +47 -30
  92. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/sunos.c +13 -11
  93. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/tcp.c +43 -8
  94. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/thread.c +21 -15
  95. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/tty.c +16 -2
  96. data/src/cxx_supportlib/vendor-copy/libuv/src/unix/udp.c +54 -14
  97. data/src/cxx_supportlib/vendor-copy/libuv/src/uv-common.c +104 -21
  98. data/src/cxx_supportlib/vendor-copy/libuv/src/uv-common.h +14 -1
  99. data/src/cxx_supportlib/vendor-copy/libuv/src/version.c +1 -5
  100. data/src/cxx_supportlib/vendor-copy/libuv/uv.gyp +22 -1
  101. data/src/nginx_module/CacheLocationConfig.c +52 -0
  102. data/src/nginx_module/CacheLocationConfig.c.erb +13 -1
  103. data/src/nginx_module/Configuration.c +1 -0
  104. data/src/nginx_module/Configuration.h +1 -0
  105. data/src/nginx_module/ConfigurationCommands.c +20 -0
  106. data/src/nginx_module/ConfigurationFields.h +4 -0
  107. data/src/nginx_module/CreateLocationConfig.c +8 -0
  108. data/src/nginx_module/MergeLocationConfig.c +12 -0
  109. data/src/nginx_module/config +31 -13
  110. data/src/nginx_module/ngx_http_passenger_module.c +4 -0
  111. data/src/ruby_supportlib/phusion_passenger.rb +1 -1
  112. data/src/ruby_supportlib/phusion_passenger/constants.rb +1 -1
  113. data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +11 -1
  114. data/src/ruby_supportlib/phusion_passenger/platform_info/apache.rb +6 -1
  115. data/src/ruby_supportlib/phusion_passenger/rack/thread_handler_extension.rb +32 -31
  116. data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +13 -2
  117. data/src/ruby_supportlib/phusion_passenger/standalone/config_utils.rb +1 -0
  118. data/src/ruby_supportlib/phusion_passenger/standalone/start_command/builtin_engine.rb +6 -1
  119. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core.rb +6 -0
  120. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/api.rb +29 -19
  121. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/context.rb +2 -2
  122. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/request_reporter.rb +2 -3
  123. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/simple_json.rb +2 -1
  124. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/spec_helper.rb +2 -0
  125. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/time_point.rb +3 -17
  126. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/transaction.rb +7 -10
  127. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/utils.rb +11 -9
  128. metadata +5 -2
@@ -181,6 +181,7 @@ public:
181
181
  dup2(errorPipeCopy, 2);
182
182
  closeAllFileDescriptors(2);
183
183
  setChroot(preparation);
184
+ setUlimits(options);
184
185
  switchUser(preparation);
185
186
  setWorkingDirectory(preparation);
186
187
  execvp(args[0], (char * const *) args.get());
@@ -228,6 +228,7 @@ private:
228
228
  dup2(errorPipeCopy, 2);
229
229
  closeAllFileDescriptors(2);
230
230
  setChroot(preparation);
231
+ setUlimits(options);
231
232
  switchUser(preparation);
232
233
  setWorkingDirectory(preparation);
233
234
  execvp(command[0].c_str(), (char * const *) args.get());
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Phusion Passenger - https://www.phusionpassenger.com/
3
- * Copyright (c) 2011-2015 Phusion Holding B.V.
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-2015 Phusion Holding B.V.
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-2015 Phusion Holding B.V.
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-2015 Phusion Holding B.V.
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 1024
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.25"
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 = *oldCell;
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 copyFrom(const StringKeyTable &other) {
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
- copyFrom(other);
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
- delete[] m_cells;
231
- free(m_storage);
232
- copyFrom(other);
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
- assert(!key.empty());
359
- assert(key.size() <= MAX_KEY_LENGTH);
360
- assert(m_population < MAX_ITEMS);
434
+ realInsert<const T &, SKT_DisableMoveSupport>(key, val, overwrite);
435
+ }
361
436
 
362
- while (true) {
363
- Cell *cell = SKT_FIRST_CELL(key.hash());
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();