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