Skip to content

Commit 00ad160

Browse files
BillyDonahueevergreen
authored andcommitted
SERVER-41654 trim somap to relevant libs on stacktrace
1 parent 6e136ef commit 00ad160

File tree

8 files changed

+679
-117
lines changed

8 files changed

+679
-117
lines changed

src/mongo/SConscript

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ baseEnv.Library(
153153
'util/signal_handlers_synchronous.cpp',
154154
'util/stacktrace.cpp',
155155
'util/stacktrace_${TARGET_OS_FAMILY}.cpp',
156+
'util/stacktrace_json.cpp',
156157
'util/stacktrace_somap.cpp',
157158
'util/str.cpp',
158159
'util/system_clock_source.cpp',

src/mongo/util/stacktrace.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,28 @@
3939
#include "mongo/platform/windows_basic.h" // for CONTEXT
4040
#endif
4141

42+
#include "mongo/base/string_data.h"
43+
4244
namespace mongo {
4345

46+
/** Abstract sink onto which stacktrace is piecewise emitted. */
47+
class StackTraceSink {
48+
public:
49+
StackTraceSink& operator<<(StringData v) {
50+
doWrite(v);
51+
return *this;
52+
}
53+
54+
StackTraceSink& operator<<(uint64_t v) {
55+
doWrite(v);
56+
return *this;
57+
}
58+
59+
private:
60+
virtual void doWrite(StringData v) = 0;
61+
virtual void doWrite(uint64_t v) = 0;
62+
};
63+
4464
// Print stack trace information to "os", default to the log stream.
4565
void printStackTrace(std::ostream& os);
4666
void printStackTrace();

src/mongo/util/stacktrace_json.cpp

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
/**
2+
* Copyright (C) 2019-present MongoDB, Inc.
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the Server Side Public License, version 1,
6+
* as published by MongoDB, Inc.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* Server Side Public License for more details.
12+
*
13+
* You should have received a copy of the Server Side Public License
14+
* along with this program. If not, see
15+
* <http://www.mongodb.com/licensing/server-side-public-license>.
16+
*
17+
* As a special exception, the copyright holders give permission to link the
18+
* code of portions of this program with the OpenSSL library under certain
19+
* conditions as described in each individual source file and distribute
20+
* linked combinations including the program with the OpenSSL library. You
21+
* must comply with the Server Side Public License in all respects for
22+
* all of the code used other than as permitted herein. If you modify file(s)
23+
* with this exception, you may extend this exception to your version of the
24+
* file(s), but you are not obligated to do so. If you do not wish to do so,
25+
* delete this exception statement from your version. If you delete this
26+
* exception statement from all source files in the program, then also delete
27+
* it in the license file.
28+
*/
29+
30+
#include "mongo/util/stacktrace_json.h"
31+
32+
#include <cctype>
33+
34+
#include "mongo/bson/bsonobj.h"
35+
#include "mongo/util/assert_util.h"
36+
37+
namespace mongo::stacktrace_detail {
38+
namespace {
39+
constexpr StringData kHexDigits = "0123456789ABCDEF"_sd;
40+
41+
/**
42+
* Wrapper that streams a string-like object to a StackTraceSink, surrounded by double
43+
* quotes.
44+
*/
45+
template <typename T>
46+
class Quoted {
47+
public:
48+
explicit Quoted(const T& v) : _v(v) {}
49+
50+
friend StackTraceSink& operator<<(StackTraceSink& sink, const Quoted& q) {
51+
return sink << kQuote << q._v << kQuote;
52+
}
53+
54+
private:
55+
static constexpr StringData kQuote = "\""_sd;
56+
const T& _v;
57+
};
58+
} // namespace
59+
60+
StringData Hex::toHex(uint64_t x, Buf& buf) {
61+
char* data = buf.data();
62+
size_t nBuf = buf.size();
63+
char* p = data + nBuf;
64+
if (!x) {
65+
*--p = '0';
66+
} else {
67+
for (int d = 0; d < 16; ++d) {
68+
if (!x)
69+
break;
70+
*--p = kHexDigits[x & 0xf];
71+
x >>= 4;
72+
}
73+
}
74+
return StringData(p, data + nBuf - p);
75+
}
76+
77+
uint64_t Hex::fromHex(StringData s) {
78+
uint64_t x = 0;
79+
for (char c : s) {
80+
char uc = std::toupper(static_cast<unsigned char>(c));
81+
if (size_t pos = kHexDigits.find(uc); pos == std::string::npos) {
82+
return x;
83+
} else {
84+
x <<= 4;
85+
x += pos;
86+
}
87+
}
88+
return x;
89+
}
90+
91+
CheapJson::Value::Value(CheapJson* env, Kind k) : _env(env), _kind(k) {
92+
if (_kind == kObj) {
93+
_env->_sink << "{";
94+
} else if (_kind == kArr) {
95+
_env->_sink << "[";
96+
}
97+
}
98+
99+
CheapJson::Value::~Value() {
100+
if (_kind == kObj) {
101+
_env->_sink << "}";
102+
} else if (_kind == kArr) {
103+
_env->_sink << "]";
104+
}
105+
}
106+
107+
auto CheapJson::Value::appendObj() -> Value {
108+
_next();
109+
return Value{_env, kObj};
110+
}
111+
112+
auto CheapJson::Value::appendArr() -> Value {
113+
_next();
114+
return Value{_env, kArr};
115+
}
116+
117+
auto CheapJson::Value::appendKey(StringData k) -> Value {
118+
fassert(_kind == kObj, "appendKey requires this to be kObj");
119+
_next();
120+
_env->_sink << Quoted(k) << ":";
121+
return Value{_env, kNop};
122+
}
123+
124+
void CheapJson::Value::append(StringData v) {
125+
_next();
126+
_env->_sink << Quoted(v);
127+
}
128+
129+
void CheapJson::Value::append(uint64_t v) {
130+
_next();
131+
_env->_sink << v;
132+
}
133+
134+
void CheapJson::Value::append(const BSONElement& be) {
135+
if (_kind == kObj)
136+
appendKey(be.fieldNameStringData())._copyBsonElementValue(be);
137+
else
138+
_copyBsonElementValue(be);
139+
}
140+
141+
void CheapJson::Value::_copyBsonElementValue(const BSONElement& be) {
142+
switch (be.type()) {
143+
case BSONType::String:
144+
append(be.valueStringData());
145+
break;
146+
case BSONType::NumberInt:
147+
append(be.Int());
148+
break;
149+
case BSONType::Object: {
150+
Value sub = appendObj();
151+
for (const BSONElement& e : be.Obj())
152+
sub.append(e);
153+
} break;
154+
case BSONType::Array: {
155+
Value sub = appendArr();
156+
for (const BSONElement& e : be.Array())
157+
sub.append(e);
158+
} break;
159+
default:
160+
// warning() << "unknown type " << be.type() << "\n";
161+
break;
162+
}
163+
}
164+
165+
void CheapJson::Value::_next() {
166+
_env->_sink << _sep;
167+
_sep = ","_sd;
168+
}
169+
170+
auto CheapJson::doc() -> Value {
171+
return Value(this);
172+
}
173+
174+
CheapJson::CheapJson(StackTraceSink& sink) : _sink(sink) {}
175+
176+
} // namespace mongo::stacktrace_detail

src/mongo/util/stacktrace_json.h

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/**
2+
* Copyright (C) 2019-present MongoDB, Inc.
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the Server Side Public License, version 1,
6+
* as published by MongoDB, Inc.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* Server Side Public License for more details.
12+
*
13+
* You should have received a copy of the Server Side Public License
14+
* along with this program. If not, see
15+
* <http://www.mongodb.com/licensing/server-side-public-license>.
16+
*
17+
* As a special exception, the copyright holders give permission to link the
18+
* code of portions of this program with the OpenSSL library under certain
19+
* conditions as described in each individual source file and distribute
20+
* linked combinations including the program with the OpenSSL library. You
21+
* must comply with the Server Side Public License in all respects for
22+
* all of the code used other than as permitted herein. If you modify file(s)
23+
* with this exception, you may extend this exception to your version of the
24+
* file(s), but you are not obligated to do so. If you do not wish to do so,
25+
* delete this exception statement from your version. If you delete this
26+
* exception statement from all source files in the program, then also delete
27+
* it in the license file.
28+
*/
29+
30+
#pragma once
31+
32+
#include <array>
33+
#include <ostream>
34+
35+
#include "mongo/base/string_data.h"
36+
#include "mongo/bson/bsonelement.h"
37+
#include "mongo/util/stacktrace.h"
38+
39+
namespace mongo::stacktrace_detail {
40+
41+
/**
42+
* A utility for uint64_t <=> uppercase hex string conversions. It
43+
* can be used to produce a StringData.
44+
*
45+
* sink << Hex(x).str(); // as a temporary
46+
*
47+
* Hex hx(x);
48+
* StringData sd = hx.str() // sd storage is in `hx`.
49+
*/
50+
class Hex {
51+
public:
52+
using Buf = std::array<char, 16>;
53+
54+
static StringData toHex(uint64_t x, Buf& buf);
55+
56+
static uint64_t fromHex(StringData s);
57+
58+
explicit Hex(uint64_t x) : _str(toHex(x, _buf)) {}
59+
60+
StringData str() const {
61+
return _str;
62+
}
63+
64+
private:
65+
Buf _buf;
66+
StringData _str;
67+
};
68+
69+
/** An append-only, async-safe, malloc-free Json emitter. */
70+
class CheapJson {
71+
public:
72+
class Value;
73+
74+
explicit CheapJson(StackTraceSink& sink);
75+
76+
// Create an empty JSON document.
77+
Value doc();
78+
79+
private:
80+
StackTraceSink& _sink;
81+
};
82+
83+
/**
84+
* A Json Value node being emitted. Emits {}/[] braces, keyval ":" separators, commas,
85+
* and quotes. To use this, make a Value for the root document and call `append*`
86+
* members, adding a nested structure of objects, arrays, and scalars to the active
87+
* Value.
88+
*
89+
* The constructor emits any appropriate opening brace, and the destructor emits any
90+
* appropriate closing brace. Keeps an internal state so that a comma is emitted on the
91+
* second and subsequent append call.
92+
*/
93+
class CheapJson::Value {
94+
public:
95+
/** The empty root document, which emits no braces. */
96+
explicit Value(CheapJson* env) : Value(env, kNop) {}
97+
98+
/** Emit the closing brace if any. */
99+
~Value();
100+
101+
/** Begin a Json Array. Returns a Value that can be used to append elements to it. */
102+
Value appendArr();
103+
104+
/** Begin a Json Object. Returns a Value that can be used to append elements to it. */
105+
Value appendObj();
106+
107+
/** Append key `k` to this Json Object. Returns the empty Value mapped to `k`. */
108+
Value appendKey(StringData k);
109+
110+
/** Append string `v`, surrounded by doublequote characters. */
111+
void append(StringData v);
112+
113+
/** Append integer `v`, in decimal. */
114+
void append(uint64_t v);
115+
116+
/**
117+
* Append the elements of `be` to this Object or Array.
118+
* Behavior depends on the kind of Value this is.
119+
* - If object: append `be` keys and values.
120+
* - If array: append `be` values only.
121+
*/
122+
void append(const BSONElement& be);
123+
124+
private:
125+
enum Kind {
126+
kNop, // A blank Value, not an aggregate, emits no punctuation. Can emit one element.
127+
kObj, // Object: can emit multiple key-value pairs: {k1:v1, k2:v2, ...}
128+
kArr, // Array: can emit multiple scalars [v1, v2, ...]
129+
};
130+
131+
/* Emit the opening brace corresponding to the specified `k`. */
132+
Value(CheapJson* env, Kind k);
133+
void _copyBsonElementValue(const BSONElement& be);
134+
void _next();
135+
136+
CheapJson* _env;
137+
Kind _kind;
138+
StringData _sep; // Emitted upon append. Starts empty, then set to ",".
139+
};
140+
141+
} // namespace mongo::stacktrace_detail

0 commit comments

Comments
 (0)