CUBRID Engine  latest
monitor_transaction.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 //
20 // monitor_transaction.hpp - interface for managing separate sheets of statistics for active transactions.
21 //
22 // cubrid monitoring module collects by default so called global statistics. in special circumstances, separate set
23 // of statistics may be tracked for one or more transactions.
24 //
25 // this interface provides statistics that can collect to separate transaction sheets automatically.
26 //
27 // to keep memory footprint as reduced as possible, statistics extend the number of sheets dynamically, based on
28 // requirements. in most workloads, no or just few extra sheets will be created.
29 //
30 // IMPORTANT - sheets are reused in order to avoid allocating more than necessary. as consequence, a reused sheet
31 // will inherit values from previous usage. the correct way of inspecting the execution of a transaction
32 // or thread is to fetch two snapshots, once at the beginning and once at the end and do the difference
33 // between snapshots.
34 //
35 
36 #if !defined _MONITOR_TRANSACTION_HPP_
37 #define _MONITOR_TRANSACTION_HPP_
38 
39 #include "monitor_statistic.hpp"
40 
41 #include <limits>
42 #include <mutex>
43 
44 #include <cassert>
45 #include <cstring>
46 
47 namespace cubmonitor
48 {
49  using transaction_sheet = std::size_t; // transaction sheet identifier type
50 
51  //
52  // sheet_manager - manage statistic sheets for transaction watchers
53  //
55  {
56  public:
57  // INVALID_SHEET - value to define no or invalid sheet
59  static const std::size_t MAX_SHEETS = 1024; // maximum number of sheets allowed
60  // note - we can consider reducing this
61 
62  static bool start_watch (void); // start watching on current transaction
63  // note - current thread should be assigned a transaction
64  // watch is re-entrant
65 
66  static void end_watch (bool end_all = false); // end watching on current transaction
67  // note - current thread should be assigned a transaction
68  // when end_all is true, all started watches are cleared
69 
70  static transaction_sheet get_sheet (void); // get current transaction sheet
71  // note - if current thread is not assigned a transaction or
72  // if transaction is not watching, INVALID_SHEET is
73  // returned.
74 
75  private:
76 
77  transaction_sheet_manager (void) = delete; // entirely static class; no instances are permitted
78 
79  static void static_init (void); // automatically initialized on first usage
80 
81  static std::size_t s_current_sheet_count; // current count of opened sheets
82  static unsigned s_sheet_start_count[MAX_SHEETS]; // watch counts for each [open] sheet
83 
84  static std::size_t s_transaction_count; // total transaction count
85  static transaction_sheet *s_transaction_sheets; // assigned sheets to each transaction
86 
87  static std::mutex s_sheets_mutex; // mutex to protect concurrent start/end watch
88  };
89 
90  //
91  // transaction_statistic - wrapper class over one statistic that can store statistics for transaction sheets
92  //
93  // transaction statistic instance always starts with a single statistic - the global statistic. if transactions
94  // start separate sheets during collection, the statistics storage is extended to required size.
95  //
96  // fetching a value for a sheet that does not exist return 0 without extending
97  //
98  template <class S>
100  {
101  public:
102  using statistic_type = S; // base statistic type
103 
104  transaction_statistic (void); // constructor
105  ~transaction_statistic (void); // destructor
106 
107  // fetchable concept
108  void fetch (statistic_value *destination, fetch_mode mode = FETCH_GLOBAL) const;
109  std::size_t get_statistics_count (void) const;
110 
111  typename statistic_type::rep get_value (fetch_mode mode = FETCH_GLOBAL) const;
112 
113  void collect (const typename statistic_type::rep &value); // collect to global statistic and to transaction
114  // sheet (if open)
115 
116  private:
117 
118  void extend (std::size_t to); // extend statistics array to given size
119  // note - extensions are synchronized
120 
121  statistic_type m_global_stat; // global statistic
122  statistic_type *m_sheet_stats; // separate sheet statistics
123  std::size_t m_sheet_stats_count; // current size of m_sheet_stats
124  std::mutex m_extend_mutex; // mutex protecting extensions
125  };
126 
128  // template/inline implementation
130 
132  // transaction_statistic
134 
135  template <class S>
137  : m_global_stat ()
138  , m_sheet_stats (NULL)
139  , m_sheet_stats_count (0)
140  , m_extend_mutex ()
141  {
142  //
143  }
144 
145  template <class S>
147  {
148  delete [] m_sheet_stats;
149  }
150 
151  template <class S>
152  void
154  {
155  assert (to > 0);
156 
157  std::unique_lock<std::mutex> ulock (m_extend_mutex);
158 
160  {
161  // to be on safe side
162  assert (false);
164  }
165 
166  if (to <= m_sheet_stats_count)
167  {
168  // already extended
169  return;
170  }
171 
172  // allocate new buffer
173  statistic_type *new_collectors = new statistic_type[to];
174  if (m_sheet_stats_count != 0)
175  {
176  // copy old buffer
177  for (std::size_t i = 0; i < m_sheet_stats_count; ++i)
178  {
179  new_collectors[i] = m_sheet_stats[i];
180  }
181  }
182 
183  // delete old buffer
184  delete [] m_sheet_stats;
185 
186  // update buffer
187  m_sheet_stats = new_collectors;
188  m_sheet_stats_count = to;
189  }
190 
191  template <class S>
192  void
193  transaction_statistic<S>::fetch (statistic_value *destination, fetch_mode mode /* = FETCH_GLOBAL */) const
194  {
195  if (mode == FETCH_GLOBAL)
196  {
197  m_global_stat.fetch (destination);
198  }
199  else
200  {
202 
204  {
205  // transaction is not watching
206  return;
207  }
208 
209  if (m_sheet_stats_count <= sheet)
210  {
211  // nothing was collected
212  return;
213  }
214 
215  // return collected value
216  m_sheet_stats[sheet].fetch (destination, FETCH_GLOBAL);
217  }
218  }
219 
220  template <class S>
221  typename S::rep
223  {
224  if (mode == FETCH_GLOBAL)
225  {
226  return m_global_stat.get_value ();
227  }
228  else
229  {
231 
233  {
234  // transaction is not watching
235  return typename statistic_type::rep ();
236  }
237 
238  if (m_sheet_stats_count <= sheet)
239  {
240  // nothing was collected
241  return typename statistic_type::rep ();
242  }
243 
244  // return collected value
245  return m_sheet_stats[sheet].get_value ();
246  }
247  }
248 
249  template <class S>
250  std::size_t
252  {
253  return 1;
254  }
255 
256  template <class S>
257  void
258  transaction_statistic<S>::collect (const typename statistic_type::rep &value)
259  {
260  m_global_stat.collect (value);
261 
264  {
265  if (sheet >= m_sheet_stats_count)
266  {
267  extend (sheet + 1);
268  }
269  m_sheet_stats[sheet].collect (value);
270  }
271  }
272 
273 } // namespace cubmonitor
274 
275 #endif // _MONITOR_TRANSACTION_HPP_
static const transaction_sheet INVALID_TRANSACTION_SHEET
const fetch_mode FETCH_GLOBAL
static API_MUTEX mutex
Definition: api_util.c:72
static transaction_sheet get_sheet(void)
std::uint64_t statistic_value
statistic_type::rep get_value(fetch_mode mode=FETCH_GLOBAL) const
static void end_watch(bool end_all=false)
#define assert(x)
static unsigned s_sheet_start_count[MAX_SHEETS]
static enum scanner_mode mode
void collect(const typename statistic_type::rep &value)
#define NULL
Definition: freelistheap.h:34
static transaction_sheet * s_transaction_sheets
#define max(a, b)
void fetch(statistic_value *destination, fetch_mode mode=FETCH_GLOBAL) const
std::size_t get_statistics_count(void) const
int i
Definition: dynamic_load.c:954
std::size_t transaction_sheet