/src/tdengine/source/util/src/tmempool.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com> |
3 | | * |
4 | | * SPDX-License-Identifier: AGPL-3.0-or-later |
5 | | * |
6 | | * This program is free software: you can use, redistribute, and/or modify |
7 | | * it under the terms of the GNU Affero General Public License, version 3 |
8 | | * or later ("AGPL"), as published by the Free Software Foundation. |
9 | | * |
10 | | * This program is distributed in the hope that it will be useful, but WITHOUT |
11 | | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
12 | | * FITNESS FOR A PARTICULAR PURPOSE. |
13 | | * |
14 | | * You should have received a copy of the GNU Affero General Public License |
15 | | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | |
18 | | #define _DEFAULT_SOURCE |
19 | | #include "osMemPool.h" |
20 | | #include "tmempoolInt.h" |
21 | | #include "tlog.h" |
22 | | #include "tutil.h" |
23 | | #include "taos.h" |
24 | | #include "tglobal.h" |
25 | | |
26 | | static TdThreadOnce gMPoolInit = PTHREAD_ONCE_INIT; |
27 | | void* gMemPoolHandle = NULL; |
28 | | threadlocal void* threadPoolSession = NULL; |
29 | | threadlocal bool threadPoolEnabled = true; |
30 | | |
31 | | SMemPoolMgmt gMPMgmt = {0}; |
32 | | SMPStrategyFp gMPFps[] = { |
33 | | {NULL}, |
34 | | {NULL, mpDirectFullAlloc, mpDirectFullFree, mpDirectGetMemSize, mpDirectFullRealloc, NULL, NULL, mpDirectTrim}, |
35 | | //{mpChunkInit, mpChunkAlloc, mpChunkFree, mpChunkGetMemSize, mpChunkRealloc, mpChunkInitSession, mpChunkUpdateCfg, NULL} |
36 | | }; |
37 | | |
38 | | |
39 | 0 | int32_t mpCheckCfg(SMemPoolCfg* cfg) { |
40 | 0 | if (cfg->chunkSize < MEMPOOL_MIN_CHUNK_SIZE || cfg->chunkSize > MEMPOOL_MAX_CHUNK_SIZE) { |
41 | 0 | uError("invalid memory pool chunkSize:%d", cfg->chunkSize); |
42 | 0 | return TSDB_CODE_INVALID_PARA; |
43 | 0 | } |
44 | | |
45 | 0 | if (cfg->evicPolicy <= 0 || cfg->evicPolicy >= E_EVICT_MAX_VALUE) { |
46 | 0 | uError("invalid memory pool evicPolicy:%d", cfg->evicPolicy); |
47 | 0 | return TSDB_CODE_INVALID_PARA; |
48 | 0 | } |
49 | | |
50 | 0 | if (cfg->threadNum <= 0) { |
51 | 0 | uError("invalid memory pool threadNum:%d", cfg->threadNum); |
52 | 0 | return TSDB_CODE_INVALID_PARA; |
53 | 0 | } |
54 | | |
55 | 0 | return TSDB_CODE_SUCCESS; |
56 | 0 | } |
57 | | |
58 | | |
59 | 0 | void mpFreeCacheGroup(SMPCacheGroup* pGrp) { |
60 | 0 | if (NULL == pGrp) { |
61 | 0 | return; |
62 | 0 | } |
63 | | |
64 | 0 | taosMemoryFree(pGrp->pNodes); |
65 | 0 | taosMemoryFree(pGrp); |
66 | 0 | } |
67 | | |
68 | | |
69 | 0 | int32_t mpAddCacheGroup(SMemPool* pPool, SMPCacheGroupInfo* pInfo, SMPCacheGroup* pHead) { |
70 | 0 | SMPCacheGroup* pGrp = NULL; |
71 | 0 | if (NULL == atomic_load_ptr(&pInfo->pGrpHead)) { |
72 | 0 | pInfo->pGrpHead = taosMemoryCalloc(1, sizeof(*pInfo->pGrpHead)); |
73 | 0 | if (NULL == pInfo->pGrpHead) { |
74 | 0 | uError("malloc pGrpHead failed, error:%s", tstrerror(terrno)); |
75 | 0 | MP_ERR_RET(terrno); |
76 | 0 | } |
77 | | |
78 | 0 | pGrp = pInfo->pGrpHead; |
79 | 0 | } else { |
80 | 0 | pGrp = (SMPCacheGroup*)taosMemoryCalloc(1, sizeof(SMPCacheGroup)); |
81 | 0 | if (NULL == pGrp) { |
82 | 0 | uError("malloc SMPCacheGroup failed, error:%s", tstrerror(terrno)); |
83 | 0 | MP_ERR_RET(terrno); |
84 | 0 | } |
85 | 0 | pGrp->pNext = pHead; |
86 | 0 | } |
87 | | |
88 | 0 | pGrp->nodesNum = pInfo->groupNum; |
89 | 0 | pGrp->pNodes = taosMemoryCalloc(pGrp->nodesNum, pInfo->nodeSize); |
90 | 0 | if (NULL == pGrp->pNodes) { |
91 | 0 | uError("calloc %d %d nodes in cache group failed", pGrp->nodesNum, pInfo->nodeSize); |
92 | 0 | MP_ERR_RET(TSDB_CODE_OUT_OF_MEMORY); |
93 | 0 | } |
94 | | |
95 | 0 | if (pHead && atomic_val_compare_exchange_ptr(&pInfo->pGrpHead, pHead, pGrp) != pHead) { |
96 | 0 | mpFreeCacheGroup(pGrp); |
97 | 0 | return TSDB_CODE_SUCCESS; |
98 | 0 | } |
99 | | |
100 | 0 | (void)atomic_add_fetch_64(&pInfo->allocNum, pGrp->nodesNum); |
101 | |
|
102 | 0 | return TSDB_CODE_SUCCESS; |
103 | 0 | } |
104 | | |
105 | 0 | void mpDestroyCacheGroup(SMPCacheGroupInfo* pInfo) { |
106 | 0 | SMPCacheGroup* pGrp = pInfo->pGrpHead; |
107 | 0 | SMPCacheGroup* pNext = NULL; |
108 | 0 | while (NULL != pGrp) { |
109 | 0 | pNext = pGrp->pNext; |
110 | |
|
111 | 0 | mpFreeCacheGroup(pGrp); |
112 | |
|
113 | 0 | pGrp = pNext; |
114 | 0 | } |
115 | 0 | } |
116 | | |
117 | | |
118 | 0 | int32_t mpPopIdleNode(SMemPool* pPool, SMPCacheGroupInfo* pInfo, void** ppRes) { |
119 | 0 | SMPCacheGroup* pGrp = NULL; |
120 | 0 | SMPListNode* pNode = NULL; |
121 | |
|
122 | 0 | taosWLockLatch(&pInfo->idleListLock); |
123 | 0 | pNode = (SMPListNode*)pInfo->pIdleList; |
124 | 0 | if (NULL != pNode) { |
125 | 0 | pInfo->pIdleList = pNode->pNext; |
126 | 0 | pNode->pNext = NULL; |
127 | 0 | taosWUnLockLatch(&pInfo->idleListLock); |
128 | 0 | goto _return; |
129 | 0 | } |
130 | 0 | taosWUnLockLatch(&pInfo->idleListLock); |
131 | |
|
132 | 0 | while (true) { |
133 | 0 | pGrp = atomic_load_ptr(&pInfo->pGrpHead); |
134 | 0 | int32_t offset = atomic_fetch_add_32(&pGrp->idleOffset, 1); |
135 | 0 | if (offset < pGrp->nodesNum) { |
136 | 0 | pNode = (SMPListNode*)((char*)pGrp->pNodes + offset * pInfo->nodeSize); |
137 | 0 | break; |
138 | 0 | } else { |
139 | 0 | (void)atomic_sub_fetch_32(&pGrp->idleOffset, 1); |
140 | 0 | } |
141 | | |
142 | 0 | MP_ERR_RET(mpAddCacheGroup(pPool, pInfo, pGrp)); |
143 | 0 | } |
144 | | |
145 | 0 | _return: |
146 | |
|
147 | 0 | *ppRes = pNode; |
148 | |
|
149 | 0 | return TSDB_CODE_SUCCESS; |
150 | 0 | } |
151 | | |
152 | 0 | void mpPushIdleNode(SMemPool* pPool, SMPCacheGroupInfo* pInfo, SMPListNode* pNode) { |
153 | 0 | taosWLockLatch(&pInfo->idleListLock); |
154 | 0 | pNode->pNext = pInfo->pIdleList; |
155 | 0 | pInfo->pIdleList = pNode; |
156 | 0 | taosWUnLockLatch(&pInfo->idleListLock); |
157 | 0 | } |
158 | | |
159 | | |
160 | 0 | int32_t mpUpdateCfg(SMemPool* pPool) { |
161 | 0 | if (gMPFps[gMPMgmt.strategy].updateCfgFp) { |
162 | 0 | MP_ERR_RET((*gMPFps[gMPMgmt.strategy].updateCfgFp)(pPool)); |
163 | 0 | } |
164 | | |
165 | 0 | uDebug("memPool %s cfg updated, reserveSize:%" PRId64 ", jobQuota:%dMB, threadNum:%d", |
166 | 0 | pPool->name, pPool->cfg.reserveSize, *pPool->cfg.jobQuota, pPool->cfg.threadNum); |
167 | |
|
168 | 0 | return TSDB_CODE_SUCCESS; |
169 | 0 | } |
170 | | |
171 | 0 | uint32_t mpFileIdHashFp(const char* fileId, uint32_t len) { |
172 | 0 | return *(uint32_t*)fileId; |
173 | 0 | } |
174 | | |
175 | 0 | void mpDestroyPosStat(SMPStatPos* pStat) { |
176 | 0 | taosHashCleanup(pStat->fileHash); |
177 | 0 | pStat->fileHash = NULL; |
178 | 0 | taosHashCleanup(pStat->remainHash); |
179 | 0 | pStat->remainHash = NULL; |
180 | 0 | taosHashCleanup(pStat->allocHash); |
181 | 0 | pStat->allocHash = NULL; |
182 | 0 | taosHashCleanup(pStat->freeHash); |
183 | 0 | pStat->freeHash = NULL; |
184 | 0 | } |
185 | | |
186 | 0 | int32_t mpInitPosStat(SMPStatPos* pStat, bool sessionStat) { |
187 | 0 | pStat->remainHash = taosHashInit(1024, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_ENTRY_LOCK); |
188 | 0 | if (NULL == pStat->remainHash) { |
189 | 0 | uError("memPool init posStat remainHash failed, error:%s, sessionStat:%d", tstrerror(terrno), sessionStat); |
190 | 0 | return terrno; |
191 | 0 | } |
192 | | |
193 | 0 | pStat->allocHash = taosHashInit(1024, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_ENTRY_LOCK); |
194 | 0 | if (NULL == pStat->allocHash) { |
195 | 0 | uError("memPool init posStat allocHash failed, error:%s, sessionStat:%d", tstrerror(terrno), sessionStat); |
196 | 0 | return terrno; |
197 | 0 | } |
198 | | |
199 | 0 | pStat->freeHash = taosHashInit(1024, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_ENTRY_LOCK); |
200 | 0 | if (NULL == pStat->freeHash) { |
201 | 0 | uError("memPool init posStat freeHash failed, error:%s, sessionStat:%d", tstrerror(terrno), sessionStat); |
202 | 0 | return terrno; |
203 | 0 | } |
204 | | |
205 | 0 | pStat->fileHash = taosHashInit(1024, mpFileIdHashFp, false, HASH_ENTRY_LOCK); |
206 | 0 | if (NULL == pStat->fileHash) { |
207 | 0 | uError("memPool init posStat fileHash failed, error:%s, sessionStat:%d", tstrerror(terrno), sessionStat); |
208 | 0 | return terrno; |
209 | 0 | } |
210 | | |
211 | 0 | uDebug("memPool stat initialized, sessionStat:%d", sessionStat); |
212 | |
|
213 | 0 | return TSDB_CODE_SUCCESS; |
214 | 0 | } |
215 | | |
216 | 0 | int32_t mpInit(SMemPool* pPool, char* poolName, SMemPoolCfg* cfg) { |
217 | | // MP_ERR_RET(mpCheckCfg(cfg)); |
218 | | |
219 | 0 | TAOS_MEMCPY(&pPool->cfg, cfg, sizeof(*cfg)); |
220 | | |
221 | 0 | pPool->name = taosStrdup(poolName); |
222 | 0 | if (NULL == pPool->name) { |
223 | 0 | uError("calloc memory pool name %s failed", poolName); |
224 | 0 | MP_ERR_RET(terrno); |
225 | 0 | } |
226 | | |
227 | 0 | MP_ERR_RET(mpUpdateCfg(pPool)); |
228 | | |
229 | 0 | pPool->sessionCache.groupNum = MP_SESSION_CACHE_ALLOC_BATCH_SIZE; |
230 | 0 | pPool->sessionCache.nodeSize = sizeof(SMPSession); |
231 | |
|
232 | 0 | MP_ERR_RET(mpAddCacheGroup(pPool, &pPool->sessionCache, NULL)); |
233 | | |
234 | 0 | if (gMPFps[gMPMgmt.strategy].initFp) { |
235 | 0 | MP_ERR_RET((*gMPFps[gMPMgmt.strategy].initFp)(pPool, poolName, cfg)); |
236 | 0 | } |
237 | | |
238 | 0 | if (tsMemPoolFullFunc) { |
239 | 0 | MP_ERR_RET(mpInitPosStat(&pPool->stat.posStat, false)); |
240 | 0 | } |
241 | | |
242 | 0 | return TSDB_CODE_SUCCESS; |
243 | 0 | } |
244 | | |
245 | 0 | FORCE_INLINE void mpUpdateMaxAllocSize(int64_t* pMaxAllocMemSize, int64_t newSize) { |
246 | 0 | int64_t maxAllocMemSize = atomic_load_64(pMaxAllocMemSize); |
247 | 0 | while (true) { |
248 | 0 | if (newSize <= maxAllocMemSize) { |
249 | 0 | break; |
250 | 0 | } |
251 | | |
252 | 0 | if (maxAllocMemSize == atomic_val_compare_exchange_64(pMaxAllocMemSize, maxAllocMemSize, newSize)) { |
253 | 0 | break; |
254 | 0 | } |
255 | | |
256 | 0 | maxAllocMemSize = atomic_load_64(pMaxAllocMemSize); |
257 | 0 | } |
258 | 0 | } |
259 | | |
260 | 0 | void mpUpdateAllocSize(SMemPool* pPool, SMPSession* pSession, int64_t size, int64_t addSize) { |
261 | 0 | if (addSize) { |
262 | 0 | if (NULL != pSession) { |
263 | 0 | (void)atomic_add_fetch_64(&pSession->pJob->job.allocMemSize, addSize); |
264 | 0 | } |
265 | 0 | (void)atomic_add_fetch_64(&pPool->allocMemSize, addSize); |
266 | 0 | } |
267 | |
|
268 | 0 | if (NULL != pSession) { |
269 | 0 | int64_t allocMemSize = atomic_add_fetch_64(&pSession->allocMemSize, size); |
270 | 0 | mpUpdateMaxAllocSize(&pSession->maxAllocMemSize, allocMemSize); |
271 | |
|
272 | 0 | allocMemSize = atomic_load_64(&pSession->pJob->job.allocMemSize); |
273 | 0 | mpUpdateMaxAllocSize(&pSession->pJob->job.maxAllocMemSize, allocMemSize); |
274 | 0 | } |
275 | | |
276 | 0 | if (MP_GET_FLAG(gMPMgmt.ctrl.funcFlags, MP_CTRL_FLAG_LOG_MAXSIZE)) { |
277 | 0 | int64_t allocMemSize = atomic_load_64(&pPool->allocMemSize); |
278 | 0 | mpUpdateMaxAllocSize(&pPool->maxAllocMemSize, allocMemSize); |
279 | 0 | } |
280 | 0 | } |
281 | | |
282 | 0 | int32_t mpPutRetireMsgToQueue(SMemPool* pPool, bool retireLowLevel) { |
283 | 0 | if (retireLowLevel) { |
284 | 0 | if (0 == atomic_val_compare_exchange_8(&gMPMgmt.msgQueue.lowLevelRetire, 0, 1)) { |
285 | 0 | atomic_store_ptr(&gMPMgmt.msgQueue.pPool, pPool); |
286 | 0 | MP_ERR_RET(tsem2_post(&gMPMgmt.threadSem)); |
287 | 0 | } |
288 | | |
289 | 0 | return TSDB_CODE_SUCCESS; |
290 | 0 | } |
291 | | |
292 | 0 | if (0 == atomic_val_compare_exchange_8(&gMPMgmt.msgQueue.midLevelRetire, 0, 1)) { |
293 | 0 | atomic_store_ptr(&gMPMgmt.msgQueue.pPool, pPool); |
294 | 0 | MP_ERR_RET(tsem2_post(&gMPMgmt.threadSem)); |
295 | 0 | } |
296 | | |
297 | 0 | return TSDB_CODE_SUCCESS; |
298 | 0 | } |
299 | | |
300 | | |
301 | 0 | int32_t mpChkFullQuota(SMemPool* pPool, SMPSession* pSession, int64_t size) { |
302 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
303 | 0 | if (NULL == pSession) { |
304 | 0 | (void)atomic_add_fetch_64(&pPool->allocMemSize, size); |
305 | 0 | return code; |
306 | 0 | } |
307 | | |
308 | 0 | SMPJob* pJob = pSession->pJob; |
309 | 0 | int64_t cAllocSize = atomic_add_fetch_64(&pJob->job.allocMemSize, size); |
310 | 0 | int64_t quota = atomic_load_32(pPool->cfg.jobQuota); |
311 | 0 | if (quota > 0 && cAllocSize > (quota * 1048576L)) { |
312 | 0 | code = TSDB_CODE_QRY_REACH_QMEM_THRESHOLD; |
313 | 0 | uWarn("job 0x%" PRIx64 " allocSize %" PRId64 " is over than quota %" PRId64, pJob->job.jobId, cAllocSize, quota); |
314 | 0 | pPool->cfg.cb.reachFp(pJob->job.jobId, pJob->job.clientId, code); |
315 | 0 | mpSchedTrim(NULL); |
316 | 0 | (void)atomic_sub_fetch_64(&pJob->job.allocMemSize, size); |
317 | 0 | MP_RET(code); |
318 | 0 | } |
319 | | |
320 | 0 | if (atomic_load_64(&tsCurrentAvailMemorySize) <= (pPool->cfg.reserveSize + size)) { |
321 | 0 | code = TSDB_CODE_QRY_QUERY_MEM_EXHAUSTED; |
322 | 0 | uWarn("%s pool sysAvailMemSize %" PRId64 " can't alloc %" PRId64" while keeping reserveSize %" PRId64 " bytes", |
323 | 0 | pPool->name, atomic_load_64(&tsCurrentAvailMemorySize), size, pPool->cfg.reserveSize); |
324 | 0 | pPool->cfg.cb.reachFp(pJob->job.jobId, pJob->job.clientId, code); |
325 | 0 | mpSchedTrim(NULL); |
326 | 0 | (void)atomic_sub_fetch_64(&pJob->job.allocMemSize, size); |
327 | 0 | MP_RET(code); |
328 | 0 | } |
329 | | |
330 | 0 | (void)atomic_add_fetch_64(&pPool->allocMemSize, size); |
331 | | |
332 | | /* |
333 | | int64_t pAllocSize = atomic_add_fetch_64(&pPool->allocMemSize, size); |
334 | | if (pAllocSize >= atomic_load_32(pPool->cfg.upperLimitSize) * 1048576UL) { |
335 | | code = TSDB_CODE_QRY_QUERY_MEM_EXHAUSTED; |
336 | | uWarn("%s pool allocSize %" PRId64 " reaches the upperLimit %" PRId64, pPool->name, pAllocSize, atomic_load_32(pPool->cfg.upperLimitSize) * 1048576UL); |
337 | | pPool->cfg.cb.retireJobFp(&pJob->job, code); |
338 | | (void)atomic_sub_fetch_64(&pJob->job.allocMemSize, size); |
339 | | (void)atomic_sub_fetch_64(&pPool->allocMemSize, size); |
340 | | MP_RET(code); |
341 | | } |
342 | | */ |
343 | |
|
344 | 0 | return TSDB_CODE_SUCCESS; |
345 | 0 | } |
346 | | |
347 | 0 | int64_t mpGetMemorySizeImpl(SMemPool* pPool, SMPSession* pSession, void *ptr) { |
348 | 0 | return (*gMPFps[gMPMgmt.strategy].getSizeFp)(pPool, pSession, ptr); |
349 | 0 | } |
350 | | |
351 | 0 | int32_t mpMalloc(SMemPool* pPool, SMPSession* pSession, int64_t* size, uint32_t alignment, void** ppRes) { |
352 | 0 | MP_RET((*gMPFps[gMPMgmt.strategy].allocFp)(pPool, pSession, size, alignment, ppRes)); |
353 | 0 | } |
354 | | |
355 | 0 | int32_t mpCalloc(SMemPool* pPool, SMPSession* pSession, int64_t* size, void** ppRes) { |
356 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
357 | 0 | void *res = NULL; |
358 | |
|
359 | 0 | MP_ERR_RET(mpMalloc(pPool, pSession, size, 0, &res)); |
360 | | |
361 | 0 | if (NULL != res) { |
362 | 0 | TAOS_MEMSET(res, 0, *size); |
363 | 0 | } |
364 | |
|
365 | 0 | _return: |
366 | |
|
367 | 0 | *ppRes = res; |
368 | |
|
369 | 0 | return code; |
370 | 0 | } |
371 | | |
372 | | |
373 | 0 | void mpFree(SMemPool* pPool, SMPSession* pSession, void *ptr, int64_t* origSize) { |
374 | 0 | if (NULL == ptr) { |
375 | 0 | if (origSize) { |
376 | 0 | *origSize = 0; |
377 | 0 | } |
378 | | |
379 | 0 | return; |
380 | 0 | } |
381 | | |
382 | 0 | (*gMPFps[gMPMgmt.strategy].freeFp)(pPool, pSession, ptr, origSize); |
383 | 0 | } |
384 | | |
385 | 0 | int32_t mpRealloc(SMemPool* pPool, SMPSession* pSession, void **pPtr, int64_t* size, int64_t* origSize) { |
386 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
387 | |
|
388 | 0 | if (NULL == *pPtr) { |
389 | 0 | *origSize = 0; |
390 | 0 | MP_RET(mpMalloc(pPool, pSession, size, 0, pPtr)); |
391 | 0 | } |
392 | | |
393 | 0 | if (0 == *size) { |
394 | 0 | mpFree(pPool, pSession, *pPtr, origSize); |
395 | 0 | *pPtr = NULL; |
396 | 0 | return TSDB_CODE_SUCCESS; |
397 | 0 | } |
398 | | |
399 | 0 | *origSize = mpGetMemorySizeImpl(pPool, pSession, *pPtr); |
400 | |
|
401 | 0 | MP_RET((*gMPFps[gMPMgmt.strategy].reallocFp)(pPool, pSession, pPtr, size, origSize)); |
402 | 0 | } |
403 | | |
404 | 0 | int32_t mpTrim(SMemPool* pPool, SMPSession* pSession, int32_t size, bool* trimed) { |
405 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
406 | |
|
407 | 0 | if (gMPFps[gMPMgmt.strategy].trimFp) { |
408 | 0 | MP_RET((*gMPFps[gMPMgmt.strategy].trimFp)(pPool, pSession, size, trimed)); |
409 | 0 | } |
410 | | |
411 | 0 | return code; |
412 | 0 | } |
413 | | |
414 | | |
415 | 0 | void mpPrintStatDetail(SMPCtrlInfo* pCtrl, SMPStatDetail* pDetail, char* detailName, int64_t maxAllocSize) { |
416 | 0 | if (!MP_GET_FLAG(pCtrl->funcFlags, MP_CTRL_FLAG_PRINT_STAT)) { |
417 | 0 | return; |
418 | 0 | } |
419 | | |
420 | 0 | uInfo("MemPool [%s] stat detail:", detailName); |
421 | |
|
422 | 0 | uInfo("Max Used Memory Size: %" PRId64, maxAllocSize); |
423 | | |
424 | 0 | uInfo("[times]:"); |
425 | 0 | switch (gMPMgmt.strategy) { |
426 | 0 | case E_MP_STRATEGY_DIRECT: |
427 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("Malloc", pDetail->times.memMalloc)); |
428 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("Calloc", pDetail->times.memCalloc)); |
429 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("Realloc", pDetail->times.memRealloc)); |
430 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("Strdup", pDetail->times.memStrdup)); |
431 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("Strndup", pDetail->times.memStrndup)); |
432 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("Free", pDetail->times.memFree)); |
433 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("Trim", pDetail->times.memTrim)); |
434 | 0 | break; |
435 | 0 | case E_MP_STRATEGY_CHUNK: |
436 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("chunkMalloc", pDetail->times.chunkMalloc)); |
437 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("chunkRecycle", pDetail->times.chunkRecycle)); |
438 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("chunkReUse", pDetail->times.chunkReUse)); |
439 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("chunkFree", pDetail->times.chunkFree)); |
440 | 0 | break; |
441 | 0 | default: |
442 | 0 | break; |
443 | 0 | } |
444 | | |
445 | 0 | uInfo("[bytes]:"); |
446 | 0 | switch (gMPMgmt.strategy) { |
447 | 0 | case E_MP_STRATEGY_DIRECT: |
448 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("Malloc", pDetail->bytes.memMalloc)); |
449 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("Calloc", pDetail->bytes.memCalloc)); |
450 | 0 | uInfo(MP_STAT_ORIG_FORMAT, MP_STAT_ORIG_VALUE("Realloc", pDetail->bytes.memRealloc)); |
451 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("Strdup", pDetail->bytes.memStrdup)); |
452 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("Strndup", pDetail->bytes.memStrndup)); |
453 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("Free", pDetail->bytes.memFree)); |
454 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("Trim", pDetail->bytes.memTrim)); |
455 | 0 | break; |
456 | 0 | case E_MP_STRATEGY_CHUNK: |
457 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("chunkMalloc", pDetail->bytes.chunkMalloc)); |
458 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("chunkRecycle", pDetail->bytes.chunkRecycle)); |
459 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("chunkReUse", pDetail->bytes.chunkReUse)); |
460 | 0 | uInfo(MP_STAT_FORMAT, MP_STAT_VALUE("chunkFree", pDetail->bytes.chunkFree)); |
461 | 0 | break; |
462 | 0 | default: |
463 | 0 | break; |
464 | 0 | } |
465 | 0 | } |
466 | | |
467 | 0 | int32_t mpAddToRemainAllocHash(SHashObj* pHash, SMPFileLine* pFileLine) { |
468 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
469 | 0 | SMPAllocStat stat = {0}, *pStat = NULL; |
470 | | |
471 | 0 | while (true) { |
472 | 0 | pStat = (SMPAllocStat*)taosHashGet(pHash, &pFileLine->fl, sizeof(pFileLine->fl)); |
473 | 0 | if (NULL == pStat) { |
474 | 0 | code = taosHashPut(pHash, &pFileLine->fl, sizeof(pFileLine->fl), &stat, sizeof(stat)); |
475 | 0 | if (TSDB_CODE_SUCCESS != code) { |
476 | 0 | if (TSDB_CODE_DUP_KEY == code) { |
477 | 0 | continue; |
478 | 0 | } |
479 | | |
480 | 0 | uError("taosHashPut to remain alloc hash failed, error:%s", tstrerror(code)); |
481 | 0 | return code; |
482 | 0 | } |
483 | | |
484 | 0 | continue; |
485 | 0 | } |
486 | | |
487 | 0 | (void)atomic_add_fetch_64(&pStat->allocBytes, pFileLine->size); |
488 | 0 | (void)atomic_add_fetch_64(&pStat->allocTimes, 1); |
489 | 0 | break; |
490 | 0 | } |
491 | | |
492 | 0 | return TSDB_CODE_SUCCESS; |
493 | 0 | } |
494 | | |
495 | 0 | void mpPrintPosRemainStat(SMPStatPos* pStat) { |
496 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
497 | 0 | int32_t remainNum = taosHashGetSize(pStat->remainHash); |
498 | 0 | if (remainNum <= 0) { |
499 | 0 | uInfo("no alloc remaining memory"); |
500 | 0 | return; |
501 | 0 | } |
502 | | |
503 | 0 | SHashObj* pAllocHash = taosHashInit(remainNum / 10, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_NO_LOCK); |
504 | 0 | if (NULL == pAllocHash) { |
505 | 0 | uError("taosHashInit pAllocHash failed, error:%s, remainNum:%d", tstrerror(terrno), remainNum); |
506 | 0 | return; |
507 | 0 | } |
508 | | |
509 | 0 | SMPFileLine* pFileLine = NULL; |
510 | 0 | void* pIter = taosHashIterate(pStat->remainHash, NULL); |
511 | 0 | while (pIter) { |
512 | 0 | pFileLine = (SMPFileLine*)pIter; |
513 | |
|
514 | 0 | MP_ERR_JRET(mpAddToRemainAllocHash(pAllocHash, pFileLine)); |
515 | | |
516 | 0 | pIter = taosHashIterate(pStat->remainHash, pIter); |
517 | 0 | } |
518 | | |
519 | 0 | SMPAllocStat* pAlloc = NULL; |
520 | 0 | pIter = taosHashIterate(pAllocHash, NULL); |
521 | 0 | while (pIter) { |
522 | 0 | pAlloc = (SMPAllocStat*)pIter; |
523 | 0 | SMPFileLineId* pId = (SMPFileLineId*)taosHashGetKey(pIter, NULL); |
524 | 0 | SMPAllocStat* pAlloc = (SMPAllocStat*)taosHashGet(pStat->allocHash, pId, sizeof(*pId)); |
525 | 0 | char* pFileName = (char*)taosHashGet(pStat->fileHash, &pId->fileId, sizeof(pId->fileId)); |
526 | 0 | if (NULL == pAlloc || NULL == pFileName) { |
527 | 0 | uError("fail to get pId in allocHash or fileHash, pAlloc:%p, pFileName:%p", pAlloc, pFileName); |
528 | 0 | goto _return; |
529 | 0 | } |
530 | | |
531 | 0 | uInfo("REMAINING: %" PRId64 " bytes allocated by %s:%d in %" PRId64 " times", pAlloc->allocBytes, pFileName, pId->line, pAlloc->allocTimes); |
532 | | |
533 | 0 | pIter = taosHashIterate(pAllocHash, pIter); |
534 | 0 | } |
535 | | |
536 | 0 | _return: |
537 | |
|
538 | 0 | taosHashCleanup(pAllocHash); |
539 | 0 | } |
540 | | |
541 | 0 | void mpPrintPosAllocStat(SMPStatPos* pStat) { |
542 | |
|
543 | 0 | } |
544 | | |
545 | 0 | void mpPrintPosFreeStat(SMPStatPos* pStat) { |
546 | |
|
547 | 0 | } |
548 | | |
549 | 0 | void mpPrintPosStat(SMPCtrlInfo* pCtrl, SMPStatPos* pStat, char* detailName) { |
550 | 0 | if (!MP_GET_FLAG(pCtrl->funcFlags, MP_CTRL_FLAG_PRINT_STAT)) { |
551 | 0 | return; |
552 | 0 | } |
553 | | |
554 | 0 | uInfo("MemPool [%s] Pos Stat:", detailName); |
555 | 0 | uInfo("error times: %" PRId64, pStat->logErrTimes); |
556 | |
|
557 | 0 | mpPrintPosRemainStat(pStat); |
558 | |
|
559 | 0 | mpPrintPosAllocStat(pStat); |
560 | |
|
561 | 0 | mpPrintPosFreeStat(pStat); |
562 | 0 | } |
563 | | |
564 | 0 | void mpPrintNodeStat(SMPCtrlInfo* pCtrl, SHashObj* pHash, char* detailName) { |
565 | | //TODO |
566 | 0 | } |
567 | | |
568 | 0 | void mpPrintSessionStat(SMPCtrlInfo* pCtrl, SMPStatSession* pSessStat, char* detailName) { |
569 | 0 | if (!MP_GET_FLAG(pCtrl->funcFlags, MP_CTRL_FLAG_PRINT_STAT)) { |
570 | 0 | return; |
571 | 0 | } |
572 | | |
573 | 0 | uInfo("MemPool [%s] session stat:", detailName); |
574 | 0 | uInfo("init session succeed num: %" PRId64, pSessStat->initSucc); |
575 | 0 | uInfo("init session failed num: %" PRId64, pSessStat->initFail); |
576 | 0 | uInfo("session destroyed num: %" PRId64, pSessStat->destroyNum); |
577 | 0 | } |
578 | | |
579 | | |
580 | | |
581 | 0 | void mpLogDetailStat(SMPStatDetail* pDetail, EMPStatLogItem item, SMPStatInput* pInput) { |
582 | 0 | switch (item) { |
583 | 0 | case E_MP_STAT_LOG_MEM_MALLOC: { |
584 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_EXEC)) { |
585 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memMalloc.exec, 1); |
586 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memMalloc.exec, pInput->size); |
587 | 0 | } |
588 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_RES_SUCC)) { |
589 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memMalloc.succ, 1); |
590 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memMalloc.succ, pInput->size); |
591 | 0 | } |
592 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_RES_FAIL)) { |
593 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memMalloc.fail, 1); |
594 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memMalloc.fail, pInput->size); |
595 | 0 | } |
596 | 0 | break; |
597 | 0 | } |
598 | 0 | case E_MP_STAT_LOG_MEM_CALLOC:{ |
599 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_EXEC)) { |
600 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memCalloc.exec, 1); |
601 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memCalloc.exec, pInput->size); |
602 | 0 | } |
603 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_RES_SUCC)) { |
604 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memCalloc.succ, 1); |
605 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memCalloc.succ, pInput->size); |
606 | 0 | } |
607 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_RES_FAIL)) { |
608 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memCalloc.fail, 1); |
609 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memCalloc.fail, pInput->size); |
610 | 0 | } |
611 | 0 | break; |
612 | 0 | } |
613 | 0 | case E_MP_STAT_LOG_MEM_REALLOC:{ |
614 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_EXEC)) { |
615 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memRealloc.exec, 1); |
616 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memRealloc.exec, pInput->size); |
617 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memRealloc.origExec, pInput->origSize); |
618 | 0 | } |
619 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_RES_SUCC)) { |
620 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memRealloc.succ, 1); |
621 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memRealloc.succ, pInput->size); |
622 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memRealloc.origSucc, pInput->origSize); |
623 | 0 | } |
624 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_RES_FAIL)) { |
625 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memRealloc.fail, 1); |
626 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memRealloc.fail, pInput->size); |
627 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memRealloc.origFail, pInput->origSize); |
628 | 0 | } |
629 | 0 | break; |
630 | 0 | } |
631 | 0 | case E_MP_STAT_LOG_MEM_FREE:{ |
632 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_EXEC)) { |
633 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memFree.exec, 1); |
634 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memFree.exec, pInput->size); |
635 | 0 | } |
636 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_RES_SUCC)) { |
637 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memFree.succ, 1); |
638 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memFree.succ, pInput->size); |
639 | 0 | } |
640 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_RES_FAIL)) { |
641 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memFree.fail, 1); |
642 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memFree.fail, pInput->size); |
643 | 0 | } |
644 | 0 | break; |
645 | 0 | } |
646 | 0 | case E_MP_STAT_LOG_MEM_STRDUP: { |
647 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_EXEC)) { |
648 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memStrdup.exec, 1); |
649 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memStrdup.exec, pInput->size); |
650 | 0 | } |
651 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_RES_SUCC)) { |
652 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memStrdup.succ, 1); |
653 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memStrdup.succ, pInput->size); |
654 | 0 | } |
655 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_RES_FAIL)) { |
656 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memStrdup.fail, 1); |
657 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memStrdup.fail, pInput->size); |
658 | 0 | } |
659 | 0 | break; |
660 | 0 | } |
661 | 0 | case E_MP_STAT_LOG_MEM_STRNDUP: { |
662 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_EXEC)) { |
663 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memStrndup.exec, 1); |
664 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memStrndup.exec, pInput->size); |
665 | 0 | } |
666 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_RES_SUCC)) { |
667 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memStrndup.succ, 1); |
668 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memStrndup.succ, pInput->size); |
669 | 0 | } |
670 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_RES_FAIL)) { |
671 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memStrndup.fail, 1); |
672 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memStrndup.fail, pInput->size); |
673 | 0 | } |
674 | 0 | break; |
675 | 0 | } |
676 | 0 | case E_MP_STAT_LOG_MEM_TRIM: { |
677 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_EXEC)) { |
678 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memTrim.exec, 1); |
679 | 0 | } |
680 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_RES_SUCC)) { |
681 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memTrim.succ, 1); |
682 | 0 | (void)atomic_add_fetch_64(&pDetail->bytes.memTrim.succ, pInput->size); |
683 | 0 | } |
684 | 0 | if (MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_RES_FAIL)) { |
685 | 0 | (void)atomic_add_fetch_64(&pDetail->times.memTrim.fail, 1); |
686 | 0 | } |
687 | 0 | break; |
688 | 0 | } |
689 | 0 | case E_MP_STAT_LOG_CHUNK_MALLOC: |
690 | 0 | case E_MP_STAT_LOG_CHUNK_RECYCLE: |
691 | 0 | case E_MP_STAT_LOG_CHUNK_REUSE: |
692 | 0 | case E_MP_STAT_LOG_CHUNK_FREE: { |
693 | |
|
694 | 0 | } |
695 | 0 | default: |
696 | 0 | uError("Invalid stat item: %d", item); |
697 | 0 | break; |
698 | 0 | } |
699 | 0 | } |
700 | | |
701 | 0 | int32_t mpGetAllocFreeStat(SHashObj* pHash, void* pKey, int32_t keyLen, void* pNew, int32_t newSize, void** ppRes) { |
702 | 0 | void* pStat = NULL; |
703 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
704 | |
|
705 | 0 | while (true) { |
706 | 0 | pStat = taosHashGet(pHash, pKey, keyLen); |
707 | 0 | if (NULL != pStat) { |
708 | 0 | *ppRes = pStat; |
709 | 0 | break; |
710 | 0 | } |
711 | | |
712 | 0 | code = taosHashPut(pHash, pKey, keyLen, pNew, newSize); |
713 | 0 | if (code) { |
714 | 0 | if (TSDB_CODE_DUP_KEY == code) { |
715 | 0 | continue; |
716 | 0 | } |
717 | | |
718 | 0 | return code; |
719 | 0 | } |
720 | 0 | } |
721 | | |
722 | 0 | return TSDB_CODE_SUCCESS; |
723 | 0 | } |
724 | | |
725 | 0 | int32_t mpGetPosStatFileId(SMPStatPos* pStat, char* fileName, uint32_t* pId, bool sessionStat) { |
726 | 0 | uint32_t hashVal = MurmurHash3_32(fileName, strlen(fileName)); |
727 | 0 | int32_t code = taosHashPut(pStat->fileHash, &hashVal, sizeof(hashVal), fileName, strlen(fileName) + 1); |
728 | 0 | if (code && TSDB_CODE_DUP_KEY != code) { |
729 | 0 | return code; |
730 | 0 | } |
731 | | |
732 | 0 | *pId = hashVal; |
733 | | |
734 | 0 | return TSDB_CODE_SUCCESS; |
735 | 0 | } |
736 | | |
737 | 0 | void mpLogPosStat(SMPStatPos* pStat, EMPStatLogItem item, SMPStatInput* pInput, bool sessionStat) { |
738 | 0 | if (!MP_GET_FLAG(pInput->procFlags, MP_STAT_PROC_FLAG_RES_SUCC)) { |
739 | 0 | return; |
740 | 0 | } |
741 | | |
742 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
743 | | |
744 | 0 | switch (item) { |
745 | 0 | case E_MP_STAT_LOG_MEM_MALLOC: |
746 | 0 | case E_MP_STAT_LOG_MEM_CALLOC: |
747 | 0 | case E_MP_STAT_LOG_MEM_STRDUP: |
748 | 0 | case E_MP_STAT_LOG_MEM_STRNDUP: { |
749 | 0 | SMPAllocStat allocStat = {0}, *pAlloc = NULL; |
750 | 0 | SMPFileLine fileLine = {.fl.line = pInput->line, .size = pInput->size}; |
751 | 0 | code = mpGetPosStatFileId(pStat, pInput->file, &fileLine.fl.fileId, sessionStat); |
752 | 0 | if (TSDB_CODE_SUCCESS != code) { |
753 | 0 | uError("add pMem:%p %s:%d to fileHash failed, error:%s, sessionStat:%d", |
754 | 0 | pInput->pMem, pInput->file, pInput->line, tstrerror(code), sessionStat); |
755 | 0 | MP_ERR_JRET(code); |
756 | 0 | } |
757 | 0 | code = taosHashPut(pStat->remainHash, &pInput->pMem, POINTER_BYTES, &fileLine, sizeof(fileLine)); |
758 | 0 | if (TSDB_CODE_SUCCESS != code) { |
759 | 0 | if (TSDB_CODE_DUP_KEY == code) { |
760 | 0 | SMPFileLine* pFileLine = (SMPFileLine*)taosHashAcquire(pStat->remainHash, &pInput->pMem, POINTER_BYTES); |
761 | 0 | if (pFileLine) { |
762 | 0 | char* pFileName = (char*)taosHashGet(pStat->fileHash, &pFileLine->fl.fileId, sizeof(pFileLine->fl.fileId)); |
763 | 0 | if (NULL == pFileName) { |
764 | 0 | uError("fail to get fileId %u in fileHash", pFileLine->fl.fileId); |
765 | 0 | } else { |
766 | 0 | uError("add pMem:%p %s:%d to remainHash failed, error:%s, sessionStat:%d, origAllocAt %s:%d", |
767 | 0 | pInput->pMem, pInput->file, pInput->line, tstrerror(code), sessionStat, pFileName, pFileLine->fl.line); |
768 | 0 | MP_ERR_JRET(code); |
769 | 0 | } |
770 | 0 | } |
771 | 0 | } |
772 | | |
773 | 0 | uError("add pMem:%p %s:%d to remainHash failed, error:%s, sessionStat:%d", |
774 | 0 | pInput->pMem, pInput->file, pInput->line, tstrerror(code), sessionStat); |
775 | | |
776 | 0 | MP_ERR_JRET(code); |
777 | 0 | } |
778 | 0 | code = mpGetAllocFreeStat(pStat->allocHash, &fileLine.fl, sizeof(fileLine.fl), (void*)&allocStat, sizeof(allocStat), (void**)&pAlloc); |
779 | 0 | if (TSDB_CODE_SUCCESS != code) { |
780 | 0 | uError("add pMem:%p %s:%d to allocHash failed, error:%s, sessionStat:%d", |
781 | 0 | pInput->pMem, pInput->file, pInput->line, tstrerror(code), sessionStat); |
782 | 0 | MP_ERR_JRET(code); |
783 | 0 | } |
784 | | |
785 | 0 | (void)atomic_add_fetch_64(&pAlloc->allocTimes, 1); |
786 | 0 | (void)atomic_add_fetch_64(&pAlloc->allocBytes, pInput->size); |
787 | 0 | break; |
788 | 0 | } |
789 | 0 | case E_MP_STAT_LOG_MEM_REALLOC: { |
790 | 0 | SMPAllocStat allocStat = {0}, *pAlloc = NULL; |
791 | 0 | SMPFreeStat freeStat = {0}, *pFree = NULL; |
792 | 0 | SMPFileLine fileLine = {.fl.line = pInput->line, .size = pInput->size}; |
793 | 0 | code = mpGetPosStatFileId(pStat, pInput->file, &fileLine.fl.fileId, sessionStat); |
794 | 0 | if (TSDB_CODE_SUCCESS != code) { |
795 | 0 | uError("realloc: add pMem:%p %s:%d to fileHash failed, error:%s, sessionStat:%d", |
796 | 0 | pInput->pMem, pInput->file, pInput->line, tstrerror(code), sessionStat); |
797 | 0 | MP_ERR_JRET(code); |
798 | 0 | } |
799 | | |
800 | | // ASSSRT((pInput->pOrigMem && pInput->origSize > 0) || (NULL == pInput->pOrigMem && pInput->origSize == 0)); |
801 | | |
802 | 0 | if (pInput->pOrigMem && pInput->origSize > 0) { |
803 | 0 | code = taosHashRemove(pStat->remainHash, &pInput->pOrigMem, POINTER_BYTES); |
804 | 0 | if (TSDB_CODE_SUCCESS != code) { |
805 | 0 | uError("realloc: rm pOrigMem:%p %s:%d from remainHash failed, error:%s, sessionStat:%d", |
806 | 0 | pInput->pOrigMem, pInput->file, pInput->line, tstrerror(code), sessionStat); |
807 | 0 | MP_ERR_JRET(code); |
808 | 0 | } |
809 | 0 | code = mpGetAllocFreeStat(pStat->freeHash, &fileLine.fl, sizeof(fileLine.fl), (void*)&freeStat, sizeof(freeStat), (void**)&pFree); |
810 | 0 | if (TSDB_CODE_SUCCESS != code) { |
811 | 0 | uError("realloc: add pOrigMem:%p %s:%d to freeHash failed, error:%s, sessionStat:%d", |
812 | 0 | pInput->pOrigMem, pInput->file, pInput->line, tstrerror(code), sessionStat); |
813 | 0 | MP_ERR_JRET(code); |
814 | 0 | } |
815 | | |
816 | 0 | (void)atomic_add_fetch_64(&pFree->freeTimes, 1); |
817 | 0 | (void)atomic_add_fetch_64(&pFree->freeBytes, pInput->origSize); |
818 | 0 | } |
819 | | |
820 | 0 | code = taosHashPut(pStat->remainHash, &pInput->pMem, POINTER_BYTES, &fileLine, sizeof(fileLine)); |
821 | 0 | if (TSDB_CODE_SUCCESS != code) { |
822 | 0 | if (TSDB_CODE_DUP_KEY == code) { |
823 | 0 | SMPFileLine* pFileLine = (SMPFileLine*)taosHashAcquire(pStat->remainHash, &pInput->pMem, POINTER_BYTES); |
824 | 0 | if (pFileLine) { |
825 | 0 | char* pFileName = (char*)taosHashGet(pStat->fileHash, &pFileLine->fl.fileId, sizeof(pFileLine->fl.fileId)); |
826 | 0 | if (NULL == pFileName) { |
827 | 0 | uError("realloc: fail to get fileId %u in fileHash", pFileLine->fl.fileId); |
828 | 0 | } else { |
829 | 0 | uError("realloc: add pMem:%p %s:%d to remainHash failed, error:%s, sessionStat:%d, origAllocAt %s:%d", |
830 | 0 | pInput->pMem, pInput->file, pInput->line, tstrerror(code), sessionStat, pFileName, pFileLine->fl.line); |
831 | 0 | MP_ERR_JRET(code); |
832 | 0 | } |
833 | 0 | } |
834 | 0 | } |
835 | | |
836 | 0 | uError("realloc: add pMem:%p %s:%d to remainHash failed, error:%s, sessionStat:%d", |
837 | 0 | pInput->pMem, pInput->file, pInput->line, tstrerror(code), sessionStat); |
838 | 0 | MP_ERR_JRET(code); |
839 | 0 | } |
840 | | |
841 | 0 | code = mpGetAllocFreeStat(pStat->allocHash, &fileLine.fl, sizeof(fileLine.fl), (void*)&allocStat, sizeof(allocStat), (void**)&pAlloc); |
842 | 0 | if (TSDB_CODE_SUCCESS != code) { |
843 | 0 | uError("realloc: add pMem:%p %s:%d to allocHash failed, error:%s, sessionStat:%d", |
844 | 0 | pInput->pMem, pInput->file, pInput->line, tstrerror(code), sessionStat); |
845 | 0 | MP_ERR_JRET(code); |
846 | 0 | } |
847 | | |
848 | 0 | (void)atomic_add_fetch_64(&pAlloc->allocTimes, 1); |
849 | 0 | (void)atomic_add_fetch_64(&pAlloc->allocBytes, pInput->size); |
850 | 0 | break; |
851 | 0 | } |
852 | 0 | case E_MP_STAT_LOG_MEM_FREE: { |
853 | 0 | SMPAllocStat allocStat = {0}, *pAlloc = NULL; |
854 | 0 | SMPFreeStat freeStat = {0}, *pFree = NULL; |
855 | 0 | SMPFileLineId fl = {.line = pInput->line}; |
856 | 0 | code = mpGetPosStatFileId(pStat, pInput->file, &fl.fileId, sessionStat); |
857 | 0 | if (TSDB_CODE_SUCCESS != code) { |
858 | 0 | uError("free: add pMem:%p %s:%d to fileHash failed, error:%s, sessionStat:%d", |
859 | 0 | pInput->pMem, pInput->file, pInput->line, tstrerror(code), sessionStat); |
860 | 0 | MP_ERR_JRET(code); |
861 | 0 | } |
862 | | |
863 | 0 | code = taosHashRemove(pStat->remainHash, &pInput->pMem, POINTER_BYTES); |
864 | 0 | if (TSDB_CODE_SUCCESS != code) { |
865 | 0 | uDebug("free: rm pMem:%p %s:%d to remainHash failed, error:%s, sessionStat:%d", |
866 | 0 | pInput->pMem, pInput->file, pInput->line, tstrerror(code), sessionStat); |
867 | 0 | } |
868 | |
|
869 | 0 | code = mpGetAllocFreeStat(pStat->freeHash, &fl, sizeof(fl), (void*)&freeStat, sizeof(freeStat), (void**)&pFree); |
870 | 0 | if (TSDB_CODE_SUCCESS != code) { |
871 | 0 | uError("free: add pMem:%p %s:%d to freeHash failed, error:%s, sessionStat:%d", |
872 | 0 | pInput->pMem, pInput->file, pInput->line, tstrerror(code), sessionStat); |
873 | 0 | MP_ERR_JRET(code); |
874 | 0 | } |
875 | | |
876 | 0 | (void)atomic_add_fetch_64(&pFree->freeTimes, 1); |
877 | 0 | (void)atomic_add_fetch_64(&pFree->freeBytes, pInput->size); |
878 | 0 | break; |
879 | 0 | } |
880 | 0 | case E_MP_STAT_LOG_MEM_TRIM: |
881 | 0 | break; |
882 | 0 | case E_MP_STAT_LOG_CHUNK_MALLOC: |
883 | 0 | case E_MP_STAT_LOG_CHUNK_RECYCLE: |
884 | 0 | case E_MP_STAT_LOG_CHUNK_REUSE: |
885 | 0 | case E_MP_STAT_LOG_CHUNK_FREE: { |
886 | 0 | break; |
887 | 0 | } |
888 | 0 | default: |
889 | 0 | uError("Invalid stat item: %d", item); |
890 | 0 | break; |
891 | 0 | } |
892 | | |
893 | 0 | return; |
894 | | |
895 | 0 | _return: |
896 | | |
897 | 0 | (void)atomic_add_fetch_64(&pStat->logErrTimes, 1); |
898 | 0 | } |
899 | | |
900 | | |
901 | 0 | void mpLogStat(SMemPool* pPool, SMPSession* pSession, EMPStatLogItem item, SMPStatInput* pInput) { |
902 | 0 | bool enablePool = false, randErr = false; |
903 | | |
904 | 0 | switch (item) { |
905 | 0 | case E_MP_STAT_LOG_MEM_MALLOC: |
906 | 0 | case E_MP_STAT_LOG_MEM_CALLOC: |
907 | 0 | case E_MP_STAT_LOG_MEM_REALLOC: |
908 | 0 | case E_MP_STAT_LOG_MEM_FREE: |
909 | 0 | case E_MP_STAT_LOG_MEM_STRDUP: |
910 | 0 | case E_MP_STAT_LOG_MEM_STRNDUP: |
911 | 0 | case E_MP_STAT_LOG_MEM_TRIM: { |
912 | 0 | if (pSession && MP_GET_FLAG(pSession->ctrl.statFlags, MP_LOG_FLAG_ALL_MEM)) { |
913 | 0 | mpLogDetailStat(&pSession->stat.statDetail, item, pInput); |
914 | 0 | } |
915 | 0 | if (MP_GET_FLAG(gMPMgmt.ctrl.statFlags, MP_LOG_FLAG_ALL_MEM)) { |
916 | 0 | mpLogDetailStat(&pPool->stat.statDetail, item, pInput); |
917 | 0 | } |
918 | 0 | if (pSession && MP_GET_FLAG(pSession->ctrl.statFlags, MP_LOG_FLAG_ALL_POS)) { |
919 | 0 | taosSaveDisableMemPoolUsage(enablePool, randErr); |
920 | 0 | mpLogPosStat(&pSession->stat.posStat, item, pInput, true); |
921 | 0 | taosRestoreEnableMemPoolUsage(enablePool, randErr); |
922 | 0 | } |
923 | 0 | if (MP_GET_FLAG(gMPMgmt.ctrl.statFlags, MP_LOG_FLAG_ALL_POS)) { |
924 | 0 | taosSaveDisableMemPoolUsage(enablePool, randErr); |
925 | 0 | mpLogPosStat(&pPool->stat.posStat, item, pInput, false); |
926 | 0 | taosRestoreEnableMemPoolUsage(enablePool, randErr); |
927 | 0 | } |
928 | 0 | break; |
929 | 0 | } |
930 | 0 | case E_MP_STAT_LOG_CHUNK_MALLOC: |
931 | 0 | case E_MP_STAT_LOG_CHUNK_RECYCLE: |
932 | 0 | case E_MP_STAT_LOG_CHUNK_REUSE: |
933 | 0 | case E_MP_STAT_LOG_CHUNK_FREE: { |
934 | 0 | break; |
935 | 0 | } |
936 | 0 | default: |
937 | 0 | uError("Invalid stat item: %d", item); |
938 | 0 | break; |
939 | 0 | } |
940 | 0 | } |
941 | | |
942 | 0 | void mpCheckStatDetail(void* poolHandle, void* session, char* detailName) { |
943 | 0 | if (0 == tsMemPoolFullFunc) { |
944 | 0 | return; |
945 | 0 | } |
946 | | |
947 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
948 | 0 | SMPSession* pSession = (SMPSession*)session; |
949 | 0 | SMPCtrlInfo* pCtrl = NULL; |
950 | 0 | SMPStatDetail* pDetail = NULL; |
951 | |
|
952 | 0 | if (NULL != session) { |
953 | 0 | pCtrl = &pSession->ctrl; |
954 | 0 | pDetail = &pSession->stat.statDetail; |
955 | 0 | if (MP_GET_FLAG(pCtrl->funcFlags, MP_CTRL_FLAG_CHECK_STAT)) { |
956 | 0 | int64_t allocSize = MEMPOOL_GET_ALLOC_SIZE(pDetail); |
957 | 0 | int64_t freeSize = MEMPOOL_GET_FREE_SIZE(pDetail); |
958 | |
|
959 | 0 | if (allocSize != freeSize) { |
960 | 0 | uError("%s Session in JOB:0x%" PRIx64 " stat check failed, allocSize:%" PRId64 ", freeSize:%" PRId64, |
961 | 0 | detailName, pSession->pJob->job.jobId, allocSize, freeSize); |
962 | |
|
963 | 0 | taosMemPoolPrintStat(NULL, pSession, detailName); |
964 | 0 | } else { |
965 | 0 | uDebug("%s Session in JOB:0x%" PRIx64 " stat check succeed, allocSize:%" PRId64 ", freeSize:%" PRId64, |
966 | 0 | detailName, pSession->pJob->job.jobId, allocSize, freeSize); |
967 | 0 | } |
968 | 0 | } |
969 | 0 | } |
970 | |
|
971 | 0 | if (NULL != poolHandle) { |
972 | 0 | pCtrl = &gMPMgmt.ctrl; |
973 | 0 | pDetail = &pPool->stat.statDetail; |
974 | 0 | int64_t sessInit = atomic_load_64(&pPool->stat.statSession.initFail) + atomic_load_64(&pPool->stat.statSession.initSucc); |
975 | 0 | if (MP_GET_FLAG(pCtrl->funcFlags, MP_CTRL_FLAG_CHECK_STAT) && sessInit == atomic_load_64(&pPool->stat.statSession.destroyNum)) { |
976 | 0 | int64_t allocSize = pDetail->bytes.memMalloc.succ + pDetail->bytes.memCalloc.succ + pDetail->bytes.memRealloc.succ + pDetail->bytes.memStrdup.succ + pDetail->bytes.memStrndup.succ; |
977 | 0 | int64_t freeSize = pDetail->bytes.memRealloc.origSucc + pDetail->bytes.memFree.succ; |
978 | |
|
979 | 0 | if (allocSize != freeSize) { |
980 | 0 | uError("%s MemPool %s stat check failed, allocSize:%" PRId64 ", freeSize:%" PRId64, detailName, pPool->name, allocSize, freeSize); |
981 | |
|
982 | 0 | taosMemPoolPrintStat(poolHandle, NULL, detailName); |
983 | 0 | } else { |
984 | 0 | uDebug("%s MemPool %s stat check succeed, allocSize:%" PRId64 ", freeSize:%" PRId64, detailName, pPool->name, allocSize, freeSize); |
985 | 0 | } |
986 | 0 | } |
987 | 0 | } |
988 | 0 | } |
989 | | |
990 | | |
991 | 0 | void mpCheckUpateCfg(void) { |
992 | | /* |
993 | | taosRLockLatch(&gMPMgmt.poolLock); |
994 | | int32_t poolNum = taosArrayGetSize(gMPMgmt.poolList); |
995 | | for (int32_t i = 0; i < poolNum; ++i) { |
996 | | SMemPool* pPool = (SMemPool*)taosArrayGetP(gMPMgmt.poolList, i); |
997 | | if (pPool->cfg.cb.cfgUpdateFp) { |
998 | | (*pPool->cfg.cb.cfgUpdateFp)((void*)pPool, &pPool->cfg); |
999 | | } |
1000 | | } |
1001 | | taosRUnLockLatch(&gMPMgmt.poolLock); |
1002 | | */ |
1003 | 0 | } |
1004 | | |
1005 | 0 | void mpUpdateSystemAvailableMemorySize() { |
1006 | 0 | static int64_t errorTimes = 0; |
1007 | 0 | int64_t sysAvailSize = 0; |
1008 | | |
1009 | 0 | int32_t code = taosGetSysAvailMemory(&sysAvailSize); |
1010 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1011 | 0 | errorTimes++; |
1012 | 0 | if (0 == errorTimes % 1000) { |
1013 | 0 | uError("get system available memory size failed, error: %s, errorTimes:%" PRId64, tstrerror(code), errorTimes); |
1014 | 0 | } |
1015 | | |
1016 | 0 | return; |
1017 | 0 | } |
1018 | | |
1019 | 0 | atomic_store_64(&tsCurrentAvailMemorySize, sysAvailSize); |
1020 | |
|
1021 | 0 | uTrace("system available memory size: %" PRId64, sysAvailSize); |
1022 | 0 | } |
1023 | | |
1024 | 0 | void mpSchedTrim(int64_t* loopTimes) { |
1025 | 0 | static int64_t trimTimes = 0; |
1026 | | |
1027 | 0 | atomic_store_8(&tsNeedTrim, 1); |
1028 | 0 | if (loopTimes) { |
1029 | 0 | *loopTimes = 0; |
1030 | 0 | } |
1031 | | |
1032 | 0 | uDebug("%" PRId64 "th memory trim scheduled", ++trimTimes); |
1033 | 0 | } |
1034 | | |
1035 | 0 | void* mpMgmtThreadFunc(void* param) { |
1036 | 0 | int32_t timeout = 0; |
1037 | 0 | int64_t retireSize = 0, loopTimes = 0; |
1038 | 0 | SMemPool* pPool = (SMemPool*)atomic_load_ptr(&gMemPoolHandle); |
1039 | | |
1040 | 0 | while (0 == atomic_load_8(&gMPMgmt.modExit)) { |
1041 | 0 | mpUpdateSystemAvailableMemorySize(); |
1042 | |
|
1043 | 0 | retireSize = pPool->cfg.reserveSize - atomic_load_64(&tsCurrentAvailMemorySize); |
1044 | 0 | if (retireSize > 0) { |
1045 | 0 | (*pPool->cfg.cb.failFp)(retireSize, TSDB_CODE_QRY_QUERY_MEM_EXHAUSTED); |
1046 | |
|
1047 | 0 | mpSchedTrim(&loopTimes); |
1048 | 0 | } |
1049 | |
|
1050 | 0 | if (0 == (++loopTimes) % 500) { |
1051 | 0 | mpSchedTrim(&loopTimes); |
1052 | 0 | } |
1053 | |
|
1054 | 0 | taosMsleep(MP_DEFAULT_MEM_CHK_INTERVAL_MS); |
1055 | | /* |
1056 | | timeout = tsem2_timewait(&gMPMgmt.threadSem, gMPMgmt.waitMs); |
1057 | | if (0 != timeout) { |
1058 | | mpUpdateSystemAvailableMemorySize(); |
1059 | | continue; |
1060 | | } |
1061 | | |
1062 | | if (atomic_load_8(&gMPMgmt.msgQueue.midLevelRetire)) { |
1063 | | (*gMPMgmt.msgQueue.pPool->cfg.cb.retireJobsFp)(gMPMgmt.msgQueue.pPool, atomic_load_64(&gMPMgmt.msgQueue.pPool->cfg.retireUnitSize), false, TSDB_CODE_QRY_QUERY_MEM_EXHAUSTED); |
1064 | | } else if (atomic_load_8(&gMPMgmt.msgQueue.lowLevelRetire)) { |
1065 | | (*gMPMgmt.msgQueue.pPool->cfg.cb.retireJobsFp)(gMPMgmt.msgQueue.pPool, atomic_load_64(&gMPMgmt.msgQueue.pPool->cfg.retireUnitSize), true, TSDB_CODE_QRY_QUERY_MEM_EXHAUSTED); |
1066 | | } |
1067 | | */ |
1068 | 0 | } |
1069 | |
|
1070 | 0 | taosMemPoolModDestroy(); |
1071 | | |
1072 | 0 | return NULL; |
1073 | 0 | } |
1074 | | |
1075 | 0 | int32_t mpCreateMgmtThread() { |
1076 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1077 | 0 | TdThreadAttr thAttr; |
1078 | 0 | MP_ERR_RET(taosThreadAttrInit(&thAttr)); |
1079 | 0 | MP_ERR_JRET(taosThreadAttrSetDetachState(&thAttr, PTHREAD_CREATE_JOINABLE)); |
1080 | 0 | code = taosThreadCreate(&gMPMgmt.poolMgmtThread, &thAttr, mpMgmtThreadFunc, NULL); |
1081 | 0 | if (code != 0) { |
1082 | 0 | uError("failed to create memPool mgmt thread, error: 0x%x", code); |
1083 | 0 | (void)taosThreadAttrDestroy(&thAttr); |
1084 | 0 | MP_ERR_JRET(code); |
1085 | 0 | } |
1086 | | |
1087 | 0 | _return: |
1088 | |
|
1089 | 0 | MP_ERR_RET(taosThreadAttrDestroy(&thAttr)); |
1090 | | |
1091 | 0 | return code; |
1092 | 0 | } |
1093 | | |
1094 | 0 | void mpModInit(void) { |
1095 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1096 | |
|
1097 | 0 | gMPMgmt.modExit = 0; |
1098 | |
|
1099 | 0 | taosInitRWLatch(&gMPMgmt.poolLock); |
1100 | | |
1101 | 0 | gMPMgmt.poolList = taosArrayInit(10, POINTER_BYTES); |
1102 | 0 | if (NULL == gMPMgmt.poolList) { |
1103 | 0 | MP_ERR_JRET(terrno); |
1104 | 0 | } |
1105 | | |
1106 | 0 | gMPMgmt.strategy = E_MP_STRATEGY_DIRECT; |
1107 | |
|
1108 | 0 | gMPMgmt.ctrl.statFlags = MP_STAT_FLAG_LOG_ALL & (~MP_LOG_FLAG_ALL_POS); |
1109 | 0 | gMPMgmt.ctrl.funcFlags = MP_CTRL_FLAG_PRINT_STAT | MP_CTRL_FLAG_CHECK_STAT | MP_CTRL_FLAG_LOG_MAXSIZE; |
1110 | | |
1111 | | //gMPMgmt.code = tsem2_init(&gMPMgmt.threadSem, 0, 0); |
1112 | | //if (TSDB_CODE_SUCCESS != gMPMgmt.code) { |
1113 | | // uError("failed to init sem2, error: 0x%x", gMPMgmt.code); |
1114 | | // return; |
1115 | | //} |
1116 | |
|
1117 | 0 | gMPMgmt.waitMs = MP_DEFAULT_MEM_CHK_INTERVAL_MS; |
1118 | |
|
1119 | 0 | _return: |
1120 | |
|
1121 | 0 | gMPMgmt.code = code; |
1122 | 0 | } |
1123 | | |
1124 | | |
1125 | 0 | void mpFreePool(void* p) { |
1126 | 0 | SMemPool* pPool = *(void**)p; |
1127 | 0 | taosMemoryFree(pPool); |
1128 | 0 | } |
1129 | | |
1130 | | |
1131 | 0 | void taosMemPoolPrintStat(void* poolHandle, void* session, char* procName) { |
1132 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
1133 | 0 | SMPSession* pSession = (SMPSession*)session; |
1134 | 0 | char detailName[128]; |
1135 | |
|
1136 | 0 | if (NULL != pSession && MP_GET_FLAG(pSession->ctrl.funcFlags, MP_CTRL_FLAG_PRINT_STAT)) { |
1137 | 0 | snprintf(detailName, sizeof(detailName) - 1, "%s - %s", procName, "Session"); |
1138 | 0 | detailName[sizeof(detailName) - 1] = 0; |
1139 | 0 | mpPrintStatDetail(&pSession->ctrl, &pSession->stat.statDetail, detailName, pSession->maxAllocMemSize); |
1140 | |
|
1141 | 0 | snprintf(detailName, sizeof(detailName) - 1, "%s - %s", procName, "SessionPos"); |
1142 | 0 | detailName[sizeof(detailName) - 1] = 0; |
1143 | 0 | mpPrintPosStat(&pSession->ctrl, &pSession->stat.posStat, detailName); |
1144 | 0 | } |
1145 | |
|
1146 | 0 | if (NULL != pPool && MP_GET_FLAG(gMPMgmt.ctrl.funcFlags, MP_CTRL_FLAG_PRINT_STAT)) { |
1147 | 0 | snprintf(detailName, sizeof(detailName) - 1, "%s - %s", procName, pPool->name); |
1148 | 0 | detailName[sizeof(detailName) - 1] = 0; |
1149 | 0 | mpPrintSessionStat(&gMPMgmt.ctrl, &pPool->stat.statSession, detailName); |
1150 | 0 | mpPrintStatDetail(&gMPMgmt.ctrl, &pPool->stat.statDetail, detailName, pPool->maxAllocMemSize); |
1151 | | |
1152 | | //snprintf(detailName, sizeof(detailName) - 1, "%s - %s", procName, "MemPoolNode"); |
1153 | | //detailName[sizeof(detailName) - 1] = 0; |
1154 | | //mpPrintNodeStat(&gMPMgmt.ctrl, pPool->stat.nodeStat, detailName); |
1155 | | |
1156 | 0 | snprintf(detailName, sizeof(detailName) - 1, "%s - %s", procName, "MemPoolPos"); |
1157 | 0 | detailName[sizeof(detailName) - 1] = 0; |
1158 | 0 | mpPrintPosStat(&gMPMgmt.ctrl, &pPool->stat.posStat, detailName); |
1159 | 0 | } |
1160 | 0 | } |
1161 | | |
1162 | | |
1163 | 0 | int32_t taosMemPoolOpen(char* poolName, SMemPoolCfg* cfg, void** poolHandle) { |
1164 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1165 | 0 | SMemPool* pPool = NULL; |
1166 | | |
1167 | | //MP_ERR_JRET(taosThreadOnce(&gMPoolInit, mpModInit)); |
1168 | 0 | mpModInit(); |
1169 | | |
1170 | 0 | if (TSDB_CODE_SUCCESS != gMPMgmt.code) { |
1171 | 0 | uError("init memory pool failed, code: 0x%x", gMPMgmt.code); |
1172 | 0 | MP_ERR_JRET(gMPMgmt.code); |
1173 | 0 | } |
1174 | | |
1175 | 0 | pPool = (SMemPool*)taosMemoryCalloc(1, sizeof(SMemPool)); |
1176 | 0 | if (NULL == pPool) { |
1177 | 0 | uError("calloc memory pool failed, code: 0x%x", terrno); |
1178 | 0 | MP_ERR_JRET(terrno); |
1179 | 0 | } |
1180 | | |
1181 | 0 | MP_ERR_JRET(mpInit(pPool, poolName, cfg)); |
1182 | | |
1183 | 0 | taosWLockLatch(&gMPMgmt.poolLock); |
1184 | | |
1185 | 0 | if (NULL == taosArrayPush(gMPMgmt.poolList, &pPool)) { |
1186 | 0 | taosWUnLockLatch(&gMPMgmt.poolLock); |
1187 | 0 | MP_ERR_JRET(terrno); |
1188 | 0 | } |
1189 | | |
1190 | 0 | pPool->slotId = taosArrayGetSize(gMPMgmt.poolList) - 1; |
1191 | | |
1192 | 0 | taosWUnLockLatch(&gMPMgmt.poolLock); |
1193 | |
|
1194 | 0 | uInfo("memory pool %s opened", poolName); |
1195 | |
|
1196 | 0 | _return: |
1197 | |
|
1198 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1199 | 0 | taosMemPoolClose(pPool); |
1200 | 0 | pPool = NULL; |
1201 | 0 | } |
1202 | |
|
1203 | 0 | *poolHandle = pPool; |
1204 | |
|
1205 | 0 | return code; |
1206 | 0 | } |
1207 | | |
1208 | 0 | void taosMemPoolCfgUpdate(void* poolHandle, SMemPoolCfg* pCfg) { |
1209 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
1210 | |
|
1211 | 0 | (void)mpUpdateCfg(pPool); |
1212 | 0 | } |
1213 | | |
1214 | 0 | void taosMemPoolDestroySession(void* poolHandle, void* session) { |
1215 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
1216 | 0 | SMPSession* pSession = (SMPSession*)session; |
1217 | 0 | if (NULL == poolHandle || NULL == pSession) { |
1218 | 0 | uWarn("null pointer of poolHandle %p or session %p", poolHandle, session); |
1219 | 0 | return; |
1220 | 0 | } |
1221 | | |
1222 | 0 | if (tsMemPoolFullFunc) { |
1223 | 0 | (void)atomic_add_fetch_64(&pPool->stat.statSession.destroyNum, 1); |
1224 | 0 | mpCheckStatDetail(pPool, pSession, "DestroySession"); |
1225 | 0 | mpDestroyPosStat(&pSession->stat.posStat); |
1226 | 0 | } |
1227 | | |
1228 | 0 | taosMemFreeClear(pSession->sessionId); |
1229 | |
|
1230 | 0 | TAOS_MEMSET(pSession, 0, sizeof(*pSession)); |
1231 | |
|
1232 | 0 | mpPushIdleNode(pPool, &pPool->sessionCache, (SMPListNode*)pSession); |
1233 | 0 | } |
1234 | | |
1235 | 0 | int32_t taosMemPoolInitSession(void* poolHandle, void** ppSession, void* pJob, char* sessionId) { |
1236 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1237 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
1238 | 0 | SMPSession* pSession = NULL; |
1239 | |
|
1240 | 0 | MP_ERR_JRET(mpPopIdleNode(pPool, &pPool->sessionCache, (void**)&pSession)); |
1241 | | |
1242 | 0 | if (NULL != sessionId) { |
1243 | 0 | pSession->sessionId = taosStrdupi(sessionId); |
1244 | 0 | if (NULL == pSession->sessionId) { |
1245 | 0 | MP_ERR_JRET(terrno); |
1246 | 0 | } |
1247 | 0 | } |
1248 | | |
1249 | 0 | TAOS_MEMCPY(&pSession->ctrl, &gMPMgmt.ctrl, sizeof(pSession->ctrl)); |
1250 | |
|
1251 | 0 | if (gMPFps[gMPMgmt.strategy].initSessionFp) { |
1252 | 0 | MP_ERR_JRET((*gMPFps[gMPMgmt.strategy].initSessionFp)(pPool, pSession)); |
1253 | 0 | } |
1254 | | |
1255 | 0 | if (tsMemPoolFullFunc) { |
1256 | 0 | MP_ERR_JRET(mpInitPosStat(&pSession->stat.posStat, true)); |
1257 | 0 | } |
1258 | | |
1259 | 0 | pSession->pJob = (SMPJob*)pJob; |
1260 | |
|
1261 | 0 | _return: |
1262 | |
|
1263 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1264 | 0 | taosMemPoolDestroySession(poolHandle, pSession); |
1265 | 0 | pSession = NULL; |
1266 | 0 | (void)atomic_add_fetch_64(&pPool->stat.statSession.initFail, 1); |
1267 | 0 | } else { |
1268 | 0 | (void)atomic_add_fetch_64(&pPool->stat.statSession.initSucc, 1); |
1269 | 0 | } |
1270 | |
|
1271 | 0 | *ppSession = pSession; |
1272 | |
|
1273 | 0 | return code; |
1274 | 0 | } |
1275 | | |
1276 | | |
1277 | 0 | void *taosMemPoolMalloc(void* poolHandle, void* session, int64_t size, char* fileName, int32_t lineNo) { |
1278 | 0 | if (0 == tsMemPoolFullFunc) { |
1279 | 0 | return mpDirectAlloc(poolHandle, ((SMPSession*)session)->pJob, size); |
1280 | 0 | } |
1281 | | |
1282 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1283 | 0 | SMPStatInput input = {.size = size, .file = fileName, .line = lineNo, .procFlags = MP_STAT_PROC_FLAG_EXEC, .pMem = NULL}; |
1284 | | |
1285 | 0 | if (NULL == poolHandle || NULL == fileName || size < 0) { |
1286 | 0 | uError("%s invalid input param, handle:%p, session:%p, fileName:%p, size:%" PRId64, __FUNCTION__, poolHandle, session, fileName, size); |
1287 | 0 | MP_ERR_JRET(TSDB_CODE_INVALID_PARA); |
1288 | 0 | } |
1289 | | |
1290 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
1291 | 0 | SMPSession* pSession = (SMPSession*)session; |
1292 | |
|
1293 | 0 | code = mpMalloc(pPool, pSession, &input.size, 0, &input.pMem); |
1294 | |
|
1295 | 0 | MP_SET_FLAG(input.procFlags, (NULL != input.pMem ? MP_STAT_PROC_FLAG_RES_SUCC : MP_STAT_PROC_FLAG_RES_FAIL)); |
1296 | 0 | mpLogStat(pPool, pSession, E_MP_STAT_LOG_MEM_MALLOC, &input); |
1297 | |
|
1298 | 0 | _return: |
1299 | |
|
1300 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1301 | 0 | terrno = code; |
1302 | 0 | } |
1303 | | |
1304 | 0 | return input.pMem; |
1305 | 0 | } |
1306 | | |
1307 | 0 | void *taosMemPoolCalloc(void* poolHandle, void* session, int64_t num, int64_t size, char* fileName, int32_t lineNo) { |
1308 | 0 | if (0 == tsMemPoolFullFunc) { |
1309 | 0 | return mpDirectCalloc(poolHandle, ((SMPSession*)session)->pJob, num, size); |
1310 | 0 | } |
1311 | | |
1312 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1313 | 0 | int64_t totalSize = num * size; |
1314 | 0 | SMPStatInput input = {.size = totalSize, .file = fileName, .line = lineNo, .procFlags = MP_STAT_PROC_FLAG_EXEC, .pMem = NULL}; |
1315 | | |
1316 | 0 | if (NULL == poolHandle || NULL == fileName || num < 0 || size < 0) { |
1317 | 0 | uError("%s invalid input param, handle:%p, session:%p, fileName:%p, num:%" PRId64 ", size:%" PRId64, |
1318 | 0 | __FUNCTION__, poolHandle, session, fileName, num, size); |
1319 | 0 | MP_ERR_JRET(TSDB_CODE_INVALID_PARA); |
1320 | 0 | } |
1321 | | |
1322 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
1323 | 0 | SMPSession* pSession = (SMPSession*)session; |
1324 | |
|
1325 | 0 | code = mpCalloc(pPool, pSession, &input.size, &input.pMem); |
1326 | |
|
1327 | 0 | MP_SET_FLAG(input.procFlags, (NULL != input.pMem ? MP_STAT_PROC_FLAG_RES_SUCC : MP_STAT_PROC_FLAG_RES_FAIL)); |
1328 | 0 | mpLogStat(pPool, pSession, E_MP_STAT_LOG_MEM_CALLOC, &input); |
1329 | |
|
1330 | 0 | _return: |
1331 | |
|
1332 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1333 | 0 | terrno = code; |
1334 | 0 | } |
1335 | |
|
1336 | 0 | return input.pMem; |
1337 | 0 | } |
1338 | | |
1339 | 0 | void *taosMemPoolRealloc(void* poolHandle, void* session, void *ptr, int64_t size, char* fileName, int32_t lineNo) { |
1340 | 0 | if (0 == tsMemPoolFullFunc) { |
1341 | 0 | return mpDirectRealloc(poolHandle, ((SMPSession*)session)->pJob, ptr, size); |
1342 | 0 | } |
1343 | | |
1344 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1345 | 0 | SMPStatInput input = {.size = size, .file = fileName, .line = lineNo, .procFlags = MP_STAT_PROC_FLAG_EXEC, .origSize = 0, .pMem = ptr, .pOrigMem = ptr}; |
1346 | | |
1347 | 0 | if (NULL == poolHandle || NULL == fileName || size < 0) { |
1348 | 0 | uError("%s invalid input param, handle:%p, session:%p, fileName:%p, size:%" PRId64, |
1349 | 0 | __FUNCTION__, poolHandle, session, fileName, size); |
1350 | 0 | MP_ERR_JRET(TSDB_CODE_INVALID_PARA); |
1351 | 0 | } |
1352 | | |
1353 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
1354 | 0 | SMPSession* pSession = (SMPSession*)session; |
1355 | |
|
1356 | 0 | code = mpRealloc(pPool, pSession, &input.pMem, &input.size, &input.origSize); |
1357 | |
|
1358 | 0 | if (NULL != input.pMem) { |
1359 | 0 | MP_SET_FLAG(input.procFlags, MP_STAT_PROC_FLAG_RES_SUCC); |
1360 | 0 | mpLogStat(pPool, pSession, E_MP_STAT_LOG_MEM_REALLOC, &input); |
1361 | 0 | } else if (0 == size){ |
1362 | 0 | input.pMem = input.pOrigMem; |
1363 | 0 | input.pOrigMem = NULL; |
1364 | 0 | input.size = input.origSize; |
1365 | 0 | MP_SET_FLAG(input.procFlags, MP_STAT_PROC_FLAG_RES_SUCC); |
1366 | 0 | mpLogStat(pPool, pSession, E_MP_STAT_LOG_MEM_FREE, &input); |
1367 | 0 | input.pMem = NULL; |
1368 | 0 | } else { |
1369 | 0 | MP_SET_FLAG(input.procFlags, MP_STAT_PROC_FLAG_RES_FAIL); |
1370 | 0 | mpLogStat(pPool, pSession, E_MP_STAT_LOG_MEM_REALLOC, &input); |
1371 | |
|
1372 | 0 | input.pMem = input.pOrigMem; |
1373 | 0 | input.pOrigMem = NULL; |
1374 | 0 | input.size = input.origSize; |
1375 | 0 | input.procFlags = MP_STAT_PROC_FLAG_EXEC; |
1376 | 0 | MP_SET_FLAG(input.procFlags, MP_STAT_PROC_FLAG_RES_SUCC); |
1377 | 0 | mpLogStat(pPool, pSession, E_MP_STAT_LOG_MEM_FREE, &input); |
1378 | 0 | input.pMem = NULL; |
1379 | 0 | } |
1380 | |
|
1381 | 0 | _return: |
1382 | |
|
1383 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1384 | 0 | terrno = code; |
1385 | 0 | } |
1386 | |
|
1387 | 0 | return input.pMem; |
1388 | 0 | } |
1389 | | |
1390 | 0 | char *taosMemPoolStrdup(void* poolHandle, void* session, const char *ptr, char* fileName, int32_t lineNo) { |
1391 | 0 | if (0 == tsMemPoolFullFunc) { |
1392 | 0 | return mpDirectStrdup(poolHandle, ((SMPSession*)session)->pJob, ptr); |
1393 | 0 | } |
1394 | | |
1395 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1396 | 0 | int64_t size = (ptr ? strlen(ptr) : 0) + 1; |
1397 | 0 | SMPStatInput input = {.size = size, .file = fileName, .line = lineNo, .procFlags = MP_STAT_PROC_FLAG_EXEC, .pMem = NULL}; |
1398 | | |
1399 | 0 | if (NULL == poolHandle || NULL == fileName || NULL == ptr) { |
1400 | 0 | uError("%s invalid input param, handle:%p, session:%p, fileName:%p, ptr:%p", |
1401 | 0 | __FUNCTION__, poolHandle, session, fileName, ptr); |
1402 | 0 | MP_ERR_JRET(TSDB_CODE_INVALID_PARA); |
1403 | 0 | } |
1404 | | |
1405 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
1406 | 0 | SMPSession* pSession = (SMPSession*)session; |
1407 | |
|
1408 | 0 | code = mpMalloc(pPool, pSession, &input.size, 0, &input.pMem); |
1409 | 0 | if (NULL != input.pMem) { |
1410 | 0 | tstrncpy((char*)input.pMem, ptr, size); |
1411 | 0 | *((char*)input.pMem + size - 1) = 0; |
1412 | 0 | } |
1413 | |
|
1414 | 0 | MP_SET_FLAG(input.procFlags, (NULL != input.pMem ? MP_STAT_PROC_FLAG_RES_SUCC : MP_STAT_PROC_FLAG_RES_FAIL)); |
1415 | 0 | mpLogStat(pPool, pSession, E_MP_STAT_LOG_MEM_STRDUP, &input); |
1416 | |
|
1417 | 0 | _return: |
1418 | |
|
1419 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1420 | 0 | terrno = code; |
1421 | 0 | } |
1422 | |
|
1423 | 0 | return input.pMem; |
1424 | 0 | } |
1425 | | |
1426 | 0 | char *taosMemPoolStrndup(void* poolHandle, void* session, const char *ptr, int64_t size, char* fileName, int32_t lineNo) { |
1427 | 0 | if (0 == tsMemPoolFullFunc) { |
1428 | 0 | return mpDirectStrndup(poolHandle, ((SMPSession*)session)->pJob, ptr, size); |
1429 | 0 | } |
1430 | | |
1431 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1432 | 0 | int64_t origSize = ptr ? strlen(ptr) : 0; |
1433 | 0 | size = TMIN(size, origSize) + 1; |
1434 | 0 | SMPStatInput input = {.size = size, .file = fileName, .line = lineNo, .procFlags = MP_STAT_PROC_FLAG_EXEC, .pMem = NULL}; |
1435 | | |
1436 | 0 | if (NULL == poolHandle || NULL == fileName || NULL == ptr || size < 0) { |
1437 | 0 | uError("%s invalid input param, handle:%p, session:%p, fileName:%p, ptr:%p, size:%" PRId64, |
1438 | 0 | __FUNCTION__, poolHandle, session, fileName, ptr, size); |
1439 | 0 | MP_ERR_JRET(TSDB_CODE_INVALID_PARA); |
1440 | 0 | } |
1441 | | |
1442 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
1443 | 0 | SMPSession* pSession = (SMPSession*)session; |
1444 | |
|
1445 | 0 | code = mpMalloc(pPool, pSession, &input.size, 0, &input.pMem); |
1446 | 0 | if (NULL != input.pMem) { |
1447 | 0 | TAOS_MEMCPY(input.pMem, ptr, size - 1); |
1448 | 0 | *((char*)input.pMem + size - 1) = 0; |
1449 | 0 | } |
1450 | |
|
1451 | 0 | MP_SET_FLAG(input.procFlags, (NULL != input.pMem ? MP_STAT_PROC_FLAG_RES_SUCC : MP_STAT_PROC_FLAG_RES_FAIL)); |
1452 | 0 | mpLogStat(pPool, pSession, E_MP_STAT_LOG_MEM_STRNDUP, &input); |
1453 | |
|
1454 | 0 | _return: |
1455 | |
|
1456 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1457 | 0 | terrno = code; |
1458 | 0 | } |
1459 | |
|
1460 | 0 | return input.pMem; |
1461 | 0 | } |
1462 | | |
1463 | | |
1464 | 0 | void taosMemPoolFree(void* poolHandle, void* session, void *ptr, char* fileName, int32_t lineNo) { |
1465 | 0 | if (0 == tsMemPoolFullFunc) { |
1466 | 0 | mpDirectFree(poolHandle, ((SMPSession*)session)->pJob, ptr); |
1467 | 0 | return; |
1468 | 0 | } |
1469 | | |
1470 | 0 | if (NULL == ptr) { |
1471 | 0 | return; |
1472 | 0 | } |
1473 | | |
1474 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1475 | 0 | if (NULL == poolHandle || NULL == fileName) { |
1476 | 0 | uError("%s invalid input param, handle:%p, session:%p, fileName:%p", |
1477 | 0 | __FUNCTION__, poolHandle, session, fileName); |
1478 | 0 | } |
1479 | |
|
1480 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
1481 | 0 | SMPSession* pSession = (SMPSession*)session; |
1482 | 0 | SMPStatInput input = {.file = fileName, .line = lineNo, .procFlags = MP_STAT_PROC_FLAG_EXEC, .pMem = ptr}; |
1483 | |
|
1484 | 0 | mpFree(pPool, pSession, ptr, &input.size); |
1485 | |
|
1486 | 0 | MP_SET_FLAG(input.procFlags, MP_STAT_PROC_FLAG_RES_SUCC); |
1487 | 0 | mpLogStat(pPool, pSession, E_MP_STAT_LOG_MEM_FREE, &input); |
1488 | 0 | } |
1489 | | |
1490 | 0 | int64_t taosMemPoolGetMemorySize(void* poolHandle, void* session, void *ptr, char* fileName, int32_t lineNo) { |
1491 | 0 | if (0 == tsMemPoolFullFunc) { |
1492 | 0 | return taosMemSize(ptr); |
1493 | 0 | } |
1494 | | |
1495 | 0 | int64_t code = 0; |
1496 | 0 | if (NULL == poolHandle || NULL == fileName) { |
1497 | 0 | uError("%s invalid input param, handle:%p, session:%p, fileName:%p", |
1498 | 0 | __FUNCTION__, poolHandle, session, fileName); |
1499 | 0 | MP_ERR_RET(TSDB_CODE_INVALID_PARA); |
1500 | 0 | } |
1501 | | |
1502 | 0 | if (NULL == ptr) { |
1503 | 0 | return 0; |
1504 | 0 | } |
1505 | | |
1506 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
1507 | 0 | SMPSession* pSession = (SMPSession*)session; |
1508 | | |
1509 | 0 | return mpGetMemorySizeImpl(pPool, pSession, ptr); |
1510 | 0 | } |
1511 | | |
1512 | 0 | void* taosMemPoolMallocAlign(void* poolHandle, void* session, uint32_t alignment, int64_t size, char* fileName, int32_t lineNo) { |
1513 | 0 | if (0 == tsMemPoolFullFunc) { |
1514 | 0 | return mpDirectAlignAlloc(poolHandle, ((SMPSession*)session)->pJob, alignment, size); |
1515 | 0 | } |
1516 | | |
1517 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1518 | 0 | SMPStatInput input = {.size = size, .file = fileName, .line = lineNo, .procFlags = MP_STAT_PROC_FLAG_EXEC, .pMem = NULL}; |
1519 | | |
1520 | 0 | if (NULL == poolHandle || NULL == fileName || size < 0 || alignment < POINTER_BYTES || alignment % POINTER_BYTES) { |
1521 | 0 | uError("%s invalid input param, handle:%p, session:%p, fileName:%p, alignment:%u, size:%" PRId64, |
1522 | 0 | __FUNCTION__, poolHandle, session, fileName, alignment, size); |
1523 | 0 | MP_ERR_JRET(TSDB_CODE_INVALID_PARA); |
1524 | 0 | } |
1525 | | |
1526 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
1527 | 0 | SMPSession* pSession = (SMPSession*)session; |
1528 | |
|
1529 | 0 | code = mpMalloc(pPool, pSession, &input.size, alignment, &input.pMem); |
1530 | |
|
1531 | 0 | MP_SET_FLAG(input.procFlags, (NULL != input.pMem ? MP_STAT_PROC_FLAG_RES_SUCC : MP_STAT_PROC_FLAG_RES_FAIL)); |
1532 | 0 | mpLogStat(pPool, pSession, E_MP_STAT_LOG_MEM_MALLOC, &input); |
1533 | |
|
1534 | 0 | _return: |
1535 | |
|
1536 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1537 | 0 | terrno = code; |
1538 | 0 | } |
1539 | |
|
1540 | 0 | return input.pMem; |
1541 | 0 | } |
1542 | | |
1543 | 0 | void taosMemPoolClose(void* poolHandle) { |
1544 | 0 | if (NULL == poolHandle) { |
1545 | 0 | return; |
1546 | 0 | } |
1547 | | |
1548 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
1549 | |
|
1550 | 0 | if (tsMemPoolFullFunc) { |
1551 | 0 | mpCheckStatDetail(pPool, NULL, "PoolClose"); |
1552 | 0 | mpDestroyPosStat(&pPool->stat.posStat); |
1553 | 0 | } |
1554 | | |
1555 | 0 | taosMemoryFree(pPool->name); |
1556 | 0 | mpDestroyCacheGroup(&pPool->sessionCache); |
1557 | |
|
1558 | 0 | atomic_store_8(&gMPMgmt.modExit, 1); |
1559 | |
|
1560 | 0 | (void)taosThreadJoin(gMPMgmt.poolMgmtThread, NULL); |
1561 | 0 | } |
1562 | | |
1563 | | |
1564 | 0 | void taosMemPoolModDestroy(void) { |
1565 | 0 | gMemPoolHandle = NULL; |
1566 | | |
1567 | 0 | taosArrayDestroyEx(gMPMgmt.poolList, mpFreePool); |
1568 | 0 | gMPMgmt.poolList = NULL; |
1569 | 0 | } |
1570 | | |
1571 | | |
1572 | 0 | int32_t taosMemPoolTrim(void* poolHandle, void* session, int32_t size, char* fileName, int32_t lineNo, bool* trimed) { |
1573 | 0 | if (0 == tsMemPoolFullFunc) { |
1574 | 0 | return taosMemTrim(size, trimed); |
1575 | 0 | } |
1576 | | |
1577 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1578 | | |
1579 | 0 | if (NULL == poolHandle || NULL == fileName || size < 0) { |
1580 | 0 | uError("%s invalid input param, handle:%p, session:%p, fileName:%p, size:%d", |
1581 | 0 | __FUNCTION__, poolHandle, session, fileName, size); |
1582 | 0 | MP_ERR_RET(TSDB_CODE_INVALID_PARA); |
1583 | 0 | } |
1584 | | |
1585 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
1586 | 0 | SMPSession* pSession = (SMPSession*)session; |
1587 | 0 | SMPStatInput input = {.size = 0, .file = fileName, .line = lineNo, .procFlags = MP_STAT_PROC_FLAG_EXEC}; |
1588 | |
|
1589 | 0 | code = mpTrim(pPool, pSession, size, trimed); |
1590 | |
|
1591 | 0 | input.size = (trimed) ? (*trimed) : 0; |
1592 | |
|
1593 | 0 | MP_SET_FLAG(input.procFlags, ((0 == code) ? MP_STAT_PROC_FLAG_RES_SUCC : MP_STAT_PROC_FLAG_RES_FAIL)); |
1594 | 0 | mpLogStat(pPool, pSession, E_MP_STAT_LOG_MEM_TRIM, &input); |
1595 | |
|
1596 | 0 | return code; |
1597 | 0 | } |
1598 | | |
1599 | 0 | int32_t taosMemPoolCallocJob(uint64_t jobId, uint64_t cId, void** ppJob) { |
1600 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1601 | 0 | *ppJob = taosMemCalloc(1, sizeof(SMPJob)); |
1602 | 0 | if (NULL == *ppJob) { |
1603 | 0 | uError("calloc mp job failed, code: 0x%x", terrno); |
1604 | 0 | MP_ERR_RET(terrno); |
1605 | 0 | } |
1606 | | |
1607 | 0 | SMPJob* pJob = (SMPJob*)*ppJob; |
1608 | 0 | pJob->job.jobId = jobId; |
1609 | 0 | pJob->job.clientId = cId; |
1610 | 0 | pJob->job.refs = 1; |
1611 | |
|
1612 | 0 | return code; |
1613 | 0 | } |
1614 | | |
1615 | 0 | void taosMemPoolRetainJob(void* pJob) { |
1616 | 0 | if (NULL != pJob) { |
1617 | 0 | (void)atomic_add_fetch_32(&((SMemPoolJob*)pJob)->refs, 1); |
1618 | 0 | } |
1619 | 0 | } |
1620 | | |
1621 | 0 | void taosMemPoolReleaseJob(void* pJob) { |
1622 | 0 | if (NULL != pJob && 0 == atomic_sub_fetch_32(&((SMemPoolJob*)pJob)->refs, 1)) { |
1623 | 0 | taosMemFree(pJob); |
1624 | 0 | } |
1625 | 0 | } |
1626 | | |
1627 | 0 | int32_t taosMemPoolReserveJobMemory(void* poolHandle, void* pJob, int64_t size) { |
1628 | 0 | if (NULL == poolHandle || NULL == pJob || size < 0) { |
1629 | 0 | return TSDB_CODE_INVALID_PARA; |
1630 | 0 | } |
1631 | 0 | if (0 == size) { |
1632 | 0 | return TSDB_CODE_SUCCESS; |
1633 | 0 | } |
1634 | 0 | SMPSession session = {.pJob = (SMPJob*)pJob}; |
1635 | 0 | return mpChkFullQuota((SMemPool*)poolHandle, &session, size); |
1636 | 0 | } |
1637 | | |
1638 | 0 | void taosMemPoolReleaseJobMemory(void* poolHandle, void* pJob, int64_t size) { |
1639 | 0 | if (NULL == poolHandle || NULL == pJob || size <= 0) { |
1640 | 0 | return; |
1641 | 0 | } |
1642 | 0 | (void)atomic_sub_fetch_64(&((SMemPoolJob*)pJob)->allocMemSize, size); |
1643 | 0 | (void)atomic_sub_fetch_64(&((SMemPool*)poolHandle)->allocMemSize, size); |
1644 | 0 | } |
1645 | | |
1646 | 0 | int32_t taosMemPoolTryLockPool(void* poolHandle, bool readLock) { |
1647 | 0 | if (NULL == poolHandle) { |
1648 | 0 | return TSDB_CODE_INVALID_PARA; |
1649 | 0 | } |
1650 | | |
1651 | 0 | int32_t code = 0; |
1652 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
1653 | 0 | if (readLock) { |
1654 | 0 | MP_TRY_LOCK(MP_READ, &pPool->cfgLock, code); |
1655 | 0 | } else { |
1656 | 0 | MP_TRY_LOCK(MP_WRITE, &pPool->cfgLock, code); |
1657 | 0 | } |
1658 | |
|
1659 | 0 | return code; |
1660 | 0 | } |
1661 | | |
1662 | 0 | void taosMemPoolUnLockPool(void* poolHandle, bool readLock) { |
1663 | 0 | if (NULL == poolHandle) { |
1664 | 0 | return; |
1665 | 0 | } |
1666 | | |
1667 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
1668 | 0 | if (readLock) { |
1669 | 0 | MP_UNLOCK(MP_READ, &pPool->cfgLock); |
1670 | 0 | } else { |
1671 | 0 | MP_UNLOCK(MP_WRITE, &pPool->cfgLock); |
1672 | 0 | } |
1673 | 0 | } |
1674 | | |
1675 | 0 | void taosMemPoolGetUsedSizeBegin(void* poolHandle, int64_t* usedSize, bool* needEnd) { |
1676 | 0 | if (NULL == poolHandle) { |
1677 | 0 | *usedSize = 0; |
1678 | 0 | *needEnd = false; |
1679 | 0 | return; |
1680 | 0 | } |
1681 | | |
1682 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
1683 | |
|
1684 | 0 | *needEnd = true; |
1685 | 0 | *usedSize = atomic_load_64(&pPool->allocMemSize); |
1686 | 0 | } |
1687 | | |
1688 | 0 | void taosMemPoolGetUsedSizeEnd(void* poolHandle) { |
1689 | 0 | SMemPool* pPool = (SMemPool*)poolHandle; |
1690 | 0 | if (NULL == pPool) { |
1691 | 0 | return; |
1692 | 0 | } |
1693 | | |
1694 | 0 | MP_UNLOCK(MP_WRITE, &pPool->cfgLock); |
1695 | 0 | } |
1696 | | |
1697 | 0 | int32_t taosMemPoolGetSessionStat(void* session, SMPStatDetail** ppStat, int64_t* allocSize, int64_t* maxAllocSize) { |
1698 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1699 | 0 | if (NULL == session || (NULL == ppStat && NULL == allocSize && NULL == maxAllocSize)) { |
1700 | 0 | uError("%s invalid input param, session:%p, ppStat:%p, allocSize:%p, maxAllocSize:%p", __FUNCTION__, session, ppStat, allocSize, maxAllocSize); |
1701 | 0 | MP_ERR_RET(TSDB_CODE_INVALID_PARA); |
1702 | 0 | } |
1703 | | |
1704 | 0 | SMPSession* pSession = (SMPSession*)session; |
1705 | |
|
1706 | 0 | if (ppStat) { |
1707 | 0 | *ppStat = &pSession->stat.statDetail; |
1708 | 0 | } |
1709 | 0 | if (allocSize) { |
1710 | 0 | *allocSize = atomic_load_64(&pSession->allocMemSize); |
1711 | 0 | } |
1712 | 0 | if (maxAllocSize) { |
1713 | 0 | *maxAllocSize = atomic_load_64(&pSession->maxAllocMemSize); |
1714 | 0 | } |
1715 | | |
1716 | 0 | return code; |
1717 | 0 | } |
1718 | | |
1719 | 0 | void taosMemPoolSchedTrim(void) { |
1720 | 0 | mpSchedTrim(NULL); |
1721 | 0 | } |
1722 | | |
1723 | 0 | int32_t taosMemoryPoolInit(mpReserveFailFp failFp, mpReserveReachFp reachFp) { |
1724 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1725 | | |
1726 | 0 | #ifdef LINUX |
1727 | 0 | if (!tsQueryUseMemoryPool) { |
1728 | 0 | #endif |
1729 | 0 | uInfo("memory pool disabled cause of configured disabled"); |
1730 | 0 | return code; |
1731 | 0 | #ifdef LINUX |
1732 | 0 | } |
1733 | 0 | #endif |
1734 | | |
1735 | 0 | code = taosGetTotalMemory(&tsTotalMemoryKB); |
1736 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1737 | 0 | uInfo("fail to system total memory, error: %s", tstrerror(code)); |
1738 | 0 | return code; |
1739 | 0 | } |
1740 | | |
1741 | 0 | if (tsTotalMemoryKB <= 0) { |
1742 | 0 | uInfo("memory pool disabled since not enough system total memory, size: %" PRId64 "KB", tsTotalMemoryKB); |
1743 | 0 | return code; |
1744 | 0 | } |
1745 | | |
1746 | 0 | uInfo("total memory size: %" PRId64 "KB", tsTotalMemoryKB); |
1747 | |
|
1748 | 0 | if (0 == tsMinReservedMemorySize) { |
1749 | 0 | tsMinReservedMemorySize = TMAX(MIN_RESERVE_MEM_SIZE, tsTotalMemoryKB / 1024 * MP_DEFAULT_RESERVE_MEM_PERCENT / 100); |
1750 | 0 | } |
1751 | | |
1752 | 0 | SMemPoolCfg cfg = {0}; |
1753 | 0 | int64_t sysAvailSize = 0; |
1754 | | |
1755 | 0 | code = taosGetSysAvailMemory(&sysAvailSize); |
1756 | 0 | if (code || sysAvailSize < MP_MIN_MEM_POOL_SIZE) { |
1757 | 0 | uInfo("memory pool disabled since not enough system available memory, size: %" PRId64, sysAvailSize); |
1758 | 0 | code = TSDB_CODE_SUCCESS; |
1759 | 0 | return code; |
1760 | 0 | } |
1761 | | |
1762 | 0 | cfg.reserveSize = tsMinReservedMemorySize * 1048576UL; |
1763 | |
|
1764 | 0 | int64_t freeSizeAfterRes = sysAvailSize - tsMinReservedMemorySize * 1048576UL; |
1765 | 0 | if (freeSizeAfterRes < MP_MIN_FREE_SIZE_AFTER_RESERVE) { |
1766 | 0 | uInfo("memory pool disabled since not enough system available memory after reserved, size: %" PRId64, freeSizeAfterRes); |
1767 | 0 | return code; |
1768 | 0 | } |
1769 | | |
1770 | 0 | atomic_store_64(&tsCurrentAvailMemorySize, sysAvailSize); |
1771 | |
|
1772 | 0 | cfg.evicPolicy = E_EVICT_AUTO; //TODO |
1773 | 0 | cfg.chunkSize = 1048576; |
1774 | 0 | cfg.jobQuota = &tsSingleQueryMaxMemorySize; |
1775 | 0 | cfg.cb.failFp = failFp; |
1776 | 0 | cfg.cb.reachFp = reachFp; |
1777 | | |
1778 | 0 | code = taosMemPoolOpen("taosd", &cfg, &gMemPoolHandle); |
1779 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1780 | 0 | return code; |
1781 | 0 | } |
1782 | | |
1783 | 0 | code = mpCreateMgmtThread(); |
1784 | 0 | if (TSDB_CODE_SUCCESS != code) { |
1785 | 0 | return code; |
1786 | 0 | } |
1787 | | |
1788 | 0 | uInfo("memory pool initialized, reservedSize:%dMB, freeAfterReserved:%" PRId64 "MB, jobQuota:%dMB", tsMinReservedMemorySize, freeSizeAfterRes/1048576UL, tsSingleQueryMaxMemorySize); |
1789 | |
|
1790 | 0 | return code; |
1791 | 0 | } |
1792 | | |
1793 | | |
1794 | 4.13k | void taosAutoMemoryFree(void *ptr) { |
1795 | 4.13k | if (NULL != gMemPoolHandle && threadPoolEnabled && threadPoolSession) { |
1796 | 0 | taosMemPoolFree(gMemPoolHandle, threadPoolSession, ptr, __FILE__, __LINE__); |
1797 | 4.13k | } else { |
1798 | 4.13k | taosMemFree(ptr); |
1799 | 4.13k | } |
1800 | 4.13k | } |
1801 | | |
1802 | 0 | static int32_t mpUpdateReservedSize(SMemPool* pPool, int32_t newReservedSizeMB) { |
1803 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1804 | 0 | int64_t sysAvailSize = 0; |
1805 | 0 | code = taosGetSysAvailMemory(&sysAvailSize); |
1806 | 0 | if (code || sysAvailSize < MP_MIN_MEM_POOL_SIZE) { |
1807 | 0 | uInfo("failed to update reserved size since not enough system available memory, size: %" PRId64, sysAvailSize); |
1808 | 0 | MP_ERR_RET(TSDB_CODE_QRY_MEMORY_POOL_MEMORY_NOT_ENOUGH); |
1809 | 0 | } |
1810 | | |
1811 | 0 | int64_t freeSizeAfterRes = sysAvailSize - newReservedSizeMB * 1048576UL; |
1812 | 0 | if (freeSizeAfterRes < MP_MIN_FREE_SIZE_AFTER_RESERVE) { |
1813 | 0 | uInfo("failed to update reserved size since not enough system available memory after reserved, size: %" PRId64, |
1814 | 0 | freeSizeAfterRes); |
1815 | 0 | MP_ERR_RET(TSDB_CODE_QRY_MEMORY_POOL_MEMORY_NOT_ENOUGH); |
1816 | 0 | } |
1817 | | |
1818 | 0 | MP_LOCK(MP_WRITE, &pPool->cfgLock); |
1819 | 0 | pPool->cfg.reserveSize = newReservedSizeMB * 1048576UL; |
1820 | 0 | MP_UNLOCK(MP_WRITE, &pPool->cfgLock); |
1821 | |
|
1822 | 0 | return code; |
1823 | 0 | } |
1824 | | |
1825 | 0 | int32_t taosMemoryPoolCfgUpdateReservedSize(int32_t newReservedSizeMB) { |
1826 | 0 | if (!threadPoolEnabled) { |
1827 | 0 | return TSDB_CODE_SUCCESS; |
1828 | 0 | } |
1829 | 0 | int32_t code = TSDB_CODE_SUCCESS; |
1830 | 0 | if (NULL == gMemPoolHandle) { |
1831 | 0 | uError("failed to update reserved size since memory pool not initialized"); |
1832 | 0 | MP_ERR_RET(TSDB_CODE_QRY_MEMORY_POOL_NOT_INITIALIZED); |
1833 | 0 | } |
1834 | 0 | if (newReservedSizeMB < 0) { |
1835 | 0 | uError("failed to update reserved size since newReservedSizeMB:%d is invalid", newReservedSizeMB); |
1836 | 0 | MP_ERR_RET(TSDB_CODE_INVALID_PARA); |
1837 | 0 | } |
1838 | | |
1839 | 0 | return mpUpdateReservedSize(gMemPoolHandle, newReservedSizeMB); |
1840 | 0 | } |