Skip to content

Commit b8fd128

Browse files
authored
Merge pull request #147 from unisoncomputing/cp/speed-up-dependents
Speed up the dependents endpoints
2 parents 1256d82 + b7742dc commit b8fd128

File tree

13 files changed

+267
-45
lines changed

13 files changed

+267
-45
lines changed
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
-- Add an additional argument for whether to include dependencies or transitive dependencies.
2+
CREATE FUNCTION term_names_for_ref(
3+
arg_bh_id integer,
4+
arg_namespace_prefix text,
5+
arg_reversed_name_prefix text,
6+
arg_should_suffixify boolean,
7+
arg_referent_builtin text,
8+
arg_referent_component_hash_id integer,
9+
arg_referent_component_index bigint,
10+
arg_referent_constructor_index bigint,
11+
arg_include_dependencies boolean,
12+
arg_include_transitive_dependencies boolean
13+
) RETURNS TABLE (
14+
reversed_name text,
15+
suffixified_name text
16+
) AS $$
17+
DECLARE
18+
names name_with_suffix[];
19+
BEGIN
20+
SELECT array_agg(ROW(names.reversed_name, names.suffixified_name)::name_with_suffix) INTO names
21+
FROM (
22+
SELECT stnl.reversed_name,
23+
CASE
24+
WHEN arg_should_suffixify THEN suffixify_term_fqn(arg_bh_id, arg_namespace_prefix, '', ROW(stnl.*))
25+
ELSE stnl.reversed_name
26+
END AS suffixified_name
27+
FROM scoped_term_name_lookup stnl
28+
WHERE root_branch_hash_id = arg_bh_id
29+
-- This may seem overly verbose, but it nudges the query planner to use the
30+
-- correct partial index, which is keyed on whether the refBuiltin is null or not.
31+
AND (
32+
(arg_referent_builtin IS NULL
33+
AND referent_builtin IS NULL
34+
AND referent_component_hash_id = arg_referent_component_hash_id
35+
AND referent_component_index = arg_referent_component_index
36+
AND referent_constructor_index IS NOT DISTINCT FROM arg_referent_constructor_index
37+
)
38+
OR
39+
( arg_referent_builtin IS NOT NULL
40+
AND referent_builtin = arg_referent_builtin
41+
)
42+
)
43+
AND (arg_namespace_prefix = '' OR namespace LIKE like_escape(arg_namespace_prefix) || '%')
44+
AND (arg_reversed_name_prefix = '' OR stnl.reversed_name LIKE like_escape(arg_reversed_name_prefix) || '%')
45+
UNION ALL
46+
SELECT (names.reversed_name || mount.reversed_mount_path) AS reversed_name,
47+
CASE
48+
WHEN arg_should_suffixify THEN suffixify_term_fqn(arg_bh_id, arg_namespace_prefix, mount.reversed_mount_path, ROW(names.*))
49+
ELSE names.reversed_name || mount.reversed_mount_path
50+
END AS suffixified_name
51+
FROM name_lookup_mounts mount
52+
INNER JOIN scoped_term_name_lookup names ON names.root_branch_hash_id = mount.mounted_root_branch_hash_id
53+
WHERE arg_include_dependencies
54+
AND mount.parent_root_branch_hash_id = arg_bh_id
55+
AND (arg_namespace_prefix = '' OR mount.mount_path LIKE like_escape(arg_namespace_prefix) || '%')
56+
AND (
57+
(arg_referent_builtin IS NULL
58+
AND referent_builtin IS NULL
59+
AND referent_component_hash_id = arg_referent_component_hash_id
60+
AND referent_component_index = arg_referent_component_index
61+
AND referent_constructor_index IS NOT DISTINCT FROM arg_referent_constructor_index
62+
)
63+
OR
64+
( arg_referent_builtin IS NOT NULL
65+
AND referent_builtin = arg_referent_builtin
66+
)
67+
)
68+
AND (arg_reversed_name_prefix = '' OR names.reversed_name LIKE like_escape(arg_reversed_name_prefix) || '%')
69+
) AS names;
70+
71+
IF NOT arg_include_transitive_dependencies OR (names IS NOT NULL AND array_length(names, 1) > 0) THEN
72+
RETURN QUERY
73+
SELECT n.reversed_name, n.suffixified_name
74+
FROM unnest(names) AS n(reversed_name, suffixified_name);
75+
ELSE
76+
RETURN QUERY
77+
SELECT (stnl.reversed_name || reversed_mount_path) AS reversed_name,
78+
CASE
79+
WHEN arg_should_suffixify THEN suffixify_term_fqn(arg_bh_id, arg_namespace_prefix, reversed_mount_path, ROW(stnl.*))
80+
ELSE stnl.reversed_name || reversed_mount_path
81+
END AS suffixified_name
82+
FROM transitive_dependency_mounts(arg_bh_id)
83+
INNER JOIN scoped_term_name_lookup stnl
84+
ON stnl.root_branch_hash_id = transitive_dependency_mounts.root_branch_hash_id
85+
WHERE (
86+
(arg_referent_builtin IS NULL
87+
AND referent_builtin IS NULL
88+
AND referent_component_hash_id = arg_referent_component_hash_id
89+
AND referent_component_index = arg_referent_component_index
90+
AND referent_constructor_index IS NOT DISTINCT FROM arg_referent_constructor_index
91+
)
92+
OR
93+
( arg_referent_builtin IS NOT NULL
94+
AND referent_builtin = arg_referent_builtin
95+
)
96+
) AND (arg_reversed_name_prefix = '' OR stnl.reversed_name LIKE like_escape(arg_reversed_name_prefix) || '%')
97+
LIMIT 1;
98+
END IF;
99+
END;
100+
$$ LANGUAGE plpgsql STABLE;
101+
102+
103+
CREATE FUNCTION type_names_for_ref(
104+
arg_bh_id integer,
105+
arg_namespace_prefix text,
106+
arg_reversed_name_prefix text,
107+
arg_should_suffixify boolean,
108+
arg_reference_builtin text,
109+
arg_reference_component_hash_id integer,
110+
arg_reference_component_index bigint,
111+
arg_include_dependencies boolean,
112+
arg_include_transitive_dependencies boolean
113+
) RETURNS TABLE (
114+
reversed_name text,
115+
suffixified_name text
116+
) AS $$
117+
DECLARE
118+
names name_with_suffix[];
119+
BEGIN
120+
SELECT array_agg(ROW(names.reversed_name, names.suffixified_name)::name_with_suffix) INTO names
121+
FROM (
122+
SELECT stnl.reversed_name,
123+
CASE
124+
WHEN arg_should_suffixify THEN suffixify_type_fqn(arg_bh_id, arg_namespace_prefix, '', ROW(stnl.*))
125+
ELSE stnl.reversed_name
126+
END AS suffixified_name
127+
FROM scoped_type_name_lookup stnl
128+
WHERE root_branch_hash_id = arg_bh_id
129+
-- This may seem overly verbose, but it nudges the query planner to use the
130+
-- correct partial index, which is keyed on whether the refBuiltin is null or not.
131+
AND (
132+
(arg_reference_builtin IS NULL
133+
AND reference_builtin IS NULL
134+
AND reference_component_hash_id = arg_reference_component_hash_id
135+
AND reference_component_index = arg_reference_component_index
136+
)
137+
OR
138+
( arg_reference_builtin IS NOT NULL
139+
AND reference_builtin = arg_reference_builtin
140+
)
141+
)
142+
AND (arg_namespace_prefix = '' OR namespace LIKE like_escape(arg_namespace_prefix) || '%')
143+
AND (arg_reversed_name_prefix = '' OR stnl.reversed_name LIKE like_escape(arg_reversed_name_prefix) || '%')
144+
UNION ALL
145+
SELECT (names.reversed_name || mount.reversed_mount_path) AS reversed_name,
146+
CASE
147+
WHEN arg_should_suffixify THEN suffixify_type_fqn(arg_bh_id, arg_namespace_prefix, mount.reversed_mount_path, ROW(names.*))
148+
ELSE names.reversed_name || mount.reversed_mount_path
149+
END AS suffixified_name
150+
FROM name_lookup_mounts mount
151+
INNER JOIN scoped_type_name_lookup names ON names.root_branch_hash_id = mount.mounted_root_branch_hash_id
152+
WHERE arg_include_dependencies
153+
AND mount.parent_root_branch_hash_id = arg_bh_id
154+
AND (arg_namespace_prefix = '' OR mount.mount_path LIKE like_escape(arg_namespace_prefix) || '%')
155+
AND (
156+
(arg_reference_builtin IS NULL
157+
AND reference_builtin IS NULL
158+
AND reference_component_hash_id = arg_reference_component_hash_id
159+
AND reference_component_index = arg_reference_component_index
160+
)
161+
OR
162+
( arg_reference_builtin IS NOT NULL
163+
AND reference_builtin = arg_reference_builtin
164+
)
165+
) AND (arg_reversed_name_prefix = '' OR names.reversed_name LIKE like_escape(arg_reversed_name_prefix) || '%')
166+
) AS names;
167+
168+
IF NOT arg_include_transitive_dependencies OR (names IS NOT NULL AND array_length(names, 1) > 0) THEN
169+
RETURN QUERY
170+
SELECT n.reversed_name, n.suffixified_name
171+
FROM unnest(names) AS n(reversed_name, suffixified_name);
172+
ELSE
173+
RETURN QUERY
174+
SELECT (stnl.reversed_name || reversed_mount_path) AS reversed_name,
175+
CASE
176+
WHEN arg_should_suffixify THEN suffixify_type_fqn(arg_bh_id, arg_namespace_prefix, reversed_mount_path, ROW(stnl.*))
177+
ELSE stnl.reversed_name || reversed_mount_path
178+
END AS suffixified_name
179+
FROM transitive_dependency_mounts(arg_bh_id)
180+
INNER JOIN scoped_type_name_lookup stnl
181+
ON stnl.root_branch_hash_id = transitive_dependency_mounts.root_branch_hash_id
182+
WHERE (
183+
(arg_reference_builtin IS NULL
184+
AND reference_builtin IS NULL
185+
AND reference_component_hash_id = arg_reference_component_hash_id
186+
AND reference_component_index = arg_reference_component_index
187+
)
188+
OR
189+
( arg_reference_builtin IS NOT NULL
190+
AND reference_builtin = arg_reference_builtin
191+
)
192+
) AND (arg_reversed_name_prefix = '' OR stnl.reversed_name LIKE like_escape(arg_reversed_name_prefix) || '%')
193+
LIMIT 1;
194+
END IF;
195+
END;
196+
$$ LANGUAGE plpgsql STABLE;

