Skip to content

Commit cae8663

Browse files
author
Nikita Glukhov
committed
Variable-length jsonb KV map entries
1 parent f100794 commit cae8663

File tree

1 file changed

+98
-33
lines changed

1 file changed

+98
-33
lines changed

src/backend/utils/adt/jsonb_util.c

Lines changed: 98 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,27 @@ typedef struct CompressedJsonb
6666
int offset;
6767
} CompressedJsonb;
6868

69+
typedef struct JsonbKVMap
70+
{
71+
union
72+
{
73+
const uint8 *entries1;
74+
const uint16 *entries2;
75+
const int32 *entries4;
76+
const void *entries;
77+
} map;
78+
int entry_size;
79+
} JsonbKVMap;
80+
81+
#define JSONB_KVMAP_ENTRY_SIZE(nPairs) \
82+
((nPairs) < 256 ? 1 : (nPairs) < 65536 ? 2 : 4)
83+
84+
#define JSONB_KVMAP_ENTRY(kvmap, index) \
85+
(!(kvmap)->entry_size ? (index) : \
86+
(kvmap)->entry_size == 1 ? (int32) (kvmap)->map.entries1[index] : \
87+
(kvmap)->entry_size == 2 ? (int32) (kvmap)->map.entries2[index] : \
88+
(kvmap)->map.entries4[index])
89+
6990
struct JsonbIterator
7091
{
7192
JsonIterator ji;
@@ -81,7 +102,7 @@ struct JsonbIterator
81102
const JEntry *children; /* JEntrys for child nodes */
82103
/* Data proper. This points to the beginning of the variable-length data */
83104
char *dataProper;
84-
uint32 *kvMap;
105+
JsonbKVMap kvmap;
85106

86107
/* Current item in buffer (up to nElems) */
87108
int curIndex;
@@ -550,6 +571,24 @@ JsonFindValueInContainer(JsonContainer *json, uint32 flags, JsonValue *key)
550571
return NULL;
551572
}
552573

