File: pfs_tls_channel.cc

package info (click to toggle)
mysql-8.0 8.0.43-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,273,924 kB
  • sloc: cpp: 4,684,605; ansic: 412,450; pascal: 108,398; java: 83,641; perl: 30,221; cs: 27,067; sql: 26,594; sh: 24,181; python: 21,816; yacc: 17,169; php: 11,522; xml: 7,388; javascript: 7,076; makefile: 2,194; lex: 1,075; awk: 670; asm: 520; objc: 183; ruby: 97; lisp: 86
file content (259 lines) | stat: -rw-r--r-- 9,288 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/* Copyright (c) 2020, 2025, Oracle and/or its affiliates.

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License, version 2.0,
  as published by the Free Software Foundation.

  This program is designed to work with certain software (including
  but not limited to OpenSSL) that is licensed under separate terms,
  as designated in a particular file or component or in included license
  documentation.  The authors of MySQL hereby grant you an additional
  permission to link the program and your derivative works with the
  separately licensed software that they have either included with
  the program or referenced in the documentation.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License, version 2.0, for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */

#include "storage/perfschema/pfs_tls_channel.h"
#include "mysql/components/services/bits/psi_bits.h"
#include "mysql/psi/mysql_rwlock.h"

/* clang-format off */

/**
  @page PAGE_PFS_TLS_CHANNEL Performance schema TLS channels instrumentation

  @section TLS_CHANNEL_REGISTRATION Registration
  @startuml
    title Registration

    participant server as "MySQL server"
    participant pfs as "Performance schema"
    participant component as "Component or Plugin"

    == Bootstrap ==

    server -> pfs : mysql_tls_channel_register(<main channel>)
    server -> pfs : mysql_tls_channel_register(<admin channel>)

    == INSTALL COMPONENT/SERVER ==

    server -> component : init()
    component -> pfs : mysql_tls_channel_register(<channel>)

    == SELECT * FROM PERFORMANCE_SCHEMA.tls_channel_status ==
    
    server -> pfs : select
    pfs -> server : (Fetch TLS configuration details)
    pfs -> component : (Fetch TLS configuration details)
    pfs --> server : result set row 1
    pfs --> server : result set row 2
    pfs --> server : ...
    pfs --> server : result set row N

    == UNINSTALL COMPONENT/PLUGIN ==

    server -> component : deinit()
    component -> pfs : mysql_tls_channel_unregister(<channel>)

    == Shutdown ==

    server -> pfs : mysql_tls_channel_unregister(<admin channel>)
    server -> pfs : mysql_tls_channel_unregister(<main channel>)

  @enduml

    To expose TLS configuration details through performance schema:
  - Implement a subclass of TLS_channel_property_iterator
  - Register it with Performance schema on init/bootstrap
  - Unregister instrumentation with Performance schema on deinit/shutdown

  @section TLS_CHANNEL_SCAN Iteration for each TLS channel
  @startuml
    title Iteration for each TLS channel

    participant server as "MySQL server"
    participant pfs as "Performance schema\nTable_tls_channel_status"
    participant pfs_container as "Performance schema\nTLS channel status container"
    participant tls_channel_iterator_1 as "TLS channel status iterator"
    participant tls_channel_iterator_2 as "Another TLS channel status iterator"

    == SELECT init ==

    server -> pfs : rnd_init()
    pfs -> pfs_container : create()
    activate pfs_container

    == For each TLS channel ==

    pfs -> tls_channel_iterator_1 : create_iterator()
    activate tls_channel_iterator_1
    pfs -> tls_channel_iterator_1 : (multiple calls)
    pfs -> tls_channel_iterator_1 : destroy_iterator()
    deactivate tls_channel_iterator_1
    pfs -> tls_channel_iterator_2 : create_iterator()
    activate tls_channel_iterator_2
    pfs -> tls_channel_iterator_2 : (multiple calls)
    pfs -> tls_channel_iterator_2 : destroy_iterator()
    deactivate tls_channel_iterator_2

    == SELECT end ==

    server -> pfs : rnd_end()
    pfs -> pfs_container : destroy()
    deactivate pfs_container

  @enduml

  When the server performs a SELECT * from performance_schema.tls_channeL_info, the performance schema creates
  a TLS_channel_status_container for the duration of the table scan.

  Then, the scan loops for each TLS channel capable of exposing status (i.e. channels that registered
  TLS channel status iterator).

  For each channel, an iterator is created, dedicated for this SELECT scan.

  @section TLS_CHANNEL_INTERNAL_SCAN Inside a registered TLS channel
  @startuml
    title Inside a registered TLS channel

    participant server as "MySQL server"
    participant pfs as "Performance schema\nTable_tls_channel_status"
    participant pfs_container as "Performance schema\nTLS channel status container"
    participant tls_channel_iterator as "TLS channel status iterator"
    participant tls_channel_container as "Local TLS channel status container"
    participant tls_channel as "TLS channel"

    == SELECT init ==

    server -> pfs : rand_init()
    pfs -> pfs_container : create()
    activate pfs_container

    == Materialize ==

    loop until all registered TLS channels are processed
    pfs -> tls_channel_iterator : create_iterator()
    activate tls_channel_iterator
    tls_channel_iterator -> tls_channel_container : create()
    activate tls_channel_container
    tls_channel_container -> tls_channel : start_fetch_status()
    activate tls_channel
    tls_channel_container -> tls_channel : fetch_status()
    tls_channel_container -> tls_channel : ...
    tls_channel_container -> tls_channel : end_fetch_status()
    deactivate tls_channel
    pfs -> tls_channel_iterator : get()
    tls_channel_iterator -> tls_channel_container : fetch_next_status()
    pfs -> tls_channel_iterator : next()
    tls_channel_iterator -> tls_channel_container : move_to_next_status()
    pfs -> tls_channel_iterator : ...
    pfs -> tls_channel_iterator : ...
    pfs -> tls_channel_iterator : destroy_iterator()
    tls_channel_iterator -> tls_channel_container : destroy_container()
    deactivate tls_channel_container
    deactivate tls_channel_iterator

    == Subsequent scans ==

    server -> pfs : rnd_next()
    pfs -> pfs_container : get_row(2)
    pfs --> server : result set row 2
    server -> pfs : rnd_next()
    pfs -> pfs_container : get_row(...)
    pfs --> server : result set row ...
    server -> pfs : rnd_next()
    pfs -> pfs_container : get_row(N)
    pfs --> server : result set row N

    == SELECT end ==

    server -> pfs : rnd_end()
    pfs -> pfs_container : destroy()
    deactivate pfs_container

  @enduml

  When rnd_init() is called, the performance schema iterates through registered TLS channels
  and add data corresponding to each channel in TLS channel data container.

  Upon subsequent calls ::rnd_next(), data present in the container is returned. This process
  continues until no more data is left in the container.

  This method allows performance schema to shorten the duration for which registered TLS
  channel container is locked. This is essential because mysql_tls_channel_register() and
  mysql_tls_channel_deregister() may modify the TLS channel container.

*/