src/Share/BackgroundJobs/Search/DefinitionSync.hs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import Share.Postgres qualified as PG
3030
import Share.Postgres.Cursors qualified as Cursors
3131
import Share.Postgres.IDs (BranchHashId)
3232
import Share.Postgres.NameLookups.Ops qualified as NLOps
33+
import Share.Postgres.NameLookups.Queries (NameSearchScope (..))
3334
import Share.Postgres.NamesPerspective.Ops qualified as NPOps
3435
import Share.Postgres.NamesPerspective.Types (NamesPerspective (..))
3536
import Share.Postgres.Notifications qualified as Notif
@@ -243,7 +244,7 @@ syncTerms codebase namesPerspective rootBranchHashId termsCursor = do
243244

244245
-- It's much more efficient to build only one PPE per batch.
245246
let allDeps = setOf (folded . folding tokens . folded . to LD.TypeReference) refDocs
246-
pped <- PG.timeTransaction "Build PPED" $ PPEPostgres.ppedForReferences namesPerspective allDeps
247+
pped <- PG.timeTransaction "Build PPED" $ PPEPostgres.ppedForReferences TransitiveDependencies namesPerspective allDeps
247248
let ppe = PPED.unsuffixifiedPPE pped
248249
let namedDocs :: [DefinitionDocument Name (Name, ShortHash)]
249250
namedDocs =
@@ -426,7 +427,7 @@ syncTypes codebase codeCache namesPerspective rootBranchHashId typesCursor = do
426427
}
427428
-- It's much more efficient to build only one PPE per batch.
428429
let allDeps = setOf (folded . folding tokens . folded . to LD.TypeReference) defDocuments
429-
pped <- PPEPostgres.ppedForReferences namesPerspective allDeps
430+
pped <- PPEPostgres.ppedForReferences TransitiveDependencies namesPerspective allDeps
430431
let ppe = PPED.unsuffixifiedPPE pped
431432
let namedDocs :: V.Vector (DefinitionDocument Name (Name, ShortHash))
432433
namedDocs =

