1 /* 2 * Copyright (c) 2015, 2021, Oracle and/or its affiliates. 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, version 2.0, 6 * as published by the Free Software Foundation. 7 * 8 * This program is also distributed with certain software (including 9 * but not limited to OpenSSL) that is licensed under separate terms, 10 * as designated in a particular file or component or in included license 11 * documentation. The authors of MySQL hereby grant you an additional 12 * permission to link the program and your derivative works with the 13 * separately licensed software that they have included with MySQL. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License, version 2.0, for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 23 * 02110-1301 USA 24 */ 25 26 #ifndef _NGS_PAGE_POOL_H_ 27 #define _NGS_PAGE_POOL_H_ 28 29 #include <stdint.h> 30 #include <list> 31 32 #include "ngs/thread.h" 33 #include "ngs/memory.h" 34 #include "ngs_common/atomic.h" 35 36 #define BUFFER_PAGE_SIZE 4096 37 38 39 namespace ngs 40 { 41 42 class Page_pool; 43 44 // 4KB aligned buffer to be used for reading data from sockets. 45 class Page 46 { 47 public: Page(uint32_t pcapacity,char * pdata)48 Page(uint32_t pcapacity, char *pdata) 49 { 50 capacity = pcapacity; 51 data = pdata; 52 length = 0; 53 references = 0; 54 saved_length = 0; 55 } 56 57 Page(uint32_t pcapacity = BUFFER_PAGE_SIZE) 58 { 59 capacity = pcapacity; 60 ngs::allocate_array(data, capacity, KEY_memory_x_recv_buffer); 61 length = 0; 62 references = 0; 63 saved_length = 0; 64 } 65 ~Page()66 virtual ~Page() { ngs::free_array(data); } 67 aquire()68 void aquire() { ++references; } release()69 void release() { if (0 == --references) destroy(); } 70 save_state()71 void save_state() { saved_length = length; } rollback()72 void rollback() { length = saved_length; } 73 get_free_bytes()74 uint32_t get_free_bytes() { return capacity - length; } 75 get_free_ptr()76 uint8_t* get_free_ptr() { return (uint8_t*)data + length; } 77 78 char *data; 79 uint32_t capacity; 80 uint32_t length; 81 82 protected: destroy()83 virtual void destroy() { } 84 85 private: 86 Page(const Page&); 87 void operator=(const Page&); 88 89 uint16_t references; 90 uint32_t saved_length; 91 }; 92 93 template<typename ResType> 94 class Resource 95 { 96 public: 97 Resource(); 98 Resource(ResType *res); 99 Resource(const Resource<ResType> &resource); 100 101 ~Resource(); 102 103 ResType *operator->(); 104 ResType *operator->() const; 105 106 private: 107 ResType *m_res; 108 }; 109 110 struct Pool_config 111 { 112 int32_t pages_max; 113 int32_t pages_cache_max; 114 int32_t page_size; 115 }; 116 117 118 class Page_pool 119 { 120 public: 121 /* Unlimited allocation, no caching */ 122 Page_pool(const int32_t page_size = BUFFER_PAGE_SIZE); 123 Page_pool(const Pool_config &pool_config); 124 ~Page_pool(); 125 126 Resource<Page> allocate(); 127 128 class No_more_pages_exception: public std::exception 129 { 130 public: what()131 virtual const char* what() const throw() { return "No more memory pages available"; } 132 }; 133 134 private: 135 Page_pool(const Page_pool &); 136 Page_pool &operator=(const Page_pool &); 137 138 class Page_memory_managed : public Page 139 { 140 public: Page_memory_managed(Page_pool & pool,uint32_t pcapacity,char * pdata)141 Page_memory_managed(Page_pool &pool, uint32_t pcapacity, char *pdata) 142 : Page(pcapacity, pdata), m_pool(pool) 143 { } 144 ~Page_memory_managed()145 ~Page_memory_managed() { data = NULL; } 146 147 private: destroy()148 virtual void destroy() 149 { 150 m_pool.deallocate(this); 151 } 152 153 Page_pool &m_pool; 154 }; 155 156 void deallocate(Page *page); 157 158 bool push_page(char *page_data); 159 char *pop_page(); 160 161 std::list<char *> m_pages_list; 162 int32_t m_pages_max; 163 int32_t m_pages_cache_max; 164 int32_t m_pages_cached; 165 const int32_t m_page_size; 166 Mutex m_mutex; 167 ngs::atomic<int32_t> m_pages_allocated; 168 }; 169 170 171 template<typename ResType> Resource()172 Resource<ResType>::Resource() 173 : m_res(NULL) 174 { 175 } 176 177 template<typename ResType> Resource(ResType * res)178 Resource<ResType>::Resource(ResType *res) 179 : m_res(res) 180 { 181 m_res->aquire(); 182 } 183 184 template<typename ResType> Resource(const Resource<ResType> & resource)185 Resource<ResType>::Resource(const Resource<ResType> &resource) 186 : m_res(resource.m_res) 187 { 188 if (NULL != m_res) 189 m_res->aquire(); 190 } 191 192 template<typename ResType> ~Resource()193 Resource<ResType>::~Resource() 194 { 195 if (NULL != m_res) 196 m_res->release(); 197 } 198 199 template<typename ResType> 200 ResType *Resource<ResType>::operator->() 201 { 202 return m_res; 203 } 204 205 template<typename ResType> 206 ResType *Resource<ResType>::operator->() const 207 { 208 return m_res; 209 } 210 } // namespace ngs 211 212 #endif // _NGS_PAGE_POOL_H_ 213