Skip to content

Commit 9e436a8

Browse files
Brutus5000claude
andauthored
Make map folderName an indexable column to fix slow map filters (#1150)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 39eea66 commit 9e436a8

8 files changed

Lines changed: 24 additions & 20 deletions

File tree

compose.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ services:
1616
- "3306:3306"
1717

1818
faf-db-migrations:
19-
image: faforever/faf-db-migrations:v140
19+
image: faforever/faf-db-migrations:v144
2020
command: migrate
2121
environment:
2222
FLYWAY_URL: jdbc:mysql://faf-db/faf?useSSL=false
@@ -35,7 +35,7 @@ services:
3535
condition: service_completed_successfully
3636

3737
minio:
38-
image: docker.io/bitnami/minio:2025
38+
image: docker.io/alpine/minio:latest-release
3939
ports:
4040
- '9000:9000'
4141
- '9001:9001'

src/inttest/java/com/faforever/api/config/MainDbTestContainers.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
@Configuration
2222
public class MainDbTestContainers {
2323
private static final MariaDBContainer<?> fafDBContainer = new MariaDBContainer<>("mariadb:11.7");
24-
private static final GenericContainer<?> flywayMigrationsContainer = new GenericContainer<>("faforever/faf-db-migrations:v140");
24+
private static final GenericContainer<?> flywayMigrationsContainer = new GenericContainer<>("faforever/faf-db-migrations:v144");
2525
private static final Network sharedNetwork = Network.newNetwork();
2626

2727
@Bean

src/inttest/resources/sql/prepMapData.sql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ INSERT INTO map (id, display_name, map_type, battle_type, author, license) VALUE
22
(1, 'SCMP_001', 'FFA', 'skirmish', 1, 1),
33
(2, 'SCMP_002', 'FFA', 'skirmish', 1, 1);
44

5-
INSERT INTO map_version (id, description, max_players, width, height, version, filename, hidden, map_id) VALUES
6-
(1, 'SCMP 001', 8, 5, 5, 1, 'maps/scmp_001.v0001.zip', 0, 1),
7-
(2, 'SCMP 002', 8, 5, 5, 1, 'maps/scmp_002.v0001.zip', 0, 2);
5+
INSERT INTO map_version (id, description, max_players, width, height, version, folder_name, hidden, map_id) VALUES
6+
(1, 'SCMP 001', 8, 5, 5, 1, 'scmp_001.v0001', 0, 1),
7+
(2, 'SCMP 002', 8, 5, 5, 1, 'scmp_002.v0001', 0, 2);
88

99
INSERT INTO map_pool (id, name) VALUES
1010
(1, 'Ladder 1v1 <300'),

src/inttest/resources/sql/prepMapVersion.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
INSERT INTO map (id, display_name, map_type, battle_type, author, recommended, license) VALUES (1, 'display name', 'mtype', 'btype', 1, false, 1);
2-
INSERT INTO map_version (id, description, max_players, width, height, version, filename, map_id, hidden, ranked)
3-
VALUES (1, 'des', 2, 2, 2, 1, 'map/ghb.zip', 1, 0, 1);
2+
INSERT INTO map_version (id, description, max_players, width, height, version, folder_name, map_id, hidden, ranked)
3+
VALUES (1, 'des', 2, 2, 2, 1, 'ghb', 1, 0, 1);
44
INSERT INTO map_reviews_summary (id, map_id, positive, negative, score, reviews, lower_bound)
55
VALUES (1, 1, 0, 0, 2, 1, 0);
66
INSERT INTO map_version_reviews_summary (id, map_version_id, positive, negative, score, reviews, lower_bound)

src/main/java/com/faforever/api/data/domain/MapVersion.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import com.yahoo.elide.annotation.Include;
1212
import com.yahoo.elide.annotation.UpdatePermission;
1313
import lombok.Setter;
14+
import org.hibernate.annotations.Generated;
15+
import org.hibernate.generator.EventType;
1416

1517
import jakarta.persistence.Column;
1618
import jakarta.persistence.Entity;
@@ -82,8 +84,10 @@ public int getVersion() {
8284
return version;
8385
}
8486

85-
@Column(name = "filename")
86-
@NotNull
87+
// DB-generated from folderName (CONCAT('maps/', folder_name, '.zip')); read-only here.
88+
// No @NotNull: bean validation runs pre-insert before the DB populates this value.
89+
@Column(name = "filename", insertable = false, updatable = false)
90+
@Generated(event = EventType.INSERT)
8791
public String getFilename() {
8892
return filename;
8993
}
@@ -138,8 +142,10 @@ public String getDownloadUrl() {
138142
return downloadUrl;
139143
}
140144

141-
@Transient
142-
@ComputedAttribute
145+
// Immutable after insert: the DB-generated filename and the derived download/
146+
// thumbnail URLs are all computed from this, so it must not change post-creation.
147+
@Column(name = "folder_name", updatable = false)
148+
@NotNull
143149
public String getFolderName() {
144150
return folderName;
145151
}

src/main/java/com/faforever/api/data/listeners/MapVersionEnricher.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,10 @@ public void init(FafApiProperties apiProperties, EntityCacheEvictor cacheEvictor
2525

2626
@PostLoad
2727
public void enhance(MapVersion mapVersion) {
28-
String filename = mapVersion.getFilename();
29-
mapVersion.setDownloadUrl(String.format(apiProperties.getMap().getDownloadUrlFormat(), filename.replace("maps/", "")));
30-
mapVersion.setThumbnailUrlLarge(String.format(apiProperties.getMap().getLargePreviewsUrlFormat(), filename.replace("maps/", "").replace(".zip", ".png")));
31-
mapVersion.setThumbnailUrlSmall(String.format(apiProperties.getMap().getSmallPreviewsUrlFormat(), filename.replace("maps/", "").replace(".zip", ".png")));
32-
mapVersion.setFolderName(filename.substring(filename.indexOf('/') + 1, filename.indexOf(".zip")));
28+
String folderName = mapVersion.getFolderName();
29+
mapVersion.setDownloadUrl(String.format(apiProperties.getMap().getDownloadUrlFormat(), folderName + ".zip"));
30+
mapVersion.setThumbnailUrlLarge(String.format(apiProperties.getMap().getLargePreviewsUrlFormat(), folderName + ".png"));
31+
mapVersion.setThumbnailUrlSmall(String.format(apiProperties.getMap().getSmallPreviewsUrlFormat(), folderName + ".png"));
3332
}
3433

3534
@PostUpdate

src/main/java/com/faforever/api/map/MapService.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ public class MapService {
8585
};
8686

8787
private static final Charset MAP_CHARSET = StandardCharsets.ISO_8859_1;
88-
private static final String LEGACY_FOLDER_PREFIX = "maps/";
8988
private final FafApiProperties fafApiProperties;
9089
private final MapRepository mapRepository;
9190
private final LicenseRepository licenseRepository;
@@ -413,7 +412,7 @@ private Map updateHibernateMapEntities(MapLuaAccessor mapLua, Optional<Map> exis
413412
.setMaxPlayers(standardTeamsConfig.get(CONFIGURATION_STANDARD_TEAMS_ARMIES).length())
414413
.setVersion(mapLua.getMapVersion$())
415414
.setMap(map)
416-
.setFilename(LEGACY_FOLDER_PREFIX + mapNameBuilder.buildFinalZipName(mapLua.getMapVersion$()));
415+
.setFolderName(mapNameBuilder.buildFolderName(mapLua.getMapVersion$()));
417416

418417
map.getVersions().add(version);
419418

src/test/java/com/faforever/api/map/MapServiceTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ void positiveUploadTest() throws Exception {
410410
assertEquals(256, mapVersion.getHeight());
411411
assertEquals(256, mapVersion.getWidth());
412412
assertEquals(8, mapVersion.getMaxPlayers());
413-
assertEquals("maps/command_conquer_rush.v0007.zip", mapVersion.getFilename());
413+
assertEquals("command_conquer_rush.v0007", mapVersion.getFolderName());
414414

415415
assertFalse(Files.exists(tmpDir));
416416

0 commit comments

Comments
 (0)