src/Share/Names/Postgres.hs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Data.Set qualified as Set
77
import Share.Postgres qualified as PG
88
import Share.Postgres.NameLookups.Conversions qualified as CV
99
import Share.Postgres.NameLookups.Ops qualified as NameLookupOps
10-
import Share.Postgres.NameLookups.Queries (ShouldSuffixify (NoSuffixify))
10+
import Share.Postgres.NameLookups.Queries (NameSearchScope, ShouldSuffixify (NoSuffixify))
1111
import Share.Postgres.NameLookups.Types qualified as NameLookups
1212
import Share.Postgres.NamesPerspective.Types (NamesPerspective)
1313
import Share.Postgres.Refs.Types
@@ -19,8 +19,8 @@ import Unison.Names qualified as Names
1919
import Unison.Reference qualified as V1
2020
import Unison.Referent qualified as V1
2121

22-
namesForReferences :: forall m. (PG.QueryM m) => NamesPerspective m -> Set LabeledDependency -> m Names
23-
namesForReferences namesPerspective refs = do
22+
namesForReferences :: forall m. (PG.QueryM m) => NameSearchScope -> NamesPerspective m -> Set LabeledDependency -> m Names
23+
namesForReferences namesScope namesPerspective refs = do
2424
(pgRefTerms, pgRefTypes) <-
2525
Set.toList refs
2626
& CV.labeledDependencies1ToPG
@@ -38,7 +38,7 @@ namesForReferences namesPerspective refs = do
3838
& asListOf trav %%~ \refs -> do
3939
let pgRefs = snd <$> refs
4040
typeNames :: [[(NameLookups.ReversedName, NameLookups.ReversedName)]] <-
41-
NameLookupOps.typeNamesForRefsWithinNamespaceOf namesPerspective Nothing NoSuffixify traversed pgRefs
41+
NameLookupOps.typeNamesForRefsWithinNamespaceOf namesPerspective Nothing NoSuffixify namesScope traversed pgRefs
4242
pure $ do
4343
((ref, _pgRef), names) <- zip refs typeNames
4444
pure $ do
@@ -51,7 +51,7 @@ namesForReferences namesPerspective refs = do
5151
& asListOf trav %%~ \refs -> do
5252
let pgRefs = snd <$> refs
5353
termNames :: [[(NameLookups.ReversedName, NameLookups.ReversedName)]] <-
54-
NameLookupOps.termNamesForRefsWithinNamespaceOf namesPerspective Nothing NoSuffixify traversed pgRefs
54+
NameLookupOps.termNamesForRefsWithinNamespaceOf namesPerspective Nothing NoSuffixify namesScope traversed pgRefs
5555
pure $ do
5656
((ref, _pgRef), names) <- zip refs termNames
5757
pure $ do

