passenger 4.0.42 → 4.0.43
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 +8 -8
- checksums.yaml.gz.asc +7 -7
- data.tar.gz.asc +7 -7
- data/CHANGELOG +13 -0
- data/CONTRIBUTING.md +2 -19
- data/build/agents.rb +4 -1
- data/build/cxx_tests.rb +7 -2
- data/build/debian.rb +1 -1
- data/debian.template/control.template +0 -2
- data/doc/CodingTipsAndPitfalls.md +56 -0
- data/doc/Users guide Apache.idmap.txt +16 -14
- data/doc/Users guide Nginx.idmap.txt +8 -6
- data/doc/Users guide Standalone.idmap.txt +3 -1
- data/doc/Users guide Standalone.txt +1 -1
- data/doc/users_guide_snippets/environment_variables.txt +1 -0
- data/doc/users_guide_snippets/installation.txt +5 -5
- data/doc/users_guide_snippets/support_information.txt +42 -9
- data/doc/users_guide_snippets/troubleshooting/default.txt +42 -0
- data/ext/common/ApplicationPool2/Common.h +1 -0
- data/ext/common/ApplicationPool2/DirectSpawner.h +2 -7
- data/ext/common/ApplicationPool2/DummySpawner.h +1 -1
- data/ext/common/ApplicationPool2/Group.h +4 -2
- data/ext/common/ApplicationPool2/Options.h +9 -7
- data/ext/common/ApplicationPool2/Pool.h +83 -40
- data/ext/common/ApplicationPool2/Process.h +2 -6
- data/ext/common/ApplicationPool2/README.md +0 -40
- data/ext/common/ApplicationPool2/SmartSpawner.h +2 -9
- data/ext/common/ApplicationPool2/Spawner.h +1 -4
- data/ext/common/ApplicationPool2/SpawnerFactory.h +6 -9
- data/ext/common/ApplicationPool2/SuperGroup.h +3 -3
- data/ext/common/Constants.h +1 -1
- data/ext/common/UnionStation/Connection.h +227 -0
- data/ext/common/UnionStation/Core.h +497 -0
- data/ext/common/UnionStation/ScopeLog.h +172 -0
- data/ext/common/UnionStation/Transaction.h +276 -0
- data/ext/common/Utils.cpp +83 -8
- data/ext/common/Utils.h +25 -4
- data/ext/common/Utils/AnsiColorConstants.h +1 -0
- data/ext/common/Utils/ProcessMetricsCollector.h +6 -170
- data/ext/common/Utils/SpeedMeter.h +258 -0
- data/ext/common/Utils/StrIntUtils.cpp +6 -0
- data/ext/common/Utils/StringScanning.h +277 -0
- data/ext/common/Utils/SystemMetricsCollector.h +1460 -0
- data/ext/common/agents/Base.cpp +8 -8
- data/ext/common/agents/HelperAgent/Main.cpp +12 -6
- data/ext/common/agents/HelperAgent/RequestHandler.h +15 -16
- data/ext/common/agents/HelperAgent/SystemMetricsTool.cpp +199 -0
- data/ext/common/agents/LoggingAgent/LoggingServer.h +2 -1
- data/ext/common/agents/SpawnPreparer.cpp +20 -32
- data/lib/phusion_passenger.rb +1 -1
- data/lib/phusion_passenger/config/list_instances_command.rb +118 -0
- data/lib/phusion_passenger/config/main.rb +22 -4
- data/lib/phusion_passenger/config/system_metrics_command.rb +37 -0
- data/lib/phusion_passenger/config/utils.rb +1 -1
- data/lib/phusion_passenger/loader_shared_helpers.rb +8 -5
- data/lib/phusion_passenger/platform_info/compiler.rb +1 -1
- data/resources/templates/error_layout.html.template +3 -3
- data/test/cxx/ApplicationPool2/DirectSpawnerTest.cpp +3 -5
- data/test/cxx/ApplicationPool2/PoolTest.cpp +1 -3
- data/test/cxx/ApplicationPool2/ProcessTest.cpp +4 -4
- data/test/cxx/ApplicationPool2/SmartSpawnerTest.cpp +5 -7
- data/test/cxx/RequestHandlerTest.cpp +9 -3
- data/test/cxx/UnionStationTest.cpp +61 -64
- metadata +13 -4
- metadata.gz.asc +7 -7
- data/ext/common/UnionStation.h +0 -968
- data/helper-scripts/system-memory-stats.py +0 -207
@@ -0,0 +1,172 @@
|
|
1
|
+
/*
|
2
|
+
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
+
* Copyright (c) 2010-2014 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
|
+
#ifndef _PASSENGER_UNION_STATION_SCOPE_LOG_H_
|
26
|
+
#define _PASSENGER_UNION_STATION_SCOPE_LOG_H_
|
27
|
+
|
28
|
+
#include <boost/noncopyable.hpp>
|
29
|
+
|
30
|
+
#include <sys/resource.h>
|
31
|
+
|
32
|
+
#include <string>
|
33
|
+
|
34
|
+
#include <StaticString.h>
|
35
|
+
#include <Exceptions.h>
|
36
|
+
#include <UnionStation/Transaction.h>
|
37
|
+
#include <Utils/StrIntUtils.h>
|
38
|
+
#include <Utils/SystemTime.h>
|
39
|
+
|
40
|
+
namespace Passenger {
|
41
|
+
namespace UnionStation {
|
42
|
+
|
43
|
+
using namespace std;
|
44
|
+
using namespace boost;
|
45
|
+
|
46
|
+
|
47
|
+
class ScopeLog: public noncopyable {
|
48
|
+
private:
|
49
|
+
Transaction * const transaction;
|
50
|
+
union {
|
51
|
+
const char *name;
|
52
|
+
struct {
|
53
|
+
const char *endMessage;
|
54
|
+
const char *abortMessage;
|
55
|
+
} granular;
|
56
|
+
} data;
|
57
|
+
enum {
|
58
|
+
NAME,
|
59
|
+
GRANULAR
|
60
|
+
} type: 1;
|
61
|
+
bool ok;
|
62
|
+
|
63
|
+
static string timevalToString(struct timeval &tv) {
|
64
|
+
unsigned long long i = (unsigned long long) tv.tv_sec * 1000000 + tv.tv_usec;
|
65
|
+
return usecToString(i);
|
66
|
+
}
|
67
|
+
|
68
|
+
static string usecToString(unsigned long long usec) {
|
69
|
+
char timestamp[2 * sizeof(unsigned long long) + 1];
|
70
|
+
integerToHexatri<unsigned long long>(usec, timestamp);
|
71
|
+
return timestamp;
|
72
|
+
}
|
73
|
+
|
74
|
+
public:
|
75
|
+
ScopeLog()
|
76
|
+
: transaction(NULL)
|
77
|
+
{ }
|
78
|
+
|
79
|
+
ScopeLog(const TransactionPtr &_transaction, const char *name)
|
80
|
+
: transaction(_transaction.get())
|
81
|
+
{
|
82
|
+
type = NAME;
|
83
|
+
data.name = name;
|
84
|
+
ok = false;
|
85
|
+
|
86
|
+
char message[150];
|
87
|
+
char *pos = message;
|
88
|
+
const char *end = message + sizeof(message);
|
89
|
+
struct rusage usage;
|
90
|
+
|
91
|
+
pos = appendData(pos, end, "BEGIN: ");
|
92
|
+
pos = appendData(pos, end, name);
|
93
|
+
pos = appendData(pos, end, " (");
|
94
|
+
pos = appendData(pos, end, usecToString(SystemTime::getUsec()));
|
95
|
+
pos = appendData(pos, end, ",");
|
96
|
+
if (getrusage(RUSAGE_SELF, &usage) == -1) {
|
97
|
+
int e = errno;
|
98
|
+
throw SystemException("getrusage() failed", e);
|
99
|
+
}
|
100
|
+
pos = appendData(pos, end, timevalToString(usage.ru_utime));
|
101
|
+
pos = appendData(pos, end, ",");
|
102
|
+
pos = appendData(pos, end, timevalToString(usage.ru_stime));
|
103
|
+
pos = appendData(pos, end, ") ");
|
104
|
+
|
105
|
+
if (transaction != NULL) {
|
106
|
+
transaction->message(StaticString(message, pos - message));
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
ScopeLog(const TransactionPtr &_transaction,
|
111
|
+
const char *beginMessage,
|
112
|
+
const char *endMessage,
|
113
|
+
const char *abortMessage = NULL)
|
114
|
+
: transaction(_transaction.get())
|
115
|
+
{
|
116
|
+
if (_transaction != NULL) {
|
117
|
+
type = GRANULAR;
|
118
|
+
data.granular.endMessage = endMessage;
|
119
|
+
data.granular.abortMessage = abortMessage;
|
120
|
+
ok = abortMessage == NULL;
|
121
|
+
_transaction->message(beginMessage);
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
~ScopeLog() {
|
126
|
+
if (transaction == NULL) {
|
127
|
+
return;
|
128
|
+
}
|
129
|
+
if (type == NAME) {
|
130
|
+
char message[150];
|
131
|
+
char *pos = message;
|
132
|
+
const char *end = message + sizeof(message);
|
133
|
+
struct rusage usage;
|
134
|
+
|
135
|
+
if (ok) {
|
136
|
+
pos = appendData(pos, end, "END: ");
|
137
|
+
} else {
|
138
|
+
pos = appendData(pos, end, "FAIL: ");
|
139
|
+
}
|
140
|
+
pos = appendData(pos, end, data.name);
|
141
|
+
pos = appendData(pos, end, " (");
|
142
|
+
pos = appendData(pos, end, usecToString(SystemTime::getUsec()));
|
143
|
+
pos = appendData(pos, end, ",");
|
144
|
+
if (getrusage(RUSAGE_SELF, &usage) == -1) {
|
145
|
+
int e = errno;
|
146
|
+
throw SystemException("getrusage() failed", e);
|
147
|
+
}
|
148
|
+
pos = appendData(pos, end, timevalToString(usage.ru_utime));
|
149
|
+
pos = appendData(pos, end, ",");
|
150
|
+
pos = appendData(pos, end, timevalToString(usage.ru_stime));
|
151
|
+
pos = appendData(pos, end, ")");
|
152
|
+
|
153
|
+
transaction->message(StaticString(message, pos - message));
|
154
|
+
} else {
|
155
|
+
if (ok) {
|
156
|
+
transaction->message(data.granular.endMessage);
|
157
|
+
} else {
|
158
|
+
transaction->message(data.granular.abortMessage);
|
159
|
+
}
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
void success() {
|
164
|
+
ok = true;
|
165
|
+
}
|
166
|
+
};
|
167
|
+
|
168
|
+
|
169
|
+
} // namespace UnionStation
|
170
|
+
} // namespace Passenger
|
171
|
+
|
172
|
+
#endif /* _PASSENGER_UNION_STATION_SCOPE_LOG_H_ */
|
@@ -0,0 +1,276 @@
|
|
1
|
+
/*
|
2
|
+
* Phusion Passenger - https://www.phusionpassenger.com/
|
3
|
+
* Copyright (c) 2010-2014 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
|
+
#ifndef _PASSENGER_UNION_STATION_TRANSACTION_H_
|
26
|
+
#define _PASSENGER_UNION_STATION_TRANSACTION_H_
|
27
|
+
|
28
|
+
#include <boost/shared_ptr.hpp>
|
29
|
+
#include <boost/noncopyable.hpp>
|
30
|
+
#include <oxt/backtrace.hpp>
|
31
|
+
|
32
|
+
#include <string>
|
33
|
+
#include <stdexcept>
|
34
|
+
|
35
|
+
#include <cstdio>
|
36
|
+
#include <cassert>
|
37
|
+
|
38
|
+
#include <Logging.h>
|
39
|
+
#include <Exceptions.h>
|
40
|
+
#include <StaticString.h>
|
41
|
+
#include <UnionStation/Connection.h>
|
42
|
+
#include <Utils/IOUtils.h>
|
43
|
+
#include <Utils/SystemTime.h>
|
44
|
+
#include <Utils/StrIntUtils.h>
|
45
|
+
|
46
|
+
namespace Passenger {
|
47
|
+
namespace UnionStation {
|
48
|
+
|
49
|
+
using namespace std;
|
50
|
+
using namespace boost;
|
51
|
+
|
52
|
+
|
53
|
+
enum ExceptionHandlingMode {
|
54
|
+
PRINT,
|
55
|
+
THROW,
|
56
|
+
IGNORE
|
57
|
+
};
|
58
|
+
|
59
|
+
|
60
|
+
class Core;
|
61
|
+
typedef boost::shared_ptr<Core> CorePtr;
|
62
|
+
|
63
|
+
inline void _checkinConnection(const CorePtr &core, const ConnectionPtr &connection);
|
64
|
+
|
65
|
+
|
66
|
+
class Transaction: public boost::noncopyable {
|
67
|
+
private:
|
68
|
+
static const int INT64_STR_BUFSIZE = 22; // Long enough for a 64-bit number.
|
69
|
+
static const unsigned long long IO_TIMEOUT = 5000000; // In microseconds.
|
70
|
+
|
71
|
+
const CorePtr core;
|
72
|
+
const ConnectionPtr connection;
|
73
|
+
const string txnId;
|
74
|
+
const string groupName;
|
75
|
+
const string category;
|
76
|
+
const string unionStationKey;
|
77
|
+
const ExceptionHandlingMode exceptionHandlingMode;
|
78
|
+
bool shouldFlushToDiskAfterClose;
|
79
|
+
|
80
|
+
/**
|
81
|
+
* Buffer must be at least txnId.size() + 1 + INT64_STR_BUFSIZE + 1 bytes.
|
82
|
+
*/
|
83
|
+
char *insertTxnIdAndTimestamp(char *buffer, const char *end) {
|
84
|
+
assert(end - buffer >= int(txnId.size() + 1 + INT64_STR_BUFSIZE + 1));
|
85
|
+
int size;
|
86
|
+
|
87
|
+
// "txn-id-here"
|
88
|
+
buffer = appendData(buffer, end, txnId);
|
89
|
+
|
90
|
+
// "txn-id-here "
|
91
|
+
buffer = appendData(buffer, end, " ", 1);
|
92
|
+
|
93
|
+
// "txn-id-here 123456"
|
94
|
+
assert(end - buffer >= INT64_STR_BUFSIZE);
|
95
|
+
size = snprintf(buffer, INT64_STR_BUFSIZE, "%llu", SystemTime::getUsec());
|
96
|
+
if (size >= INT64_STR_BUFSIZE) {
|
97
|
+
// The buffer is too small.
|
98
|
+
throw IOException("Cannot format a new transaction log message timestamp.");
|
99
|
+
}
|
100
|
+
buffer += size;
|
101
|
+
|
102
|
+
// "txn-id-here 123456 "
|
103
|
+
buffer = appendData(buffer, end, " ", 1);
|
104
|
+
|
105
|
+
return buffer;
|
106
|
+
}
|
107
|
+
|
108
|
+
template<typename ExceptionType>
|
109
|
+
void handleException(const ExceptionType &e) {
|
110
|
+
switch (exceptionHandlingMode) {
|
111
|
+
case THROW:
|
112
|
+
throw e;
|
113
|
+
case PRINT: {
|
114
|
+
const tracable_exception *te =
|
115
|
+
dynamic_cast<const tracable_exception *>(&e);
|
116
|
+
if (te != NULL) {
|
117
|
+
P_WARN(te->what() << "\n" << te->backtrace());
|
118
|
+
} else {
|
119
|
+
P_WARN(e.what());
|
120
|
+
}
|
121
|
+
break;
|
122
|
+
}
|
123
|
+
default:
|
124
|
+
break;
|
125
|
+
}
|
126
|
+
}
|
127
|
+
|
128
|
+
public:
|
129
|
+
Transaction()
|
130
|
+
: exceptionHandlingMode(PRINT)
|
131
|
+
{ }
|
132
|
+
|
133
|
+
Transaction(const CorePtr &_core,
|
134
|
+
const ConnectionPtr &_connection,
|
135
|
+
const string &_txnId,
|
136
|
+
const string &_groupName,
|
137
|
+
const string &_category,
|
138
|
+
const string &_unionStationKey,
|
139
|
+
ExceptionHandlingMode _exceptionHandlingMode = PRINT)
|
140
|
+
: core(_core),
|
141
|
+
connection(_connection),
|
142
|
+
txnId(_txnId),
|
143
|
+
groupName(_groupName),
|
144
|
+
category(_category),
|
145
|
+
unionStationKey(_unionStationKey),
|
146
|
+
exceptionHandlingMode(_exceptionHandlingMode),
|
147
|
+
shouldFlushToDiskAfterClose(false)
|
148
|
+
{ }
|
149
|
+
|
150
|
+
~Transaction() {
|
151
|
+
TRACE_POINT();
|
152
|
+
if (connection == NULL) {
|
153
|
+
return;
|
154
|
+
}
|
155
|
+
ConnectionLock l(connection);
|
156
|
+
if (!connection->connected()) {
|
157
|
+
return;
|
158
|
+
}
|
159
|
+
|
160
|
+
char timestamp[2 * sizeof(unsigned long long) + 1];
|
161
|
+
integerToHexatri<unsigned long long>(SystemTime::getUsec(),
|
162
|
+
timestamp);
|
163
|
+
|
164
|
+
UPDATE_TRACE_POINT();
|
165
|
+
ConnectionGuard guard(connection.get());
|
166
|
+
try {
|
167
|
+
unsigned long long timeout = IO_TIMEOUT;
|
168
|
+
writeArrayMessage(connection->fd, &timeout,
|
169
|
+
"closeTransaction",
|
170
|
+
txnId.c_str(),
|
171
|
+
timestamp,
|
172
|
+
NULL);
|
173
|
+
|
174
|
+
if (shouldFlushToDiskAfterClose) {
|
175
|
+
UPDATE_TRACE_POINT();
|
176
|
+
timeout = IO_TIMEOUT;
|
177
|
+
writeArrayMessage(connection->fd, &timeout,
|
178
|
+
"flush", NULL);
|
179
|
+
readArrayMessage(connection->fd, &timeout);
|
180
|
+
}
|
181
|
+
|
182
|
+
_checkinConnection(core, connection);
|
183
|
+
guard.clear();
|
184
|
+
} catch (const SystemException &e) {
|
185
|
+
string errorResponse;
|
186
|
+
|
187
|
+
UPDATE_TRACE_POINT();
|
188
|
+
guard.clear();
|
189
|
+
if (connection->disconnect(errorResponse)) {
|
190
|
+
handleException(IOException(
|
191
|
+
"Logging agent disconnected with error: " +
|
192
|
+
errorResponse));
|
193
|
+
} else {
|
194
|
+
handleException(e);
|
195
|
+
}
|
196
|
+
}
|
197
|
+
}
|
198
|
+
|
199
|
+
void message(const StaticString &text) {
|
200
|
+
TRACE_POINT();
|
201
|
+
if (connection == NULL) {
|
202
|
+
P_TRACE(3, "[Union Station log to null] " << text);
|
203
|
+
return;
|
204
|
+
}
|
205
|
+
ConnectionLock l(connection);
|
206
|
+
if (!connection->connected()) {
|
207
|
+
P_TRACE(3, "[Union Station log to null] " << text);
|
208
|
+
return;
|
209
|
+
}
|
210
|
+
|
211
|
+
char timestamp[2 * sizeof(unsigned long long) + 1];
|
212
|
+
integerToHexatri<unsigned long long>(SystemTime::getUsec(), timestamp);
|
213
|
+
|
214
|
+
UPDATE_TRACE_POINT();
|
215
|
+
ConnectionGuard guard(connection.get());
|
216
|
+
try {
|
217
|
+
unsigned long long timeout = IO_TIMEOUT;
|
218
|
+
P_TRACE(3, "[Union Station log] " << txnId << " " << timestamp << " " << text);
|
219
|
+
writeArrayMessage(connection->fd, &timeout,
|
220
|
+
"log",
|
221
|
+
txnId.c_str(),
|
222
|
+
timestamp,
|
223
|
+
NULL);
|
224
|
+
writeScalarMessage(connection->fd, text, &timeout);
|
225
|
+
guard.clear();
|
226
|
+
} catch (const std::exception &e) {
|
227
|
+
string errorResponse;
|
228
|
+
|
229
|
+
UPDATE_TRACE_POINT();
|
230
|
+
guard.clear();
|
231
|
+
if (connection->disconnect(errorResponse)) {
|
232
|
+
handleException(IOException(
|
233
|
+
"Logging agent disconnected with error: " +
|
234
|
+
errorResponse));
|
235
|
+
} else {
|
236
|
+
handleException(e);
|
237
|
+
}
|
238
|
+
}
|
239
|
+
}
|
240
|
+
|
241
|
+
void abort(const StaticString &text) {
|
242
|
+
message("ABORT");
|
243
|
+
}
|
244
|
+
|
245
|
+
void flushToDiskAfterClose(bool value) {
|
246
|
+
shouldFlushToDiskAfterClose = value;
|
247
|
+
}
|
248
|
+
|
249
|
+
bool isNull() const {
|
250
|
+
return connection == NULL;
|
251
|
+
}
|
252
|
+
|
253
|
+
const string &getTxnId() const {
|
254
|
+
return txnId;
|
255
|
+
}
|
256
|
+
|
257
|
+
const string &getGroupName() const {
|
258
|
+
return groupName;
|
259
|
+
}
|
260
|
+
|
261
|
+
const string &getCategory() const {
|
262
|
+
return category;
|
263
|
+
}
|
264
|
+
|
265
|
+
const string &getUnionStationKey() const {
|
266
|
+
return unionStationKey;
|
267
|
+
}
|
268
|
+
};
|
269
|
+
|
270
|
+
typedef boost::shared_ptr<Transaction> TransactionPtr;
|
271
|
+
|
272
|
+
|
273
|
+
} // namespace UnionStation
|
274
|
+
} // namespace Passenger
|
275
|
+
|
276
|
+
#endif /* _PASSENGER_UNION_STATION_TRANSACTION_H_ */
|
data/ext/common/Utils.cpp
CHANGED
@@ -55,6 +55,7 @@
|
|
55
55
|
#include <Utils/Base64.h>
|
56
56
|
#include <Utils/CachedFileStat.hpp>
|
57
57
|
#include <Utils/StrIntUtils.h>
|
58
|
+
#include <Utils/IOUtils.h>
|
58
59
|
#include <Utils/HttpHeaderBufferer.h>
|
59
60
|
|
60
61
|
#ifndef HOST_NAME_MAX
|
@@ -338,8 +339,8 @@ extractBaseName(const StaticString &path) {
|
|
338
339
|
}
|
339
340
|
|
340
341
|
string
|
341
|
-
escapeForXml(const
|
342
|
-
string result(input);
|
342
|
+
escapeForXml(const StaticString &input) {
|
343
|
+
string result(input.data(), input.size());
|
343
344
|
string::size_type input_pos = 0;
|
344
345
|
string::size_type input_end_pos = input.size();
|
345
346
|
string::size_type result_pos = 0;
|
@@ -994,6 +995,74 @@ runShellCommand(const StaticString &command) {
|
|
994
995
|
}
|
995
996
|
}
|
996
997
|
|
998
|
+
string
|
999
|
+
runCommandAndCaptureOutput(const char **command) {
|
1000
|
+
pid_t pid;
|
1001
|
+
int e;
|
1002
|
+
Pipe p;
|
1003
|
+
|
1004
|
+
p = createPipe();
|
1005
|
+
|
1006
|
+
this_thread::disable_syscall_interruption dsi;
|
1007
|
+
pid = syscalls::fork();
|
1008
|
+
if (pid == 0) {
|
1009
|
+
// Make ps nicer, we want to have as little impact on the rest
|
1010
|
+
// of the system as possible while collecting the metrics.
|
1011
|
+
int prio = getpriority(PRIO_PROCESS, getpid());
|
1012
|
+
prio++;
|
1013
|
+
if (prio > 20) {
|
1014
|
+
prio = 20;
|
1015
|
+
}
|
1016
|
+
setpriority(PRIO_PROCESS, getpid(), prio);
|
1017
|
+
|
1018
|
+
dup2(p[1], 1);
|
1019
|
+
close(p[0]);
|
1020
|
+
close(p[1]);
|
1021
|
+
closeAllFileDescriptors(2);
|
1022
|
+
execvp(command[0], (char * const *) command);
|
1023
|
+
_exit(1);
|
1024
|
+
} else if (pid == -1) {
|
1025
|
+
e = errno;
|
1026
|
+
throw SystemException("Cannot fork() a new process", e);
|
1027
|
+
} else {
|
1028
|
+
bool done = false;
|
1029
|
+
string result;
|
1030
|
+
|
1031
|
+
p[1].close();
|
1032
|
+
while (!done) {
|
1033
|
+
char buf[1024 * 4];
|
1034
|
+
ssize_t ret;
|
1035
|
+
|
1036
|
+
try {
|
1037
|
+
this_thread::restore_syscall_interruption rsi(dsi);
|
1038
|
+
ret = syscalls::read(p[0], buf, sizeof(buf));
|
1039
|
+
} catch (const thread_interrupted &) {
|
1040
|
+
syscalls::kill(SIGKILL, pid);
|
1041
|
+
syscalls::waitpid(pid, NULL, 0);
|
1042
|
+
throw;
|
1043
|
+
}
|
1044
|
+
if (ret == -1) {
|
1045
|
+
e = errno;
|
1046
|
+
syscalls::kill(SIGKILL, pid);
|
1047
|
+
syscalls::waitpid(pid, NULL, 0);
|
1048
|
+
throw SystemException(string("Cannot read output from the '") +
|
1049
|
+
command[1] + "' command", e);
|
1050
|
+
}
|
1051
|
+
done = ret == 0;
|
1052
|
+
result.append(buf, ret);
|
1053
|
+
}
|
1054
|
+
p[0].close();
|
1055
|
+
syscalls::waitpid(pid, NULL, 0);
|
1056
|
+
|
1057
|
+
if (result.empty()) {
|
1058
|
+
throw RuntimeException(string("The '") + command[1] +
|
1059
|
+
"' command failed");
|
1060
|
+
} else {
|
1061
|
+
return result;
|
1062
|
+
}
|
1063
|
+
}
|
1064
|
+
}
|
1065
|
+
|
997
1066
|
#ifdef __APPLE__
|
998
1067
|
// http://www.opensource.apple.com/source/Libc/Libc-825.26/sys/fork.c
|
999
1068
|
// This bypasses atfork handlers.
|
@@ -1054,7 +1123,7 @@ getFileDescriptorLimit() {
|
|
1054
1123
|
// descriptor that the process is currently using.
|
1055
1124
|
// See also http://stackoverflow.com/questions/899038/getting-the-highest-allocated-file-descriptor
|
1056
1125
|
static int
|
1057
|
-
getHighestFileDescriptor() {
|
1126
|
+
getHighestFileDescriptor(bool asyncSignalSafe) {
|
1058
1127
|
#if defined(F_MAXFD)
|
1059
1128
|
int ret;
|
1060
1129
|
|
@@ -1099,9 +1168,15 @@ getHighestFileDescriptor() {
|
|
1099
1168
|
goto done;
|
1100
1169
|
}
|
1101
1170
|
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1171
|
+
if (asyncSignalSafe) {
|
1172
|
+
do {
|
1173
|
+
pid = asyncFork();
|
1174
|
+
} while (pid == -1 && errno == EINTR);
|
1175
|
+
} else {
|
1176
|
+
do {
|
1177
|
+
pid = fork();
|
1178
|
+
} while (pid == -1 && errno == EINTR);
|
1179
|
+
}
|
1105
1180
|
|
1106
1181
|
if (pid == 0) {
|
1107
1182
|
// Don't close p[0] here or it might affect the result.
|
@@ -1243,7 +1318,7 @@ done:
|
|
1243
1318
|
}
|
1244
1319
|
|
1245
1320
|
void
|
1246
|
-
closeAllFileDescriptors(int lastToKeepOpen) {
|
1321
|
+
closeAllFileDescriptors(int lastToKeepOpen, bool asyncSignalSafe) {
|
1247
1322
|
#if defined(F_CLOSEM)
|
1248
1323
|
int ret;
|
1249
1324
|
do {
|
@@ -1257,7 +1332,7 @@ closeAllFileDescriptors(int lastToKeepOpen) {
|
|
1257
1332
|
return;
|
1258
1333
|
#endif
|
1259
1334
|
|
1260
|
-
for (int i = getHighestFileDescriptor(); i > lastToKeepOpen; i--) {
|
1335
|
+
for (int i = getHighestFileDescriptor(asyncSignalSafe); i > lastToKeepOpen; i--) {
|
1261
1336
|
/* Even though we normally shouldn't retry on EINTR
|
1262
1337
|
* (http://news.ycombinator.com/item?id=3363819)
|
1263
1338
|
* it's okay to do that here because because this function
|