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

taosdata / TDengine / #4720

08 Sep 2025 08:43AM UTC coverage: 58.139% (-0.6%) from 58.762%
#4720

push

travis-ci

web-flow
Merge pull request #32881 from taosdata/enh/add-new-windows-ci

fix(ci): update workflow reference to use new Windows CI YAML

133181 of 292179 branches covered (45.58%)

Branch coverage included in aggregate %.

201691 of 283811 relevant lines covered (71.07%)

5442780.71 hits per line

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

61.42
/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) {
53✔
37
  /* need one redundant slot */
38
  *pHisto = taosMemoryMalloc(sizeof(SHistogramInfo) + sizeof(SHistBin) * (numOfEntries + 1));
53!
39
  if (NULL == *pHisto) {
53!
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);
53✔
58
  return TSDB_CODE_SUCCESS;
53✔
59
}
60

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

64
  SHistogramInfo* pHisto = (SHistogramInfo*)pBuf;
74,833✔
65
  pHisto->elems = (SHistBin*)((char*)pBuf + sizeof(SHistogramInfo));
74,833✔
66
  for (int32_t i = 0; i < numOfBins; ++i) {
37,306,780✔
67
    pHisto->elems[i].val = -DBL_MAX;
37,231,947✔
68
  }
69

70
  pHisto->maxEntries = numOfBins;
74,833✔
71

72
  pHisto->min = DBL_MAX;
74,833✔
73
  pHisto->max = -DBL_MAX;
74,833✔
74

75
  return pBuf;
74,833✔
76
}
77