src/Share/NamespaceDiffs.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import Share.Postgres qualified as PG
5353
import Share.Postgres.Definitions.Queries qualified as DefnsQ
5454
import Share.Postgres.IDs (BranchHashId)
5555
import Share.Postgres.NameLookups.Ops qualified as NL
56+
import Share.Postgres.NameLookups.Queries (NameSearchScope (TransitiveDependencies))
5657
import Share.Postgres.NameLookups.Types (NameLookupReceipt)
5758
import Share.Postgres.NameLookups.Types qualified as NL
5859
import Share.Postgres.NamesPerspective.Ops qualified as NPOps
@@ -298,7 +299,7 @@ computeThreeWayNamespaceDiff codebaseEnvs2 aliceCodeCache bobCodeCache branchHas
298299
traverse NPOps.namesPerspectiveForRoot branchHashIds
299300
names <-
300301
PG.transactionSpan "load names" mempty do
301-
sequence (PGNames.namesForReferences <$> perspectives <*> ThreeWay.toTwoOrThreeWay dependencies)
302+
sequence (PGNames.namesForReferences TransitiveDependencies <$> perspectives <*> ThreeWay.toTwoOrThreeWay dependencies)
302303
pure (TwoOrThreeWay.toThreeWay Names.empty names)
303304

