1 /**
2  * @file   resource_pool.h
3  *
4  * @section LICENSE
5  *
6  * The MIT License
7  *
8  * @copyright Copyright (c) 2020-2021 TileDB, Inc.
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a copy
11  * of this software and associated documentation files (the "Software"), to deal
12  * in the Software without restriction, including without limitation the rights
13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14  * copies of the Software, and to permit persons to whom the Software is
15  * furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included in
18  * all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  *
28  * @section DESCRIPTION
29  *
30  * This defines a pool of resources that can be shared for example amongst
31  * threads.
32  */
33 
34 #ifndef RESOURCE_POOL_H
35 #define RESOURCE_POOL_H
36 
37 namespace tiledb {
38 namespace sm {
39 
40 template <class T, template <class> class P>
41 class ResourceHandle {
42  public:
ResourceHandle(P<T> & p,unsigned int n)43   ResourceHandle(P<T>& p, unsigned int n)
44       : p_(p)
45       , n_(n) {
46   }
47 
get()48   T& get() {
49     return p_.at(n_);
50   }
51 
release()52   void release() {
53     p_.release(n_);
54   }
55 
56  private:
57   /** The pool that issued this handle. */
58   P<T>& p_;
59 
60   /** The index of a vector within the pool to the resource. */
61   unsigned int n_;
62 };
63 
64 /**
65  * @tparam T The resource type
66  * @tparam P Class P<T> provides instances of ResourceGuard<T>
67  */
68 template <class T, template <class> class P>
69 class ResourceGuard {
70  public:
71   /** Constructor. */
ResourceGuard(P<T> & p)72   ResourceGuard(P<T>& p)
73       : h_(p.take()) {
74   }
75 
76   /** Destructor. */
~ResourceGuard()77   ~ResourceGuard() {
78     h_.release();
79   }
80 
81   /** Get the handle. */
get()82   T& get() {
83     return h_.get();
84   }
85 
86  private:
87   /** A resource handle from the provider. */
88   typename P<T>::resource_handle h_;
89 };
90 
91 template <class T>
92 class ResourcePool {
93  public:
94   using resource_handle = ResourceHandle<T, tiledb::sm::ResourcePool>;
95 
96   /** Constructor. */
ResourcePool(unsigned int n)97   ResourcePool(unsigned int n)
98       : resources_(n)
99       , unused_(n)
100       , unused_idx_(n - 1) {
101     for (unsigned int i = 0; i < n; i++)
102       unused_[i] = i;
103   }
104 
105   /** Take a resource from the pool. */
take()106   resource_handle take() {
107     std::lock_guard x(m_);
108     if (unused_idx_ == -1)
109       throw std::runtime_error("Ran out of resources in resource pool");
110     return ResourceHandle(*this, unused_[unused_idx_--]);
111   }
112 
113  private:
114   /** Release a resource from the pool. */
release(unsigned int n)115   void release(unsigned int n) {
116     std::lock_guard x(m_);
117     unused_[++unused_idx_] = n;
118   }
119 
120   /** Access a resource from the internal vector. */
at(unsigned int n)121   T& at(unsigned int n) {
122     return resources_.at(n);
123   }
124 
125   /** Vector of resources. */
126   std::vector<T> resources_;
127 
128   /** Vector of unused resource indexes. */
129   std::vector<unsigned int> unused_;
130 
131   /** Index of the last valid resource in the unused vector. */
132   int unused_idx_;
133 
134   /** Mutex protecting unused_ and unused_idx_. */
135   std::mutex m_;
136 
137   friend class ResourceHandle<T, tiledb::sm::ResourcePool>;
138 };
139 
140 }  // namespace sm
141 }  // namespace tiledb
142 
143 #endif  // TILEDB_MULTI_THREADED_RESOURCE_PROVIDER_H