YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/util/object_pool.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  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,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
//
18
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
// Simple pool/freelist for objects of the same type, typically used
33
// in local context.
34
#ifndef YB_UTIL_OBJECT_POOL_H
35
#define YB_UTIL_OBJECT_POOL_H
36
37
#include <stdint.h>
38
39
#include <functional>
40
41
#if defined(__APPLE__)
42
#include <thread>
43
#else
44
#include <sched.h>
45
#endif
46
47
#include <boost/container/stable_vector.hpp>
48
#include <boost/lockfree/stack.hpp>
49
50
#include "yb/gutil/manual_constructor.h"
51
#include "yb/gutil/sysinfo.h"
52
53
namespace yb {
54
55
using base::ManualConstructor;
56
57
template<class T>
58
class ReturnToPool;
59
60
// An object pool allocates and destroys a single class of objects
61
// off of a free-list.
62
//
63
// Upon destruction of the pool, any objects allocated from this pool are
64
// destroyed, regardless of whether they have been explicitly returned to the
65
// pool.
66
//
67
// This class is similar to the boost::pool::object_pool, except that the boost
68
// implementation seems to have O(n) deallocation performance and benchmarked
69
// really poorly.
70
//
71
// This class is not thread-safe.
72
template<typename T>
73
class ObjectPool {
74
 public:
75
  typedef ReturnToPool<T> deleter_type;
76
  typedef std::unique_ptr<T, deleter_type> scoped_ptr;
77
78
  ObjectPool() :
79
    free_list_head_(NULL),
80
    alloc_list_head_(NULL),
81
    deleter_(this) {
82
  }
83
84
  ~ObjectPool() {
85
    // Delete all objects ever allocated from this pool
86
    ListNode *node = alloc_list_head_;
87
    while (node != NULL) {
88
      ListNode *tmp = node;
89
      node = node->next_on_alloc_list;
90
      if (!tmp->is_on_freelist) {
91
        // Have to run the actual destructor if the user forgot to free it.
92
        tmp->Destroy();
93
      }
94
      delete tmp;
95
    }
96
  }
97
98
  // Construct a new object instance from the pool.
99
  T *Construct() {
100
    ManualConstructor<T> *obj = GetObject();
101
    obj->Init();
102
    return obj->get();
103
  }
104
105
  template<class Arg1>
106
  T *Construct(Arg1 arg1) {
107
    ManualConstructor<T> *obj = GetObject();
108
    obj->Init(arg1);
109
    return obj->get();
110
  }
111
112
  // Destroy an object, running its destructor and returning it to the
113
  // free-list.
114
  void Destroy(T *t) {
115
    CHECK_NOTNULL(t);
116
    ListNode *node = static_cast<ListNode *>(
117
      reinterpret_cast<ManualConstructor<T> *>(t));
118
119
    node->Destroy();
120
121
    DCHECK(!node->is_on_freelist);
122
    node->is_on_freelist = true;
123
    node->next_on_free_list = free_list_head_;
124
    free_list_head_ = node;
125
  }
126
127
  // Create a scoped_ptr wrapper around the given pointer which came from this
128
  // pool.
129
  // When the scoped_ptr goes out of scope, the object will get released back
130
  // to the pool.
131
  scoped_ptr make_scoped_ptr(T *ptr) {
132
    return scoped_ptr(ptr, deleter_);
133
  }
134
135
 private:
136
  class ListNode : ManualConstructor<T> {
137
    friend class ObjectPool<T>;
138
139
    ListNode *next_on_free_list;
140
    ListNode *next_on_alloc_list;
141
142
    bool is_on_freelist;
143
  };
144
145
146
  ManualConstructor<T> *GetObject() {
147
    if (free_list_head_ != NULL) {
148
      ListNode *tmp = free_list_head_;
149
      free_list_head_ = tmp->next_on_free_list;
150
      tmp->next_on_free_list = NULL;
151
      DCHECK(tmp->is_on_freelist);
152
      tmp->is_on_freelist = false;
153
154
      return static_cast<ManualConstructor<T> *>(tmp);
155
    }
156
    auto new_node = new ListNode();
157
    new_node->next_on_free_list = NULL;
158
    new_node->next_on_alloc_list = alloc_list_head_;
159
    new_node->is_on_freelist = false;
160
    alloc_list_head_ = new_node;
161
    return new_node;
162
  }
163
164
  // Keeps track of free objects in this pool.
165
  ListNode *free_list_head_;
166
167
  // Keeps track of all objects ever allocated by this pool.
168
  ListNode *alloc_list_head_;
169
170
  deleter_type deleter_;
171
};
172
173
// Functor which returns the passed objects to a specific object pool.
174
// This can be used in conjunction with scoped_ptr to automatically release
175
// an object back to a pool when it goes out of scope.
176
template<class T>
177
class ReturnToPool {
178
 public:
179
  explicit ReturnToPool(ObjectPool<T> *pool) :
180
    pool_(pool) {
181
  }
182
183
  inline void operator()(T *ptr) const {
184
    pool_->Destroy(ptr);
185
  }
186
187
 private:
188
  ObjectPool<T> *pool_;
189
};
190
191
template <class T>
192
struct DefaultFactory {
193
1
  T* operator()() const {
194
1
    return new T;
195
1
  }
196
};
197
198
template <class T>
199
class ThreadSafeObjectPool {
200
 public:
201
  typedef std::function<T*()> Factory;
202
  typedef std::function<void(T*)> Deleter;
203
204
  explicit ThreadSafeObjectPool(Factory factory = DefaultFactory<T>(),
205
                                Deleter deleter = std::default_delete<T>())
206
20.2k
      : factory_(std::move(factory)), deleter_(std::move(deleter)) {
207
    // Need the actual number of CPUs, so we do not use the Gflag value
208
20.2k
    size_t num_cpus = base::RawNumCPUs();
209
20.2k
    pools_.reserve(num_cpus);
210
222k
    while (pools_.size() != num_cpus) {
211
202k
      pools_.emplace_back(50);
212
202k
    }
213
20.2k
  }
yb::ThreadSafeObjectPool<yb::ql::Parser>::ThreadSafeObjectPool(std::__1::function<yb::ql::Parser* ()>, std::__1::function<void (yb::ql::Parser*)>)
Line
Count
Source
206
15.4k
      : factory_(std::move(factory)), deleter_(std::move(deleter)) {
207
    // Need the actual number of CPUs, so we do not use the Gflag value
208
15.4k
    size_t num_cpus = base::RawNumCPUs();
209
15.4k
    pools_.reserve(num_cpus);
210
169k
    while (pools_.size() != num_cpus) {
211
154k
      pools_.emplace_back(50);
212
154k
    }
213
15.4k
  }
yb::ThreadSafeObjectPool<yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits> >::ThreadSafeObjectPool(std::__1::function<yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits>* ()>, std::__1::function<void (yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits>*)>)
Line
Count
Source
206
4.82k
      : factory_(std::move(factory)), deleter_(std::move(deleter)) {
207
    // Need the actual number of CPUs, so we do not use the Gflag value
208
4.82k
    size_t num_cpus = base::RawNumCPUs();
209
4.82k
    pools_.reserve(num_cpus);
210
53.0k
    while (pools_.size() != num_cpus) {
211
48.1k
      pools_.emplace_back(50);
212
48.1k
    }
213
4.82k
  }
214
215
2.20k
  ~ThreadSafeObjectPool() {
216
2.20k
    T* object;
217
22.0k
    for (auto& pool : pools_) {
218
84.2k
      while (pool.pop(object)) {
219
62.1k
        deleter_(object);
220
62.1k
      }
221
22.0k
    }
222
2.20k
  }
yb::ThreadSafeObjectPool<yb::ql::Parser>::~ThreadSafeObjectPool()
Line
Count
Source
215
501
  ~ThreadSafeObjectPool() {
216
501
    T* object;
217
5.01k
    for (auto& pool : pools_) {
218
5.01k
      while (pool.pop(object)) {
219
1
        deleter_(object);
220
1
      }
221
5.01k
    }
222
501
  }
yb::ThreadSafeObjectPool<yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits> >::~ThreadSafeObjectPool()
Line
Count
Source
215
1.70k
  ~ThreadSafeObjectPool() {
216
1.70k
    T* object;
217
17.0k
    for (auto& pool : pools_) {
218
79.1k
      while (pool.pop(object)) {
219
62.1k
        deleter_(object);
220
62.1k
      }
221
17.0k
    }
222
1.70k
  }
223
224
90.1M
  T* Take() {
225
90.1M
    auto& pool = pools_[GetCPU()];
226
90.1M
    T* result;
227
90.1M
    if (pool.pop(result)) {
228
63.4M
      return result;
229
63.4M
    }
230
26.6M
    return factory_();
231
90.1M
  }
yb::ThreadSafeObjectPool<yb::ql::Parser>::Take()
Line
Count
Source
224
342k
  T* Take() {
225
342k
    auto& pool = pools_[GetCPU()];
226
342k
    T* result;
227
342k
    if (pool.pop(result)) {
228
324k
      return result;
229
324k
    }
230
18.4k
    return factory_();
231
342k
  }
yb::ThreadSafeObjectPool<yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits> >::Take()
Line
Count
Source
224
89.7M
  T* Take() {
225
89.7M
    auto& pool = pools_[GetCPU()];
226
89.7M
    T* result;
227
89.7M
    if (pool.pop(result)) {
228
63.1M
      return result;
229
63.1M
    }
230
26.6M
    return factory_();
231
89.7M
  }
232
233
90.0M
  void Release(T* value) {
234
90.0M
    auto& pool = pools_[GetCPU()];
235
90.0M
    if (!pool.bounded_push(value)) {
236
26.2M
      deleter_(value);
237
26.2M
    }
238
90.0M
  }
yb::ThreadSafeObjectPool<yb::ql::Parser>::Release(yb::ql::Parser*)
Line
Count
Source
233
338k
  void Release(T* value) {
234
338k
    auto& pool = pools_[GetCPU()];
235
338k
    if (!pool.bounded_push(value)) {
236
0
      deleter_(value);
237
0
    }
238
338k
  }
yb::ThreadSafeObjectPool<yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits> >::Release(yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits>*)
Line
Count
Source
233
89.7M
  void Release(T* value) {
234
89.7M
    auto& pool = pools_[GetCPU()];
235
89.7M
    if (!pool.bounded_push(value)) {
236
26.2M
      deleter_(value);
237
26.2M
    }
238
89.7M
  }
239
240
 private:
241
180M
  size_t GetCPU() const {
242
180M
#if defined(__APPLE__)
243
    // OSX doesn't have a way to get the CPU, so we'll pick a random one.
244
180M
    return std::hash<std::thread::id>()(std::this_thread::get_id()) % pools_.size();
245
#else
246
    size_t cpu = sched_getcpu();
247
    DCHECK_LT(cpu, pools_.size());
248
    return cpu;
249
#endif // defined(__APPLE__)
250
180M
  }
yb::ThreadSafeObjectPool<yb::ql::Parser>::GetCPU() const
Line
Count
Source
241
683k
  size_t GetCPU() const {
242
683k
#if defined(__APPLE__)
243
    // OSX doesn't have a way to get the CPU, so we'll pick a random one.
244
683k
    return std::hash<std::thread::id>()(std::this_thread::get_id()) % pools_.size();
245
#else
246
    size_t cpu = sched_getcpu();
247
    DCHECK_LT(cpu, pools_.size());
248
    return cpu;
249
#endif // defined(__APPLE__)
250
683k
  }
yb::ThreadSafeObjectPool<yb::internal::ArenaBase<yb::internal::ThreadSafeArenaTraits> >::GetCPU() const
Line
Count
Source
241
179M
  size_t GetCPU() const {
242
179M
#if defined(__APPLE__)
243
    // OSX doesn't have a way to get the CPU, so we'll pick a random one.
244
179M
    return std::hash<std::thread::id>()(std::this_thread::get_id()) % pools_.size();
245
#else
246
    size_t cpu = sched_getcpu();
247
    DCHECK_LT(cpu, pools_.size());
248
    return cpu;
249
#endif // defined(__APPLE__)
250
179M
  }
251
252
  typedef boost::lockfree::stack<T*> Pool;
253
254
  Factory factory_;
255
  Deleter deleter_;
256
  boost::container::stable_vector<Pool> pools_;
257
};
258
259
} // namespace yb
260
261
#endif // YB_UTIL_OBJECT_POOL_H