Skip to content

Commit eb7f58f

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

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
@@ -67,6 +67,27 @@ typedef struct CompressedJsonb
6767
int offset;
6868
} CompressedJsonb;
6969

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

87108
/* Current item in buffer (up to nElems) */
88109
int curIndex;
@@ -544,6 +565,24 @@ JsonFindValueInContainer(JsonContainer *json, uint32 flags, JsonValue *key)
544565
return NULL;
545566
}
546567

568+
static void *
569+
initKVMap(JsonbKVMap *kvmap, void *pentries, int field_count, bool sorted)
570+
{
571+
if (sorted)
572+
{
573+
kvmap->map.entries = pentries;
574+
kvmap->entry_size = JSONB_KVMAP_ENTRY_SIZE(field_count);
575+
576+
return (char *) pentries + INTALIGN(field_count * kvmap->entry_size);
577+
}
578+
else
579+
{
580+
kvmap->entry_size = 0;
581+
582+
return pentries;
583+
}
584+
}
585+
547586
/*
548587
* Find value by key in Jsonb object and fetch it into 'res', which is also
549588
* returned.
@@ -557,9 +596,9 @@ jsonbFindKeyInObject(JsonContainer *jsc, const char *keyVal, int keyLen,
557596
const JsonbContainerHeader *container = JsonContainerDataPtr(jsc);
558597
const JEntry *children = container->children;
559598
int count = JsonContainerSize(jsc);
560-
char *baseAddr;
599+
char *baseAddr = (char *) (children + count * 2);
561600
bool sorted_values = (container->header & JBC_TMASK) == JBC_TOBJECT_SORTED;
562-
const uint32 *kvmap;
601+
JsonbKVMap kvmap;
563602
uint32 stopLow,
564603
stopHigh;
565604

@@ -573,16 +612,8 @@ jsonbFindKeyInObject(JsonContainer *jsc, const char *keyVal, int keyLen,
573612
* Binary search the container. Since we know this is an object, account
574613
* for *Pairs* of Jentrys
575614
*/
576-
if (sorted_values)
577-
{
578-
kvmap = &children[count * 2];
579-
baseAddr = (char *) &kvmap[count];
580-
}
581-
else
582-
{
583-
kvmap = NULL;
584-
baseAddr = (char *) (children + count * 2);
585-
}
615+
baseAddr = initKVMap(&kvmap, baseAddr, count, sorted_values);
616+
586617
stopLow = 0;
587618
stopHigh = count;
588619
while (stopLow < stopHigh)
@@ -603,7 +634,7 @@ jsonbFindKeyInObject(JsonContainer *jsc, const char *keyVal, int keyLen,
603634
if (difference == 0)
604635
{
605636
/* Found our key, return corresponding value */
606-
int index = (sorted_values ? kvmap[stopMiddle] : stopMiddle) + count;
637+
int index = JSONB_KVMAP_ENTRY(&kvmap, stopMiddle) + count;
607638

608639
if (!res)
609640
res = palloc(sizeof(JsonbValue));
@@ -1099,6 +1130,7 @@ static JsonbIteratorToken
10991130
jsonbIteratorNext(JsonIterator **jsit, JsonbValue *val, bool skipNested)
11001131
{
11011132
jsonbIterator **it = (jsonbIterator **) jsit;
1133+
int entry_index;
11021134

11031135
if (*it == NULL)
11041136
return WJB_DONE;
@@ -1215,17 +1247,19 @@ jsonbIteratorNext(JsonIterator **jsit, JsonbValue *val, bool skipNested)
12151247
/* Set state for next call */
12161248
(*it)->state = JBI_OBJECT_KEY;
12171249

1250+
entry_index = JSONB_KVMAP_ENTRY(&(*it)->kvmap, (*it)->curIndex) + (*it)->nElems;
1251+
12181252
fillCompressedJsonbValue((*it)->compressed, (*it)->container,
1219-
((*it)->kvMap ? (*it)->kvMap[(*it)->curIndex] : (*it)->curIndex) + (*it)->nElems,
1253+
entry_index,
12201254
(*it)->dataProper,
1221-
(*it)->kvMap ?
1222-
getJsonbOffset((*it)->container, (*it)->kvMap[(*it)->curIndex] + (*it)->nElems) :
1255+
(*it)->kvmap.entry_size ?
1256+
getJsonbOffset((*it)->container, entry_index) :
12231257
(*it)->curValueOffset,
12241258
val);
12251259

12261260
JBE_ADVANCE_OFFSET((*it)->curDataOffset,
12271261
(*it)->children[(*it)->curIndex]);
1228-
if (!(*it)->kvMap)
1262+
if (!(*it)->kvmap.entry_size)
12291263
JBE_ADVANCE_OFFSET((*it)->curValueOffset,
12301264
(*it)->children[(*it)->curIndex + (*it)->nElems]);
12311265
(*it)->curIndex++;
@@ -1268,6 +1302,7 @@ jsonbIteratorInitExt(JsonContainer *cont,
12681302
struct CompressedJsonb *cjb)
12691303
{
12701304
jsonbIterator *it;
1305+
int type = container->header & JBC_TMASK;
12711306

12721307
it = palloc0(sizeof(jsonbIterator));
12731308
it->ji.container = cont;
@@ -1280,7 +1315,7 @@ jsonbIteratorInitExt(JsonContainer *cont,
12801315
/* Array starts just after header */
12811316
it->children = container->children;
12821317

1283-
switch (container->header & JBC_TMASK)
1318+
switch (type)
12841319
{
12851320
case JBC_TSCALAR:
12861321
it->isScalar = true;
@@ -1295,16 +1330,12 @@ jsonbIteratorInitExt(JsonContainer *cont,
12951330
break;
12961331

12971332
case JBC_TOBJECT:
1298-
it->kvMap = NULL;
1333+
case JBC_TOBJECT_SORTED:
12991334
it->dataProper =
13001335
(char *) it->children + it->nElems * sizeof(JEntry) * 2;
1301-
it->state = JBI_OBJECT_START;
1302-
break;
1336+
it->dataProper = initKVMap(&it->kvmap, it->dataProper, it->nElems,
1337+
type == JBC_TOBJECT_SORTED);
13031338

1304-
case JBC_TOBJECT_SORTED:
1305-
it->kvMap = (uint32 *)
1306-
((char *) it->children + it->nElems * sizeof(JEntry) * 2);
1307-
it->dataProper = (char *) &it->kvMap[it->nElems];
13081339
it->state = JBI_OBJECT_START;
13091340
break;
13101341

@@ -2031,6 +2062,7 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
20312062
uint32 header;
20322063
int nPairs = val->val.object.nPairs;
20332064
int reserved_size;
2065+
int kvmap_entry_size;
20342066
bool sorted_values = jsonb_sort_field_values && nPairs > 1;
20352067
struct
20362068
{
@@ -2057,6 +2089,7 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
20572089
{
20582090
if (values[i].index != i)
20592091
{
2092+
kvmap_entry_size = JSONB_KVMAP_ENTRY_SIZE(nPairs);
20602093
sorted_values = true;
20612094
break;
20622095
}
@@ -2079,16 +2112,45 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
20792112
/* Reserve space for the JEntries of the keys and values. */
20802113
reserved_size = sizeof(JEntry) * nPairs * 2;
20812114
if (sorted_values)
2082-
reserved_size += sizeof(int32) * nPairs;
2115+
reserved_size += INTALIGN(kvmap_entry_size * nPairs);
20832116

20842117
jentry_offset = reserveFromBuffer(buffer, reserved_size);
20852118

20862119
/* Write key-value map */
20872120
if (sorted_values)
20882121
{
2122+
int kvmap_offset = jentry_offset + sizeof(JEntry) * nPairs * 2;
2123+
20892124
for (i = 0; i < nPairs; i++)
2090-
copyToBuffer(buffer, jentry_offset + sizeof(JEntry) * nPairs * 2 + values[i].index * sizeof(int32),
2091-
(void *) &i, sizeof(int32));
2125+
{
2126+
uint8 entry1;
2127+
uint16 entry2;
2128+
uint32 entry4;
2129+
void *pentry;
2130+
2131+
if (kvmap_entry_size == 1)
2132+
{
2133+
entry1 = (uint8) i;
2134+
pentry = &entry1;
2135+
}
2136+
else if (kvmap_entry_size == 2)
2137+
{
2138+
entry2 = (uint16) i;
2139+
pentry = &entry2;
2140+
}
2141+
else
2142+
{
2143+
entry4 = (int32) i;
2144+
pentry = &entry4;
2145+
}
2146+
2147+
copyToBuffer(buffer, kvmap_offset + values[i].index * kvmap_entry_size,
2148+
pentry, kvmap_entry_size);
2149+
}
2150+
2151+
if ((kvmap_entry_size * nPairs) % ALIGNOF_INT)
2152+
memset(buffer->data + kvmap_offset + kvmap_entry_size * nPairs, 0,
2153+
ALIGNOF_INT - (kvmap_entry_size * nPairs) % ALIGNOF_INT);
20922154
}
20932155

20942156
/*
@@ -2614,9 +2676,9 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
26142676
int count = container->header & JBC_CMASK;
26152677
/* Since this is an object, account for *Pairs* of Jentrys */
26162678
bool sorted_values = (container->header & JBC_TMASK) == JBC_TOBJECT_SORTED;
2617-
char *base_addr = (char *) (children + count * 2) + (sorted_values ? sizeof(uint32) * count : 0);
2618-
uint32 *kvmap = sorted_values ? &container->children[count * 2] : NULL;
2619-
Size base_offset = base_addr - (char *) jb;
2679+
char *base_addr = (char *) (children + count * 2);
2680+
JsonbKVMap kvmap;
2681+
Size base_offset;
26202682
uint32 stopLow = 0,
26212683
stopHigh = count;
26222684

@@ -2627,6 +2689,9 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
26272689
if (count <= 0)
26282690
return NULL;
26292691

2692+
base_addr = initKVMap(&kvmap, base_addr, count, sorted_values);
2693+
base_offset = base_addr - (char *) jb;
2694+
26302695
key.type = jbvString;
26312696
key.val.string.val = keystr;
26322697
key.val.string.len = keylen;
@@ -2658,7 +2723,7 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
26582723
if (difference == 0)
26592724
{
26602725
/* Found our key, return corresponding value */
2661-
int index = (sorted_values ? kvmap[stopMiddle] : stopMiddle) + count;
2726+
int index = JSONB_KVMAP_ENTRY(&kvmap, stopMiddle) + count;
26622727

26632728
if (!res)
26642729
res = palloc(sizeof(*res));

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