Skip to content

Commit 958d4ce

Browse files
authored
support of range scans in pg sys cache (#2545)
1 parent df8664b commit 958d4ce

File tree

3 files changed

+168
-41
lines changed

3 files changed

+168
-41
lines changed

ydb/library/yql/parser/pg_wrapper/postgresql/src/backend/utils/cache/catcache.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1783,6 +1783,7 @@ SearchCatCacheList(CatCache *cache,
17831783
void
17841784
ReleaseCatCacheList(CatCList *list)
17851785
{
1786+
return;
17861787
/* Safety checks to ensure we were handed a cache entry */
17871788
Assert(list->cl_magic == CL_MAGIC);
17881789
Assert(list->refcount > 0);

ydb/library/yql/parser/pg_wrapper/postgresql/src/backend/utils/cache/syscache.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1437,7 +1437,7 @@ GetSysCacheHashValue(int cacheId,
14371437
* List-search interface
14381438
*/
14391439
struct catclist *
1440-
SearchSysCacheList(int cacheId, int nkeys,
1440+
SearchSysCacheList_original(int cacheId, int nkeys,
14411441
Datum key1, Datum key2, Datum key3)
14421442
{
14431443
if (cacheId < 0 || cacheId >= SysCacheSize ||

ydb/library/yql/parser/pg_wrapper/syscache.cpp

Lines changed: 166 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
extern "C" {
77
#include "utils/syscache.h"
8+
#include "utils/catcache.h"
89
#include "catalog/pg_database.h"
910
#include "catalog/pg_class.h"
1011
#include "catalog/pg_proc.h"
@@ -15,6 +16,7 @@ extern "C" {
1516
#include "access/htup_details.h"
1617
#include "utils/fmgroids.h"
1718
#include "utils/array.h"
19+
#include "utils/builtins.h"
1820
}
1921

2022
#undef TypeName
@@ -47,6 +49,13 @@ using THeapTupleHasher = std::function<size_t(const THeapTupleKey&)>;
4749
using THeapTupleEquals = std::function<bool(const THeapTupleKey&, const THeapTupleKey&)>;
4850
using TSysCacheHashMap = std::unordered_map<THeapTupleKey, HeapTuple, THeapTupleHasher, THeapTupleEquals>;
4951

52+
struct TRangeItem {
53+
TVector<HeapTuple> Items;
54+
CatCList* CList = nullptr;
55+
};
56+
57+
using TSysCacheRangeMap = std::unordered_map<THeapTupleKey, TRangeItem, THeapTupleHasher, THeapTupleEquals>;
58+
5059
size_t OidHasher1(const THeapTupleKey& key) {
5160
return std::hash<Oid>()((Oid)std::get<0>(key));
5261
}
@@ -66,14 +75,112 @@ bool NsNameEquals(const THeapTupleKey& key1, const THeapTupleKey& key2) {
6675
(Oid)std::get<1>(key1) == (Oid)std::get<1>(key2);
6776
}
6877

78+
size_t OidVectorHash(Datum d) {
79+
oidvector *v = (oidvector *)d;
80+
Y_DEBUG_ABORT_UNLESS(v->ndim == 1);
81+
size_t hash = v->dim1;
82+
for (int i = 0; i < v->dim1; ++i) {
83+
hash = CombineHashes(hash, std::hash<Oid>()(v->values[i]));
84+
}
85+
86+
return hash;
87+
}
88+
89+
bool OidVectorEquals(Datum d1, Datum d2) {
90+
oidvector *v1 = (oidvector *)d1;
91+
oidvector *v2 = (oidvector *)d2;
92+
Y_DEBUG_ABORT_UNLESS(v1->ndim == 1 && v2->ndim == 1);
93+
if (v1->dim1 != v2->dim1) {
94+
return false;
95+
}
96+
97+
for (int i = 0; i < v1->dim1; ++i) {
98+
if (v1->values[i] != v2->values[i]) {
99+
return false;
100+
}
101+
}
102+
103+
return true;
104+
}
105+
106+
size_t ByNameProcHasher1(const THeapTupleKey& key) {
107+
return std::hash<std::string_view>()((const char*)std::get<0>(key));
108+
}
109+
110+
size_t ByNameProcHasher3(const THeapTupleKey& key) {
111+
return CombineHashes(CombineHashes(std::hash<std::string_view>()((const char*)std::get<0>(key)),
112+
OidVectorHash(std::get<1>(key))),
113+
std::hash<Oid>()((Oid)std::get<2>(key)));
114+
}
115+
116+
bool ByNameProcEquals1(const THeapTupleKey& key1, const THeapTupleKey& key2) {
117+
return strcmp((const char*)std::get<0>(key1), (const char*)std::get<0>(key2)) == 0;
118+
}
119+
120+
bool ByNameProcEquals3(const THeapTupleKey& key1, const THeapTupleKey& key2) {
121+
return strcmp((const char*)std::get<0>(key1), (const char*)std::get<0>(key2)) == 0 &&
122+
OidVectorEquals(std::get<1>(key1), std::get<1>(key2)) &&
123+
(Oid)std::get<2>(key1) == (Oid)std::get<2>(key2);
124+
}
125+
69126
struct TSysCacheItem {
70-
TSysCacheItem(THeapTupleHasher hasher, THeapTupleEquals equals, TupleDesc desc)
71-
: Map(0, hasher, equals)
127+
TSysCacheItem(THeapTupleHasher hasher, THeapTupleEquals equals, TupleDesc desc, ui32 numKeys = 1,
128+
THeapTupleHasher hasherRange1 = {}, THeapTupleEquals equalsRange1 = {})
129+
: NumKeys(numKeys)
130+
, LookupMap(0, hasher, equals)
131+
, RangeMap1(numKeys > 1 ? TMaybe<TSysCacheRangeMap>(TSysCacheRangeMap(0, hasherRange1, equalsRange1)) : Nothing())
72132
, Desc(desc)
73133
{}
74134

75-
TSysCacheHashMap Map;
135+
CatCList* BuildCList(const TVector<HeapTuple>& items) {
136+
auto cl = (CatCList *)palloc(offsetof(CatCList, members) + items.size() * sizeof(CatCTup *));
137+
cl->cl_magic = CL_MAGIC;
138+
cl->my_cache = nullptr;
139+
cl->refcount = 0;
140+
cl->dead = false;
141+
cl->ordered = false;
142+
cl->nkeys = NumKeys;
143+
cl->hash_value = 0;
144+
cl->n_members = items.size();
145+
for (size_t i = 0; i < items.size(); ++i) {
146+
auto dtp = items[i];
147+
auto ct = (CatCTup *) palloc(sizeof(CatCTup) + MAXIMUM_ALIGNOF + dtp->t_len);
148+
ct->ct_magic = CT_MAGIC;
149+
ct->my_cache = nullptr;
150+
ct->c_list = NULL;
151+
ct->refcount = 0;
152+
ct->dead = false;
153+
ct->negative = false;
154+
ct->hash_value = 0;
155+
Zero(ct->keys);
156+
157+
ct->tuple.t_len = dtp->t_len;
158+
ct->tuple.t_self = dtp->t_self;
159+
ct->tuple.t_tableOid = dtp->t_tableOid;
160+
ct->tuple.t_data = (HeapTupleHeader)MAXALIGN(((char *) ct) + sizeof(CatCTup));
161+
/* copy tuple contents */
162+
std::memcpy((char *) ct->tuple.t_data, (const char *) dtp->t_data, dtp->t_len);
163+
cl->members[i] = ct;
164+
}
165+
166+
return cl;
167+
}
168+
169+
void FinalizeRangeMaps() {
170+
if (RangeMap1) {
171+
for (auto& x : *RangeMap1) {
172+
x.second.CList = BuildCList(x.second.Items);
173+
}
174+
}
175+
176+
EmptyCList = BuildCList({});
177+
}
178+
179+
const ui32 NumKeys;
180+
TSysCacheHashMap LookupMap;
181+
TMaybe<TSysCacheRangeMap> RangeMap1;
76182
TupleDesc Desc;
183+
CatCList* EmptyCList = nullptr;
77184
};
78185

79186
struct TSysCache {
@@ -91,6 +198,12 @@ struct TSysCache {
91198
InitializeDatabase();
92199
InitializeAuthId();
93200
InitializeNameNamespaces();
201+
for (auto& item : Items) {
202+
if (item) {
203+
item->FinalizeRangeMaps();
204+
}
205+
}
206+
94207
Arena.Release();
95208
}
96209

@@ -142,7 +255,11 @@ struct TSysCache {
142255
FillAttr(tupleDesc, Anum_pg_proc_proconfig, TEXTARRAYOID);
143256
FillAttr(tupleDesc, Anum_pg_proc_proacl, ACLITEMARRAYOID);
144257
auto& cacheItem = Items[PROCOID] = std::make_unique<TSysCacheItem>(OidHasher1, OidEquals1, tupleDesc);
145-
auto& map = cacheItem->Map;
258+
auto& lookupMap = cacheItem->LookupMap;
259+
260+
auto& byNameCacheItem = Items[PROCNAMEARGSNSP] = std::make_unique<TSysCacheItem>(ByNameProcHasher3, ByNameProcEquals3, tupleDesc, 3, ByNameProcHasher1, ByNameProcEquals1);
261+
auto& byNameLookupMap = byNameCacheItem->LookupMap;
262+
auto& byNameRangeMap1 = *byNameCacheItem->RangeMap1;
146263

147264
const auto& oidDesc = NPg::LookupType(OIDOID);
148265
const auto& charDesc = NPg::LookupType(CHAROID);
@@ -162,33 +279,18 @@ struct TSysCache {
162279
FillDatum(Natts_pg_proc, values, nulls, Anum_pg_proc_proname, (Datum)name);
163280
FillDatum(Natts_pg_proc, values, nulls, Anum_pg_proc_pronargs, (Datum)desc.ArgTypes.size());
164281
{
165-
int dims[MAXDIM];
166-
int lbs[MAXDIM];
167-
dims[0] = desc.ArgTypes.size();
168-
lbs[0] = 1;
169-
std::unique_ptr<Datum[]> dvalues(new Datum[desc.ArgTypes.size()]);
170-
std::unique_ptr<bool[]> dnulls(new bool[desc.ArgTypes.size()]);
171-
std::copy(desc.ArgTypes.begin(), desc.ArgTypes.end(), dvalues.get());
172-
std::fill_n(dnulls.get(), desc.ArgTypes.size(), false);
173-
174-
auto arr = construct_md_array(dvalues.get(), dnulls.get(), 1, dims, lbs, OIDOID, oidDesc.TypeLen, oidDesc.PassByValue, oidDesc.TypeAlign);
282+
auto arr = buildoidvector(desc.ArgTypes.data(), (int)desc.ArgTypes.size());
175283
FillDatum(Natts_pg_proc, values, nulls, Anum_pg_proc_proargtypes, (Datum)arr);
176284
}
177285

178286
const ui32 fullArgsCount = desc.ArgTypes.size() + desc.OutputArgTypes.size();
179287
if (!desc.OutputArgTypes.empty())
180288
{
181-
int dims[MAXDIM];
182-
int lbs[MAXDIM];
183-
dims[0] = fullArgsCount;
184-
lbs[0] = 1;
185-
std::unique_ptr<Datum[]> dvalues(new Datum[fullArgsCount]);
186-
std::unique_ptr<bool[]> dnulls(new bool[fullArgsCount]);
187-
std::copy(desc.ArgTypes.begin(), desc.ArgTypes.end(), dvalues.get());
188-
std::copy(desc.OutputArgTypes.begin(), desc.OutputArgTypes.end(), dvalues.get() + desc.ArgTypes.size());
189-
std::fill_n(dnulls.get(), fullArgsCount, false);
289+
std::unique_ptr<Oid[]> allOids(new Oid[fullArgsCount]);
290+
std::copy(desc.ArgTypes.begin(), desc.ArgTypes.end(), allOids.get());
291+
std::copy(desc.OutputArgTypes.begin(), desc.OutputArgTypes.end(), allOids.get() + desc.ArgTypes.size());
190292

191-
auto arr = construct_md_array(dvalues.get(), dnulls.get(), 1, dims, lbs, OIDOID, oidDesc.TypeLen, oidDesc.PassByValue, oidDesc.TypeAlign);
293+
auto arr = buildoidvector(allOids.get(), (int)fullArgsCount);
192294
FillDatum(Natts_pg_proc, values, nulls, Anum_pg_proc_proallargtypes, (Datum)arr);
193295
}
194296
if (!desc.OutputArgTypes.empty())
@@ -236,7 +338,13 @@ struct TSysCache {
236338
Y_ENSURE(row->prorettype == desc.ResultType);
237339
Y_ENSURE(NameStr(row->proname) == desc.Name);
238340
Y_ENSURE(row->pronargs == desc.ArgTypes.size());
239-
map.emplace(key, h);
341+
lookupMap.emplace(key, h);
342+
343+
THeapTupleKey byNameLookupKey((Datum)name, (Datum)&row->proargtypes, PG_CATALOG_NAMESPACE, 0);
344+
THeapTupleKey byNameRangeKey1((Datum)name, 0, 0, 0);
345+
346+
byNameLookupMap.emplace(byNameLookupKey, h);
347+
byNameRangeMap1[byNameRangeKey1].Items.push_back(h);
240348
});
241349
}
242350

@@ -274,8 +382,8 @@ struct TSysCache {
274382
FillAttr(tupleDesc, Anum_pg_type_typdefaultbin, PG_NODE_TREEOID);
275383
FillAttr(tupleDesc, Anum_pg_type_typdefault, TEXTOID);
276384
FillAttr(tupleDesc, Anum_pg_type_typacl, ACLITEMARRAYOID);
277-
auto& cacheItems = Items[TYPEOID] = std::make_unique<TSysCacheItem>(OidHasher1, OidEquals1, tupleDesc);
278-
auto& map = cacheItems->Map;
385+
auto& cacheItem = Items[TYPEOID] = std::make_unique<TSysCacheItem>(OidHasher1, OidEquals1, tupleDesc);
386+
auto& lookupMap = cacheItem->LookupMap;
279387

280388
NPg::EnumTypes([&](ui32 oid, const NPg::TTypeDesc& desc){
281389
auto key = THeapTupleKey(oid, 0, 0, 0);
@@ -329,7 +437,7 @@ struct TSysCache {
329437
Y_ENSURE(row->typmodout == desc.TypeModOutFuncId);
330438
Y_ENSURE(row->typalign == desc.TypeAlign);
331439
Y_ENSURE(row->typstorage == storage);
332-
map.emplace(key, h);
440+
lookupMap.emplace(key, h);
333441
});
334442

335443
}
@@ -350,8 +458,8 @@ struct TSysCache {
350458
FillAttr(tupleDesc, Anum_pg_database_datminmxid, XIDOID);
351459
FillAttr(tupleDesc, Anum_pg_database_dattablespace, OIDOID);
352460
FillAttr(tupleDesc, Anum_pg_database_datacl, ACLITEMARRAYOID);
353-
auto& cacheItems = Items[DATABASEOID] = std::make_unique<TSysCacheItem>(OidHasher1, OidEquals1, tupleDesc);
354-
auto& map = cacheItems->Map;
461+
auto& cacheItem = Items[DATABASEOID] = std::make_unique<TSysCacheItem>(OidHasher1, OidEquals1, tupleDesc);
462+
auto& lookupMap = cacheItem->LookupMap;
355463

356464
for (ui32 oid = 1; oid <= 3; ++oid) {
357465
auto key = THeapTupleKey(oid, 0, 0, 0);
@@ -373,7 +481,7 @@ struct TSysCache {
373481
auto row = (Form_pg_database) GETSTRUCT(h);
374482
Y_ENSURE(row->oid == oid);
375483
Y_ENSURE(strcmp(NameStr(row->datname), name) == 0);
376-
map.emplace(key, h);
484+
lookupMap.emplace(key, h);
377485
}
378486
}
379487

@@ -391,8 +499,8 @@ struct TSysCache {
391499
FillAttr(tupleDesc, Anum_pg_authid_rolconnlimit, INT4OID);
392500
FillAttr(tupleDesc, Anum_pg_authid_rolpassword, TEXTOID);
393501
FillAttr(tupleDesc, Anum_pg_authid_rolvaliduntil, TIMESTAMPTZOID);
394-
auto& cacheItems = Items[AUTHOID] = std::make_unique<TSysCacheItem>(OidHasher1, OidEquals1, tupleDesc);
395-
auto& map = cacheItems->Map;
502+
auto& cacheItem = Items[AUTHOID] = std::make_unique<TSysCacheItem>(OidHasher1, OidEquals1, tupleDesc);
503+
auto& lookupMap = cacheItem->LookupMap;
396504

397505
auto key = THeapTupleKey(1, 0, 0, 0);
398506

@@ -424,7 +532,7 @@ struct TSysCache {
424532
Y_ENSURE(row->rolreplication);
425533
Y_ENSURE(row->rolbypassrls);
426534
Y_ENSURE(row->rolconnlimit == -1);
427-
map.emplace(key, h);
535+
lookupMap.emplace(key, h);
428536
}
429537

430538
void InitializeNameNamespaces() {
@@ -462,8 +570,8 @@ struct TSysCache {
462570
FillAttr(tupleDesc, Anum_pg_class_relacl, ACLITEMARRAYOID);
463571
FillAttr(tupleDesc, Anum_pg_class_reloptions, TEXTARRAYOID);
464572
FillAttr(tupleDesc, Anum_pg_class_relpartbound, PG_NODE_TREEOID);
465-
auto& cacheItems = Items[RELNAMENSP] = std::make_unique<TSysCacheItem>(NsNameHasher, NsNameEquals, tupleDesc);
466-
auto& map = cacheItems->Map;
573+
auto& cacheItem = Items[RELNAMENSP] = std::make_unique<TSysCacheItem>(NsNameHasher, NsNameEquals, tupleDesc);
574+
auto& lookupMap = cacheItem->LookupMap;
467575

468576
Datum values[Natts_pg_class];
469577
bool nulls[Natts_pg_class];
@@ -485,7 +593,7 @@ struct TSysCache {
485593
Y_ENSURE(row->relnamespace == ns);
486594

487595
auto key = THeapTupleKey(name, ns, 0, 0);
488-
map.emplace(key, h);
596+
lookupMap.emplace(key, h);
489597
}
490598
}
491599
};
@@ -501,9 +609,9 @@ HeapTuple SearchSysCache(int cacheId, Datum key1, Datum key2, Datum key3, Datum
501609
return nullptr;
502610
}
503611

504-
const auto& map = cacheItem->Map;
505-
auto it = map.find(std::make_tuple(key1, key2, key3, key4));
506-
if (it == map.end()) {
612+
const auto& lookupMap = cacheItem->LookupMap;
613+
auto it = lookupMap.find(std::make_tuple(key1, key2, key3, key4));
614+
if (it == lookupMap.end()) {
507615
return nullptr;
508616
}
509617

@@ -554,3 +662,21 @@ Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bo
554662
Y_ENSURE(cacheItem);
555663
return heap_getattr(tup, attributeNumber, cacheItem->Desc, isNull);
556664
}
665+
666+
struct catclist* SearchSysCacheList(int cacheId, int nkeys, Datum key1, Datum key2, Datum key3) {
667+
Y_ENSURE(cacheId >= 0 && cacheId < SysCacheSize);
668+
const auto& cacheItem = NYql::TSysCache::Instance().Items[cacheId];
669+
Y_ENSURE(cacheItem);
670+
if (nkeys == 1 && cacheItem->NumKeys > 1) {
671+
const auto& rangeMap1 = *cacheItem->RangeMap1;
672+
auto it = rangeMap1.find(std::make_tuple(key1, 0, 0, 0));
673+
if (it == rangeMap1.end()) {
674+
return cacheItem->EmptyCList;
675+
}
676+
677+
return it->second.CList;
678+
}
679+
680+
return cacheItem->EmptyCList;
681+
}
682+

0 commit comments

Comments
 (0)