304305
Merge.makeDiffblob

src/Share/Postgres/NameLookups/Ops.hs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,20 +74,20 @@ fuzzySearchDefinitions includeDependencies namesPerspective@NamesPerspective {re
7474

7575
-- | Get the list of (fqn, suffixified) names for a given Referent.
7676
-- If 'shouldSuffixify' is 'NoSuffixify', the suffixified name will be the same as the fqn.
77-
termNamesForRefsWithinNamespaceOf :: (PG.QueryM m) => NamesPerspective m -> Maybe ReversedName -> ShouldSuffixify -> Traversal s t PGReferent [(ReversedName, ReversedName)] -> s -> m t
78-
termNamesForRefsWithinNamespaceOf namesPerspective maySuffix shouldSuffixify trav s = do
77+
termNamesForRefsWithinNamespaceOf :: (PG.QueryM m) => NamesPerspective m -> Maybe ReversedName -> ShouldSuffixify -> Q.NameSearchScope -> Traversal s t PGReferent [(ReversedName, ReversedName)] -> s -> m t
78+
termNamesForRefsWithinNamespaceOf namesPerspective maySuffix shouldSuffixify nameScope trav s = do
7979
s
8080
& asListOf trav %%~ \refs -> do
81-
NameLookupQ.termNamesForRefsWithinNamespaceOf namesPerspective maySuffix shouldSuffixify traversed refs
81+
NameLookupQ.termNamesForRefsWithinNamespaceOf namesPerspective maySuffix shouldSuffixify nameScope traversed refs
8282
<&> (fmap . fmap) \(NameWithSuffix {reversedName, suffixifiedName}) -> (reversedName, suffixifiedName)
8383

8484
-- | Get the list of (fqn, suffixified) names for a given Reference.
8585
-- If 'shouldSuffixify' is 'NoSuffixify', the suffixified name will be the same as the fqn.
86-
typeNamesForRefsWithinNamespaceOf :: (PG.QueryM m) => NamesPerspective m -> Maybe ReversedName -> ShouldSuffixify -> Traversal s t PGReference [(ReversedName, ReversedName)] -> s -> m t
87-
typeNamesForRefsWithinNamespaceOf namesPerspective maySuffix shouldSuffixify trav s = do
86+
typeNamesForRefsWithinNamespaceOf :: (PG.QueryM m) => NamesPerspective m -> Maybe ReversedName -> ShouldSuffixify -> Q.NameSearchScope -> Traversal s t PGReference [(ReversedName, ReversedName)] -> s -> m t
87+
typeNamesForRefsWithinNamespaceOf namesPerspective maySuffix shouldSuffixify nameScope trav s = do
8888
s
8989
& asListOf trav %%~ \refs -> do
90-
NameLookupQ.typeNamesForRefsWithinNamespaceOf namesPerspective maySuffix shouldSuffixify traversed refs
90+
NameLookupQ.typeNamesForRefsWithinNamespaceOf namesPerspective maySuffix shouldSuffixify nameScope traversed refs
9191
<&> (fmap . fmap) \(NameWithSuffix {reversedName, suffixifiedName}) -> (reversedName, suffixifiedName)
9292

9393
termRefsForExactNamesOf :: (PG.QueryM m) => NamesPerspective m -> Traversal s t ReversedName [NamedRef V1.Referent] -> s -> m t

0 commit comments

Comments
 (0)