MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NdbIndexStat.hpp
1 /*
2  Copyright (C) 2005, 2006, 2008 MySQL AB, 2009 Sun Microsystems, Inc.
3  All rights reserved. Use is subject to license terms.
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; version 2 of the License.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #ifndef NdbIndexStat_H
20 #define NdbIndexStat_H
21 
22 #include <ndb_types.h>
23 #include "NdbDictionary.hpp"
24 #include "NdbError.hpp"
25 #include "NdbIndexScanOperation.hpp"
26 class NdbIndexStatImpl;
27 
28 /*
29  * Ordered index stats "v4". Includes 1) the old records_in_range in
30  * simplified form 2) the new scanned and stored stats. These are
31  * completely different. 1) makes a one-round-trip query directly to
32  * the index while 2) reads more extensive stats from sys tables where
33  * they were stored previously by NDB kernel.
34  *
35  * Methods in general return 0 on success and -1 on error. The error
36  * details are available via getNdbError().
37  */
38 
39 class NdbIndexStat {
40 public:
41  NdbIndexStat();
42  ~NdbIndexStat();
43 
44  // dummy defs to make handler compile at "ndb api" patch level
45  int alloc_cache(Uint32 entries) { return 0; }
46  enum { RR_UseDb = 1, RR_NoUpdate = 2 };
47 
48  /*
49  * Get latest error. Can be printed like any NdbError instance and
50  * includes some extras.
51  */
52  struct Error : public NdbError {
53  int line; // source code line number
54  int extra; // extra error code
55  Error();
56  };
57  const Error& getNdbError() const;
58 
59  /*
60  * Estimate how many records exist in given range. Does a single
61  * tree-dive on each index fragment, estimates the count from tree
62  * properties, and sums up the results.
63  *
64  * Caller provides index and scan transaction and range bounds.
65  * A scan operation is created and executed. The result is returned
66  * in out-parameter "count". The result is not transactional. Value
67  * zero is exact (range was empty when checked).
68  *
69  * This is basically a static method. The class instance is used only
70  * to return errors.
71  */
72  int records_in_range(const NdbDictionary::Index* index,
73  NdbTransaction* trans,
74  const NdbRecord* key_record,
75  const NdbRecord* result_record,
77  Uint64 table_rows, // not used
78  Uint64* count,
79  int flags); // not used
80 
81  /*
82  * Methods for stored stats.
83  *
84  * There are two distinct users: 1) writer reads samples from sys
85  * tables and creates a new query cache 2) readers make concurrent
86  * stats queries on current query cache.
87  *
88  * Writer provides any Ndb object required. Its database name must be
89  * "mysql". No reference to it is kept.
90  *
91  * Readers provide structs such as Bound on stack or in TLS. The
92  * structs are opaque. With source code the structs can be cast to
93  * NdbIndexStatImpl structs.
94  */
95 
96  enum {
97  NoSysTables = 4714, // all sys tables missing
98  NoIndexStats = 4715, // given index has no stored stats
99  UsageError = 4716, // wrong state, invalid input
100  NoMemError = 4717,
101  InvalidCache = 4718,
102  InternalError = 4719,
103  BadSysTables = 4720, // sys tables partly missing or invalid
104  HaveSysTables = 4244, // create error if all sys tables exist
105  NoSysEvents = 4710,
106  BadSysEvents = BadSysTables,
107  HaveSysEvents = 746
108  };
109 
110  /*
111  * Methods for sys tables.
112  *
113  * Create fails if any objects exist. Specific errors are
114  * BadSysTables (drop required) and HaveSysTables.
115  *
116  * Drop always succeeds and drops any objects that exist.
117  *
118  * Check succeeds if all correct objects exist. Specific errors are
119  * BadSysTables (drop required) and NoSysTables.
120  *
121  * Database of the Ndb object is used and must be "mysql" for kernel
122  * to see the tables.
123  */
124  int create_systables(Ndb* ndb);
125  int drop_systables(Ndb* ndb);
126  int check_systables(Ndb* ndb);
127 
128  /*
129  * Set index operated on. Allocates internal structs. Makes no
130  * database access and keeps no references to the objects.
131  */
132  int set_index(const NdbDictionary::Index& index,
133  const NdbDictionary::Table& table);
134 
135  /*
136  * Release index. Required only if re-used for another index.
137  */
138  void reset_index();
139 
140  /*
141  * Trivial invocation of NdbDictionary::Dictionary::updateIndexStat.
142  */
143  int update_stat(Ndb* ndb);
144 
145  /*
146  * Trivial invocation of NdbDictionary::Dictionary::deleteIndexStat.
147  */
148  int delete_stat(Ndb* ndb);
149 
150  /*
151  * Cache types.
152  */
153  enum CacheType {
154  CacheBuild = 1, // new cache under construction
155  CacheQuery = 2, // cache used to answer queries
156  CacheClean = 3 // old caches waiting to be deleted
157  };
158 
159  /*
160  * Move CacheQuery (if any) to CacheClean and CacheBuild (if any) to
161  * CacheQuery. The CacheQuery switch is atomic.
162  */
163  void move_cache();
164 
165  /*
166  * Delete all CacheClean instances. This can be safely done after old
167  * cache queries have finished. Cache queries are fast since they do
168  * binary searches in memory.
169  */
170  void clean_cache();
171 
172  /*
173  * Cache info. CacheClean may have several instances and the values
174  * for them are summed up.
175  */
176  struct CacheInfo {
177  Uint32 m_count; // number of instances
178  Uint32 m_valid; // should be except for incomplete CacheBuild
179  Uint32 m_sampleCount; // number of samples
180  Uint32 m_totalBytes; // total bytes memory used
181  Uint64 m_save_time; // microseconds to read stats into cache
182  Uint64 m_sort_time; // microseconds to sort the cache
183  // end v4 fields
184  };
185 
186  /*
187  * Get info about a cache type.
188  */
189  void get_cache_info(CacheInfo& info, CacheType type) const;
190 
191  /*
192  * Saved head record retrieved with get_head(). The database fields
193  * are updated by any method which reads stats tables. Stats exist if
194  * sampleVersion is not zero.
195  */
196  struct Head {
197  Int32 m_found; // -1 no read done, 0 = no record, 1 = exists
198  Int32 m_eventType; // if polling, NdbDictionary::Event::TE_INSERT etc
199  Uint32 m_indexId;
200  Uint32 m_indexVersion;
201  Uint32 m_tableId;
202  Uint32 m_fragCount;
203  Uint32 m_valueFormat;
204  Uint32 m_sampleVersion;
205  Uint32 m_loadTime;
206  Uint32 m_sampleCount;
207  Uint32 m_keyBytes;
208  // end v4 fields
209  };
210 
211  /*
212  * Get latest saved head record. Makes no database access.
213  */
214  void get_head(Head& head) const;
215 
216  /*
217  * Read stats head record for the index. Returns error and sets code
218  * to NoIndexStats if head record does not exist or sample version is
219  * zero. Use get_head() to retrieve the results.
220  */
221  int read_head(Ndb* ndb);
222 
223  /*
224  * Read current version of stats into CacheBuild. A move_cache() is
225  * required before it is available for queries.
226  */
227  int read_stat(Ndb* ndb);
228 
229  /*
230  * Reader provides bounds for cache query. The struct must be
231  * initialized from a thread-local byte buffer of the given size.
232  * NdbIndexStat instance is used and must have index set. Note that
233  * a bound becomes low or high only as part of Range.
234  */
235  enum { BoundBufferBytes = 8192 };
236  struct Bound {
237  Bound(const NdbIndexStat* is, void* buffer);
238  void* m_impl;
239  };
240 
241  /*
242  * Add non-NULL attribute value to the bound. May return error for
243  * invalid data.
244  */
245  int add_bound(Bound& bound, const void* value);
246 
247  /*
248  * Add NULL attribute value to the bound.
249  */
250  int add_bound_null(Bound& bound);
251 
252  /*
253  * A non-empty bound must be set strict (true) or non-strict (false).
254  * For empty bound this must remain unset (-1).
255  */
256  void set_bound_strict(Bound& bound, int strict);
257 
258  /*
259  * To re-use same bound instance, a reset is required.
260  */
261  void reset_bound(Bound& bound);
262 
263  /*
264  * Queries take a range consisting of low and high bound (start key
265  * and end key in mysql).
266  */
267  struct Range {
268  Range(Bound& bound1, Bound& bound2);
269  Bound& m_bound1;
270  Bound& m_bound2;
271  };
272 
273  /*
274  * After defining bounds, the range must be finalized. This updates
275  * internal info. Usage error is possible.
276  */
277  int finalize_range(Range& range);
278 
279  /*
280  * Reset the bounds.
281  */
282  void reset_range(Range& range);
283 
284  /*
285  * Convert NdbRecord index bound to Range. Invokes reset and finalize
286  * and cannot be mixed with the other methods.
287  */
288  int convert_range(Range& range,
289  const NdbRecord* key_record,
291 
292  /*
293  * Reader provides storage for stats values. The struct must be
294  * initialized from a thread-local byte buffer of the given size.
295  */
296  enum { StatBufferBytes = 2048 };
297  struct Stat {
298  Stat(void* buffer);
299  void* m_impl;
300  };
301 
302  /*
303  * Compute Stat for a Range from the query cache. Returns error
304  * if there is no valid query cache. The Stat is used to get
305  * stats values without further reference to the Range.
306  */
307  int query_stat(const Range& range, Stat& stat);
308 
309  /*
310  * Check if range is empty i.e. bound1 >= bound2 (for bounds this
311  * means empty) or the query cache is empty. The RIR and RPK return
312  * 1.0 if range is empty.
313  */
314  static void get_empty(const Stat& stat, bool* empty);
315 
316  /*
317  * Get estimated RIR (records in range). Value is always >= 1.0 since
318  * no exact 0 rows can be returned.
319  */
320  static void get_rir(const Stat& stat, double* rir);
321 
322  /*
323  * Get estimated RPK (records per key) at given level k (from 0 to
324  * NK-1 where NK = number of index keys). Value is >= 1.0.
325  */
326  static void get_rpk(const Stat& stat, Uint32 k, double* rpk);
327 
328  /*
329  * Get a short string summarizing the rules used.
330  */
331  enum { RuleBufferBytes = 80 };
332  static void get_rule(const Stat& stat, char* buffer);
333 
334  /*
335  * Events (there is 1) for polling. These are dictionary objects.
336  * Correct sys tables must exist. Drop ignores non-existing events.
337  */
338  int create_sysevents(Ndb* ndb);
339  int drop_sysevents(Ndb* ndb);
340  int check_sysevents(Ndb* ndb);
341 
342  /*
343  * Create listener for stats updates. Only 1 is allowed.
344  */
345  int create_listener(Ndb* ndb);
346 
347  /*
348  * Start listening for events (call NdbEventOperation::execute).
349  */
350  int execute_listener(Ndb* ndb);
351 
352  /*
353  * Poll the listener (call Ndb::pollEvents). Returns 1 if there are
354  * events available and 0 otherwise, or -1 on failure as usual.
355  */
356  int poll_listener(Ndb* ndb, int max_wait_ms);
357 
358  /*
359  * Get next available event. Returns 1 if a new event was returned
360  * and 0 otherwise, or -1 on failure as usual. Use get_heed() to
361  * retrieve event type and data.
362  */
363  int next_listener(Ndb* ndb);
364 
365  /*
366  * Drop the listener.
367  */
368  int drop_listener(Ndb* ndb);
369 
370  /*
371  * Memory allocator for stats cache data (key and value byte arrays).
372  * Implementation default uses malloc/free. The memory in use is the
373  * sum of CacheInfo::m_totalBytes from all cache types.
374  */
375  struct Mem {
376  Mem();
377  virtual ~Mem();
378  virtual void* mem_alloc(UintPtr size) = 0;
379  virtual void mem_free(void* ptr) = 0;
380  };
381 
382  /*
383  * Set a non-default memory allocator.
384  */
385  void set_mem_handler(Mem* mem);
386 
387  // get impl class for use in NDB API programs
388  NdbIndexStatImpl& getImpl();
389 
390 private:
391  int addKeyPartInfo(const NdbRecord* record,
392  const char* keyRecordData,
393  Uint32 keyPartNum,
394  const NdbIndexScanOperation::BoundType boundType,
395  Uint32* keyStatData,
396  Uint32& keyLength);
397 
398  // stored stats
399 
400  friend class NdbIndexStatImpl;
402  NdbIndexStatImpl& m_impl;
403 };
404 
405 class NdbOut&
406 operator<<(class NdbOut& out, const NdbIndexStat::Error&);
407 
408 #endif