PostgreSQL Source Code: src/backend/utils/hash/dynahash.c Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
96
97#include <limits.h>
98
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123#define DEF_SEGSIZE 256
124#define DEF_SEGSIZE_SHIFT 8
125#define DEF_DIRSIZE 256
126
127
128#define NUM_FREELISTS 32
129
130
132
133
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153typedef struct
154{
159
160
161
162
163
164
165
166
167
169{
170
171
172
173
174
175
176
177
178
179
181
182
183
189
190
193 long num_partitions;
197 int nelem_alloc;
198
199#ifdef HASH_STATISTICS
200
201
202
203
204
205 long accesses;
206 long collisions;
207#endif
208};
209
210#define IS_PARTITIONED(hctl) ((hctl)->num_partitions != 0)
211
212#define FREELIST_IDX(hctl, hashcode) \
213 (IS_PARTITIONED(hctl) ? (hashcode) % NUM_FREELISTS : 0)
214
215
216
217
218
220{
231
232
234
235
239};
240
241
242
243
244#define ELEMENTKEY(helem) (((char *)(helem)) + MAXALIGN(sizeof(HASHELEMENT)))
245
246
247
248
249#define ELEMENT_FROM_KEY(key) \
250 ((HASHELEMENT *) (((char *) (key)) - MAXALIGN(sizeof(HASHELEMENT))))
251
252
253
254
255#define MOD(x,y) ((x) & ((y)-1))
256
257#ifdef HASH_STATISTICS
258static long hash_accesses,
259 hash_collisions,
260 hash_expansions;
261#endif
262
263
264
265
268static bool element_alloc(HTAB *hashp, int nelem, int freelist_idx);
283
284
285
286
287
289
290static void *
292{
296}
297
298
299
300
301
302
303
304
305
306static int
308{
309 return strncmp(key1, key2, keysize - 1);
310}
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
353{
356
357
358
359
360
364
365
366
367
368
369
370
371
372
373
374
376 {
377
379 }
380 else
381 {
382
385 else
388 "dynahash",
390 }
391
392
394 sizeof(HTAB) + strlen(tabname) + 1);
396
397 hashp->tabname = (char *) (hashp + 1);
398 strcpy(hashp->tabname, tabname);
399
400
403
404
405
406
408 {
411 }
413 {
415
418 else
420 }
421 else
422 {
423
424
425
426
427
428
429
430
433
435 }
436
437
438
439
440
441
442
443
444
445
450 else
451 hashp->match = memcmp;
452
453
454
455
459 {
460
461
462
463
464
465
466
468 }
469 else
471
472
475 else
477
479 {
480
481
482
483
484
487 hashp->hcxt = NULL;
489
490
492 {
493
494 hctl = hashp->hctl;
498
499 return hashp;
500 }
501 }
502 else
503 {
504
505 hashp->hctl = NULL;
506 hashp->dir = NULL;
509 }
510
511 if (!hashp->hctl)
512 {
514 if (!hashp->hctl)
516 (errcode(ERRCODE_OUT_OF_MEMORY),
517 errmsg("out of memory")));
518 }
519
520 hashp->frozen = false;
521
523
524 hctl = hashp->hctl;
525
527 {
528
530
531
532
533
534
535
537
539 }
540
542 {
545
547 }
548
549
550
551
553 {
556 }
557
558
561
562
566
567
569 elog(ERROR, "failed to initialize hash table \"%s\"", hashp->tabname);
570
571
572
573
574
575
576
577
578
580 nelem < hctl->nelem_alloc)
581 {
582 int i,
583 freelist_partitions,
584 nelem_alloc,
585 nelem_alloc_first;
586
587
588
589
590
593 else
594 freelist_partitions = 1;
595
596 nelem_alloc = nelem / freelist_partitions;
597 if (nelem_alloc <= 0)
598 nelem_alloc = 1;
599
600
601
602
603
604 if (nelem_alloc * freelist_partitions < nelem)
605 nelem_alloc_first =
606 nelem - nelem_alloc * (freelist_partitions - 1);
607 else
608 nelem_alloc_first = nelem_alloc;
609
610 for (i = 0; i < freelist_partitions; i++)
611 {
612 int temp = (i == 0) ? nelem_alloc_first : nelem_alloc;
613
616 (errcode(ERRCODE_OUT_OF_MEMORY),
617 errmsg("out of memory")));
618 }
619 }
620
623 return hashp;
624}
625
626
627
628
629static void
631{
633
635
638
640
641
643
646
647#ifdef HASH_STATISTICS
648 hctl->accesses = hctl->collisions = 0;
649#endif
650}
651
652
653
654
655
656static int
658{
659 int nelem_alloc;
660 Size elementSize;
661 Size allocSize;
662
663
664
666
667
668
669
670
671
672
673
674
675 allocSize = 32 * 4;
676 do
677 {
678 allocSize <<= 1;
679 nelem_alloc = allocSize / elementSize;
680 } while (nelem_alloc < 32);
681
682 return nelem_alloc;
683}
684
685
686
687
688
689static bool
691{
694 int nbuckets;
695 int nsegs;
696 int i;
697
698
699
700
704
705
706
707
708
710
711
712
713
714
715
716
717 while (nbuckets < hctl->num_partitions)
718 nbuckets <<= 1;
719
721 hctl->high_mask = (nbuckets << 1) - 1;
722
723
724
725
726 nsegs = (nbuckets - 1) / hctl->ssize + 1;
728
729
730
731
732
733 if (nsegs > hctl->dsize)
734 {
735 if (!(hashp->dir))
736 hctl->dsize = nsegs;
737 else
738 return false;
739 }
740
741
742 if (!(hashp->dir))
743 {
747 if (!hashp->dir)
748 return false;
749 }
750
751
752 for (segp = hashp->dir; hctl->nsegs < nsegs; hctl->nsegs++, segp++)
753 {
755 if (*segp == NULL)
756 return false;
757 }
758
759
761
762#ifdef HASH_DEBUG
763 fprintf(stderr, "init_htab:\n%s%p\n%s%ld\n%s%ld\n%s%d\n%s%ld\n%s%u\n%s%x\n%s%x\n%s%ld\n",
764 "TABLE POINTER ", hashp,
765 "DIRECTORY SIZE ", hctl->dsize,
766 "SEGMENT SIZE ", hctl->ssize,
767 "SEGMENT SHIFT ", hctl->sshift,
771 "NSEGS ", hctl->nsegs);
772#endif
773 return true;
774}
775
776
777
778
779
780
781
782
785{
787 long nBuckets,
788 nSegments,
789 nDirEntries,
790 nElementAllocs,
791 elementSize,
792 elementAllocCnt;
793
794
796
798
800 while (nDirEntries < nSegments)
801 nDirEntries <<= 1;
802
803
804 size = MAXALIGN(sizeof(HASHHDR));
805
807
810
812 nElementAllocs = (num_entries - 1) / elementAllocCnt + 1;
816 mul_size(elementAllocCnt, elementSize)));
817
818 return size;
819}
820
821
822
823
824
825
826
827
828
829
830long
832{
833 long nBuckets,
834 nSegments,
835 nDirEntries;
836
837
839
841
843 while (nDirEntries < nSegments)
844 nDirEntries <<= 1;
845
846 return nDirEntries;
847}
848
849
850
851
852
853
856{
860}
861
862
863
864
865void
867{
868 if (hashp != NULL)
869 {
870
872
874
876
877
878
879
881 }
882}
883
884void
886{
887#ifdef HASH_STATISTICS
888 fprintf(stderr, "%s: this HTAB -- accesses %ld collisions %ld\n",
889 where, hashp->hctl->accesses, hashp->hctl->collisions);
890
891 fprintf(stderr, "hash_stats: entries %ld keysize %ld maxp %u segmentcount %ld\n",
894 fprintf(stderr, "%s: total accesses %ld total collisions %ld\n",
895 where, hash_accesses, hash_collisions);
896 fprintf(stderr, "hash_stats: total expansions %ld\n",
897 hash_expansions);
898#endif
899}
900
901
902
903
904
905
906
907
908
909
910
913{
914 return hashp->hash(keyPtr, hashp->keysize);
915}
916
917
920{
922
923 bucket = hash_val & hctl->high_mask;
925 bucket = bucket & hctl->low_mask;
926
927 return bucket;
928}
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955void *
957 const void *keyPtr,
959 bool *foundPtr)
960{
962 keyPtr,
965 foundPtr);
966}
967
968void *
970 const void *keyPtr,
973 bool *foundPtr)
974{
976 int freelist_idx = FREELIST_IDX(hctl, hashvalue);
977 Size keysize;
981
982#ifdef HASH_STATISTICS
983 hash_accesses++;
984 hctl->accesses++;
985#endif
986
987
988
989
990
991
992
993
994
996 {
997
998
999
1000
1005 }
1006
1007
1008
1009
1011 currBucket = *prevBucketPtr;
1012
1013
1014
1015
1016 match = hashp->match;
1017 keysize = hashp->keysize;
1018
1019 while (currBucket != NULL)
1020 {
1021 if (currBucket->hashvalue == hashvalue &&
1022 match(ELEMENTKEY(currBucket), keyPtr, keysize) == 0)
1023 break;
1024 prevBucketPtr = &(currBucket->link);
1025 currBucket = *prevBucketPtr;
1026#ifdef HASH_STATISTICS
1027 hash_collisions++;
1028 hctl->collisions++;
1029#endif
1030 }
1031
1032 if (foundPtr)
1033 *foundPtr = (bool) (currBucket != NULL);
1034
1035
1036
1037
1039 {
1041 if (currBucket != NULL)
1043 return NULL;
1044
1046 if (currBucket != NULL)
1047 {
1048
1051
1052
1055
1056
1057 *prevBucketPtr = currBucket->link;
1058
1059
1062
1065
1066
1067
1068
1069
1070
1072 }
1073 return NULL;
1074
1077
1078 if (currBucket != NULL)
1080
1081
1083 elog(ERROR, "cannot insert into frozen hashtable \"%s\"",
1085
1087 if (currBucket == NULL)
1088 {
1089
1091 return NULL;
1092
1095 (errcode(ERRCODE_OUT_OF_MEMORY),
1096 errmsg("out of shared memory")));
1097 else
1099 (errcode(ERRCODE_OUT_OF_MEMORY),
1100 errmsg("out of memory")));
1101 }
1102
1103
1104 *prevBucketPtr = currBucket;
1105 currBucket->link = NULL;
1106
1107
1108 currBucket->hashvalue = hashvalue;
1110
1111
1112
1113
1114
1115
1116
1117
1119 }
1120
1121 elog(ERROR, "unrecognized hash action code: %d", (int) action);
1122
1123 return NULL;
1124}
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145bool
1147 void *existingEntry,
1148 const void *newKeyPtr)
1149{
1151 uint32 newhashvalue;
1152 Size keysize;
1159
1160#ifdef HASH_STATISTICS
1161 hash_accesses++;
1162 hctl->accesses++;
1163#endif
1164
1165
1167 elog(ERROR, "cannot update in frozen hashtable \"%s\"",
1169
1170
1171
1172
1173
1174
1176 &prevBucketPtr);
1177 currBucket = *prevBucketPtr;
1178
1179 while (currBucket != NULL)
1180 {
1181 if (currBucket == existingElement)
1182 break;
1183 prevBucketPtr = &(currBucket->link);
1184 currBucket = *prevBucketPtr;
1185 }
1186
1187 if (currBucket == NULL)
1188 elog(ERROR, "hash_update_hash_key argument is not in hashtable \"%s\"",
1190
1191 oldPrevPtr = prevBucketPtr;
1192
1193
1194
1195
1196
1197 newhashvalue = hashp->hash(newKeyPtr, hashp->keysize);
1199 currBucket = *prevBucketPtr;
1200
1201
1202
1203
1204 match = hashp->match;
1205 keysize = hashp->keysize;
1206
1207 while (currBucket != NULL)
1208 {
1209 if (currBucket->hashvalue == newhashvalue &&
1210 match(ELEMENTKEY(currBucket), newKeyPtr, keysize) == 0)
1211 break;
1212 prevBucketPtr = &(currBucket->link);
1213 currBucket = *prevBucketPtr;
1214#ifdef HASH_STATISTICS
1215 hash_collisions++;
1216 hctl->collisions++;
1217#endif
1218 }
1219
1220 if (currBucket != NULL)
1221 return false;
1222
1223 currBucket = existingElement;
1224
1225
1226
1227
1228
1229
1230
1231
1232 if (bucket != newbucket)
1233 {
1234
1235 *oldPrevPtr = currBucket->link;
1236
1237
1238 *prevBucketPtr = currBucket;
1239 currBucket->link = NULL;
1240 }
1241
1242
1243 currBucket->hashvalue = newhashvalue;
1245
1246
1247
1248 return true;
1249}
1250
1251
1252
1253
1254
1255
1258{
1261
1262 for (;;)
1263 {
1264
1267
1268
1270
1271 if (newElement != NULL)
1272 break;
1273
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1290 {
1291 int borrow_from_idx;
1292
1294 return NULL;
1295
1296
1297 borrow_from_idx = freelist_idx;
1298 for (;;)
1299 {
1300 borrow_from_idx = (borrow_from_idx + 1) % NUM_FREELISTS;
1301 if (borrow_from_idx == freelist_idx)
1302 break;
1303
1306
1307 if (newElement != NULL)
1308 {
1311
1312
1316
1317 return newElement;
1318 }
1319
1321 }
1322
1323
1324 return NULL;
1325 }
1326 }
1327
1328
1331
1334
1335 return newElement;
1336}
1337
1338
1339
1340
1341long
1343{
1344 int i;
1346
1347
1348
1349
1350
1351
1353 {
1356 }
1357
1358 return sum;
1359}
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385void
1387{
1388 status->hashp = hashp;
1394}
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405void
1408{
1410
1412
1415
1417 status->curEntry = *bucketPtr;
1418}
1419
1420void *
1422{
1423 HTAB *hashp;
1426 long ssize;
1427 long segment_num;
1428 long segment_ndx;
1432
1434 {
1435
1436
1437
1438
1439 while ((curElem = status->curEntry) != NULL)
1440 {
1443 continue;
1444 return (void *) ELEMENTKEY(curElem);
1445 }
1446
1448 return NULL;
1449 }
1450
1451 if ((curElem = status->curEntry) != NULL)
1452 {
1453
1455 if (status->curEntry == NULL)
1458 }
1459
1460
1461
1462
1464 hashp = status->hashp;
1465 hctl = hashp->hctl;
1466 ssize = hashp->ssize;
1468
1469 if (curBucket > max_bucket)
1470 {
1472 return NULL;
1473 }
1474
1475
1476
1477
1478 segment_num = curBucket >> hashp->sshift;
1479 segment_ndx = MOD(curBucket, ssize);
1480
1481 segp = hashp->dir[segment_num];
1482
1483
1484
1485
1486
1487
1488
1489 while ((curElem = segp[segment_ndx]) == NULL)
1490 {
1491
1492 if (++curBucket > max_bucket)
1493 {
1496 return NULL;
1497 }
1498 if (++segment_ndx >= ssize)
1499 {
1500 segment_num++;
1501 segment_ndx = 0;
1502 segp = hashp->dir[segment_num];
1503 }
1504 }
1505
1506
1508 if (status->curEntry == NULL)
1509 ++curBucket;
1512}
1513
1514void
1516{
1519}
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534void
1536{
1538 elog(ERROR, "cannot freeze shared hashtable \"%s\"", hashp->tabname);
1540 elog(ERROR, "cannot freeze hashtable \"%s\" because it has active scans",
1542 hashp->frozen = true;
1543}
1544
1545
1546
1547
1548
1549
1550
1551static bool
1553{
1556 new_seg;
1557 long old_bucket,
1558 new_bucket;
1559 long new_segnum,
1560 new_segndx;
1561 long old_segnum,
1562 old_segndx;
1564 *newlink;
1566 nextElement;
1567
1569
1570#ifdef HASH_STATISTICS
1571 hash_expansions++;
1572#endif
1573
1575 new_segnum = new_bucket >> hashp->sshift;
1576 new_segndx = MOD(new_bucket, hashp->ssize);
1577
1578 if (new_segnum >= hctl->nsegs)
1579 {
1580
1581 if (new_segnum >= hctl->dsize)
1583 return false;
1584 if (!(hashp->dir[new_segnum] = seg_alloc(hashp)))
1585 return false;
1587 }
1588
1589
1591
1592
1593
1594
1595
1596
1597
1598 old_bucket = (new_bucket & hctl->low_mask);
1599
1600
1601
1602
1604 {
1607 }
1608
1609
1610
1611
1612
1613
1614
1615 old_segnum = old_bucket >> hashp->sshift;
1616 old_segndx = MOD(old_bucket, hashp->ssize);
1617
1618 old_seg = hashp->dir[old_segnum];
1619 new_seg = hashp->dir[new_segnum];
1620
1621 oldlink = &old_seg[old_segndx];
1622 newlink = &new_seg[new_segndx];
1623
1624 for (currElement = *oldlink;
1625 currElement != NULL;
1626 currElement = nextElement)
1627 {
1628 nextElement = currElement->link;
1630 {
1631 *oldlink = currElement;
1632 oldlink = &currElement->link;
1633 }
1634 else
1635 {
1636 *newlink = currElement;
1637 newlink = &currElement->link;
1638 }
1639 }
1640
1641 *oldlink = NULL;
1642 *newlink = NULL;
1643
1644 return true;
1645}
1646
1647
1648static bool
1650{
1653 long new_dsize;
1654 long old_dirsize;
1655 long new_dirsize;
1656
1658 return false;
1659
1660
1661 new_dsize = hashp->hctl->dsize << 1;
1663 new_dirsize = new_dsize * sizeof(HASHSEGMENT);
1664
1665 old_p = hashp->dir;
1668
1669 if (p != NULL)
1670 {
1671 memcpy(p, old_p, old_dirsize);
1672 MemSet(((char *) p) + old_dirsize, 0, new_dirsize - old_dirsize);
1673 hashp->dir = p;
1675
1676
1679
1680 return true;
1681 }
1682
1683 return false;
1684}
1685
1686
1689{
1691
1694
1695 if (!segp)
1696 return NULL;
1697
1699
1700 return segp;
1701}
1702
1703
1704
1705
1706static bool
1708{
1710 Size elementSize;
1714 int i;
1715
1717 return false;
1718
1719
1721
1723 firstElement = (HASHELEMENT *) hashp->alloc(nelem * elementSize);
1724
1725 if (!firstElement)
1726 return false;
1727
1728
1729 prevElement = NULL;
1730 tmpElement = firstElement;
1731 for (i = 0; i < nelem; i++)
1732 {
1733 tmpElement->link = prevElement;
1734 prevElement = tmpElement;
1735 tmpElement = (HASHELEMENT *) (((char *) tmpElement) + elementSize);
1736 }
1737
1738
1741
1742
1745
1748
1749 return true;
1750}
1751
1752
1753
1754
1755
1758{
1761 long segment_num;
1762 long segment_ndx;
1764
1766
1767 segment_num = bucket >> hashp->sshift;
1768 segment_ndx = MOD(bucket, hashp->ssize);
1769
1770 segp = hashp->dir[segment_num];
1771
1772 if (segp == NULL)
1774
1775 *bucketptr = &segp[segment_ndx];
1776 return bucket;
1777}
1778
1779
1780static void
1782{
1783
1784
1785
1786
1789 else
1791}
1792
1793
1794int
1796{
1797
1798
1799
1800
1801 if (num > LONG_MAX / 2)
1802 num = LONG_MAX / 2;
1803
1804#if SIZEOF_LONG < 8
1806#else
1808#endif
1809}
1810
1811
1812static long
1814{
1815
1816 return 1L << my_log2(num);
1817}
1818
1819
1820static int
1822{
1823 if (num > INT_MAX / 2)
1824 num = INT_MAX / 2;
1825 return 1 << my_log2(num);
1826}
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857#define MAX_SEQ_SCANS 100
1858
1862
1863
1864
1865static void
1867{
1869 elog(ERROR, "too many active hash_seq_search scans, cannot start one on \"%s\"",
1874}
1875
1876
1877static void
1879{
1880 int i;
1881
1882
1884 {
1886 {
1890 return;
1891 }
1892 }
1893 elog(ERROR, "no hash_seq_search scan for hash table \"%s\"",
1895}
1896
1897
1898static bool
1900{
1901 int i;
1902
1904 {
1906 return true;
1907 }
1908 return false;
1909}
1910
1911
1912void
1914{
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924 if (isCommit)
1925 {
1926 int i;
1927
1929 {
1930 elog(WARNING, "leaked hash_seq_search scan for hash table %p",
1932 }
1933 }
1935}
1936
1937
1938void
1940{
1941 int i;
1942
1943
1944
1945
1946
1947
1949 {
1951 {
1952 if (isCommit)
1953 elog(WARNING, "leaked hash_seq_search scan for hash table %p",
1958 }
1959 }
1960}
#define MemSet(start, val, len)
void(* pg_funcptr_t)(void)
#define fprintf(file, fmt, msg)
static HTAB * seq_scan_tables[MAX_SEQ_SCANS]
static int seq_scan_level[MAX_SEQ_SCANS]
void hash_seq_init_with_hash_value(HASH_SEQ_STATUS *status, HTAB *hashp, uint32 hashvalue)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
#define ELEMENT_FROM_KEY(key)
static void * DynaHashAlloc(Size size)
static bool element_alloc(HTAB *hashp, int nelem, int freelist_idx)
void AtEOXact_HashTables(bool isCommit)
static bool init_htab(HTAB *hashp, long nelem)
static HASHSEGMENT seg_alloc(HTAB *hashp)
static MemoryContext CurrentDynaHashCxt
static int choose_nelem_alloc(Size entrysize)
static int next_pow2_int(long num)
Size hash_get_shared_size(HASHCTL *info, int flags)
static void register_seq_scan(HTAB *hashp)
#define IS_PARTITIONED(hctl)
#define DEF_SEGSIZE_SHIFT
void AtEOSubXact_HashTables(bool isCommit, int nestDepth)
static HASHBUCKET get_hash_entry(HTAB *hashp, int freelist_idx)
void hash_destroy(HTAB *hashp)
static int string_compare(const char *key1, const char *key2, Size keysize)
void * hash_search_with_hash_value(HTAB *hashp, const void *keyPtr, uint32 hashvalue, HASHACTION action, bool *foundPtr)
void * hash_seq_search(HASH_SEQ_STATUS *status)
static bool expand_table(HTAB *hashp)
static void hdefault(HTAB *hashp)
static void deregister_seq_scan(HTAB *hashp)
#define ELEMENTKEY(helem)
void hash_seq_term(HASH_SEQ_STATUS *status)
#define FREELIST_IDX(hctl, hashcode)
long hash_get_num_entries(HTAB *hashp)
long hash_select_dirsize(long num_entries)
static pg_noreturn void hash_corrupted(HTAB *hashp)
Size hash_estimate_size(long num_entries, Size entrysize)
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
void hash_stats(const char *where, HTAB *hashp)
void hash_freeze(HTAB *hashp)
static bool dir_realloc(HTAB *hashp)
bool hash_update_hash_key(HTAB *hashp, void *existingEntry, const void *newKeyPtr)
static uint32 hash_initial_lookup(HTAB *hashp, uint32 hashvalue, HASHBUCKET **bucketptr)
uint32 get_hash_value(HTAB *hashp, const void *keyPtr)
static uint32 calc_bucket(HASHHDR *hctl, uint32 hash_val)
static bool has_seq_scans(HTAB *hashp)
static long next_pow2_long(long num)
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
#define MCXT_ALLOC_NO_OOM
uint32 tag_hash(const void *key, Size keysize)
uint32 uint32_hash(const void *key, Size keysize)
uint32 string_hash(const void *key, Size keysize)
Assert(PointerIsAligned(start, uint64))
void *(* HashAllocFunc)(Size request)
int(* HashCompareFunc)(const void *key1, const void *key2, Size keysize)
uint32(* HashValueFunc)(const void *key, Size keysize)
void *(* HashCopyFunc)(void *dest, const void *src, Size keysize)
void * MemoryContextAlloc(MemoryContext context, Size size)
void pfree(void *pointer)
MemoryContext TopMemoryContext
void * MemoryContextAllocExtended(MemoryContext context, Size size, int flags)
void MemoryContextDelete(MemoryContext context)
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
#define MemoryContextIsValid(context)
#define AllocSetContextCreate
#define ALLOCSET_DEFAULT_SIZES
static uint64 pg_ceil_log2_64(uint64 num)
static uint32 pg_ceil_log2_32(uint32 num)
size_t strlcpy(char *dst, const char *src, size_t siz)
Size add_size(Size s1, Size s2)
Size mul_size(Size s1, Size s2)
#define SpinLockInit(lock)
#define SpinLockRelease(lock)
#define SpinLockAcquire(lock)
struct HASHELEMENT * link
FreeListData freeList[NUM_FREELISTS]
int GetCurrentTransactionNestLevel(void)