/* clang-format on */

tls_channels g_instrumented_tls_channels;
static bool g_instrumented_tls_channels_inited = false;

/**
  RW lock that protects list of instrumented TLS channels.
  @sa g_instrumented_tls_channels
*/
mysql_rwlock_t LOCK_pfs_tls_channels;
static PSI_rwlock_key key_LOCK_pfs_tls_channels;
static PSI_rwlock_info info_LOCK_pfs_tls_channels = {
    &key_LOCK_pfs_tls_channels, "LOCK_pfs_tls_channels", PSI_FLAG_SINGLETON, 0,
    "This lock protects list of instrumented TLS channels."};

void init_pfs_tls_channels_instrumentation() {
  /* This is called once at startup */
  mysql_rwlock_register("pfs", &info_LOCK_pfs_tls_channels, 1);
  mysql_rwlock_init(key_LOCK_pfs_tls_channels, &LOCK_pfs_tls_channels);
  g_instrumented_tls_channels_inited = true;
}

void cleanup_pfs_tls_channels_instrumentation() {
  g_instrumented_tls_channels_inited = false;
  mysql_rwlock_destroy(&LOCK_pfs_tls_channels);
}

void pfs_register_tls_channel_v1(TLS_channel_property_iterator *provider) {
  if (!g_instrumented_tls_channels_inited) return;
  bool insert = true;
  mysql_rwlock_wrlock(&LOCK_pfs_tls_channels);
  for (auto *channel : g_instrumented_tls_channels) {
    if (channel == provider) {
      insert = false;
      break;
    }
  }
  if (insert) g_instrumented_tls_channels.push_back(provider);
  mysql_rwlock_unlock(&LOCK_pfs_tls_channels);
}

void pfs_unregister_tls_channel_v1(TLS_channel_property_iterator *provider) {
  if (!g_instrumented_tls_channels_inited) return;
  if (g_instrumented_tls_channels.empty()) return;
  mysql_rwlock_wrlock(&LOCK_pfs_tls_channels);
  for (auto it = g_instrumented_tls_channels.cbegin();
       it != g_instrumented_tls_channels.cend(); ++it) {
    if (*it == provider) {
      g_instrumented_tls_channels.erase(it);
      break;
    }
  }
  mysql_rwlock_unlock(&LOCK_pfs_tls_channels);
}

void pfs_tls_channels_lock_for_read() {
  mysql_rwlock_rdlock(&LOCK_pfs_tls_channels);
}

void pfs_tls_channels_unlock() { mysql_rwlock_unlock(&LOCK_pfs_tls_channels); }

tls_channels &pfs_get_instrumented_tls_channels() {
  return g_instrumented_tls_channels;
}