1 /*
2    Copyright (c) 2015, Facebook, Inc.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
16 #pragma once
17 
18 /* C++ system header files */
19 #include <map>
20 #include <memory>
21 #include <string>
22 #include <unordered_set>
23 #include <vector>
24 
25 /* RocksDB header files */
26 #include "rocksdb/db.h"
27 
28 /* MyRocks header files */
29 #include "./ha_rocksdb.h"
30 
31 namespace myrocks {
32 
33 class Rdb_ddl_manager;
34 class Rdb_key_def;
35 
36 extern std::atomic<uint64_t> rocksdb_num_sst_entry_put;
37 extern std::atomic<uint64_t> rocksdb_num_sst_entry_delete;
38 extern std::atomic<uint64_t> rocksdb_num_sst_entry_singledelete;
39 extern std::atomic<uint64_t> rocksdb_num_sst_entry_merge;
40 extern std::atomic<uint64_t> rocksdb_num_sst_entry_other;
41 extern my_bool rocksdb_compaction_sequential_deletes_count_sd;
42 
43 struct Rdb_compact_params {
44   uint64_t m_deletes, m_window, m_file_size;
45 };
46 
47 struct Rdb_index_stats {
48   enum {
49     INDEX_STATS_VERSION_INITIAL = 1,
50     INDEX_STATS_VERSION_ENTRY_TYPES = 2,
51   };
52   GL_INDEX_ID m_gl_index_id;
53   int64_t m_data_size, m_rows, m_actual_disk_size;
54   int64_t m_entry_deletes, m_entry_single_deletes;
55   int64_t m_entry_merges, m_entry_others;
56   std::vector<int64_t> m_distinct_keys_per_prefix;
57   std::string m_name;  // name is not persisted
58 
59   static std::string materialize(const std::vector<Rdb_index_stats> &stats);
60   static int unmaterialize(const std::string &s,
61                            std::vector<Rdb_index_stats> *const ret);
62 
63   Rdb_index_stats() : Rdb_index_stats({0, 0}) {}
64   explicit Rdb_index_stats(GL_INDEX_ID gl_index_id)
65       : m_gl_index_id(gl_index_id),
66         m_data_size(0),
67         m_rows(0),
68         m_actual_disk_size(0),
69         m_entry_deletes(0),
70         m_entry_single_deletes(0),
71         m_entry_merges(0),
72         m_entry_others(0) {}
73 
74   void merge(const Rdb_index_stats &s, const bool increment = true,
75              const int64_t estimated_data_len = 0);
76 };
77 
78 // The helper class to calculate index cardinality
79 class Rdb_tbl_card_coll {
80  public:
81   explicit Rdb_tbl_card_coll(const uint8_t table_stats_sampling_pct);
82 
83  public:
84   void ProcessKey(const rocksdb::Slice &key, const Rdb_key_def *keydef,
85                   Rdb_index_stats *stats);
86   /*
87    * Resets the state of the collector to start calculating statistics for a
88    * next index.
89    */
90   void Reset();
91 
92   /*
93    * Cardinality statistics might be calculated using some sampling strategy.
94    * This method adjusts gathered statistics according to the sampling
95    * strategy used. Note that adjusted cardinality value is just an estimate
96    * and can return a value exeeding number of rows in a table, so the
97    * returned value should be capped by row count before using it by
98    * an optrimizer or displaying it to a clent.
99    */
100   void AdjustStats(Rdb_index_stats *stats);
101 
102  private:
103   bool ShouldCollectStats();
104   bool IsSampingDisabled();
105 
106  private:
107   std::string m_last_key;
108   uint8_t m_table_stats_sampling_pct;
109   unsigned int m_seed;
110 };
111 
112 class Rdb_tbl_prop_coll : public rocksdb::TablePropertiesCollector {
113  public:
114   Rdb_tbl_prop_coll(Rdb_ddl_manager *const ddl_manager,
115                     const Rdb_compact_params &params, const uint32_t cf_id,
116                     const uint8_t table_stats_sampling_pct);
117 
118   /*
119     Override parent class's virtual methods of interest.
120   */
121 
122   virtual rocksdb::Status AddUserKey(const rocksdb::Slice &key,
123                                      const rocksdb::Slice &value,
124                                      rocksdb::EntryType type,
125                                      rocksdb::SequenceNumber seq,
126                                      uint64_t file_size) override;
127 
128   virtual rocksdb::Status Finish(
129       rocksdb::UserCollectedProperties *properties) override;
130 
131   virtual const char *Name() const override { return "Rdb_tbl_prop_coll"; }
132 
133   rocksdb::UserCollectedProperties GetReadableProperties() const override;
134 
135   bool NeedCompact() const override;
136 
137  public:
138   uint64_t GetMaxDeletedRows() const { return m_max_deleted_rows; }
139 
140   static void read_stats_from_tbl_props(
141       const std::shared_ptr<const rocksdb::TableProperties> &table_props,
142       std::vector<Rdb_index_stats> *out_stats_vector);
143 
144  private:
145   static std::string GetReadableStats(const Rdb_index_stats &it);
146 
147   bool ShouldCollectStats();
148   void CollectStatsForRow(const rocksdb::Slice &key,
149                           const rocksdb::Slice &value,
150                           const rocksdb::EntryType &type,
151                           const uint64_t file_size);
152   Rdb_index_stats *AccessStats(const rocksdb::Slice &key);
153   void AdjustDeletedRows(rocksdb::EntryType type);
154 
155  private:
156   uint32_t m_cf_id;
157   std::shared_ptr<const Rdb_key_def> m_keydef;
158   Rdb_ddl_manager *m_ddl_manager;
159   std::vector<Rdb_index_stats> m_stats;
160   Rdb_index_stats *m_last_stats;
161   static const char *INDEXSTATS_KEY;
162 
163   // last added key
164   std::string m_last_key;
165 
166   // floating window to count deleted rows
167   std::vector<bool> m_deleted_rows_window;
168   uint64_t m_rows, m_window_pos, m_deleted_rows, m_max_deleted_rows;
169   uint64_t m_file_size;
170   Rdb_compact_params m_params;
171   Rdb_tbl_card_coll m_cardinality_collector;
172   bool m_recorded;
173 };
174 
175 class Rdb_tbl_prop_coll_factory
176     : public rocksdb::TablePropertiesCollectorFactory {
177  public:
178   Rdb_tbl_prop_coll_factory(const Rdb_tbl_prop_coll_factory &) = delete;
179   Rdb_tbl_prop_coll_factory &operator=(const Rdb_tbl_prop_coll_factory &) =
180       delete;
181 
182   explicit Rdb_tbl_prop_coll_factory(Rdb_ddl_manager *ddl_manager)
183       : m_ddl_manager(ddl_manager) {}
184 
185   /*
186     Override parent class's virtual methods of interest.
187   */
188 
189   virtual rocksdb::TablePropertiesCollector *CreateTablePropertiesCollector(
190       rocksdb::TablePropertiesCollectorFactory::Context context) override {
191     return new Rdb_tbl_prop_coll(m_ddl_manager, m_params,
192                                  context.column_family_id,
193                                  m_table_stats_sampling_pct);
194   }
195 
196   virtual const char *Name() const override {
197     return "Rdb_tbl_prop_coll_factory";
198   }
199 
200  public:
201   void SetCompactionParams(const Rdb_compact_params &params) {
202     m_params = params;
203   }
204 
205   void SetTableStatsSamplingPct(const uint8_t table_stats_sampling_pct) {
206     m_table_stats_sampling_pct = table_stats_sampling_pct;
207   }
208 
209  private:
210   Rdb_ddl_manager *const m_ddl_manager;
211   Rdb_compact_params m_params;
212   uint8_t m_table_stats_sampling_pct;
213 };
214 
215 }  // namespace myrocks
216