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
|
#ifndef TABLE_CACHE_H_INCLUDED
#define TABLE_CACHE_H_INCLUDED
/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
Copyright (c) 2010, 2011 Monty Program Ab
Copyright (C) 2013 Sergey Vojtovich and MariaDB Foundation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
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 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-1335 USA */
#include "table.h"
struct Share_free_tables
{
typedef I_P_List <TABLE, TABLE_share> List;
List list;
/** Avoid false sharing between instances */
char pad[CPU_LEVEL1_DCACHE_LINESIZE];
};
struct TDC_element
{
uchar m_key[NAME_LEN + 1 + NAME_LEN + 1];
uint m_key_length;
bool flushed;
TABLE_SHARE *share;
/**
Protects ref_count, m_flush_tickets, all_tables, flushed, all_tables_refs.
*/
mysql_mutex_t LOCK_table_share;
mysql_cond_t COND_release;
TDC_element *next, **prev; /* Link to unused shares */
uint ref_count; /* How many TABLE objects uses this */
uint all_tables_refs; /* Number of refs to all_tables */
/**
List of tickets representing threads waiting for the share to be flushed.
*/
Wait_for_flush_list m_flush_tickets;
/*
Doubly-linked (back-linked) lists of used and unused TABLE objects
for this share.
*/
All_share_tables_list all_tables;
/** Avoid false sharing between TDC_element and free_tables */
char pad[CPU_LEVEL1_DCACHE_LINESIZE];
Share_free_tables free_tables[1];
inline void wait_for_refs(uint my_refs);
void flush(THD *thd, bool mark_flushed);
void flush_unused(bool mark_flushed);
};
extern ulong tdc_size;
extern ulong tc_size;
extern uint32 tc_instances;
extern bool tdc_init(void);
extern void tdc_start_shutdown(void);
extern void tdc_deinit(void);
extern ulong tdc_records(void);
extern void tdc_purge(bool all);
extern TDC_element *tdc_lock_share(THD *thd, const char *db,
const char *table_name);
extern void tdc_unlock_share(TDC_element *element);
int tdc_share_is_cached(THD *thd, const char *db, const char *table_name);
extern TABLE_SHARE *tdc_acquire_share(THD *thd, TABLE_LIST *tl, uint flags,
TABLE **out_table= 0);
extern void tdc_release_share(TABLE_SHARE *share);
void tdc_remove_referenced_share(THD *thd, TABLE_SHARE *share);
void tdc_remove_table(THD *thd, const char *db, const char *table_name);
extern int tdc_wait_for_old_version(THD *thd, const char *db,
const char *table_name,
ulong wait_timeout, uint deadlock_weight);
extern int tdc_iterate(THD *thd, my_hash_walk_action action, void *argument,
bool no_dups= false);
extern uint tc_records(void);
int show_tc_active_instances(THD *thd, SHOW_VAR *var, char *buff,
enum enum_var_type scope);
extern void tc_purge();
extern void tc_add_table(THD *thd, TABLE *table);
extern void tc_release_table(TABLE *table);
extern TABLE *tc_acquire_table(THD *thd, TDC_element *element);
class Share_lock
{
public:
TDC_element *element;
Share_lock(THD *thd, const char *db, const char *table)
{
element= tdc_lock_share(thd, db, table);
}
~Share_lock()
{
if (element)
tdc_unlock_share(element);
}
};
class Share_acquire
{
public:
bool flush_unused;
TABLE_SHARE *share;
Share_acquire() : flush_unused(false), share(NULL) {}
Share_acquire(THD *thd, TABLE_LIST &tl, uint flags= 0) : flush_unused(false)
{
acquire(thd, tl, flags);
}
Share_acquire(const Share_acquire &src)= delete;
// NB: noexcept is required for STL containers
Share_acquire(Share_acquire &&src) noexcept :
flush_unused(src.flush_unused), share(src.share)
{
src.share= NULL;
}
Share_acquire& operator= (Share_acquire &&src)
{
flush_unused= src.flush_unused;
share= src.share;
src.share= NULL;
return *this;
}
~Share_acquire();
bool is_error(THD *thd);
void acquire(THD *thd, TABLE_LIST &tl, uint flags= 0);
void release()
{
if (share)
{
if (flush_unused)
share->tdc->flush_unused(true);
tdc_release_share(share);
share= NULL;
}
}
};
/**
Create a table cache key for non-temporary table.
@param key Buffer for key (must be at least NAME_LEN*2+2 bytes).
@param db Database name.
@param table_name Table name.
@return Length of key.
*/
inline uint tdc_create_key(char *key, const char *db, const char *table_name)
{
/*
In theory caller should ensure that both db and table_name are
not longer than NAME_LEN bytes. In practice we play safe to avoid
buffer overruns.
*/
return (uint) (strmake(strmake(key, db, NAME_LEN) + 1, table_name,
NAME_LEN) - key + 1);
}
#endif /* TABLE_CACHE_H_INCLUDED */
|