78
int32_t tHistogramAdd(SHistogramInfo** pHisto, double val) {
1,018,501✔
79
  int32_t code = TSDB_CODE_SUCCESS;
1,018,501✔
80
  if (*pHisto == NULL) {
1,018,501!
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,018,501✔
89
  if (idx < 0 || idx > (*pHisto)->maxEntries || (*pHisto)->elems == NULL) {
1,018,562!
90
    qError("tHistogramAdd Error, idx:%d, maxEntries:%d, elems:%p", idx, (*pHisto)->maxEntries, (*pHisto)->elems);
×
91
    return TSDB_CODE_FUNC_HISTOGRAM_ERROR;
×
92
  }
93

94
  if ((*pHisto)->elems[idx].val == val && idx >= 0) {
1,018,703!
95
    (*pHisto)->elems[idx].num += 1;
826,260✔
96

97
    if ((*pHisto)->numOfEntries == 0) {
826,260!
98
      (*pHisto)->numOfEntries += 1;
×
99
    }
100
  } else { /* insert a new slot */
101
    if ((*pHisto)->numOfElems >= 1 && idx < (*pHisto)->numOfEntries) {
192,443✔
102
      if (idx > 0) {
132,251✔
103
        if ((*pHisto)->elems[idx - 1].val > val) {
120,133!
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) {
12,118!
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) {
60,192!
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);
192,443✔
119
    if (code != TSDB_CODE_SUCCESS) {
192,687!
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,018,947✔
296
    (*pHisto)->max = val;
60,428✔
297
  }
298

299
  if (val < (*pHisto)->min) {
1,018,947✔
300
    (*pHisto)->min = val;
56,087✔
301
  }
302

303
  (*pHisto)->numOfElems += 1;
1,018,947✔
304
  return code;
1,018,947✔
305
}
306

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

311
  while (start <= end) {
2,010,566✔
312
    int32_t mid = (end - start) / 2 + start;
1,818,281✔
313
    if (pEntry[mid].val == val) {
1,818,281✔
314
      return mid;
826,160✔
315
    }
316

317
    if (pEntry[mid].val < val) {
992,121✔
318
      start = mid + 1;
545,090✔
319
    } else {
320
      end = mid - 1;
447,031✔
321
    }
322
  }
323

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

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

336
  double  delta = DBL_MAX;
19,000✔
337
  int32_t index = -1;
19,000✔
338
  for (int32_t i = 1; i < oldSize; ++i) {
9,519,000✔
339
    double d = pHistBin[i].val - pHistBin[i - 1].val;
9,500,000✔
340
    if (d < delta) {
9,500,000✔
341
      delta = d;
142,236✔
342
      index = i - 1;
142,236✔
343
    }
344
  }
345

346
  SHistBin* s1 = &pHistBin[index];
19,000✔
347
  SHistBin* s2 = &pHistBin[index + 1];
19,000✔
348

349
  double newVal = (s1->val * s1->num + s2->val * s2->num) / (s1->num + s2->num);
19,000✔
350
  s1->val = newVal;
19,000✔
351
  s1->num = s1->num + s2->num;
19,000✔
352

353
  (void)memmove(&pHistBin[index + 1], &pHistBin[index + 2], (oldSize - index - 2) * sizeof(SHistBin));
19,000✔
354
  (*size) -= 1;
19,000✔
355
#endif
356
}
19,000✔
357

358
/* optimize this procedure */
359
int32_t histogramCreateBin(SHistogramInfo* pHisto, int32_t index, double val) {
192,687✔
360
#if defined(USE_ARRAYLIST)
361
  int32_t remain = pHisto->numOfEntries - index;
192,687✔
362
  if (remain > 0) {
192,687✔
363
    (void)memmove(&pHisto->elems[index + 1], &pHisto->elems[index], sizeof(SHistBin) * remain);
132,251✔
364
  }
365

366
  if (index < 0 || index > pHisto->maxEntries) {
192,687!
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;
192,687✔
372
  pHisto->elems[index].val = val;
192,687✔
373
  pHisto->numOfEntries += 1;
192,687✔
374

375
  /* we need to merge the slot */
376
  if (pHisto->numOfEntries == pHisto->maxEntries + 1) {
192,687✔
377
    histogramMergeImpl(pHisto->elems, &pHisto->numOfEntries);
19,000✔
378

379
    pHisto->elems[pHisto->maxEntries].val = 0;
19,000✔
380
    pHisto->elems[pHisto->maxEntries].num = 0;
19,000✔
381
  }
382
#endif
383
  if (pHisto->numOfEntries > pHisto->maxEntries) {
192,687!
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;
192,687✔
389
}
390

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

396
  taosMemoryFree(*pHisto);
53!
397
  *pHisto = NULL;
53✔
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) {
35,882✔
468
#if defined(USE_ARRAYLIST)
469
  *pVal = taosMemoryMalloc(num * sizeof(double));
35,882!
470
  if (NULL == *pVal) {
35,882!
471
    return terrno;
×
472
  }
473

474
  for (int32_t i = 0; i < num; ++i) {
71,764✔
475
    double numOfElem = (ratio[i] / 100) * pHisto->numOfElems;
35,882✔
476

477
    if (numOfElem == 0) {
35,882✔
478
      (*pVal)[i] = pHisto->min;
30✔
479
      continue;
30✔
480
    } else if (numOfElem <= pHisto->elems[0].num) {
35,852✔
481
      (*pVal)[i] = pHisto->elems[0].val;
33,004✔
482
      continue;
33,004✔
483
    } else if (numOfElem == pHisto->numOfElems) {
2,848✔
484
      (*pVal)[i] = pHisto->max;
209✔
485
      continue;
209✔
486
    }
487

488
    int32_t j = 0;
2,639✔
489
    int64_t total = 0;
2,639✔
490

491
    while (j < pHisto->numOfEntries) {
45,498!
492
      total += pHisto->elems[j].num;
45,498✔
493
      if (total <= numOfElem && total + pHisto->elems[j + 1].num > numOfElem) {
45,498!
494
        break;
2,639✔
495
      }
496

497
      j += 1;
42,859✔
498
    }
499

500
    if (total > numOfElem || total + pHisto->elems[j + 1].num <= numOfElem) {
2,639!
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;
2,639✔
507
    if (fabs(delta) < FLT_EPSILON) {
2,639✔
508
      (*pVal)[i] = pHisto->elems[j].val;
1,212✔
509
    }
510

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

514
    if (range == 0) {
2,639✔
515
      (*pVal)[i] = (pHisto->elems[j + 1].val - pHisto->elems[j].val) * delta / start + pHisto->elems[j].val;
2,514✔
516
    } else {
517
      double factor = (-2 * start + sqrt(4 * start * start - 4 * range * (-2 * delta))) / (2 * range);
125✔
518
      (*pVal)[i] = pHisto->elems[j].val + (pHisto->elems[j + 1].val - pHisto->elems[j].val) * factor;
125✔
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;
35,882✔
589
}
590

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

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

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

608
  while (i < pHisto1->numOfEntries && j < pHisto2->numOfEntries) {
1,271✔
609
    if (pHisto1->elems[i].val < pHisto2->elems[j].val) {
1,218✔
610
      pHistoBins[k++] = pHisto1->elems[i++];
389✔
611
    } else if (pHisto1->elems[i].val > pHisto2->elems[j].val) {
829✔
612
      pHistoBins[k++] = pHisto2->elems[j++];
274✔
613
    } else {
614
      pHistoBins[k] = pHisto1->elems[i++];
555✔
615
      pHistoBins[k++].num += pHisto2->elems[j++].num;
555✔
616
    }
617
  }
618

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

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

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

636
  while (k > numOfEntries) {
53!
637
    histogramMergeImpl(pHistoBins, &k);
×
638
  }
639

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

643
  taosMemoryFree(pHistoBins);
53!
644
  return TSDB_CODE_SUCCESS;
53✔
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

© 2025 Coveralls, Inc