Skip to content

Commit 3ee5a54

Browse files
authored
Merge pull request #8 from PaperMC/feat/performance
chore: try to improve performance of some queries
2 parents 2800866 + e712a4c commit 3ee5a54

File tree

10 files changed

+112
-57
lines changed

10 files changed

+112
-57
lines changed

src/main/java/io/papermc/fill/controller/GraphMutationController.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,9 @@ public UpdateVersionPayload updateVersion(
161161
) {
162162
final ProjectEntity project = this.projects.findByName(input.project()).orElseThrow(ProjectNotFoundException::new);
163163
VersionEntity version = this.versions.findByProjectAndName(project, input.id()).orElseThrow(VersionNotFoundException::new);
164-
version.setJava(input.java());
165-
final Support support = input.support();
166-
if (support != null) {
167-
version.setSupport(support);
164+
final Support newSupport = input.support();
165+
if (newSupport != null) {
166+
version.setSupport(newSupport);
168167
}
169168
version.setJava(input.java());
170169
version = this.versions.save(version);

src/main/java/io/papermc/fill/controller/GraphQueryController.java

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import io.papermc.fill.database.VersionRepository;
2626
import io.papermc.fill.graphql.input.BuildFilters;
2727
import io.papermc.fill.graphql.input.VersionFilters;
28-
import io.papermc.fill.model.Build;
2928
import io.papermc.fill.model.BuildChannel;
3029
import io.papermc.fill.model.Download;
3130
import io.papermc.fill.model.DownloadWithUrl;
@@ -44,6 +43,7 @@
4443
import org.jspecify.annotations.NullMarked;
4544
import org.jspecify.annotations.Nullable;
4645
import org.springframework.beans.factory.annotation.Autowired;
46+
import org.springframework.data.domain.Pageable;
4747
import org.springframework.graphql.data.method.annotation.Argument;
4848
import org.springframework.graphql.data.method.annotation.QueryMapping;
4949
import org.springframework.graphql.data.method.annotation.SchemaMapping;
@@ -137,7 +137,6 @@ public List<VersionEntity> mapProjectVersions(
137137
final @Nullable Integer last
138138
) {
139139
Stream<VersionEntity> versions = this.versions.findAllByProject(project);
140-
versions = versions.sorted(Version.COMPARATOR_CREATED_AT_REVERSE);
141140
if (filterBy != null) {
142141
final String filterByFamilyId = filterBy.familyId();
143142
if (filterByFamilyId != null) {
@@ -191,16 +190,13 @@ public List<BuildEntity> mapVersionBuilds(
191190
@Argument
192191
final @Nullable Integer last
193192
) {
194-
Stream<BuildEntity> builds = this.builds.findAllByVersion(version);
195-
builds = builds.sorted(Build.COMPARATOR_ID_REVERSE);
193+
final Pageable pageable = last != null ? Pageable.ofSize(last) : Pageable.unpaged();
194+
final Stream<BuildEntity> builds;
196195
if (filterBy != null) {
197196
final BuildChannel filterByChannel = filterBy.channel();
198-
if (filterByChannel != null) {
199-
builds = builds.filter(Build.isChannel(filterByChannel));
200-
}
201-
}
202-
if (last != null) {
203-
builds = builds.limit(last);
197+
builds = this.builds.findByVersionAndOptionalChannel(version, filterByChannel, pageable);
198+
} else {
199+
builds = this.builds.findAllByVersion(version, pageable);
204200
}
205201
return builds.toList();
206202
}
@@ -224,7 +220,7 @@ public BuildChannel mapBuildChannel(final BuildEntity build) {
224220
public List<DownloadWithUrl> mapBuildDownloads(final BuildEntity build) {
225221
return build.downloads().values()
226222
.stream()
227-
.map(download -> download.withUrl(this.storage.getDownloadUrl(build, download)))
223+
.map(download -> download.withUrl(this.storage.getDownloadUrl(build.project(), build.version(), build, download)))
228224
.toList();
229225
}
230226

@@ -236,7 +232,7 @@ public List<DownloadWithUrl> mapBuildDownloads(final BuildEntity build) {
236232
) {
237233
final Download download = build.getDownloadByKey(name);
238234
return download != null
239-
? download.withUrl(this.storage.getDownloadUrl(build, download))
235+
? download.withUrl(this.storage.getDownloadUrl(build.project(), build.version(), build, download))
240236
: null;
241237
}
242238
}

src/main/java/io/papermc/fill/controller/Meta2Controller.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public ResponseEntity<?> getFamily(
132132
) {
133133
final ProjectEntity project = this.projects.findByName(projectId).orElseThrow(ProjectNotFoundException::new);
134134
final FamilyEntity family = this.families.findByProjectAndName(project, familyId).orElseThrow(VersionNotFoundException::new);
135-
final List<VersionEntity> versions = this.versions.findAllByProjectAndFamily(project, family).toList();
135+
final List<VersionEntity> versions = this.versions.findAllByFamily(family).toList();
136136
final FamilyResponse response = new FamilyResponse(
137137
project.id(),
138138
project.name(),
@@ -152,7 +152,7 @@ public ResponseEntity<?> getFamilyBuilds(
152152
) {
153153
final ProjectEntity project = this.projects.findByName(projectId).orElseThrow(ProjectNotFoundException::new);
154154
final FamilyEntity family = this.families.findByProjectAndName(project, familyId).orElseThrow(FamilyNotFoundException::new);
155-
final List<VersionEntity> versions = this.versions.findAllByProjectAndFamily(project, family).toList();
155+
final List<VersionEntity> versions = this.versions.findAllByFamily(family).toList();
156156
final List<BuildEntity> builds = this.builds.findAllByVersionIn(versions)
157157
.sorted(Build.COMPARATOR_ID)
158158
.toList();

src/main/java/io/papermc/fill/controller/Meta3Controller.java

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
package io.papermc.fill.controller;
1717

1818
import com.google.common.collect.Lists;
19+
import io.papermc.fill.database.AbstractEntity;
1920
import io.papermc.fill.database.BuildEntity;
21+
import io.papermc.fill.database.BuildIdentity;
2022
import io.papermc.fill.database.BuildRepository;
2123
import io.papermc.fill.database.ProjectEntity;
2224
import io.papermc.fill.database.ProjectRepository;
@@ -25,7 +27,6 @@
2527
import io.papermc.fill.exception.BuildNotFoundException;
2628
import io.papermc.fill.exception.ProjectNotFoundException;
2729
import io.papermc.fill.exception.VersionNotFoundException;
28-
import io.papermc.fill.model.Build;
2930
import io.papermc.fill.model.BuildChannel;
3031
import io.papermc.fill.model.BuildWithDownloads;
3132
import io.papermc.fill.model.Download;
@@ -59,9 +60,11 @@
5960
import java.util.Objects;
6061
import java.util.TreeMap;
6162
import java.util.stream.Collectors;
63+
import org.bson.types.ObjectId;
6264
import org.jspecify.annotations.NullMarked;
6365
import org.jspecify.annotations.Nullable;
6466
import org.springframework.beans.factory.annotation.Autowired;
67+
import org.springframework.data.domain.Pageable;
6568
import org.springframework.http.MediaType;
6669
import org.springframework.http.ResponseEntity;
6770
import org.springframework.web.bind.annotation.CrossOrigin;
@@ -194,11 +197,15 @@ public ResponseEntity<?> getVersions(
194197
final String projectId
195198
) {
196199
final ProjectEntity project = this.projects.findByName(projectId).orElseThrow(ProjectNotFoundException::new);
197-
final List<VersionEntity> versions = this.versions.findAllByProject(project)
198-
.sorted(Version.COMPARATOR_CREATED_AT_REVERSE)
199-
.toList();
200+
final List<VersionEntity> versions = this.versions.findAllByProject(project).toList();
201+
final List<ObjectId> versionIds = versions.stream().map(AbstractEntity::_id).toList();
202+
final Map<ObjectId, List<BuildIdentity>> buildsByVersion = this.builds.findAllIdentitiesByVersionIn(versionIds)
203+
.collect(Collectors.groupingBy(BuildIdentity::version));
200204
final VersionsResponse response = new VersionsResponse(
201-
Lists.transform(versions, this::createVersionResponse)
205+
Lists.transform(versions, version -> {
206+
final List<BuildIdentity> buildsIn = buildsByVersion.getOrDefault(version._id(), List.of());
207+
return this.createVersionResponse(version, buildsIn);
208+
})
202209
);
203210
return Responses.ok(response, Caching.publicShared(CACHE_LENGTH_VERSIONS));
204211
}
@@ -234,7 +241,8 @@ public ResponseEntity<?> getVersion(
234241
) {
235242
final ProjectEntity project = this.projects.findByName(projectId).orElseThrow(ProjectNotFoundException::new);
236243
final VersionEntity version = this.versions.findByProjectAndName(project, versionId).orElseThrow(VersionNotFoundException::new);
237-
final VersionResponse response = this.createVersionResponse(version);
244+
final List<BuildIdentity> builds = this.builds.findAllIdentitiesByVersion(version).toList();
245+
final VersionResponse response = this.createVersionResponse(version, builds);
238246
return Responses.ok(response, Caching.publicShared(CACHE_LENGTH_VERSION));
239247
}
240248

@@ -274,10 +282,7 @@ public ResponseEntity<?> getBuilds(
274282
) {
275283
final ProjectEntity project = this.projects.findByName(projectId).orElseThrow(ProjectNotFoundException::new);
276284
final VersionEntity version = this.versions.findByProjectAndName(project, versionId).orElseThrow(VersionNotFoundException::new);
277-
final List<BuildEntity> builds = this.builds.findAllByVersion(version)
278-
.filter(Build.isChannel(filterByChannel))
279-
.sorted(Build.COMPARATOR_ID_REVERSE)
280-
.toList();
285+
final List<BuildEntity> builds = this.builds.findByVersionAndOptionalChannel(version, filterByChannel, Pageable.unpaged()).toList();
281286
final List<BuildResponse> response = builds.stream()
282287
.map(build -> this.createBuildResponse(project, version, build))
283288
.toList();
@@ -355,9 +360,7 @@ public ResponseEntity<?> getLatestBuild(
355360
) {
356361
final ProjectEntity project = this.projects.findByName(projectId).orElseThrow(ProjectNotFoundException::new);
357362
final VersionEntity version = this.versions.findByProjectAndName(project, versionId).orElseThrow(VersionNotFoundException::new);
358-
final List<BuildEntity> builds = this.builds.findAllByVersion(version)
359-
.sorted(Build.COMPARATOR_ID_REVERSE)
360-
.toList();
363+
final List<BuildEntity> builds = this.builds.findAllByVersion(version).toList();
361364
if (builds.isEmpty()) {
362365
throw new BuildNotFoundException();
363366
} else {
@@ -397,17 +400,14 @@ private ProjectResponse createProjectResponse(final ProjectEntity project) {
397400
);
398401
}
399402

400-
private VersionResponse createVersionResponse(final VersionEntity version) {
401-
final List<BuildEntity> builds = this.builds.findAllByVersion(version)
402-
.sorted(Build.COMPARATOR_ID_REVERSE)
403-
.toList();
403+
private VersionResponse createVersionResponse(final VersionEntity version, final List<BuildIdentity> builds) {
404404
return new VersionResponse(
405405
new VersionResponse.Version(
406406
version.id(),
407407
version.support(),
408408
Objects.requireNonNullElse(version.java(), version.family().java())
409409
),
410-
Lists.transform(builds, Build::id)
410+
Lists.transform(builds, BuildIdentity::number)
411411
);
412412
}
413413

src/main/java/io/papermc/fill/database/BuildEntity.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
@CompoundIndex(def = "{'project': 1}")
3535
@CompoundIndex(def = "{'version': 1}")
3636
@CompoundIndex(def = "{'version': 1, 'number': 1}", unique = true)
37+
@CompoundIndex(def = "{'version': 1, 'number': -1}")
38+
@CompoundIndex(def = "{'version': 1, 'channel': 1, 'number': -1}")
3739
@Document(collection = "builds")
3840
@NullMarked
3941
public class BuildEntity extends AbstractEntity implements BuildWithDownloads<Download> {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright 2024 PaperMC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.papermc.fill.database;
17+
18+
import org.bson.types.ObjectId;
19+
import org.jspecify.annotations.NullMarked;
20+
21+
@NullMarked
22+
public record BuildIdentity(
23+
ObjectId _id,
24+
ObjectId version,
25+
int number
26+
) {
27+
}

src/main/java/io/papermc/fill/database/BuildRepository.java

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,61 @@
1515
*/
1616
package io.papermc.fill.database;
1717

18+
import io.papermc.fill.model.BuildChannel;
1819
import java.util.Collection;
1920
import java.util.Optional;
2021
import java.util.stream.Stream;
2122
import org.bson.types.ObjectId;
2223
import org.jspecify.annotations.NullMarked;
24+
import org.jspecify.annotations.Nullable;
25+
import org.springframework.data.domain.Pageable;
2326
import org.springframework.data.mongodb.repository.MongoRepository;
27+
import org.springframework.data.mongodb.repository.Query;
2428
import org.springframework.stereotype.Repository;
2529

2630
@NullMarked
2731
@Repository
2832
public interface BuildRepository extends MongoRepository<BuildEntity, ObjectId> {
29-
Stream<BuildEntity> findAllByVersion(final VersionEntity version);
33+
default Stream<BuildEntity> findAllByVersion(final VersionEntity version) {
34+
return this.findAllByVersion(version, Pageable.unpaged());
35+
}
3036

37+
@Query(sort = "{'number': -1}")
38+
Stream<BuildEntity> findAllByVersion(
39+
final VersionEntity version,
40+
final Pageable pageable
41+
);
42+
43+
@Query(sort = "{'number': -1}")
44+
Stream<BuildEntity> findAllByVersionAndChannel(
45+
final VersionEntity version,
46+
final @Nullable BuildChannel channel,
47+
final Pageable pageable
48+
);
49+
50+
default Stream<BuildEntity> findByVersionAndOptionalChannel(
51+
final VersionEntity version,
52+
final @Nullable BuildChannel channel,
53+
final Pageable pageable
54+
) {
55+
if (channel != null) {
56+
return this.findAllByVersionAndChannel(version, channel, pageable);
57+
} else {
58+
return this.findAllByVersion(version, pageable);
59+
}
60+
}
61+
62+
@Deprecated(forRemoval = true)
3163
Stream<BuildEntity> findAllByVersionIn(final Collection<VersionEntity> version);
3264

3365
Optional<BuildEntity> findByVersionAndNumber(
3466
final VersionEntity version,
3567
final int number
3668
);
69+
70+
@Query(sort = "{'number': -1}")
71+
Stream<BuildIdentity> findAllIdentitiesByVersion(final VersionEntity version);
72+
73+
@Query(sort = "{'number': -1}")
74+
Stream<BuildIdentity> findAllIdentitiesByVersionIn(final Collection<ObjectId> version);
3775
}

src/main/java/io/papermc/fill/database/VersionEntity.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@
2828
import org.springframework.data.mongodb.core.mapping.DocumentReference;
2929

3030
@CompoundIndex(def = "{'project': 1}")
31+
@CompoundIndex(def = "{'project': 1, 'createdAt': -1}")
3132
@CompoundIndex(def = "{'project': 1, 'family': 1}")
3233
@CompoundIndex(def = "{'project': 1, 'name': 1}", unique = true)
34+
@CompoundIndex(def = "{'family': 1}")
3335
@Document(collection = "versions")
3436
@NullMarked
3537
public class VersionEntity extends AbstractEntity implements Version {
@@ -42,8 +44,7 @@ public class VersionEntity extends AbstractEntity implements Version {
4244
private Support support;
4345
private @Nullable Java java;
4446
@Deprecated
45-
@DocumentReference
46-
private @Nullable BuildEntity mostRecentPromotedBuild;
47+
private @Nullable ObjectId mostRecentPromotedBuild;
4748

4849
public VersionEntity() {
4950
}
@@ -106,12 +107,12 @@ public void setJava(final @Nullable Java java) {
106107
}
107108

108109
@Deprecated
109-
public @Nullable BuildEntity mostRecentPromotedBuild() {
110+
public @Nullable ObjectId mostRecentPromotedBuild() {
110111
return this.mostRecentPromotedBuild;
111112
}
112113

113114
@Deprecated
114115
public void setMostRecentPromotedBuild(final @Nullable BuildEntity mostRecentPromotedBuild) {
115-
this.mostRecentPromotedBuild = mostRecentPromotedBuild;
116+
this.mostRecentPromotedBuild = mostRecentPromotedBuild != null ? mostRecentPromotedBuild._id() : null;
116117
}
117118
}

src/main/java/io/papermc/fill/database/VersionRepository.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,25 @@
1919
import java.util.stream.Stream;
2020
import org.bson.types.ObjectId;
2121
import org.jspecify.annotations.NullMarked;
22+
import org.springframework.data.domain.Pageable;
2223
import org.springframework.data.mongodb.repository.MongoRepository;
24+
import org.springframework.data.mongodb.repository.Query;
2325
import org.springframework.stereotype.Repository;
2426

2527
@NullMarked
2628
@Repository
2729
public interface VersionRepository extends MongoRepository<VersionEntity, ObjectId> {
28-
Stream<VersionEntity> findAllByProject(final ProjectEntity project);
30+
default Stream<VersionEntity> findAllByProject(final ProjectEntity project) {
31+
return this.findAllByProject(project, Pageable.unpaged());
32+
}
33+
34+
@Query(sort = "{'createdAt': -1}")
35+
Stream<VersionEntity> findAllByProject(final ProjectEntity project, final Pageable pageable);
2936

3037
Optional<VersionEntity> findByProjectAndName(
3138
final ProjectEntity project,
3239
final String name
3340
);
3441

3542
Stream<VersionEntity> findAllByFamily(final FamilyEntity family);
36-
37-
@Deprecated(forRemoval = true)
38-
Stream<VersionEntity> findAllByProjectAndFamily(
39-
final ProjectEntity project,
40-
final FamilyEntity family
41-
);
4243
}

src/main/java/io/papermc/fill/service/StorageService.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
package io.papermc.fill.service;
1717

1818
import io.papermc.fill.configuration.properties.ApplicationApiProperties;
19-
import io.papermc.fill.database.BuildEntity;
2019
import io.papermc.fill.exception.StorageReadException;
2120
import io.papermc.fill.exception.StorageWriteException;
2221
import io.papermc.fill.model.BuildWithDownloads;
@@ -68,14 +67,6 @@ static String createPath(
6867
);
6968
}
7069

71-
@Deprecated
72-
default URI getDownloadUrl(
73-
final BuildEntity build,
74-
final Download download
75-
) {
76-
return this.getDownloadUrl(build.project(), build.version(), build, download);
77-
}
78-
7970
URI getDownloadUrl(
8071
final Project project,
8172
final Version version,

0 commit comments

Comments
 (0)