-
Notifications
You must be signed in to change notification settings - Fork 3.8k
/
hydrate.go
191 lines (180 loc) · 6.94 KB
/
hydrate.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
// Copyright 2021 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
package descs
import (
"context"
"github.com/cockroachdb/cockroach/pkg/kv"
"github.com/cockroachdb/cockroach/pkg/sql/catalog"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/hydrateddesc"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/nstree"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/typedesc"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
"github.com/cockroachdb/cockroach/pkg/util"
"github.com/cockroachdb/cockroach/pkg/util/tracing"
)
// hydrateDescriptors installs user defined type metadata in all types.T present
// in the descriptors slice.
//
// Hydration is not thread-safe while immutable descriptors are, therefore this
// method will replace un-hydrated immutable descriptors in the slice with
// hydrated copies. Mutable descriptors are not thread-safe and so are hydrated
// in-place. Dropped descriptors do not get hydrated.
//
// Optionally, when hydrating we can include offline descriptors and avoid
// leasing depending on the context. This is set via the flags.
//
// Collection method callers expect the descriptors to come back hydrated.
// In practice, array types here are not hydrated, and that's a bummer.
// Nobody presently is upset about it, but it's not a good thing.
// Ideally we'd have a clearer contract regarding hydration and the values
// stored in the various maps inside the collection. One might want to
// store only hydrated values in the various maps. This turns out to be
// somewhat tricky because we'd need to make sure to properly re-hydrate
// all the relevant descriptors when a type descriptor change. Leased
// descriptors are at least as tricky, plus, there we have a cache that
// works relatively well.
//
// TODO(ajwerner): Sort out the hydration mess; define clearly what is
// hydrated where and test the API boundary accordingly.
func (tc *Collection) hydrateDescriptors(
ctx context.Context, txn *kv.Txn, flags tree.CommonLookupFlags, descs []catalog.Descriptor,
) error {
if flags.SkipHydration {
return nil
}
var hydratableMutableIndexes, hydratableImmutableIndexes util.FastIntSet
for i, desc := range descs {
if desc == nil || !hydrateddesc.IsHydratable(desc) {
continue
}
if _, ok := desc.(catalog.MutableDescriptor); ok {
hydratableMutableIndexes.Add(i)
} else {
hydratableImmutableIndexes.Add(i)
}
}
// Hydrate mutable hydratable descriptors of the slice in-place.
if !hydratableMutableIndexes.Empty() {
typeFn := makeMutableTypeLookupFunc(tc, txn, descs)
for _, i := range hydratableMutableIndexes.Ordered() {
if err := hydrateddesc.Hydrate(ctx, descs[i], typeFn); err != nil {
return err
}
}
}
// Replace immutable hydratable descriptors in the slice with hydrated copies
// from the cache, or otherwise by creating a copy and hydrating it.
if !hydratableImmutableIndexes.Empty() {
typeFn := makeImmutableTypeLookupFunc(tc, txn, flags, descs)
for _, i := range hydratableImmutableIndexes.Ordered() {
desc := descs[i]
// Utilize the cache of hydrated tables if we have one and this descriptor
// was leased.
// TODO(ajwerner): Consider surfacing the mechanism used to retrieve the
// descriptor up to this layer.
if hd := desc.(catalog.HydratableDescriptor); tc.canUseHydratedDescriptorCache(hd.GetID()) {
if cached, err := tc.hydrated.GetHydratedDescriptor(ctx, hd, typeFn); err != nil {
return err
} else if cached != nil {
descs[i] = cached
continue
}
}
// The cache decided not to give back a hydrated descriptor, likely
// because either we've modified the table or one of the types or because
// this transaction has a stale view of one of the relevant descriptors.
// Proceed to hydrating a fresh copy.
desc = desc.NewBuilder().BuildImmutable()
if err := hydrateddesc.Hydrate(ctx, desc, typeFn); err != nil {
return err
}
descs[i] = desc
}
}
return nil
}
func makeMutableTypeLookupFunc(
tc *Collection, txn *kv.Txn, descs []catalog.Descriptor,
) typedesc.TypeLookupFunc {
var mut nstree.MutableCatalog
for _, desc := range descs {
if desc == nil {
continue
}
if _, ok := desc.(catalog.MutableDescriptor); !ok {
continue
}
mut.UpsertDescriptorEntry(desc)
}
mutableLookupFunc := func(ctx context.Context, id descpb.ID, skipHydration bool) (catalog.Descriptor, error) {
return tc.getDescriptorByID(ctx, txn, tree.CommonLookupFlags{
Required: true,
AvoidLeased: true,
RequireMutable: true,
IncludeOffline: true,
IncludeDropped: true,
SkipHydration: skipHydration,
}, id)
}
return hydrateddesc.MakeTypeLookupFuncForHydration(mut, mutableLookupFunc)
}
func makeImmutableTypeLookupFunc(
tc *Collection, txn *kv.Txn, flags tree.CommonLookupFlags, descs []catalog.Descriptor,
) typedesc.TypeLookupFunc {
var imm nstree.MutableCatalog
for _, desc := range descs {
if desc == nil {
continue
}
if _, ok := desc.(catalog.MutableDescriptor); ok {
continue
}
imm.UpsertDescriptorEntry(desc)
}
immutableLookupFunc := func(ctx context.Context, id descpb.ID, skipHydration bool) (catalog.Descriptor, error) {
return tc.GetImmutableDescriptorByID(ctx, txn, id, tree.CommonLookupFlags{
Required: true,
AvoidLeased: flags.AvoidLeased,
IncludeOffline: flags.IncludeOffline,
AvoidSynthetic: true,
SkipHydration: skipHydration,
})
}
return hydrateddesc.MakeTypeLookupFuncForHydration(imm, immutableLookupFunc)
}
// HydrateCatalog installs type metadata in the type.T objects present for all
// objects referencing them in the catalog.
func HydrateCatalog(ctx context.Context, c nstree.MutableCatalog) error {
ctx, sp := tracing.ChildSpan(ctx, "descs.HydrateCatalog")
defer sp.Finish()
fakeLookupFunc := func(_ context.Context, id descpb.ID, skipHydration bool) (catalog.Descriptor, error) {
return nil, catalog.NewDescriptorNotFoundError(id)
}
typeLookupFunc := hydrateddesc.MakeTypeLookupFuncForHydration(c, fakeLookupFunc)
return c.ForEachDescriptorEntry(func(desc catalog.Descriptor) error {
if !hydrateddesc.IsHydratable(desc) {
return nil
}
if _, isMutable := desc.(catalog.MutableDescriptor); isMutable {
return hydrateddesc.Hydrate(ctx, desc, typeLookupFunc)
}
// Deep-copy the immutable descriptor and overwrite the catalog entry.
desc = desc.NewBuilder().BuildImmutable()
defer c.UpsertDescriptorEntry(desc)
return hydrateddesc.Hydrate(ctx, desc, typeLookupFunc)
})
}
func (tc *Collection) canUseHydratedDescriptorCache(id descpb.ID) bool {
return tc.hydrated != nil &&
tc.stored.GetCachedByID(id) == nil &&
tc.uncommitted.getUncommittedByID(id) == nil &&
tc.synthetic.getSyntheticByID(id) == nil
}