MySQL 8.4.0
Source Code Documentation
table_histograms.h
Go to the documentation of this file.
1#ifndef HISTOGRAMS_TABLE_HISTOGRAMS_INCLUDED
2#define HISTOGRAMS_TABLE_HISTOGRAMS_INCLUDED
3
4/* Copyright (c) 2022, 2024, Oracle and/or its affiliates.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License, version 2.0,
8 as published by the Free Software Foundation.
9
10 This program is designed to work with certain software (including
11 but not limited to OpenSSL) that is licensed under separate terms,
12 as designated in a particular file or component or in included license
13 documentation. The authors of MySQL hereby grant you an additional
14 permission to link the program and your derivative works with the
15 separately licensed software that they have either included with
16 the program or referenced in the documentation.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License, version 2.0, for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
26
27#include <array>
28#include <cassert>
29
30#include "map_helpers.h" // mem_root_unordered_map
31#include "my_alloc.h" // MEM_ROOT
32
34#include "sql/psi_memory_key.h"
35
36/*
37The Table_histograms_collection holds a reference-counted collection of
38Table_histograms objects.
39
40Table_histograms_collection memory management
41---------------------------------------------
42
43Each TABLE_SHARE has a pointer to a Table_histograms_collection that is
44allocated on the TABLE_SHARE MEM_ROOT when prepare_share() is called from
45dd_table_share.cc:open_table_def().
46
47The Table_histograms_collection is destroyed (its destructor is invoked) when
48TABLE_SHARE::destroy() is called. The TABLE_SHARE MEM_ROOT also frees its memory
49so the Table_histograms_collection object is also freed.
50
51Table_histograms_collection and its managing of Table_histograms
52----------------------------------------------------------------
53
54The Table_histograms objects in the Table_histograms_collection each represent a
55snapshot of the histograms on a table. The state of this collection is
56manipulated through three methods:
57
58insert(): Inserts a Table_histograms object and marks it current, removing the
59current object if it has a reference count of zero.
60
61acquire(): Returns a pointer to the current Table_histograms object and
62increments its reference count.
63
64release(): Releases a Table_histograms object back by decreasing its reference
65count. Removes the object if it has a reference count of zero and is
66non-current.
67
68A Table_histograms object is inserted into the collection when the TABLE_SHARE
69is first opened (not found in the table definition cache) in
70sql_base.cc:get_table_share(). An updated Table_histograms object is inserted
71following a successful ANALYZE TABLE UPDATE/DROP HISTOGRAM command. This happens
72in sql_admin.cc:update_share_histograms().
73
74TABLE objects acquire() a pointer to a Table_histograms object from the
75Table_histograms_collection when a table is first opened through
76table.cc:open_table_from_share(). This is the only place where acquire() is
77called.
78
79TABLE objects release() the pointer to the Table_histograms object back to the
80Table_histograms_collection when the TABLE is destroyed and freed in
81sql_base.cc:intern_close_table. If an error happens after a Table_histograms
82object has been acquired during open_table_from_share() we also make sure to
83release() it back. Finally histograms are released back in a few code paths that
84perform ad-hoc opening of tables in connection with the REPAIR statement.
85
86Table_histograms_collection concurrency
87---------------------------------------
88
89Because multiple threads can be attempting to insert/acquire/release
90Table_histograms from the Table_histograms_collection on a single TABLE_SHARE we
91require some concurrency control.
92
93In order to protect the Table_histograms_collection from concurrent modification
94we make sure to lock/unlock the LOCK_open mutex around certain operations. The
95mutex protection is performed outside of the object (each object does not have
96its own mutex), and must be seen in the context of the lifetime of the
97TABLE_SHARE.
98
99We do not use mutex protection when setting up or tearing down the TABLE_SHARE
100object, because the appropriate protection should already be in place. For
101example, for the insert() in sql_base.cc:get_table_share() we do not use mutex
102protection since we are in the process of constructing the TABLE_SHARE.
103
104-- insert() in histogram.cc:update_share_histograms(): protected by LOCK_open.
105
106-- acquire() in table.cc:open_table_from_share(): protected by LOCK_open.
107
108-- release() in sql_base.cc:intern_close_table(): protected by LOCK_open.
109
110With respect to performance, for the insert() and release() operations we are
111able to re-use existing lock/unlock pairs, but for the acquire() operation we
112take out an additional lock. Since this lock is global and central to a lot of
113server operations, we would have to benchmark to see if it is better to
114introduce a new lock.
115
116Table_histograms memory management
117----------------------------------
118
119Table_histograms objects are allocated on a MEM_ROOT that is a member of the
120object itself. We create a Table_histograms object through the factory method
121Table_histograms::create() which allocates a new Table_histograms object and
122returns a pointer to it. It is the responsibility of the caller to ensure that
123the destructor of this object is invoked which will free its memory.
124
125When we want to insert() a new Table_histograms object in the
126Table_histograms_collection on a TABLE_SHARE we first call
127Table_histograms::create() to create an empty Table_histograms object. Next we
128fill it with histograms by retrieving histograms from the data dictionary and
129calling Table_histograms::insert_histogram() which copies the histogram to the
130MEM_ROOT on the Table_histograms object. Finally we insert() the object into the
131Table_histograms_collection which transfers ownership/lifetime responsibility
132from the calling code to the collection.
133*/
134
135/**
136 The Table_histograms class represents a snapshot of the collection of
137 histograms associated with a table. Table_histograms contains a reference
138 counter to keep track of the number of TABLE objects that point to it.
139
140 Table_histogram objects are created using the static factory method create().
141 The object itself and everything it points to (including its MEM_ROOT) is
142 allocated on its own MEM_ROOT. Table_histogram objects are destroyed/freed by
143 calling destroy() that clears the MEM_ROOT.
144*/
146 public:
147 /**
148 Factory method to create Table_histogram objects. Allocates a
149 Table_histogram object on its own MEM_ROOT and returns a pointer.
150 Should be matched by a call to destroy().
151
152 @param psi_key performance schema instrumentation memory key to track all
153 memory used by the object.
154 @return A pointer to a Table_histograms object if construction was
155 successful, returns nullptr otherwise.
156 */
157 static Table_histograms *create(PSI_memory_key psi_key) noexcept;
158
159 private:
160 Table_histograms() = default;
161
162 public:
168
169 /**
170 Destroys the object and frees memory.
171 */
172 void destroy();
173
174 /**
175 Perform a lookup in the local collection of histograms for a histogram on
176 a given field.
177
178 @param field_index Index of the field to find a histogram for.
179
180 @return Pointer to a histogram or nullptr if no histogram was found.
181 */
182 const histograms::Histogram *find_histogram(unsigned int field_index) const;
183
184 /**
185 Copies the given histogram onto the local MEM_ROOT and inserts the copy
186 into the local collection of histograms.
187
188 @param field_index Index of the field to insert a histogram for.
189 @param histogram Pointer to the histogram to be copied and inserted.
190 @return False if success, true on error.
191 */
192 bool insert_histogram(unsigned int field_index,
193 const histograms::Histogram *histogram);
194
196
197 private:
200 *m_histograms{nullptr};
201
202 // The following members are only intended to be manipulated by the
203 // Table_histograms_collection that the Table_histograms object is inserted
204 // into.
205
206 /// The number of TABLE objects referencing this object.
207 int reference_count() const { return m_reference_counter; }
210 assert(m_reference_counter > 0);
212 }
213
214 /// The index of this object in the Table_histograms_collection.
215 int get_index() const { return m_index; }
216 void set_index(int index) { m_index = index; }
217
219 size_t m_index{0};
220};
221
223/**
224 The Table_histograms_collection manages a collection of reference-counted
225 snapshots of histogram statistics (Table_histograms objects) for a table. It
226 is intended to live on the TABLE_SHARE and provide TABLE objects with
227 reference-counted access to Table_histogram objects through the acquire() and
228 release() methods. The motivation for this class is to decouple the lifetime
229 of histogram statistics from the lifetime of the TABLE_SHARE, so that we
230 avoid having to invalidate the TABLE_SHARE when updating/dropping histograms.
231
232 Multiple threads can be opening/closing tables concurrently. Member functions
233 on the Table_histograms_collection should be protected by holding LOCK_open.
234
235 When the TABLE_SHARE is initialized and whenever the histograms associated
236 with a table are updated, we create a new Table_histograms object, insert it
237 into the collection, and mark it current.
238*/
240 public:
244 delete;
247 delete;
249
250 /**
251 Acquire a pointer to the most recently inserted Table_histograms object.
252 Increments the reference counter on the returned Table_histograms object.
253
254 @return Pointer to the current Table_histograms object or nullptr if none
255 exists.
256 */
257 const Table_histograms *acquire();
258
259 /**
260 Release a previously acquired Table_histograms object, decreasing its
261 reference count. If the reference count of a non-current Table_histograms
262 object reaches zero we delete it. This frees up memory and makes room for a
263 new Table_histograms object in the collection.
264
265 @param histograms Pointer to a Table_histograms object to be released.
266 */
268
269 /**
270 Attempt to insert the supplied Table_histograms object into the collection.
271 The insertion will fail if the collection is full. If the insertion succeeds
272 we mark the object as current and take ownership. The previous current
273 object is deleted if it has a reference count of zero
274
275 @param histograms Pointer to the Table_histograms object to be inserted.
276
277 @return False if the insertion took place, true otherwise.
278 */
280
281 /**
282 Count the total number of TABLE objects referencing Table_histograms objects
283 in the collection. Primarily used for testing.
284
285 @return The sum of Table_histogram reference counters. Zero if the
286 collection is empty.
287 */
288 int total_reference_count() const;
289
290 /**
291 Counts the number of Table_histograms objects in the collection. Primarily
292 used for testing.
293
294 @return The count of non-null pointers to Table_histograms objects in the
295 collection.
296 */
297 size_t size() const;
298
299 private:
300 /**
301 Frees a Table_histograms object from the collection and sets its pointer to
302 nullptr.
303
304 @param idx Index of the Table_histograms object to free.
305 */
306 void free_table_histograms(size_t idx) {
307 m_table_histograms[idx]->destroy();
308 m_table_histograms[idx] = nullptr;
309 }
310
311 std::array<Table_histograms *, kMaxNumberOfTableHistogramsInCollection>
314};
315
316#endif
The Table_histograms_collection manages a collection of reference-counted snapshots of histogram stat...
Definition: table_histograms.h:239
Table_histograms_collection & operator=(Table_histograms_collection &&)=delete
void free_table_histograms(size_t idx)
Frees a Table_histograms object from the collection and sets its pointer to nullptr.
Definition: table_histograms.h:306
size_t size() const
Counts the number of Table_histograms objects in the collection.
Definition: table_histograms.cc:154
std::array< Table_histograms *, kMaxNumberOfTableHistogramsInCollection > m_table_histograms
Definition: table_histograms.h:312
Table_histograms_collection()
Definition: table_histograms.cc:101
int total_reference_count() const
Count the total number of TABLE objects referencing Table_histograms objects in the collection.
Definition: table_histograms.cc:162
const Table_histograms * acquire()
Acquire a pointer to the most recently inserted Table_histograms object.
Definition: table_histograms.cc:114
void release(const Table_histograms *histograms)
Release a previously acquired Table_histograms object, decreasing its reference count.
Definition: table_histograms.cc:122
size_t m_current_index
Definition: table_histograms.h:313
~Table_histograms_collection()
Definition: table_histograms.cc:105
Table_histograms_collection & operator=(const Table_histograms_collection &)=delete
Table_histograms_collection(const Table_histograms_collection &)=delete
bool insert(Table_histograms *histograms)
Attempt to insert the supplied Table_histograms object into the collection.
Definition: table_histograms.cc:135
Table_histograms_collection(Table_histograms_collection &&)=delete
The Table_histograms class represents a snapshot of the collection of histograms associated with a ta...
Definition: table_histograms.h:145
const histograms::Histogram * find_histogram(unsigned int field_index) const
Perform a lookup in the local collection of histograms for a histogram on a given field.
Definition: table_histograms.cc:92
static Table_histograms * create(PSI_memory_key psi_key) noexcept
Factory method to create Table_histogram objects.
Definition: table_histograms.cc:45
void set_index(int index)
Definition: table_histograms.h:216
MEM_ROOT m_mem_root
Definition: table_histograms.h:198
void decrement_reference_counter()
Definition: table_histograms.h:209
~Table_histograms()=delete
Table_histograms & operator=(const Table_histograms &)=delete
Table_histograms(Table_histograms &&)=delete
bool insert_histogram(unsigned int field_index, const histograms::Histogram *histogram)
Copies the given histogram onto the local MEM_ROOT and inserts the copy into the local collection of ...
Definition: table_histograms.cc:77
mem_root_unordered_map< unsigned int, const histograms::Histogram * > * m_histograms
Definition: table_histograms.h:200
int reference_count() const
The number of TABLE objects referencing this object.
Definition: table_histograms.h:207
Table_histograms(const Table_histograms &)=delete
void increment_reference_counter()
Definition: table_histograms.h:208
size_t m_index
Definition: table_histograms.h:219
int m_reference_counter
Definition: table_histograms.h:218
Table_histograms & operator=(Table_histograms &&)=delete
void destroy()
Destroys the object and frees memory.
Definition: table_histograms.cc:65
int get_index() const
The index of this object in the Table_histograms_collection.
Definition: table_histograms.h:215
Table_histograms()=default
Histogram base class.
Definition: histogram.h:314
std::unordered_map, but allocated on a MEM_ROOT.
Definition: map_helpers.h:291
unsigned int PSI_memory_key
Instrumented memory key.
Definition: psi_memory_bits.h:49
Histogram base class.
This file follows Google coding style, except for the name MEM_ROOT (which is kept for historical rea...
Definition: column_statistics.h:34
The MEM_ROOT is a simple arena, where allocations are carved out of larger blocks.
Definition: my_alloc.h:83
constexpr size_t kMaxNumberOfTableHistogramsInCollection
Definition: table_histograms.h:222