bufferpool.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. /*
  2. * Copyright: JessMA Open Source (ldcsaa@gmail.com)
  3. *
  4. * Version : 2.3.15
  5. * Author : Bruce Liang
  6. * Website : http://www.jessma.org
  7. * Project : https://github.com/ldcsaa
  8. * Blog : http://www.cnblogs.com/ldcsaa
  9. * Wiki : http://www.oschina.net/p/hp-socket
  10. * QQ Group : 75375912
  11. *
  12. * Licensed under the Apache License, Version 2.0 (the "License");
  13. * you may not use this file except in compliance with the License.
  14. * You may obtain a copy of the License at
  15. *
  16. * http://www.apache.org/licenses/LICENSE-2.0
  17. *
  18. * Unless required by applicable law or agreed to in writing, software
  19. * distributed under the License is distributed on an "AS IS" BASIS,
  20. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  21. * See the License for the specific language governing permissions and
  22. * limitations under the License.
  23. */
  24. /******************************************************************************
  25. Module: BufferPool.cpp
  26. Notices: Copyright (c) 2013 Bruce Liang
  27. Purpose: ¼òµ¥Äڴ滺³å³Ø
  28. Desc:
  29. ******************************************************************************/
  30. #include "stdafx.h"
  31. #include "bufferpool.h"
  32. #include "SysHelper.h"
  33. #include "WaitFor.h"
  34. const DWORD TItem::DEFAULT_ITEM_CAPACITY = ::SysGetPageSize();
  35. const DWORD CBufferPool::DEFAULT_MAX_CACHE_SIZE = 0;
  36. const DWORD CBufferPool::DEFAULT_ITEM_CAPACITY = CItemPool::DEFAULT_ITEM_CAPACITY;
  37. const DWORD CBufferPool::DEFAULT_ITEM_POOL_SIZE = CItemPool::DEFAULT_POOL_SIZE;
  38. const DWORD CBufferPool::DEFAULT_ITEM_POOL_HOLD = CItemPool::DEFAULT_POOL_HOLD;
  39. const DWORD CBufferPool::DEFAULT_BUFFER_LOCK_TIME = 10 * 1000;
  40. const DWORD CBufferPool::DEFAULT_BUFFER_POOL_SIZE = 150;
  41. const DWORD CBufferPool::DEFAULT_BUFFER_POOL_HOLD = 600;
  42. TItem* TItem::Construct(CPrivateHeap& heap, int capacity, BYTE* pData, int length)
  43. {
  44. ASSERT(capacity > 0);
  45. int item_size = sizeof(TItem);
  46. TItem* pItem = (TItem*)heap.Alloc(item_size + capacity);
  47. pItem->head = (BYTE*)pItem + item_size;
  48. pItem->TItem::TItem(heap, capacity, pData, length);
  49. return pItem;
  50. }
  51. void TItem::Destruct(TItem* pItem)
  52. {
  53. ASSERT(pItem != nullptr);
  54. CPrivateHeap& heap = pItem->heap;
  55. pItem->TItem::~TItem();
  56. heap.Free(pItem);
  57. }
  58. inline int TItem::Cat(const BYTE* pData, int length)
  59. {
  60. ASSERT(pData != nullptr && length > 0);
  61. int cat = min(Remain(), length);
  62. if(cat > 0)
  63. {
  64. memcpy(end, pData, cat);
  65. end += cat;
  66. }
  67. return cat;
  68. }
  69. inline int TItem::Cat(const TItem& other)
  70. {
  71. ASSERT(this != &other);
  72. return Cat(other.Ptr(), other.Size());
  73. }
  74. inline int TItem::Fetch(BYTE* pData, int length)
  75. {
  76. ASSERT(pData != nullptr && length > 0);
  77. int fetch = min(Size(), length);
  78. memcpy(pData, begin, fetch);
  79. begin += fetch;
  80. return fetch;
  81. }
  82. inline int TItem::Peek(BYTE* pData, int length)
  83. {
  84. ASSERT(pData != nullptr && length > 0);
  85. int peek = min(Size(), length);
  86. memcpy(pData, begin, peek);
  87. return peek;
  88. }
  89. inline int TItem::Reduce(int length)
  90. {
  91. ASSERT(length > 0);
  92. int reduce = min(Size(), length);
  93. begin += reduce;
  94. return reduce;
  95. }
  96. inline void TItem::Reset(int first, int last)
  97. {
  98. ASSERT(first >= -1 && first <= capacity);
  99. ASSERT(last >= -1 && last <= capacity);
  100. if(first >= 0) begin = head + min(first, capacity);
  101. if(last >= 0) end = head + min(last, capacity);
  102. }
  103. int TItemList::Cat(const BYTE* pData, int length)
  104. {
  105. int remain = length;
  106. while(remain > 0)
  107. {
  108. TItem* pItem = Back();
  109. if(pItem == nullptr || pItem->IsFull())
  110. pItem = PushBack(itPool.PickFreeItem());
  111. int cat = pItem->Cat(pData, remain);
  112. pData += cat;
  113. remain -= cat;
  114. }
  115. return length;
  116. }
  117. int TItemList::Cat(const TItem* pItem)
  118. {
  119. return Cat(pItem->Ptr(), pItem->Size());
  120. }
  121. int TItemList::Cat(const TItemList& other)
  122. {
  123. ASSERT(this != &other);
  124. int length = 0;
  125. for(TItem* pItem = other.Front(); pItem != nullptr; pItem = pItem->next)
  126. length += Cat(pItem);
  127. return length;
  128. }
  129. int TItemList::Fetch(BYTE* pData, int length)
  130. {
  131. int remain = length;
  132. while(remain > 0 && Size() > 0)
  133. {
  134. TItem* pItem = Front();
  135. int fetch = pItem->Fetch(pData, remain);
  136. pData += fetch;
  137. remain -= fetch;
  138. if(pItem->IsEmpty())
  139. itPool.PutFreeItem(PopFront());
  140. }
  141. return length - remain;
  142. }
  143. int TItemList::Peek(BYTE* pData, int length)
  144. {
  145. int remain = length;
  146. TItem* pItem = Front();
  147. while(remain > 0 && pItem != nullptr)
  148. {
  149. int peek = pItem->Peek(pData, remain);
  150. pData += peek;
  151. remain -= peek;
  152. pItem = pItem->next;
  153. }
  154. return length - remain;
  155. }
  156. int TItemList::Reduce(int length)
  157. {
  158. int remain = length;
  159. while(remain > 0 && Size() > 0)
  160. {
  161. TItem* pItem = Front();
  162. remain -= pItem->Reduce(remain);
  163. if(pItem->IsEmpty())
  164. itPool.PutFreeItem(PopFront());
  165. }
  166. return length - remain;
  167. }
  168. void TItemList::Release()
  169. {
  170. itPool.PutFreeItem(*this);
  171. }
  172. TBuffer* TBuffer::Construct(CBufferPool& pool, ULONG_PTR dwID)
  173. {
  174. ASSERT(dwID != 0);
  175. CPrivateHeap& heap = pool.GetPrivateHeap();
  176. TBuffer* pBuffer = (TBuffer*)heap.Alloc(sizeof(TBuffer));
  177. pBuffer->TBuffer::TBuffer(heap, pool.GetItemPool(), dwID);
  178. return pBuffer;
  179. }
  180. void TBuffer::Destruct(TBuffer* pBuffer)
  181. {
  182. ASSERT(pBuffer != nullptr);
  183. CPrivateHeap& heap = pBuffer->heap;
  184. pBuffer->TBuffer::~TBuffer();
  185. heap.Free(pBuffer);
  186. }
  187. inline void TBuffer::Reset()
  188. {
  189. id = 0;
  190. length = 0;
  191. freeTime = ::TimeGetTime();
  192. }
  193. int TBuffer::Cat(const BYTE* pData, int len)
  194. {
  195. items.Cat(pData, len);
  196. return IncreaseLength(len);
  197. }
  198. int TBuffer::Cat(const TItem* pItem)
  199. {
  200. items.Cat(pItem);
  201. return IncreaseLength(pItem->Size());
  202. }
  203. int TBuffer::Cat(const TItemList& other)
  204. {
  205. ASSERT(&items != &other);
  206. for(TItem* pItem = other.Front(); pItem != nullptr; pItem = pItem->next)
  207. Cat(pItem);
  208. return length;
  209. }
  210. int TBuffer::Fetch(BYTE* pData, int len)
  211. {
  212. int fetch = items.Fetch(pData, len);
  213. DecreaseLength(fetch);
  214. return fetch;
  215. }
  216. int TBuffer::Peek(BYTE* pData, int len)
  217. {
  218. return items.Peek(pData, len);
  219. }
  220. int TBuffer::Reduce(int len)
  221. {
  222. int reduce = items.Reduce(len);
  223. DecreaseLength(reduce);
  224. return reduce;
  225. }
  226. void CBufferPool::PutFreeBuffer(ULONG_PTR dwID)
  227. {
  228. ASSERT(dwID != 0);
  229. TBuffer* pBuffer = FindCacheBuffer(dwID);
  230. if(pBuffer != nullptr)
  231. PutFreeBuffer(pBuffer);
  232. }
  233. void CBufferPool::PutFreeBuffer(TBuffer* pBuffer)
  234. {
  235. ASSERT(pBuffer != nullptr);
  236. if(!pBuffer->IsValid())
  237. return;
  238. m_bfCache.Remove(pBuffer->ID());
  239. BOOL bOK = FALSE;
  240. {
  241. CCriSecLock locallock(pBuffer->cs);
  242. if(pBuffer->IsValid())
  243. {
  244. pBuffer->Reset();
  245. bOK = TRUE;
  246. }
  247. }
  248. if(bOK)
  249. {
  250. m_itPool.PutFreeItem(pBuffer->items);
  251. if(!m_lsFreeBuffer.TryPut(pBuffer))
  252. {
  253. m_lsGCBuffer.PushBack(pBuffer);
  254. if(m_lsGCBuffer.Size() > m_dwBufferPoolSize)
  255. ReleaseGCBuffer();
  256. }
  257. }
  258. }
  259. void CBufferPool::ReleaseGCBuffer(BOOL bForce)
  260. {
  261. TBuffer* pBuffer = nullptr;
  262. DWORD now = ::TimeGetTime();
  263. while(m_lsGCBuffer.PopFront(&pBuffer))
  264. {
  265. if(bForce || (int)(now - pBuffer->freeTime) >= (int)m_dwBufferLockTime)
  266. TBuffer::Destruct(pBuffer);
  267. else
  268. {
  269. m_lsGCBuffer.PushBack(pBuffer);
  270. break;
  271. }
  272. }
  273. }
  274. TBuffer* CBufferPool::PutCacheBuffer(ULONG_PTR dwID)
  275. {
  276. ASSERT(dwID != 0);
  277. TBuffer* pBuffer = PickFreeBuffer(dwID);
  278. m_bfCache.Set(dwID, pBuffer);
  279. return pBuffer;
  280. }
  281. TBuffer* CBufferPool::PickFreeBuffer(ULONG_PTR dwID)
  282. {
  283. ASSERT( dwID != 0);
  284. DWORD dwIndex;
  285. TBuffer* pBuffer = nullptr;
  286. if(m_lsFreeBuffer.TryLock(&pBuffer, dwIndex))
  287. {
  288. if(::GetTimeGap32(pBuffer->freeTime) >= m_dwBufferLockTime)
  289. m_lsFreeBuffer.ReleaseLock(nullptr, dwIndex);
  290. else
  291. {
  292. m_lsFreeBuffer.ReleaseLock(pBuffer, dwIndex);
  293. pBuffer = nullptr;
  294. }
  295. }
  296. if(pBuffer) pBuffer->id = dwID;
  297. else pBuffer = TBuffer::Construct(*this, dwID);
  298. ASSERT(pBuffer);
  299. return pBuffer;
  300. }
  301. TBuffer* CBufferPool::FindCacheBuffer(ULONG_PTR dwID)
  302. {
  303. ASSERT(dwID != 0);
  304. TBuffer* pBuffer = nullptr;
  305. if(!m_bfCache.Get(dwID, &pBuffer))
  306. pBuffer = nullptr;
  307. return pBuffer;
  308. }
  309. void CBufferPool::Prepare()
  310. {
  311. m_itPool.Prepare();
  312. m_bfCache.Reset(m_dwMaxCacheSize);
  313. m_lsFreeBuffer.Reset(m_dwBufferPoolHold);
  314. }
  315. void CBufferPool::Clear()
  316. {
  317. DWORD size = 0;
  318. unique_ptr<ULONG_PTR[]> ids = m_bfCache.GetAllElementIndexes(size, FALSE);
  319. for(DWORD i = 0; i < size; i++)
  320. {
  321. TBuffer* pBuffer = FindCacheBuffer(ids[i]);
  322. if(pBuffer) TBuffer::Destruct(pBuffer);
  323. }
  324. m_bfCache.Reset();
  325. TBuffer* pBuffer = nullptr;
  326. while(m_lsFreeBuffer.TryGet(&pBuffer))
  327. TBuffer::Destruct(pBuffer);
  328. VERIFY(m_lsFreeBuffer.IsEmpty());
  329. m_lsFreeBuffer.Reset();
  330. ReleaseGCBuffer(TRUE);
  331. VERIFY(m_lsGCBuffer.IsEmpty());
  332. m_itPool.Clear();
  333. m_heap.Reset();
  334. }