1 /* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
22 
23 #ifndef NDB_INDEX_STAT_IMPL_HPP
24 #define NDB_INDEX_STAT_IMPL_HPP
25 
26 #include <ndb_global.h>
27 #include <ndb_limits.h>
28 #include <NdbDictionary.hpp>
29 #include <NdbIndexStat.hpp>
30 #include <util/NdbPack.hpp>
31 #include <NdbError.hpp>
32 #include <NdbMutex.h>
33 #include <NdbTick.h>
34 class Ndb;
35 class NdbTransaction;
36 class NdbIndexScanOperation;
37 class NdbRecAttr;
38 class NdbOperation;
39 class NdbEventOperation;
40 
41 extern const uint g_ndb_index_stat_head_frm_len;
42 extern const uint8 g_ndb_index_stat_head_frm_data[];
43 extern const uint g_ndb_index_stat_sample_frm_len;
44 extern const uint8 g_ndb_index_stat_sample_frm_data[];
45 
46 class NdbIndexStatImpl : public NdbIndexStat {
47 public:
48   friend class NdbIndexStat;
49   struct Con;
50   struct Cache;
51 
52   enum { MaxKeyCount = MAX_INDEX_STAT_KEY_COUNT };
53   enum { MaxKeyBytes = MAX_INDEX_STAT_KEY_SIZE * 4 };
54   enum { MaxValueBytes = MAX_INDEX_STAT_VALUE_SIZE * 4 };
55   enum { MaxValueCBytes = MAX_INDEX_STAT_VALUE_CSIZE * 4 };
56 
57   NdbIndexStatImpl(NdbIndexStat& facade);
58   ~NdbIndexStatImpl();
59   void init();
60 
61   NdbIndexStat* const m_facade;
62   Head m_facadeHead; // owned by facade
63   bool m_indexSet;
64   Uint32 m_indexId;
65   Uint32 m_indexVersion;
66   Uint32 m_tableId;
67   uint m_keyAttrs;
68   uint m_valueAttrs;
69   NdbPack::Spec m_keySpec;
70   NdbPack::Spec m_valueSpec;
71   NdbPack::Type* m_keySpecBuf;
72   NdbPack::Type* m_valueSpecBuf;
73   NdbPack::Data m_keyData;
74   NdbPack::Data m_valueData;
75   Uint8* m_keyDataBuf;
76   Uint8* m_valueDataBuf;
77   Cache* m_cacheBuild;
78   Cache* m_cacheQuery;
79   Cache* m_cacheClean;
80   // mutex for query cache switch, memory barrier would do
81   NdbMutex* m_query_mutex;
82   NdbEventOperation* m_eventOp;
83   Mem* m_mem_handler;
84   NdbIndexStat::Error m_error;
85 
86   // sys tables meta
87   struct Sys {
88     NdbIndexStatImpl* const m_impl;
89     Ndb* const m_ndb;
90     NdbDictionary::Dictionary* m_dic;
91     const NdbDictionary::Table* m_headtable;
92     const NdbDictionary::Table* m_sampletable;
93     const NdbDictionary::Index* m_sampleindex1;
94     int m_obj_cnt;
95     enum { ObjCnt = 3 };
96     Sys(NdbIndexStatImpl* impl, Ndb* ndb);
97     ~Sys();
98   };
99   void sys_release(Sys& sys);
100   int make_headtable(NdbDictionary::Table& tab);
101   int make_sampletable(NdbDictionary::Table& tab);
102   int make_sampleindex1(NdbDictionary::Index& ind);
103   int check_table(const NdbDictionary::Table& tab1,
104                   const NdbDictionary::Table& tab2);
105   int check_index(const NdbDictionary::Index& ind1,
106                   const NdbDictionary::Index& ind2);
107   int get_systables(Sys& sys);
108   int create_systables(Ndb* ndb);
109   int drop_systables(Ndb* ndb);
110   int check_systables(Sys& sys);
111   int check_systables(Ndb* ndb);
112 
113   // operation context
114   struct Con {
115     NdbIndexStatImpl* const m_impl;
116     Head& m_head;
117     Ndb* const m_ndb;
118     NdbDictionary::Dictionary* m_dic;
119     const NdbDictionary::Table* m_headtable;
120     const NdbDictionary::Table* m_sampletable;
121     const NdbDictionary::Index* m_sampleindex1;
122     NdbTransaction* m_tx;
123     NdbOperation* m_op;
124     NdbIndexScanOperation* m_scanop;
125     Cache* m_cacheBuild;
126     uint m_cachePos;
127     uint m_cacheKeyOffset;   // in bytes
128     uint m_cacheValueOffset; // in bytes
129     MicroSecondTimer m_start;
130     Con(NdbIndexStatImpl* impl, Head& head, Ndb* ndb);
131     ~Con();
132     int startTransaction();
133     int execute(bool commit);
134     int getNdbOperation();
135     int getNdbIndexScanOperation();
136     void set_time();
137     NDB_TICKS get_time();
138   };
139 
140   // index
141   int set_index(const NdbDictionary::Index& index,
142                 const NdbDictionary::Table& table);
143   void reset_index();
144 
145   // init m_facadeHead here (keep API struct a POD)
146   void init_head(Head& head);
147 
148   // sys tables data
149   int sys_init(Con& con);
150   void sys_release(Con& con);
151   int sys_read_head(Con& con, bool commit);
152   int sys_head_setkey(Con& con);
153   int sys_head_getvalue(Con& con);
154   int sys_sample_setkey(Con& con);
155   int sys_sample_getvalue(Con& con);
156   int sys_sample_setbound(Con& con, int sv_bound);
157 
158   // update, delete (head may record elapsed time)
159   int update_stat(Ndb* ndb, Head& head);
160   int delete_stat(Ndb* ndb, Head& head);
161 
162   // read
163   int read_head(Ndb* ndb, Head& head);
164   int read_stat(Ndb* ndb, Head& head);
165   int read_start(Con& con);
166   int read_next(Con& con);
167   int read_commit(Con& con);
168   int save_start(Con& con);
169   int save_next(Con& con);
170   int save_commit(Con& con);
171   int cache_init(Con& con);
172   int cache_insert(Con& con);
173   int cache_commit(Con& con);
174 
175   // cache
176   struct Cache {
177     bool m_valid;
178     uint m_keyAttrs;      // number of attrs in index key
179     uint m_valueAttrs;    // number of values
180     uint m_fragCount;     // index fragments
181     uint m_sampleVersion;
182     uint m_sampleCount;   // sample count from head record
183     uint m_keyBytes;      // total key bytes from head record
184     uint m_valueLen;      // value bytes per entry i.e. valueAttrs * ValueSize
185     uint m_valueBytes;    // total value bytes i.e. sampleCount * valuelen
186     uint m_addrLen;       // 1-4 based on keyBytes
187     uint m_addrBytes;     // total address bytes
188     Uint8* m_addrArray;
189     Uint8* m_keyArray;
190     Uint8* m_valueArray;
191     Cache* m_nextClean;
192     // performance
193     mutable Uint64 m_save_time;
194     mutable Uint64 m_sort_time;
195     Cache();
196     // pos is index < sampleCount, addr is offset in keyArray
197     uint get_keyaddr(uint pos) const;
198     void set_keyaddr(uint pos, uint addr);
199     // get pointers to key and value arrays at pos
200     const Uint8* get_keyptr(uint addr) const;
201     Uint8* get_keyptr(uint addr);
202     const Uint8* get_valueptr(uint pos) const;
203     Uint8* get_valueptr(uint pos);
204     // for sort
205     void swap_entry(uint pos1, uint pos2);
206     // get stats values primitives
207     double get_rir(uint pos) const;
208     double get_rir(uint pos1, uint pos2) const;
209     double get_unq(uint pos, uint k) const;
210     double get_unq(uint pos1, uint pos2, uint k) const;
211     double get_rpk(uint pos, uint k) const;
212     double get_rpk(uint pos1, uint pos2, uint k) const;
213   };
214   int cache_cmpaddr(const Cache& c, uint addr1, uint addr2) const;
215   int cache_cmppos(const Cache& c, uint pos1, uint pos2) const;
216   int cache_sort(Cache& c);
217   void cache_isort(Cache& c);
218   void cache_hsort(Cache& c);
219   void cache_hsort_sift(Cache& c, int i, int count);
220   void cache_hsort_verify(Cache& c, int count);
221   int cache_verify(const Cache& c);
222   void move_cache();
223   void clean_cache();
224   void free_cache(Cache* c);
225   void free_cache();
226 
227   // query cache dump (not available via facade)
228   struct CacheIter {
229     Uint32 m_keyCount;
230     Uint32 m_sampleCount;
231     Uint32 m_sampleIndex;
232     NdbPack::DataC m_keyData;
233     NdbPack::DataC m_valueData;
234     CacheIter(const NdbIndexStatImpl& impl);
235   };
236   int dump_cache_start(CacheIter& iter);
237   bool dump_cache_next(CacheIter& iter);
238 
239   // bound
240   struct Bound {
241     NdbPack::Data m_data;
242     NdbPack::Bound m_bound;
243     int m_type;     // 0-lower 1-upper
244     int m_strict;
245     Bound(const NdbPack::Spec& spec);
246   };
247   int finalize_bound(Bound&);
248 
249   // range
250   struct Range {
251     Range(Bound& bound1, Bound& bound2);
252     Bound& m_bound1;
253     Bound& m_bound2;
254   };
255   int finalize_range(Range& range);
256   int convert_range(Range& range,
257                     const NdbRecord* key_record,
258                     const NdbIndexScanOperation::IndexBound* ib);
259 
260   // computed stats values
261   struct StatValue {
262     bool m_empty;
263     double m_rir;
264     double m_unq[MaxKeyCount];
265     StatValue();
266   };
267 
268   // query
269   struct StatBound {
270     uint m_pos;       // non-empty bound is between pos-1,pos
271     uint m_numEqL;    // components matching key at pos-1
272     uint m_numEqH;    // components matching key at pos
273     StatValue m_value;
274     const char* m_rule;
275     StatBound();
276   };
277   struct Stat {
278     StatBound m_stat1;
279     StatBound m_stat2;
280     StatValue m_value;
281     const char* m_rule[3];
282     Stat();
283   };
284   void query_normalize(const Cache&, StatValue&);
285   void query_unq2rpk(const Cache&, StatValue&);
286   int query_stat(const Range&, Stat&);
287   void query_interpolate(const Cache&, const Range&, Stat&);
288   void query_interpolate(const Cache&, const Bound&, StatBound&);
289   void query_search(const Cache&, const Bound&, StatBound&);
290   int query_keycmp(const Cache&, const Bound&, uint pos, Uint32& numEq);
291 
292   // events and polling
293   int create_sysevents(Ndb* ndb);
294   int drop_sysevents(Ndb* ndb);
295   int check_sysevents(Ndb* ndb);
296   //
297   int create_listener(Ndb* ndb);
298   int execute_listener(Ndb* ndb);
299   int poll_listener(Ndb* ndb, int max_wait_ms);
300   int next_listener(Ndb* ndb);
301   int drop_listener(Ndb* ndb);
302 
303   // default memory allocator
304   struct MemDefault : public Mem {
305     virtual void* mem_alloc(UintPtr bytes);
306     virtual void mem_free(void* ptr);
307     MemDefault();
308     virtual ~MemDefault();
309   };
310   MemDefault c_mem_default_handler;
311 
312   // error
313   const NdbIndexStat::Error& getNdbError() const;
314   void setError(int code, int line, int extra = 0);
315   void setError(const Con& con, int line);
316   void mapError(const int* map, int code);
317 
318 // moved from NdbIndexStat.hpp by jonas
319 
320   /* Need 2 words per column in a bound plus space for the
321    * bound data.
322    * Worst case is 32 cols in key and max key size used.
323    */
324   STATIC_CONST( BoundBufWords = (2 * NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY)
325                 + NDB_MAX_KEYSIZE_IN_WORDS );
326 };
327 
328 inline
Bound(const NdbPack::Spec & spec)329 NdbIndexStatImpl::Bound::Bound(const NdbPack::Spec& spec) :
330   m_data(spec, true, 0),
331   m_bound(m_data)
332 {
333   m_type = -1;
334   m_strict = -1;
335 }
336 
337 inline
Range(Bound & bound1,Bound & bound2)338 NdbIndexStatImpl::Range::Range(Bound& bound1, Bound& bound2) :
339   m_bound1(bound1),
340   m_bound2(bound2)
341 {
342   bound1.m_type = 0;
343   bound2.m_type = 1;
344 }
345 
346 inline int
finalize_range(Range & range)347 NdbIndexStatImpl::finalize_range(Range& range)
348 {
349   if (finalize_bound(range.m_bound1) == -1)
350     return -1;
351   if (finalize_bound(range.m_bound2) == -1)
352     return -1;
353   return 0;
354 }
355 
356 inline
StatValue()357 NdbIndexStatImpl::StatValue::StatValue()
358 {
359   m_empty = false;
360 }
361 
362 inline
StatBound()363 NdbIndexStatImpl::StatBound::StatBound()
364 {
365   m_pos = 0;
366   m_numEqL = 0;
367   m_numEqH = 0;
368 }
369 
370 inline
Stat()371 NdbIndexStatImpl::Stat::Stat()
372 {
373   m_rule[0] = 0;
374   m_rule[1] = 0;
375   m_rule[2] = 0;
376 }
377 
378 #endif
379