Skip to content

Commit e0a9476

Browse files
author
Nikita Glukhov
committed
Variable-length jsonb KV map entries
1 parent 973254e commit e0a9476

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;
@@ -549,6 +570,24 @@ JsonFindValueInContainer(JsonContainer *json, uint32 flags, JsonValue *key)
549570
return NULL;
550571
}
551572

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

@@ -578,16 +617,8 @@ getKeyJsonValueFromContainer(JsonContainer *jsc,
578617
* Binary search the container. Since we know this is an object, account
579618
* for *Pairs* of Jentrys
580619
*/
581-
if (sorted_values)
582-
{
583-
kvmap = &children[count * 2];
584-
baseAddr = (char *) &kvmap[count];
585-
}
586-
else
587-
{
588-
kvmap = NULL;
589-
baseAddr = (char *) (children + count * 2);
590-
}
620+
baseAddr = initKVMap(&kvmap, baseAddr, count, sorted_values);
621+
591622
stopLow = 0;
592623
stopHigh = count;
593624
while (stopLow < stopHigh)
@@ -608,7 +639,7 @@ getKeyJsonValueFromContainer(JsonContainer *jsc,
608639
if (difference == 0)
609640
{
610641
/* Found our key, return corresponding value */
611-
int index = (sorted_values ? kvmap[stopMiddle] : stopMiddle) + count;
642+
int index = JSONB_KVMAP_ENTRY(&kvmap, stopMiddle) + count;
612643

613644
if (!res)
614645
res = palloc(sizeof(JsonbValue));
@@ -1097,6 +1128,7 @@ JsonbIteratorToken
10971128
JsonbIteratorNext(JsonIterator **jsit, JsonbValue *val, bool skipNested)
10981129
{
10991130
JsonbIterator **it = (JsonbIterator **) jsit;
1131+
int entry_index;
11001132

11011133
if (*it == NULL)
11021134
return WJB_DONE;
@@ -1209,17 +1241,19 @@ JsonbIteratorNext(JsonIterator **jsit, JsonbValue *val, bool skipNested)
12091241
/* Set state for next call */
12101242
(*it)->state = JBI_OBJECT_KEY;
12111243

1244+
entry_index = JSONB_KVMAP_ENTRY(&(*it)->kvmap, (*it)->curIndex) + (*it)->nElems;
1245+
12121246
fillCompressedJsonbValue((*it)->compressed, (*it)->container,
1213-
((*it)->kvMap ? (*it)->kvMap[(*it)->curIndex] : (*it)->curIndex) + (*it)->nElems,
1247+
entry_index,
12141248
(*it)->dataProper,
1215-
(*it)->kvMap ?
1216-
getJsonbOffset((*it)->container, (*it)->kvMap[(*it)->curIndex] + (*it)->nElems) :
1249+
(*it)->kvmap.entry_size ?
1250+
getJsonbOffset((*it)->container, entry_index) :
12171251
(*it)->curValueOffset,
12181252
val);
12191253

12201254
JBE_ADVANCE_OFFSET((*it)->curDataOffset,
12211255
(*it)->children[(*it)->curIndex]);
1222-
if (!(*it)->kvMap)
1256+
if (!(*it)->kvmap.entry_size)
12231257
JBE_ADVANCE_OFFSET((*it)->curValueOffset,
12241258
(*it)->children[(*it)->curIndex + (*it)->nElems]);
12251259
(*it)->curIndex++;
@@ -1261,6 +1295,7 @@ jsonbIteratorInit(JsonContainer *cont, const JsonbContainer *container,
12611295
struct CompressedJsonb *cjb)
12621296
{
12631297
JsonbIterator *it;
1298+
int type = container->header & JB_TMASK;
12641299

12651300
it = palloc0(sizeof(JsonbIterator));
12661301
it->ji.container = cont;
@@ -1273,7 +1308,7 @@ jsonbIteratorInit(JsonContainer *cont, const JsonbContainer *container,
12731308
/* Array starts just after header */
12741309
it->children = container->children;
12751310

1276-
switch (container->header & JB_TMASK)
1311+
switch (type)
12771312
{
12781313
case JB_TSCALAR:
12791314
it->isScalar = true;
@@ -1288,16 +1323,12 @@ jsonbIteratorInit(JsonContainer *cont, const JsonbContainer *container,
12881323
break;
12891324

12901325
case JB_TOBJECT:
1291-
it->kvMap = NULL;
1326+
case JB_TOBJECT_SORTED:
12921327
it->dataProper =
12931328
(char *) it->children + it->nElems * sizeof(JEntry) * 2;
1294-
it->state = JBI_OBJECT_START;
1295-
break;
1329+
it->dataProper = initKVMap(&it->kvmap, it->dataProper, it->nElems,
1330+
type == JB_TOBJECT_SORTED);
12961331

1297-
case JB_TOBJECT_SORTED:
1298-
it->kvMap = (uint32 *)
1299-
((char *) it->children + it->nElems * sizeof(JEntry) * 2);
1300-
it->dataProper = (char *) &it->kvMap[it->nElems];
13011332
it->state = JBI_OBJECT_START;
13021333
break;
13031334

@@ -2021,6 +2052,7 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
20212052
uint32 header;
20222053
int nPairs = val->val.object.nPairs;
20232054
int reserved_size;
2055+
int kvmap_entry_size;
20242056
bool sorted_values = jsonb_sort_field_values && nPairs > 1;
20252057
struct
20262058
{
@@ -2047,6 +2079,7 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
20472079
{
20482080
if (values[i].index != i)
20492081
{
2082+
kvmap_entry_size = JSONB_KVMAP_ENTRY_SIZE(nPairs);
20502083
sorted_values = true;
20512084
break;
20522085
}
@@ -2069,16 +2102,45 @@ convertJsonbObject(StringInfo buffer, JEntry *pheader, const JsonbValue *val, in
20692102
/* Reserve space for the JEntries of the keys and values. */
20702103
reserved_size = sizeof(JEntry) * nPairs * 2;
20712104
if (sorted_values)
2072-
reserved_size += sizeof(int32) * nPairs;
2105+
reserved_size += INTALIGN(kvmap_entry_size * nPairs);
20732106

20742107
jentry_offset = reserveFromBuffer(buffer, reserved_size);
20752108

20762109
/* Write key-value map */
20772110
if (sorted_values)
20782111
{
2112+
int kvmap_offset = jentry_offset + sizeof(JEntry) * nPairs * 2;
2113+
20792114
for (i = 0; i < nPairs; i++)
2080-
copyToBuffer(buffer, jentry_offset + sizeof(JEntry) * nPairs * 2 + values[i].index * sizeof(int32),
2081-
&i, sizeof(int32));
2115+
{
2116+
uint8 entry1;
2117+
uint16 entry2;
2118+
uint32 entry4;
2119+
void *pentry;
2120+
2121+
if (kvmap_entry_size == 1)
2122+
{
2123+
entry1 = (uint8) i;
2124+
pentry = &entry1;
2125+
}
2126+
else if (kvmap_entry_size == 2)
2127+
{
2128+
entry2 = (uint16) i;
2129+
pentry = &entry2;
2130+
}
2131+
else
2132+
{
2133+
entry4 = (int32) i;
2134+
pentry = &entry4;
2135+
}
2136+
2137+
copyToBuffer(buffer, kvmap_offset + values[i].index * kvmap_entry_size,
2138+
pentry, kvmap_entry_size);
2139+
}
2140+
2141+
if ((kvmap_entry_size * nPairs) % ALIGNOF_INT)
2142+
memset(buffer->data + kvmap_offset + kvmap_entry_size * nPairs, 0,
2143+
ALIGNOF_INT - (kvmap_entry_size * nPairs) % ALIGNOF_INT);
20822144
}
20832145

20842146
/*
@@ -2670,9 +2732,9 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
26702732
int count = container->header & JB_CMASK;
26712733
/* Since this is an object, account for *Pairs* of Jentrys */
26722734
bool sorted_values = (container->header & JB_TMASK) == JB_TOBJECT_SORTED;
2673-
char *base_addr = (char *) (children + count * 2) + (sorted_values ? sizeof(uint32) * count : 0);
2674-
uint32 *kvmap = sorted_values ? &container->children[count * 2] : NULL;
2675-
Size base_offset = base_addr - (char *) jb;
2735+
char *base_addr = (char *) (children + count * 2);
2736+
JsonbKVMap kvmap;
2737+
Size base_offset;
26762738
uint32 stopLow = 0,
26772739
stopHigh = count;
26782740

@@ -2682,6 +2744,9 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
26822744
if (count <= 0)
26832745
return NULL;
26842746

2747+
base_addr = initKVMap(&kvmap, base_addr, count, sorted_values);
2748+
base_offset = base_addr - (char *) jb;
2749+
26852750
key.type = jbvString;
26862751
key.val.string.val = keystr;
26872752
key.val.string.len = keylen;
@@ -2713,7 +2778,7 @@ findValueInCompressedJsonbObject(CompressedJsonb *cjb, const char *keystr, int k
27132778
if (difference == 0)
27142779
{
27152780
/* Found our key, return corresponding value */
2716-
int index = (sorted_values ? kvmap[stopMiddle] : stopMiddle) + count;
2781+
int index = JSONB_KVMAP_ENTRY(&kvmap, stopMiddle) + count;
27172782

27182783
return fillCompressedJsonbValue(cjb, container, index, base_addr,
27192784
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