/src/brpc/src/butil/resource_pool.h
Line | Count | Source (jump to first uncovered line) |
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 | | // bthread - An M:N threading library to make applications more concurrent. |
19 | | |
20 | | // Date: Sun Jul 13 15:04:18 CST 2014 |
21 | | |
22 | | #ifndef BUTIL_RESOURCE_POOL_H |
23 | | #define BUTIL_RESOURCE_POOL_H |
24 | | |
25 | | #include <cstddef> // size_t |
26 | | |
27 | | // Efficiently allocate fixed-size (small) objects addressable by identifiers |
28 | | // in multi-threaded environment. |
29 | | // |
30 | | // Comparison with new/delete(glibc 2.3.4) under high contention: |
31 | | // ----------------------------- |
32 | | // get<int>=26.1 return<int>=4.7 |
33 | | // get<int>=46.1 return<int>=5.4 |
34 | | // get<int>=27.5 return<int>=5.3 |
35 | | // get<int>=24.8 return<int>=6.5 |
36 | | // get<int>=26.6 return<int>=5.3 |
37 | | // get<int>=24.7 return<int>=4.9 |
38 | | // get<int>=67.8 return<int>=5.5 |
39 | | // get<int>=36.7 return<int>=5.0 |
40 | | // -------------------------------- |
41 | | // new<int>=295.0 delete<int>=234.5 |
42 | | // new<int>=299.2 delete<int>=359.7 |
43 | | // new<int>=288.1 delete<int>=219.0 |
44 | | // new<int>=298.6 delete<int>=428.0 |
45 | | // new<int>=319.2 delete<int>=426.5 |
46 | | // new<int>=293.9 delete<int>=651.8 |
47 | | // new<int>=304.9 delete<int>=672.8 |
48 | | // new<int>=170.6 delete<int>=292.8 |
49 | | // -------------------------------- |
50 | | |
51 | | namespace butil { |
52 | | |
53 | | // Specialize following classes to override default parameters for type T. |
54 | | // namespace butil { |
55 | | // template <> struct ResourcePoolBlockMaxSize<Foo> { |
56 | | // static const size_t value = 1024; |
57 | | // }; |
58 | | // } |
59 | | |
60 | | // Memory is allocated in blocks, memory size of a block will not exceed: |
61 | | // min(ResourcePoolBlockMaxSize<T>::value, |
62 | | // ResourcePoolBlockMaxItem<T>::value * sizeof(T)) |
63 | | template <typename T> struct ResourcePoolBlockMaxSize { |
64 | | static const size_t value = 64 * 1024; // bytes |
65 | | }; |
66 | | template <typename T> struct ResourcePoolBlockMaxItem { |
67 | | static const size_t value = 256; |
68 | | }; |
69 | | |
70 | | // Free objects of each thread are grouped into a chunk before they are merged |
71 | | // to the global list. Memory size of objects in one free chunk will not exceed: |
72 | | // min(ResourcePoolFreeChunkMaxItem<T>::value(), |
73 | | // ResourcePoolBlockMaxSize<T>::value, |
74 | | // ResourcePoolBlockMaxItem<T>::value * sizeof(T)) |
75 | | template <typename T> struct ResourcePoolFreeChunkMaxItem { |
76 | 0 | static size_t value() { return 256; } Unexecuted instantiation: butil::ResourcePoolFreeChunkMaxItem<bthread::TaskMeta>::value() Unexecuted instantiation: butil::ResourcePoolFreeChunkMaxItem<bthread::TimerThread::Task>::value() Unexecuted instantiation: butil::ResourcePoolFreeChunkMaxItem<brpc::IOEventData>::value() Unexecuted instantiation: butil::ResourcePoolFreeChunkMaxItem<brpc::Socket>::value() Unexecuted instantiation: butil::ResourcePoolFreeChunkMaxItem<butil::details::ExtendedEndPoint>::value() Unexecuted instantiation: butil::ResourcePoolFreeChunkMaxItem<bthread::ExecutionQueueBase>::value() Unexecuted instantiation: butil::ResourcePoolFreeChunkMaxItem<bthread::Id>::value() |
77 | | }; |
78 | | |
79 | | // ResourcePool calls this function on newly constructed objects. If this |
80 | | // function returns false, the object is destructed immediately and |
81 | | // get_resource() shall return NULL. This is useful when the constructor |
82 | | // failed internally(namely ENOMEM). |
83 | | template <typename T> struct ResourcePoolValidator { |
84 | 0 | static bool validate(const T*) { return true; } Unexecuted instantiation: butil::ResourcePoolValidator<bthread::TaskMeta>::validate(bthread::TaskMeta const*) Unexecuted instantiation: butil::ResourcePoolValidator<bthread::TimerThread::Task>::validate(bthread::TimerThread::Task const*) Unexecuted instantiation: butil::ResourcePoolValidator<brpc::Socket>::validate(brpc::Socket const*) Unexecuted instantiation: butil::ResourcePoolValidator<brpc::IOEventData>::validate(brpc::IOEventData const*) Unexecuted instantiation: butil::ResourcePoolValidator<butil::details::ExtendedEndPoint>::validate(butil::details::ExtendedEndPoint const*) Unexecuted instantiation: butil::ResourcePoolValidator<bthread::ExecutionQueueBase>::validate(bthread::ExecutionQueueBase const*) Unexecuted instantiation: butil::ResourcePoolValidator<bthread::Id>::validate(bthread::Id const*) |
85 | | }; |
86 | | |
87 | | } // namespace butil |
88 | | |
89 | | #include "butil/resource_pool_inl.h" |
90 | | |
91 | | namespace butil { |
92 | | |
93 | | // Get an object typed |T| and write its identifier into |id|. |
94 | | // The object should be cleared before usage. |
95 | | // NOTE: If there are no arguments, T must be default-constructible. |
96 | | template <typename T, typename... Args> |
97 | 0 | inline T* get_resource(ResourceId<T>* id, Args&&... args) { |
98 | 0 | return ResourcePool<T>::singleton()->get_resource(id, std::forward<Args>(args)...); |
99 | 0 | } Unexecuted instantiation: bthread::TaskMeta* butil::get_resource<bthread::TaskMeta>(butil::ResourceId<bthread::TaskMeta>*) Unexecuted instantiation: bthread::TimerThread::Task* butil::get_resource<bthread::TimerThread::Task>(butil::ResourceId<bthread::TimerThread::Task>*) Unexecuted instantiation: brpc::Socket* butil::get_resource<brpc::Socket, brpc::VersionedRefWithId<brpc::Socket>::Forbidden>(butil::ResourceId<brpc::Socket>*, brpc::VersionedRefWithId<brpc::Socket>::Forbidden&&) Unexecuted instantiation: brpc::IOEventData* butil::get_resource<brpc::IOEventData, brpc::VersionedRefWithId<brpc::IOEventData>::Forbidden>(butil::ResourceId<brpc::IOEventData>*, brpc::VersionedRefWithId<brpc::IOEventData>::Forbidden&&) Unexecuted instantiation: butil::details::ExtendedEndPoint* butil::get_resource<butil::details::ExtendedEndPoint>(butil::ResourceId<butil::details::ExtendedEndPoint>*) Unexecuted instantiation: bthread::ExecutionQueueBase* butil::get_resource<bthread::ExecutionQueueBase, bthread::ExecutionQueueBase::Forbidden>(butil::ResourceId<bthread::ExecutionQueueBase>*, bthread::ExecutionQueueBase::Forbidden&&) Unexecuted instantiation: bthread::Id* butil::get_resource<bthread::Id>(butil::ResourceId<bthread::Id>*) |
100 | | |
101 | | // Return the object associated with identifier |id| back. The object is NOT |
102 | | // destructed and will be returned by later get_resource<T>. Similar with |
103 | | // free/delete, validity of the id is not checked, user shall not return a |
104 | | // not-yet-allocated or already-returned id otherwise behavior is undefined. |
105 | | // Returns 0 when successful, -1 otherwise. |
106 | 0 | template <typename T> inline int return_resource(ResourceId<T> id) { |
107 | 0 | return ResourcePool<T>::singleton()->return_resource(id); |
108 | 0 | } Unexecuted instantiation: int butil::return_resource<bthread::TaskMeta>(butil::ResourceId<bthread::TaskMeta>) Unexecuted instantiation: int butil::return_resource<bthread::TimerThread::Task>(butil::ResourceId<bthread::TimerThread::Task>) Unexecuted instantiation: int butil::return_resource<brpc::IOEventData>(butil::ResourceId<brpc::IOEventData>) Unexecuted instantiation: int butil::return_resource<brpc::Socket>(butil::ResourceId<brpc::Socket>) Unexecuted instantiation: int butil::return_resource<butil::details::ExtendedEndPoint>(butil::ResourceId<butil::details::ExtendedEndPoint>) Unexecuted instantiation: int butil::return_resource<bthread::ExecutionQueueBase>(butil::ResourceId<bthread::ExecutionQueueBase>) Unexecuted instantiation: int butil::return_resource<bthread::Id>(butil::ResourceId<bthread::Id>) |
109 | | |
110 | | // Get the object associated with the identifier |id|. |
111 | | // Returns NULL if |id| was not allocated by get_resource<T> or |
112 | | // ResourcePool<T>::get_resource() of a variant before. |
113 | | // Addressing a free(returned to pool) identifier does not return NULL. |
114 | | // NOTE: Calling this function before any other get_resource<T>/ |
115 | | // return_resource<T>/address<T>, even if the identifier is valid, |
116 | | // may race with another thread calling clear_resources<T>. |
117 | 0 | template <typename T> inline T* address_resource(ResourceId<T> id) { |
118 | 0 | return ResourcePool<T>::address_resource(id); |
119 | 0 | } Unexecuted instantiation: bthread::TaskMeta* butil::address_resource<bthread::TaskMeta>(butil::ResourceId<bthread::TaskMeta>) Unexecuted instantiation: bthread::TimerThread::Task* butil::address_resource<bthread::TimerThread::Task>(butil::ResourceId<bthread::TimerThread::Task>) Unexecuted instantiation: brpc::IOEventData* butil::address_resource<brpc::IOEventData>(butil::ResourceId<brpc::IOEventData>) Unexecuted instantiation: brpc::Socket* butil::address_resource<brpc::Socket>(butil::ResourceId<brpc::Socket>) Unexecuted instantiation: butil::details::ExtendedEndPoint* butil::address_resource<butil::details::ExtendedEndPoint>(butil::ResourceId<butil::details::ExtendedEndPoint>) Unexecuted instantiation: bthread::ExecutionQueueBase* butil::address_resource<bthread::ExecutionQueueBase>(butil::ResourceId<bthread::ExecutionQueueBase>) Unexecuted instantiation: bthread::Id* butil::address_resource<bthread::Id>(butil::ResourceId<bthread::Id>) |
120 | | |
121 | | // Reclaim all allocated resources typed T if caller is the last thread called |
122 | | // this function, otherwise do nothing. You rarely need to call this function |
123 | | // manually because it's called automatically when each thread quits. |
124 | | template <typename T> inline void clear_resources() { |
125 | | ResourcePool<T>::singleton()->clear_resources(); |
126 | | } |
127 | | |
128 | | // Get description of resources typed T. |
129 | | // This function is possibly slow because it iterates internal structures. |
130 | | // Don't use it frequently like a "getter" function. |
131 | 0 | template <typename T> ResourcePoolInfo describe_resources() { |
132 | 0 | return ResourcePool<T>::singleton()->describe_resources(); |
133 | 0 | } Unexecuted instantiation: butil::ResourcePoolInfo butil::describe_resources<bthread::Id>() Unexecuted instantiation: butil::ResourcePoolInfo butil::describe_resources<brpc::Socket>() |
134 | | |
135 | | } // namespace butil |
136 | | |
137 | | #endif // BUTIL_RESOURCE_POOL_H |