• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

taosdata / TDengine / #4926

13 Jan 2026 05:43AM UTC coverage: 66.053% (-0.05%) from 66.107%
#4926

push

travis-ci

web-flow
feat: [6654385780] show snap progress (#34203)

48 of 59 new or added lines in 7 files covered. (81.36%)

582 existing lines in 124 files now uncovered.

200362 of 303334 relevant lines covered (66.05%)

132283104.31 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.06
/source/libs/function/src/thistogram.c
1
/*
2
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
3
 *
4
 * This program is free software: you can use, redistribute, and/or modify
5
 * it under the terms of the GNU Affero General Public License, version 3
6
 * or later ("AGPL"), as published by the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * You should have received a copy of the GNU Affero General Public License
13
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14
 */
15
#include "os.h"
16

17
#include "query.h"
18
#include "taosdef.h"
19
#include "thistogram.h"
20
#include "tlosertree.h"
21
#include "tmsg.h"
22

23
/**
24
 *
25
 * implement the histogram and percentile_approx based on the paper:
26
 * Yael Ben-Haim, Elad Tom-Tov. A Streaming Parallel Decision Tree Algorithm,
27
 * The Journal of Machine Learning Research.Volume 11, 3/1/2010 pp.849-872
28
 * https://dl.acm.org/citation.cfm?id=1756034
29
 *
30
 * @data 2018-12-14
31
 * @version 0.1
32
 *
33
 */
34
static int32_t histogramCreateBin(SHistogramInfo* pHisto, int32_t index, double val);
35

36
int32_t tHistogramCreate(int32_t numOfEntries, SHistogramInfo** pHisto) {
13,363✔
37
  /* need one redundant slot */
38
  *pHisto = taosMemoryMalloc(sizeof(SHistogramInfo) + sizeof(SHistBin) * (numOfEntries + 1));
13,363✔
39
  if (NULL == *pHisto) {
13,363✔
40
    return terrno;
×
41
  }
42

43
#if !defined(USE_ARRAYLIST)
44
  pHisto->pList = SSkipListCreate(MAX_SKIP_LIST_LEVEL, TSDB_DATA_TYPE_DOUBLE, sizeof(double));
45
  SInsertSupporter* pss = taosMemoryMalloc(sizeof(SInsertSupporter));
46
  if (NULL == pss) {
47
    taosMemoryFree(*pHisto);
48
    return terrno;
49
  }
50
  pss->numOfEntries = pHisto->maxEntries;
51
  pss->pSkipList = pHisto->pList;
52

53
  int32_t ret = tLoserTreeCreate1(&pHisto->pLoserTree, numOfEntries, pss, compare);
54
  pss->pTree = pHisto->pLoserTree;
55
#endif
56

57
  *pHisto = tHistogramCreateFrom(*pHisto, numOfEntries);
13,363✔
58
  return TSDB_CODE_SUCCESS;
13,363✔
59
}
60

61
SHistogramInfo* tHistogramCreateFrom(void* pBuf, int32_t numOfBins) {
53,260,498✔
62
  (void)memset(pBuf, 0, sizeof(SHistogramInfo) + sizeof(SHistBin) * (numOfBins + 1));
53,260,498✔
63

64
  SHistogramInfo* pHisto = (SHistogramInfo*)pBuf;
53,260,498✔
65
  pHisto->elems = (SHistBin*)((char*)pBuf + sizeof(SHistogramInfo));
53,260,498✔
66
  for (int32_t i = 0; i < numOfBins; ++i) {
2,147,483,647✔
67
    pHisto->elems[i].val = -DBL_MAX;
2,147,483,647✔
68
  }
69

70
  pHisto->maxEntries = numOfBins;
53,262,912✔
71

72
  pHisto->min = DBL_MAX;
53,262,432✔
73
  pHisto->max = -DBL_MAX;
53,262,432✔
74

75
  return pBuf;
53,262,912✔
76
}
77

78
int32_t tHistogramAdd(SHistogramInfo** pHisto, double val) {
1,056,099,086✔
79
  int32_t code = TSDB_CODE_SUCCESS;
1,056,099,086✔
80
  if (*pHisto == NULL) {
1,056,099,086✔
81
    code = tHistogramCreate(MAX_HISTOGRAM_BIN, pHisto);
×
82
    if (TSDB_CODE_SUCCESS != code) {
×
83
      return code;
×
84
    }
85
  }
86

87
#if defined(USE_ARRAYLIST)
88
  int32_t idx = histoBinarySearch((*pHisto)->elems, (*pHisto)->numOfEntries, val);
1,056,122,641✔
89
  if (idx < 0 || idx > (*pHisto)->maxEntries || (*pHisto)->elems == NULL) {
1,053,870,596✔
90
    qError("tHistogramAdd Error, idx:%d, maxEntries:%d, elems:%p", idx, (*pHisto)->maxEntries, (*pHisto)->elems);
5,314✔
91
    return TSDB_CODE_FUNC_HISTOGRAM_ERROR;
×
92
  }
93

94
  if ((*pHisto)->elems[idx].val == val && idx >= 0) {
1,054,379,461✔
95
    (*pHisto)->elems[idx].num += 1;
558,098,269✔
96

97
    if ((*pHisto)->numOfEntries == 0) {
558,214,951✔
98
      (*pHisto)->numOfEntries += 1;
×
99
    }
100
  } else { /* insert a new slot */
101
    if ((*pHisto)->numOfElems >= 1 && idx < (*pHisto)->numOfEntries) {
496,747,416✔
102
      if (idx > 0) {
456,006,503✔
103
        if ((*pHisto)->elems[idx - 1].val > val) {
430,325,938✔
104
          qError("tHistogramAdd Error, elems[%d].val:%lf, val:%lf", idx - 1, (*pHisto)->elems[idx - 1].val, val);
×
105
          return TSDB_CODE_FUNC_HISTOGRAM_ERROR;
×
106
        }
107
      } else {
108
        if ((*pHisto)->elems[idx].val <= val) {
25,680,565✔
109
          qError("tHistogramAdd Error, elems[%d].val:%lf, val:%lf", idx, (*pHisto)->elems[idx].val, val);
×
110
          return TSDB_CODE_FUNC_HISTOGRAM_ERROR;
×
111
        }
112
      }
113
    } else if ((*pHisto)->numOfElems > 0 && (*pHisto)->elems[(*pHisto)->numOfEntries].val > val) {
41,741,568✔
114
      qError("tHistogramAdd Error, elems[%d].val:%lf, val:%lf", (*pHisto)->numOfEntries, (*pHisto)->elems[idx].val, val);
×
115
      return TSDB_CODE_FUNC_HISTOGRAM_ERROR;
×
116
    }
117

118
    code = histogramCreateBin(*pHisto, idx, val);
497,804,608✔
119
    if (code != TSDB_CODE_SUCCESS) {
498,072,958✔
120
      return code;
×
121
    }
122
  }
123
#else
124
  tSkipListKey key = tSkipListCreateKey(TSDB_DATA_TYPE_DOUBLE, &val, tDataTypes[TSDB_DATA_TYPE_DOUBLE].nSize);
125
  SHistBin*    entry = taosMemoryCalloc(1, sizeof(SHistBin));
126
  if (entry == NULL) {
127
    return terrno;
128
  }
129
  entry->val = val;
130

131
  tSkipListNode* pResNode = SSkipListPut((*pHisto)->pList, entry, &key, 0);
132

133
  SHistBin* pEntry1 = (SHistBin*)pResNode->pData;
134
  pEntry1->index = -1;
135

136
  tSkipListNode* pLast = NULL;
137

138
  if (pEntry1->num == 0) { /* it is a new node */
139
    (*pHisto)->numOfEntries += 1;
140
    pEntry1->num += 1;
141

142
    /* number of entries reaches the upper limitation */
143
    if (pResNode->pForward[0] != NULL) {
144
      /* we need to update the last updated slot in loser tree*/
145
      pEntry1->delta = ((SHistBin*)pResNode->pForward[0]->pData)->val - val;
146

147
      if ((*pHisto)->ordered) {
148
        int32_t                 lastIndex = (*pHisto)->maxIndex;
149
        SMultiwayMergeTreeInfo* pTree = (*pHisto)->pLoserTree;
150

151
        (*pHisto)->pLoserTree->pNode[lastIndex + pTree->numOfEntries].pData = pResNode;
152
        pEntry1->index = (*pHisto)->pLoserTree->pNode[lastIndex + pTree->numOfEntries].index;
153

154
        // update the loser tree
155
        if ((*pHisto)->ordered) {
156
          tMergeTreeAdjust(pTree, pEntry1->index + pTree->numOfEntries);
157
        }
158

159
        tSkipListKey kx =
160
            tSkipListCreateKey(TSDB_DATA_TYPE_DOUBLE, &(*pHisto)->max, tDataTypes[TSDB_DATA_TYPE_DOUBLE].nSize);
161
        pLast = tSkipListGetOne((*pHisto)->pList, &kx);
162
      }
163
    } else {
164
      /* this node located at the last position of the skiplist, we do not
165
       * update the loser-tree */
166
      pEntry1->delta = DBL_MAX;
167
      pLast = pResNode;
168
    }
169

170
    if (pResNode->pBackward[0] != &(*pHisto)->pList->pHead) {
171
      SHistBin* pPrevEntry = (SHistBin*)pResNode->pBackward[0]->pData;
172
      pPrevEntry->delta = val - pPrevEntry->val;
173

174
      SMultiwayMergeTreeInfo* pTree = (*pHisto)->pLoserTree;
175
      if ((*pHisto)->ordered) {
176
        tMergeTreeAdjust(pTree, pPrevEntry->index + pTree->numOfEntries);
177
        tMergeTreePrint(pTree);
178
      }
179
    }
180

181
    if ((*pHisto)->numOfEntries >= (*pHisto)->maxEntries + 1) {
182
      // set the right value for loser-tree
183
      if (!(*pHisto)->ordered) {
184
        SSkipListPrint((*pHisto)->pList, 1);
185

186
        SMultiwayMergeTreeInfo* pTree = (*pHisto)->pLoserTree;
187
        tSkipListNode*          pHead = (*pHisto)->pList->pHead.pForward[0];
188

189
        tSkipListNode* p1 = pHead;
190

191
        printf("\n");
192
        while (p1 != NULL) {
193
          printf("%f\t", ((SHistBin*)(p1->pData))->delta);
194
          p1 = p1->pForward[0];
195
        }
196
        printf("\n");
197

198
        /* last one in skiplist is ignored */
199
        for (int32_t i = pTree->numOfEntries; i < pTree->totalEntries; ++i) {
200
          pTree->pNode[i].pData = pHead;
201
          pTree->pNode[i].index = i - pTree->numOfEntries;
202
          SHistBin* pBin = (SHistBin*)pHead->pData;
203
          pBin->index = pTree->pNode[i].index;
204

205
          pHead = pHead->pForward[0];
206
        }
207

208
        pLast = pHead;
209

210
        for (int32_t i = 0; i < pTree->numOfEntries; ++i) {
211
          pTree->pNode[i].index = -1;
212
        }
213

214
        tMergeTreePrint(pTree);
215

216
        for (int32_t i = pTree->totalEntries - 1; i >= pTree->numOfEntries; i--) {
217
          tMergeTreeAdjust(pTree, i);
218
        }
219

220
        tMergeTreePrint(pTree);
221
        (*pHisto)->ordered = true;
222
      }
223

224
      printf("delta is:%lf\n", pEntry1->delta);
225

226
      SSkipListPrint((*pHisto)->pList, 1);
227

228
      /* the chosen node */
229
      tSkipListNode* pNode = (*pHisto)->pLoserTree->pNode[0].pData;
230
      SHistBin*      pEntry = (SHistBin*)pNode->pData;
231

232
      tSkipListNode* pNext = pNode->pForward[0];
233
      SHistBin*      pNextEntry = (SHistBin*)pNext->pData;
234
      if (pNextEntry->val - pEntry->val != pEntry->delta) {
235
        qError("tHistogramAdd Error, pNextEntry->val:%lf, pEntry->val:%lf, pEntry->delta:%lf", pNextEntry->val, pEntry->val, pEntry->delta);
236
        return TSDB_CODE_FUNC_HISTOGRAM_ERROR;
237
      }
238

239
      double newVal = (pEntry->val * pEntry->num + pNextEntry->val * pNextEntry->num) / (pEntry->num + pNextEntry->num);
240
      pEntry->val = newVal;
241
      pNode->key.dKey = newVal;
242
      pEntry->num = pEntry->num + pNextEntry->num;
243

244
      // update delta value in current node
245
      pEntry->delta = (pNextEntry->delta + pNextEntry->val) - pEntry->val;
246

247
      // reset delta value in the previous node
248
      SHistBin* pPrevEntry = (SHistBin*)pNode->pBackward[0]->pData;
249
      if (pPrevEntry) {
250
        pPrevEntry->delta = pEntry->val - pPrevEntry->val;
251
      }
252

253
      SMultiwayMergeTreeInfo* pTree = (*pHisto)->pLoserTree;
254
      if (pNextEntry->index != -1) {
255
        (*pHisto)->maxIndex = pNextEntry->index;
256

257
        // set the last element in skiplist, of which delta is FLT_MAX;
258
        pTree->pNode[pNextEntry->index + pTree->numOfEntries].pData = pLast;
259
        ((SHistBin*)pLast->pData)->index = pNextEntry->index;
260
        int32_t f = pTree->pNode[pNextEntry->index + pTree->numOfEntries].index;
261
        printf("disappear index is:%d\n", f);
262
      }
263

264
      tMergeTreeAdjust(pTree, pEntry->index + pTree->numOfEntries);
265
      // remove the next node in skiplist
266
      tSkipListRemoveNode((*pHisto)->pList, pNext);
267
      SSkipListPrint((*pHisto)->pList, 1);
268

269
      tMergeTreePrint((*pHisto)->pLoserTree);
270
    } else {  // add to heap
271
      if (pResNode->pForward[0] != NULL) {
272
        pEntry1->delta = ((SHistBin*)pResNode->pForward[0]->pData)->val - val;
273
      } else {
274
        pEntry1->delta = DBL_MAX;
275
      }
276

277
      if (pResNode->pBackward[0] != &(*pHisto)->pList->pHead) {
278
        SHistBin* pPrevEntry = (SHistBin*)pResNode->pBackward[0]->pData;
279
        pEntry1->delta = val - pPrevEntry->val;
280
      }
281

282
      printf("delta is:%9lf\n", pEntry1->delta);
283
    }
284

285
  } else {
286
    SHistBin* pEntry = (SHistBin*)pResNode->pData;
287
    if (pEntry->val != val) {
288
      qError("tHistogramAdd Error, pEntry->val:%lf, val:%lf", pEntry->val, val);
289
      return TSDB_CODE_FUNC_HISTOGRAM_ERROR;
290
    }
291
    pEntry->num += 1;
292
  }
293

294
#endif
295
  if (val > (*pHisto)->max) {
1,056,297,870✔
296
    (*pHisto)->max = val;
41,585,229✔
297
  }
298

299
  if (val < (*pHisto)->min) {
1,055,865,388✔
300
    (*pHisto)->min = val;
63,738,049✔
301
  }
302

303
  (*pHisto)->numOfElems += 1;
1,055,892,525✔
304
  return code;
1,055,914,760✔
305
}
306

307
int32_t histoBinarySearch(SHistBin* pEntry, int32_t len, double val) {
1,056,026,727✔
308
  int32_t end = len - 1;
1,056,026,727✔
309
  int32_t start = 0;
1,056,026,727✔
310

311
  while (start <= end) {
2,147,483,647✔
312
    int32_t mid = (end - start) / 2 + start;
2,147,483,647✔
313
    if (pEntry[mid].val == val) {
2,147,483,647✔
314
      return mid;
557,975,616✔
315
    }
316

317
    if (pEntry[mid].val < val) {
2,147,483,647✔
318
      start = mid + 1;
2,147,483,647✔
319
    } else {
320
      end = mid - 1;
2,147,483,647✔
321
    }
322
  }
323

324
  int32_t ret = start > end ? start : end;
508,924,065✔
325
  if (ret < 0) {
508,924,065✔
326
    return 0;
×
327
  } else {
328
    return ret;
508,924,065✔
329
  }
330
}
331

332
static void histogramMergeImpl(SHistBin* pHistBin, int32_t* size) {
385,289,166✔
333
#if defined(USE_ARRAYLIST)
334
  int32_t oldSize = *size;
385,289,166✔
335

336
  double  delta = DBL_MAX;
385,319,556✔
337
  int32_t index = -1;
385,319,556✔
338
  for (int32_t i = 1; i < oldSize; ++i) {
2,147,483,647✔
339
    double d = pHistBin[i].val - pHistBin[i - 1].val;
2,147,483,647✔
340
    if (d < delta) {
2,147,483,647✔
341
      delta = d;
2,147,483,647✔
342
      index = i - 1;
2,147,483,647✔
343
    }
344
  }
345

346
  SHistBin* s1 = &pHistBin[index];
1,659,689,766✔
347
  SHistBin* s2 = &pHistBin[index + 1];
384,718,150✔
348

349
  double newVal = (s1->val * s1->num + s2->val * s2->num) / (s1->num + s2->num);
384,842,159✔
350
  s1->val = newVal;
385,219,666✔
351
  s1->num = s1->num + s2->num;
385,301,038✔
352

353
  (void)memmove(&pHistBin[index + 1], &pHistBin[index + 2], (oldSize - index - 2) * sizeof(SHistBin));
385,378,947✔
354
  (*size) -= 1;
385,386,150✔
355
#endif
356
}
385,287,980✔
357

358
/* optimize this procedure */
359
int32_t histogramCreateBin(SHistogramInfo* pHisto, int32_t index, double val) {
497,862,041✔
360
#if defined(USE_ARRAYLIST)
361
  int32_t remain = pHisto->numOfEntries - index;
497,862,041✔
362
  if (remain > 0) {
497,885,410✔
363
    (void)memmove(&pHisto->elems[index + 1], &pHisto->elems[index], sizeof(SHistBin) * remain);
456,074,107✔
364
  }
365

366
  if (index < 0 || index > pHisto->maxEntries) {
498,085,613✔
UNCOV
367
    qError("histogramCreateBin Error, index:%d, maxEntries:%d", index, pHisto->maxEntries);
×
368
    return TSDB_CODE_FUNC_HISTOGRAM_ERROR;
×
369
  }
370

371
  pHisto->elems[index].num = 1;
498,229,505✔
372
  pHisto->elems[index].val = val;
498,192,586✔
373
  pHisto->numOfEntries += 1;
498,216,240✔
374

375
  /* we need to merge the slot */
376
  if (pHisto->numOfEntries == pHisto->maxEntries + 1) {
498,213,385✔
377
    histogramMergeImpl(pHisto->elems, &pHisto->numOfEntries);
385,341,184✔
378

379
    pHisto->elems[pHisto->maxEntries].val = 0;
385,232,508✔
380
    pHisto->elems[pHisto->maxEntries].num = 0;
385,229,492✔
381
  }
382
#endif
383
  if (pHisto->numOfEntries > pHisto->maxEntries) {
498,110,561✔
384
    qError("histogramCreateBin Error, numOfEntries:%d, maxEntries:%d", pHisto->numOfEntries, pHisto->maxEntries);
×
385
    return TSDB_CODE_FUNC_HISTOGRAM_ERROR;
×
386
  }
387

388
  return TSDB_CODE_SUCCESS;
498,084,586✔
389
}
390

391
void tHistogramDestroy(SHistogramInfo** pHisto) {
13,363✔
392
  if (*pHisto == NULL) {
13,363✔
393
    return;
×
394
  }
395

396
  taosMemoryFree(*pHisto);
13,363✔
397
  *pHisto = NULL;
13,363✔
398
}
399

400
void tHistogramPrint(SHistogramInfo* pHisto) {
×
401
  (void)printf("total entries: %d, elements: %" PRId64 "\n", pHisto->numOfEntries, pHisto->numOfElems);
×
402
#if defined(USE_ARRAYLIST)
403
  for (int32_t i = 0; i < pHisto->numOfEntries; ++i) {
×
404
    (void)printf("%d: (%f, %" PRId64 ")\n", i + 1, pHisto->elems[i].val, pHisto->elems[i].num);
×
405
  }
406
#else
407
  tSkipListNode* pNode = pHisto->pList->pHead.pForward[0];
408

409
  for (int32_t i = 0; i < pHisto->numOfEntries; ++i) {
410
    SHistBin* pEntry = (SHistBin*)pNode->pData;
411
    (void)printf("%d: (%f, %" PRId64 ")\n", i + 1, pEntry->val, pEntry->num);
412
    pNode = pNode->pForward[0];
413
  }
414
#endif
415
}
×
416

417
/**
418
 * Estimated number of points in the interval (−inf,b].
419
 * @param pHisto
420
 * @param v
421
 * @param res
422
 */
423
int32_t tHistogramSum(SHistogramInfo* pHisto, double v, int64_t *res) {
×
424
#if defined(USE_ARRAYLIST)
425
  int32_t slotIdx = histoBinarySearch(pHisto->elems, pHisto->numOfEntries, v);
×
426
  if (pHisto->elems[slotIdx].val != v) {
×
427
    slotIdx -= 1;
×
428

429
    if (slotIdx < 0) {
×
430
      slotIdx = 0;
×
431
      if (v > pHisto->elems[slotIdx].val) {
×
432
        qError("tHistogramSum Error, elems[%d].val:%lf, v:%lf", slotIdx, pHisto->elems[slotIdx].val, v);
×
433
        return TSDB_CODE_FUNC_HISTOGRAM_ERROR;
×
434
      }
435
    } else {
436
      if (v < pHisto->elems[slotIdx].val) {
×
437
        qError("tHistogramSum Error, elems[%d].val:%lf, v:%lf", slotIdx, pHisto->elems[slotIdx].val, v);
×
438
        return TSDB_CODE_FUNC_HISTOGRAM_ERROR;
×
439
      }
440
      if (slotIdx + 1 < pHisto->numOfEntries && v >= pHisto->elems[slotIdx + 1].val) {
×
441
        qError("tHistogramSum Error, elems[%d].val:%lf, v:%lf", slotIdx + 1, pHisto->elems[slotIdx + 1].val, v);
×
442
        return TSDB_CODE_FUNC_HISTOGRAM_ERROR;
×
443
      }
444
    }
445
  }
446

447
  double m1 = (double)pHisto->elems[slotIdx].num;
×
448
  double v1 = pHisto->elems[slotIdx].val;
×
449

450
  double m2 = (double)pHisto->elems[slotIdx + 1].num;
×
451
  double v2 = pHisto->elems[slotIdx + 1].val;
×
452

453
  double estNum = m1 + (m2 - m1) * (v - v1) / (v2 - v1);
×
454
  double s1 = (m1 + estNum) * (v - v1) / (2 * (v2 - v1));
×
455

456
  for (int32_t i = 0; i < slotIdx; ++i) {
×
457
    s1 += pHisto->elems[i].num;
×
458
  }
459

460
  s1 = s1 + m1 / 2;
×
461

462
  *res = (int64_t)s1;
×
463
#endif
464
  return TSDB_CODE_SUCCESS;
×
465
}
466

467
int32_t tHistogramUniform(SHistogramInfo* pHisto, double* ratio, int32_t num, double** pVal) {
37,705,201✔
468
#if defined(USE_ARRAYLIST)
469
  *pVal = taosMemoryMalloc(num * sizeof(double));
37,705,201✔
470
  if (NULL == *pVal) {
37,705,201✔
471
    return terrno;
×
472
  }
473

474
  for (int32_t i = 0; i < num; ++i) {
75,410,402✔
475
    double numOfElem = (ratio[i] / 100) * pHisto->numOfElems;
37,705,201✔
476

477
    if (numOfElem == 0) {
37,705,201✔
478
      (*pVal)[i] = pHisto->min;
5,430✔
479
      continue;
5,430✔
480
    } else if (numOfElem <= pHisto->elems[0].num) {
37,699,771✔
481
      (*pVal)[i] = pHisto->elems[0].val;
37,033,146✔
482
      continue;
37,033,146✔
483
    } else if (numOfElem == pHisto->numOfElems) {
666,625✔
484
      (*pVal)[i] = pHisto->max;
19,419✔
485
      continue;
19,419✔
486
    }
487

488
    int32_t j = 0;
647,206✔
489
    int64_t total = 0;
647,206✔
490

491
    while (j < pHisto->numOfEntries) {
11,180,051✔
492
      total += pHisto->elems[j].num;
11,180,051✔
493
      if (total <= numOfElem && total + pHisto->elems[j + 1].num > numOfElem) {
11,180,051✔
494
        break;
647,206✔
495
      }
496

497
      j += 1;
10,532,845✔
498
    }
499

500
    if (total > numOfElem || total + pHisto->elems[j + 1].num <= numOfElem) {
647,206✔
501
      qError("tHistogramUniform Error, total:%d, numOfElem:%d, elems[%d].num:%d",
×
502
             (int32_t)total, (int32_t)numOfElem, j + 1, (int32_t)pHisto->elems[j + 1].num);
503
      return TSDB_CODE_FUNC_HISTOGRAM_ERROR;
×
504
    }
505

506
    double delta = numOfElem - total;
647,206✔
507
    if (fabs(delta) < FLT_EPSILON) {
647,206✔
508
      (*pVal)[i] = pHisto->elems[j].val;
227,264✔
509
    }
510

511
    double start = (double)pHisto->elems[j].num;
647,206✔
512
    double range = pHisto->elems[j + 1].num - start;
647,206✔
513

514
    if (range == 0) {
647,206✔
515
      (*pVal)[i] = (pHisto->elems[j + 1].val - pHisto->elems[j].val) * delta / start + pHisto->elems[j].val;
553,596✔
516
    } else {
517
      double factor = (-2 * start + sqrt(4 * start * start - 4 * range * (-2 * delta))) / (2 * range);
93,610✔
518
      (*pVal)[i] = pHisto->elems[j].val + (pHisto->elems[j + 1].val - pHisto->elems[j].val) * factor;
93,610✔
519
    }
520
  }
521
#else
522
  double* pVal = taosMemoryMalloc(num * sizeof(double));
523
  if (NULL == *pVal) {
524
    return terrno;
525
  }
526
  for (int32_t i = 0; i < num; ++i) {
527
    double numOfElem = ratio[i] * pHisto->numOfElems;
528

529
    tSkipListNode* pFirst = pHisto->pList->pHead.pForward[0];
530
    SHistBin*      pEntry = (SHistBin*)pFirst->pData;
531
    if (numOfElem == 0) {
532
      (*pVal)[i] = pHisto->min;
533
      printf("i/numofSlot: %f, v:%f, %f\n", ratio[i], numOfElem, pVal[i]);
534
      continue;
535
    } else if (numOfElem <= pEntry->num) {
536
      (*pVal)[i] = pEntry->val;
537
      printf("i/numofSlot: %f, v:%f, %f\n", ratio[i], numOfElem, pVal[i]);
538
      continue;
539
    } else if (numOfElem == pHisto->numOfElems) {
540
      (*pVal)[i] = pHisto->max;
541
      printf("i/numofSlot: %f, v:%f, %f\n", ratio[i], numOfElem, pVal[i]);
542
      continue;
543
    }
544

545
    int32_t   j = 0;
546
    int64_t   total = 0;
547
    SHistBin* pPrev = pEntry;
548

549
    while (j < pHisto->numOfEntries) {
550
      if (total <= numOfElem && total + pEntry->num > numOfElem) {
551
        break;
552
      }
553

554
      total += pEntry->num;
555
      pPrev = pEntry;
556

557
      pFirst = pFirst->pForward[0];
558
      pEntry = (SHistBin*)pFirst->pData;
559

560
      j += 1;
561
    }
562

563
    if (total > numOfElem || total + pEntry->num <= numOfElem) {
564
      qError("tHistogramUniform Error, total:%d, numOfElem:%d, pEntry->num:%d", (int32_t)total, (int32_t)numOfElem, (int32_t)pEntry->num);
565
      return TSDB_CODE_FUNC_HISTOGRAM_ERROR;
566
    }
567

568
    double delta = numOfElem - total;
569
    if (fabs(delta) < FLT_EPSILON) {
570
      //                printf("i/numofSlot: %f, v:%f, %f\n",
571
      //                (double)i/numOfSlots, numOfElem, pHisto->elems[j].val);
572
      (*pVal)[i] = pPrev->val;
573
    }
574

575
    double start = pPrev->num;
576
    double range = pEntry->num - start;
577

578
    if (range == 0) {
579
      (*pVal)[i] = (pEntry->val - pPrev->val) * delta / start + pPrev->val;
580
    } else {
581
      double factor = (-2 * start + sqrt(4 * start * start - 4 * range * (-2 * delta))) / (2 * range);
582
      (*pVal)[i] = pPrev->val + (pEntry->val - pPrev->val) * factor;
583
    }
584
    //            printf("i/numofSlot: %f, v:%f, %f\n", (double)i/numOfSlots,
585
    //            numOfElem, val);
586
  }
587
#endif
588
  return TSDB_CODE_SUCCESS;
37,705,201✔
589
}
590

591
int32_t tHistogramMerge(SHistogramInfo* pHisto1, SHistogramInfo* pHisto2, int32_t numOfEntries, SHistogramInfo** pResHistogram) {
13,363✔
592
  int32_t code = tHistogramCreate(numOfEntries, pResHistogram);
13,363✔
593
  if (TSDB_CODE_SUCCESS != code) {
13,363✔
594
    return code;
×
595
  }
596

597
  // error in histogram info
598
  if (pHisto1->numOfEntries > MAX_HISTOGRAM_BIN || pHisto2->numOfEntries > MAX_HISTOGRAM_BIN) {
13,363✔
599
    return code;
×
600
  }
601

602
  SHistBin* pHistoBins = taosMemoryCalloc(1, sizeof(SHistBin) * (pHisto1->numOfEntries + pHisto2->numOfEntries));
13,363✔
603
  if (NULL == pHistoBins) {
13,363✔
604
    return terrno;
×
605
  }
606
  int32_t   i = 0, j = 0, k = 0;
13,363✔
607

608
  while (i < pHisto1->numOfEntries && j < pHisto2->numOfEntries) {
701,689✔
609
    if (pHisto1->elems[i].val < pHisto2->elems[j].val) {
688,326✔
610
      pHistoBins[k++] = pHisto1->elems[i++];
90,480✔
611
    } else if (pHisto1->elems[i].val > pHisto2->elems[j].val) {
597,846✔
612
      pHistoBins[k++] = pHisto2->elems[j++];
141,636✔
613
    } else {
614
      pHistoBins[k] = pHisto1->elems[i++];
456,210✔
615
      pHistoBins[k++].num += pHisto2->elems[j++].num;
456,210✔
616
    }
617
  }
618

619
  if (i < pHisto1->numOfEntries) {
13,363✔
620
    int32_t remain = pHisto1->numOfEntries - i;
4,404✔
621
    (void)memcpy(&pHistoBins[k], &pHisto1->elems[i], sizeof(SHistBin) * remain);
4,404✔
622
    k += remain;
4,404✔
623
  }
624

625
  if (j < pHisto2->numOfEntries) {
13,363✔
626
    int32_t remain = pHisto2->numOfEntries - j;
1,924✔
627
    (void)memcpy(&pHistoBins[k], &pHisto2->elems[j], sizeof(SHistBin) * remain);
1,924✔
628
    k += remain;
1,924✔
629
  }
630

631
  /* update other information */
632
  (*pResHistogram)->numOfElems = pHisto1->numOfElems + pHisto2->numOfElems;
13,363✔
633
  (*pResHistogram)->min = (pHisto1->min < pHisto2->min) ? pHisto1->min : pHisto2->min;
13,363✔
634
  (*pResHistogram)->max = (pHisto1->max > pHisto2->max) ? pHisto1->max : pHisto2->max;
13,363✔
635

636
  while (k > numOfEntries) {
13,363✔
637
    histogramMergeImpl(pHistoBins, &k);
×
638
  }
639

640
  (*pResHistogram)->numOfEntries = k;
13,363✔
641
  (void)memcpy((*pResHistogram)->elems, pHistoBins, sizeof(SHistBin) * k);
13,363✔
642

643
  taosMemoryFree(pHistoBins);
13,363✔
644
  return TSDB_CODE_SUCCESS;
13,363✔
645
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc