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