Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+98-33
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)