574+
static void *
575+
initKVMap(JsonbKVMap *kvmap, void *pentries, int field_count, bool sorted)
576+
{
577+
if (sorted)
578+
{
579+
kvmap->map.entries = pentries;
580+
kvmap->entry_size = JSONB_KVMAP_ENTRY_SIZE(field_count);
581+
582+
return (char *) pentries + INTALIGN(field_count * kvmap->entry_size);
583+
}
584+
else
585+
{
586+
kvmap->entry_size = 0;
587+
588+
return pentries;
589+
}
590+
}
591+
553592
/*
554593
* Find value by key in Jsonb object and fetch it into 'res', which is also
555594
* returned.
@@ -563,9 +602,9 @@ getKeyJsonValueFromContainer(JsonContainer *jsc,
563602
const JsonbContainer *container = JsonContainerDataPtr(jsc);
564603
const JEntry *children = container->children;
565604
int count = JsonContainerSize(jsc);
566-
char *baseAddr;
605+
char *baseAddr = (char *) (children + count * 2);
567606
bool sorted_values = (container->header & JB_TMASK) == JB_TOBJECT_SORTED;
568-
const uint32 *kvmap;
607+
JsonbKVMap kvmap;
569608
uint32 stopLow,
570609
stopHigh;
571610

@@ -579,16 +618,8 @@ getKeyJsonValueFromContainer(JsonContainer *jsc,
579618
* Binary search the container. Since we know this is an object, account
580619
* for *Pairs* of Jentrys
581620
*/
582-
if (sorted_values)
583-
{
584-
kvmap = &children[count * 2];
585-
baseAddr = (char *) &kvmap[count];
586-
}
587-
else
588-
{
589-
kvmap = NULL;
590-
baseAddr = (char *) (children + count * 2);
591-
}
621+
baseAddr = initKVMap(&kvmap, baseAddr, count, sorted_values);
622+
592623
stopLow = 0;
593624
stopHigh = count;
594625
while (stopLow < stopHigh)
@@ -609,7 +640,7 @@ getKeyJsonValueFromContainer(JsonContainer *jsc,
609640
if (difference == 0)
610641
{
611642
/* Found our key, return corresponding value */
612-
int index = (sorted_values ? kvmap[stopMiddle] : stopMiddle) + count;
643+
int index = JSONB_KVMAP_ENTRY(&kvmap, stopMiddle) + count;
613644

614645
if (!res)
615646
res = palloc(sizeof(JsonbValue));
@@ -1034,6 +1065,7 @@ JsonbIteratorToken
10341065
JsonbIteratorNext(JsonIterator **jsit, JsonbValue *val, bool skipNested)
10351066
{
10361067
JsonbIterator **it = (JsonbIterator **) jsit;
1068+
int entry_index;
10371069

10381070
if (*it == NULL)
10391071
return WJB_DONE;
@@ -1146,17 +1178,19 @@ JsonbIteratorNext(JsonIterator **jsit, JsonbValue *val, bool skipNested)
11461178
/* Set state for next call */
11471179
(*it)->state = JBI_OBJECT_KEY;
11481180

1181+
entry_index = JSONB_KVMAP_ENTRY(&(*it)->kvmap, (*it)->curIndex) + (*it)->nElems;
1182+
11491183
fillCompressedJsonbValue((*it)->compressed, (*it)->container,
1150-
((*it)->kvMap ? (*it)->kvMap[(*it)->curIndex] : (*it)->curIndex) + (*it)->nElems,
1184+
entry_index,
11511185
(*it)->dataProper,
1152-
(*it)->kvMap ?
1153-
getJsonbOffset((*it)->container, (*it)->kvMap[(*it)->curIndex] + (*it)->nElems) :
1186+
(*it)->kvmap.entry_size ?
1187+
getJsonbOffset((*it)->container, entry_index) :
11541188
(*it)->curValueOffset,
11551189
val);
11561190

11571191
JBE_ADVANCE_OFFSET((*it)->curDataOffset,
11581192
(*it)->children[(*it)->curIndex]);
1159-
if (!(*it)->kvMap)
1193+
if (!(*it)->kvmap.entry_size)
11601194
JBE_ADVANCE_OFFSET((*it)->curValueOffset,
11611195
(*it)->children[(*it)->curIndex + (*it)->nElems]);
11621196
(*it)->curIndex++;
@@ -1198,6 +1232,7 @@ jsonbIteratorInit(JsonContainer *cont, const JsonbContainer *container,
11981232
struct CompressedJsonb *cjb)
11991233
{
12001234
JsonbIterator *it;
1235+
int type = container->header & JB_TMASK;
12011236

12021237
it = palloc0(sizeof(JsonbIterator));
12031238
it->ji.container = cont;
@@ -1210,7 +1245,7 @@ jsonbIteratorInit(JsonContainer *cont, const JsonbContainer *container,
12101245
/* Array starts just after header */
12111246
it->children = container->children;
12121247

1213-
switch (container->header & JB_TMASK)
1248+
switch (type)
12141249
{
12151250
case JB_TSCALAR:
12161251
it->isScalar = true;
@@ -1225,16 +1260,12 @@ jsonbIteratorInit(JsonContainer *cont, const JsonbContainer *container,
12251260
break;
12261261

12271262
case JB_TOBJECT:
1228-
it->kvMap = NULL;
1263+
case JB_TOBJECT_SORTED:
12291264
it->dataProper =
12301265
(char *) it->children + it->nElems * sizeof(JEntry) * 2;
1231-
it->state = JBI_OBJECT_START;
1232-
break;
1266+
it->dataProper = initKVMap(&it->kvmap, it->dataProper, it->nElems,
1267+
type == JB_TOBJECT_SORTED);
12331268

1234-
case JB_TOBJECT_SORTED:
1235-
it->kvMap = (uint32 *)
1236-
((char *) it->children + it->nElems * sizeof(JEntry) * 2);
1237-
it->dataProper = (char *) &it->kvMap[it->nElems];
12381269
it->state = JBI_OBJECT_START;
12391270
break;
12401271

@@ -1958,6 +1989,7 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
19581989
uint32 header;
19591990
int nPairs = val->val.object.nPairs;
19601991
int reserved_size;
1992+
int kvmap_entry_size;
19611993
bool sorted_values = jsonb_sort_field_values && nPairs > 1;
19621994
struct
19631995
{
@@ -1984,6 +2016,7 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
19842016
{
19852017
if (values[i].index != i)
19862018
{
2019+
kvmap_entry_size = JSONB_KVMAP_ENTRY_SIZE(nPairs);
19872020
sorted_values = true;
19882021
break;
19892022
}
@@ -2006,16 +2039,45 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
20062039
/* Reserve space for the JEntries of the keys and values. */
20072040
reserved_size = sizeof(JEntry) * nPairs * 2;
20082041
if (sorted_values)
2009-
reserved_size += sizeof(int32) * nPairs;
2042+
reserved_size += INTALIGN(kvmap_entry_size * nPairs);
20102043

20112044
jentry_offset = reserveFromBuffer(buffer, reserved_size);
20122045

20132046
/* Write key-value map */
20142047
if (sorted_values)
20152048
{
2049+
int kvmap_offset = jentry_offset + sizeof(JEntry) * nPairs * 2;
2050+
20162051
for (i = 0; i < nPairs; i++)
2017-
copyToBuffer(buffer, jentry_offset + sizeof(JEntry) * nPairs * 2 + values[i].index * sizeof(int32),
2018-
&i, sizeof(int32));
2052+
{
2053+
uint8 entry1;
2054+
uint16 entry2;
2055+
uint32 entry4;
2056+
void *pentry;
2057+
2058+
if (kvmap_entry_size == 1)
2059+
{
2060+
entry1 = (uint8) i;
2061+
pentry = &entry1;
2062+
}
2063+
else if (kvmap_entry_size == 2)
2064+
{
2065+
entry2 = (uint16) i;
2066+
pentry = &entry2;
2067+
}
2068+
else
2069+
{
2070+
entry4 = (int32) i;
2071+
pentry = &entry4;
2072+
}
2073+
2074+
copyToBuffer(buffer, kvmap_offset + values[i].index * kvmap_entry_size,
2075+
pentry, kvmap_entry_size);
2076+
}
2077+
2078+
if ((kvmap_entry_size * nPairs) % ALIGNOF_INT)
2079+
memset(buffer->data + kvmap_offset + kvmap_entry_size * nPairs, 0,
2080+
ALIGNOF_INT - (kvmap_entry_size * nPairs) % ALIGNOF_INT);
20192081
}
20202082

20212083
/*
@@ -2607,9 +2669,9 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
26072669
int count = container->header & JB_CMASK;
26082670
/* Since this is an object, account for *Pairs* of Jentrys */
26092671
bool sorted_values = (container->header & JB_TMASK) == JB_TOBJECT_SORTED;
2610-
char *base_addr = (char *) (children + count * 2) + (sorted_values ? sizeof(uint32) * count : 0);
2611-
uint32 *kvmap = sorted_values ? &container->children[count * 2] : NULL;
2612-
Size base_offset = base_addr - (char *) jb;
2672+
char *base_addr = (char *) (children + count * 2);
2673+
JsonbKVMap kvmap;
2674+
Size base_offset;
26132675
uint32 stopLow = 0,
26142676
stopHigh = count;
26152677

@@ -2619,6 +2681,9 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
26192681
if (count <= 0)
26202682
return NULL;
26212683

2684+
base_addr = initKVMap(&kvmap, base_addr, count, sorted_values);
2685+
base_offset = base_addr - (char *) jb;
2686+
26222687
key.type = jbvString;
26232688
key.val.string.val = keystr;
26242689
key.val.string.len = keylen;
@@ -2650,7 +2715,7 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
26502715
if (difference == 0)
26512716
{
26522717
/* Found our key, return corresponding value */
2653-
int index = (sorted_values ? kvmap[stopMiddle] : stopMiddle) + count;
2718+
int index = JSONB_KVMAP_ENTRY(&kvmap, stopMiddle) + count;
26542719

26552720
return fillCompressedJsonbValue(cjb, container, index, base_addr,
26562721
getJsonbOffset(container, index),

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy