MySQL 9.1.0
Source Code Documentation
optimizer_trace.h
Go to the documentation of this file.
1/* Copyright (c) 2023, 2024, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is designed to work with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have either included with
13 the program or referenced in the documentation.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
23
24#ifndef SQL_JOIN_OPTIMIZER_OPTIMIZER_TRACE_H_
25#define SQL_JOIN_OPTIMIZER_OPTIMIZER_TRACE_H_ 1
26
27#include <array>
28#include <cassert>
29#include <deque>
30#include <memory>
31#include <ostream>
32
34#include "sql/sql_lex.h"
35
36/**
37 This class is used for storing unstructured optimizer trace text
38 (as used by the Hypergraph optimizer). It is used as the
39 std::streambuf object of an associated std::ostream (which writes
40 the formatted text into a TraceBuffer object).
41 The text is stored in a non-consecutive sequence of segments, where
42 each segment has a chunk of consecutive memory. That way, the
43 buffer can grow without having to copy the text into ever bigger
44 buffers of consecutive memory.
45*/
46class TraceBuffer final : public std::streambuf {
47 public:
48 /// The size of each consecutive buffer.
49 static constexpr int64_t kSegmentSize{4096};
50
51 private:
52 /// A consecutive buffer.
53 using Segment = std::array<char, kSegmentSize>;
54
55 public:
56 /// @param max_bytes The maximal number of trace bytes, as given by the
57 /// optimizer_trace_max_mem_size system variable.
58 explicit TraceBuffer(int64_t max_bytes)
59 : // We round upwards so that we can hold at least 'max_bytes' bytes.
60 m_max_segments{max_bytes / kSegmentSize +
61 (max_bytes % kSegmentSize == 0 ? 0 : 1)} {
62 assert(max_bytes >= 0);
63 assert(m_max_segments >= 0);
64 }
65 /**
66 Called by std::ostream if the current segment is full. Allocate
67 a new segment (or use m_excess_segment if we have reached
68 m_max_segments) and put 'ch' at the beginning of it.
69 */
70 int_type overflow(int_type ch) override;
71
72 /**
73 Apply 'sink' to each character in the trace text. Free each segment
74 when its contents have been consumed. (That way, we avoid storing two
75 copies of a potentially huge trace at the same time.)
76 */
77 template <typename Sink>
78 void Consume(Sink sink) {
79 assert(!m_segments.empty() || m_excess_segment != nullptr ||
80 (pptr() == nullptr && pbase() == nullptr && epptr() == nullptr));
81
82 while (!m_segments.empty()) {
83 for (char &ch : m_segments.front()) {
84 // If the last segment is allocated directly before another segment,
85 // then last_segment.end() == other_segment.begin(). For that reason,
86 // we need to check if m_segments.size() == 1 to know that we are on
87 // the last segment. Otherwise, we get pptr()==other_segment.begin()
88 // if the the total trace volume is a multiple of kSegmentSize.
89 if (m_segments.size() == 1 && &ch == pptr()) {
90 setp(nullptr, nullptr);
91 break;
92 }
93 sink(ch);
94 }
95 m_segments.pop_front();
96 }
97 }
98
99 /// Get the number of bytes that did not fit in m_segments.
100 int64_t excess_bytes() const {
101 return m_excess_segment == nullptr
102 ? 0
104 (pptr() - std::to_address(m_excess_segment->cbegin()));
105 }
106
107 /// Return a copy of the contents as a string. This may be expensive for
108 /// large traces, and is only intended for unit tests.
109 std::string ToString() const {
110 std::string result;
111
112 for (auto segment = m_segments.cbegin(); segment < m_segments.cend();
113 segment++) {
114 for (const char &ch : *segment) {
115 // See Consume().
116 if (segment + 1 == m_segments.cend() && &ch == pptr()) {
117 break;
118 }
119 result += ch;
120 }
121 }
122 return result;
123 }
124
125 private:
126 /// Max number of segments (as given by the optimizer_trace_max_mem_size
127 /// system variable).
129
130 /// The sequence of segments.
131 std::deque<Segment> m_segments;
132
133 /// If we fill m_max_segments, allocate a single extra segment that is
134 /// repeatedly overwritten with any additional data. This field will point
135 /// to that segment.
136 std::unique_ptr<Segment> m_excess_segment;
137
138 /// The number of full segments that did not fit in m_segments.
140};
141
142/**
143 Trace in the form of plain text (i.e. no JSON tree), as used by
144 the Hypergraph optimizer.
145*/
146class UnstructuredTrace final {
147 public:
148 /// @param max_bytes The maximal number of trace bytes, as given by the
149 /// optimizer_trace_max_mem_size system variable.
150 explicit UnstructuredTrace(int64_t max_bytes)
151 : m_buffer{max_bytes}, m_stream{&m_buffer} {}
152
153 /// Get the stream in which to put the trace text.
154 std::ostream &stream() { return m_stream; }
155
157 const TraceBuffer &contents() const { return m_buffer; }
158
159 private:
160 /// The trace text.
162
163 /// The stream that formats text and appends it to m_buffer.
164 std::ostream m_stream;
165};
166
167// Shorthand functions.
168
169/// Fetch the ostream that we write optimizer trace into.
170inline std::ostream &Trace(THD *thd) {
171 return thd->opt_trace.unstructured_trace()->stream();
172}
173
174/// @returns 'true' if unstructured optimizer trace (as used by Hypergraph)
175/// is started.
176inline bool TraceStarted(THD *thd) {
177 return thd->opt_trace.is_started() &&
178 thd->opt_trace.unstructured_trace() != nullptr;
179}
180#endif
UnstructuredTrace * unstructured_trace()
Definition: opt_trace_context.h:276
bool is_started() const
Returns whether there is a current trace.
Definition: opt_trace_context.h:148
For each client connection we create a separate thread with THD serving as a thread/connection descri...
Definition: sql_lexer_thd.h:36
Opt_trace_context opt_trace
optimizer trace of current statement
Definition: sql_class.h:4088
This class is used for storing unstructured optimizer trace text (as used by the Hypergraph optimizer...
Definition: optimizer_trace.h:46
TraceBuffer(int64_t max_bytes)
Definition: optimizer_trace.h:58
std::array< char, kSegmentSize > Segment
A consecutive buffer.
Definition: optimizer_trace.h:53
std::unique_ptr< Segment > m_excess_segment
If we fill m_max_segments, allocate a single extra segment that is repeatedly overwritten with any ad...
Definition: optimizer_trace.h:136
std::deque< Segment > m_segments
The sequence of segments.
Definition: optimizer_trace.h:131
std::string ToString() const
Return a copy of the contents as a string.
Definition: optimizer_trace.h:109
static constexpr int64_t kSegmentSize
The size of each consecutive buffer.
Definition: optimizer_trace.h:49
int64_t m_full_excess_segments
The number of full segments that did not fit in m_segments.
Definition: optimizer_trace.h:139
void Consume(Sink sink)
Apply 'sink' to each character in the trace text.
Definition: optimizer_trace.h:78
int_type overflow(int_type ch) override
Called by std::ostream if the current segment is full.
Definition: optimizer_trace.cc:27
int64_t excess_bytes() const
Get the number of bytes that did not fit in m_segments.
Definition: optimizer_trace.h:100
int64_t m_max_segments
Max number of segments (as given by the optimizer_trace_max_mem_size system variable).
Definition: optimizer_trace.h:128
Trace in the form of plain text (i.e.
Definition: optimizer_trace.h:146
std::ostream m_stream
The stream that formats text and appends it to m_buffer.
Definition: optimizer_trace.h:164
TraceBuffer m_buffer
The trace text.
Definition: optimizer_trace.h:161
TraceBuffer & contents()
Definition: optimizer_trace.h:156
UnstructuredTrace(int64_t max_bytes)
Definition: optimizer_trace.h:150
const TraceBuffer & contents() const
Definition: optimizer_trace.h:157
std::ostream & stream()
Get the stream in which to put the trace text.
Definition: optimizer_trace.h:154
This contains the declaration of class Opt_trace_context, which is needed to declare THD.
std::ostream & Trace(THD *thd)
Fetch the ostream that we write optimizer trace into.
Definition: optimizer_trace.h:170
bool TraceStarted(THD *thd)
Definition: optimizer_trace.h:176
struct result result
Definition: result.h:34
Definition: result.h:30