Skip to content

Commit 9e23af5

Browse files
committed
chore: Remove redundand indexes
1 parent bf1ecc9 commit 9e23af5

7 files changed

Lines changed: 80 additions & 26 deletions

File tree

modules/core/shared/src/main/scala/scaladex/core/service/SchedulerDatabase.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ trait SchedulerDatabase extends WebDatabase:
3030
def updateArtifacts(artifacts: Seq[Artifact.Reference], newRef: Project.Reference): Future[Int]
3131
def updateArtifactReleaseDate(ref: Artifact.Reference, releaseDate: Instant): Future[Int]
3232
def getGroupIds(): Future[Seq[Artifact.GroupId]]
33+
def getGroupIds(limit: Int, offset: Int): Future[Seq[Artifact.GroupId]]
3334
def getArtifactIds(ref: Project.Reference): Future[Seq[(Artifact.GroupId, Artifact.ArtifactId)]]
3435
def getArtifactRefs(): Future[Seq[Artifact.Reference]]
3536
def getArtifactRefs(groupId: Artifact.GroupId): Future[Seq[Artifact.Reference]]
37+
def getArtifactRefs(groupId: Artifact.GroupId, limit: Int, offset: Int): Future[Seq[Artifact.Reference]]
3638
def updateLatestVersion(ref: Project.Reference, artifact: Artifact.Reference): Future[Unit]
3739
end SchedulerDatabase

modules/core/shared/src/test/scala/scaladex/core/test/InMemoryDatabase.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,11 @@ class InMemoryDatabase extends SchedulerDatabase:
157157

158158
override def updateArtifacts(allArtifacts: Seq[Artifact.Reference], newRef: Project.Reference): Future[Int] = ???
159159
override def getGroupIds(): Future[Seq[Artifact.GroupId]] = ???
160+
override def getGroupIds(limit: Int, offset: Int): Future[Seq[Artifact.GroupId]] = ???
160161
override def getArtifactRefs(): Future[Seq[Artifact.Reference]] = ???
161162
override def getArtifactRefs(groupId: Artifact.GroupId): Future[Seq[Artifact.Reference]] = ???
163+
override def getArtifactRefs(groupId: Artifact.GroupId, limit: Int, offset: Int): Future[Seq[Artifact.Reference]] =
164+
???
162165
override def insertUser(userId: UUID, userInfo: UserInfo): Future[Unit] = ???
163166
override def updateUser(userId: UUID, userInfo: UserState): Future[Unit] = ???
164167
override def getUser(userId: UUID): Future[Option[UserState]] = ???

modules/infra/src/main/resources/migrations/V28__add_performance_indexes.sql

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,6 @@ CREATE INDEX IF NOT EXISTS artifact_latest_version_idx
55
ON artifacts (organization, repository)
66
WHERE is_latest_version = true;
77

8-
-- Index for Maven coordinate lookups (group_id, artifact_id)
9-
CREATE INDEX IF NOT EXISTS artifact_maven_coords_idx
10-
ON artifacts (group_id, artifact_id);
11-
12-
-- Index for dependency lookups by source
13-
CREATE INDEX IF NOT EXISTS artifact_dep_source_idx
14-
ON artifact_dependencies (source_group_id, source_artifact_id, source_version);
15-
168
-- Index for reverse dependency lookups by target
179
CREATE INDEX IF NOT EXISTS artifact_dep_target_idx
1810
ON artifact_dependencies (target_group_id, target_artifact_id, target_version);

modules/infra/src/main/scala/scaladex/infra/SqlDatabase.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ class SqlDatabase(datasource: HikariDataSource, xa: doobie.Transactor[IO]) exten
206206
override def getGroupIds(): Future[Seq[Artifact.GroupId]] =
207207
run(ArtifactTable.selectGroupIds.to[Seq])
208208

209+
override def getGroupIds(limit: Int, offset: Int): Future[Seq[Artifact.GroupId]] =
210+
run(ArtifactTable.selectGroupIdsPage.to[Seq]((limit, offset)))
211+
209212
override def getArtifactIds(ref: Project.Reference): Future[Seq[(Artifact.GroupId, Artifact.ArtifactId)]] =
210213
run(ArtifactTable.selectArtifactIds.to[Seq](ref))
211214

@@ -215,6 +218,9 @@ class SqlDatabase(datasource: HikariDataSource, xa: doobie.Transactor[IO]) exten
215218
override def getArtifactRefs(groupId: Artifact.GroupId): Future[Seq[Artifact.Reference]] =
216219
run(ArtifactTable.selectReferencesByGroupId.to[Seq](groupId))
217220

221+
override def getArtifactRefs(groupId: Artifact.GroupId, limit: Int, offset: Int): Future[Seq[Artifact.Reference]] =
222+
run(ArtifactTable.selectReferencesByGroupIdPage.to[Seq]((groupId, limit, offset)))
223+
218224
override def insertUser(userId: UUID, userInfo: UserInfo): Future[Unit] =
219225
run(UserSessionsTable.insert.run((userId, userInfo)).map(_ => ()))
220226

modules/infra/src/main/scala/scaladex/infra/sql/ArtifactTable.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ object ArtifactTable:
140140
val selectGroupIds: Query0[GroupId] =
141141
selectRequest(table, Seq("DISTINCT group_id"))
142142

143+
/** Paged group IDs: params are (limit, offset). */
144+
val selectGroupIdsPage: Query[(Int, Int), GroupId] =
145+
Query(s"SELECT DISTINCT group_id FROM $table ORDER BY group_id LIMIT ? OFFSET ?")
146+
143147
val selectArtifactIds: Query[Project.Reference, (GroupId, ArtifactId)] =
144148
selectRequest(table, Seq("DISTINCT group_id", "artifact_id"), keys = projectReferenceFields)
145149

@@ -149,6 +153,13 @@ object ArtifactTable:
149153
val selectReferencesByGroupId: Query[GroupId, Reference] =
150154
selectRequest(table, Seq("DISTINCT group_id", "artifact_id", "\"version\""), keys = Seq("group_id"))
151155

156+
/** Paged refs for a group: params are (groupId, limit, offset). */
157+
val selectReferencesByGroupIdPage: Query[(GroupId, Int, Int), Reference] =
158+
Query(
159+
s"""SELECT DISTINCT group_id, artifact_id, "version" FROM $table
160+
|WHERE group_id = ? ORDER BY artifact_id, "version" LIMIT ? OFFSET ?""".stripMargin
161+
)
162+
152163
val selectReferencesByProject: Query[Project.Reference, Reference] =
153164
selectRequest(table, Seq("DISTINCT group_id", "artifact_id", "\"version\""), keys = projectReferenceFields)
154165

modules/infra/src/test/scala/scaladex/infra/sql/ArtifactTableTests.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ class ArtifactTableTests extends AnyFunSpec with BaseDatabaseSuite with Matchers
3030
it("check selectOldestByProject")(check(selectOldestByProject))
3131
it("check updateProjectRef")(check(updateProjectRef))
3232
it("check selectGroupIds")(check(selectGroupIds))
33+
it("check selectGroupIdsPage")(check(selectGroupIdsPage))
3334
it("check selectReferences")(check(selectReferences))
3435
it("check selectReferencesByGroupId")(check(selectReferencesByGroupId))
36+
it("check selectReferencesByGroupIdPage")(check(selectReferencesByGroupIdPage))
3537
it("check selectReferencesByProject")(check(selectReferencesByProject))
3638
it("check updateReleaseDate")(check(updateReleaseDate))
3739
it("check selectByReference")(check(selectByReference))

modules/server/src/main/scala/scaladex/server/service/MavenCentralService.scala

Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,21 @@ class MavenCentralService(
2626
extends LazyLogging:
2727
private val system = summon[ActorSystem]
2828

29+
private val groupIdPageSize = 50
30+
private val artifactRefPageSize = 1000
31+
private val artifactIdPageSize = 20
32+
private val pageDelay = 500.millis
33+
private val publishDelay = 100.millis
34+
2935
def findNonStandard(): Future[String] =
3036
val nonStandardLibs = NonStandardLib.load(dataPaths)
3137
for result <- nonStandardLibs.mapSync { lib =>
3238
val groupId = Artifact.GroupId(lib.groupId)
3339
// get should not throw: it is a fixed set of artifactIds
3440
val artifactId = Artifact.ArtifactId(lib.artifactId)
3541
for
36-
knownRefs <- database.getArtifactRefs(groupId)
37-
inserted <- findAndIndexMissingArtifacts(groupId, artifactId, knownRefs.toSet)
42+
knownRefs <- loadKnownRefs(groupId)
43+
inserted <- findAndIndexMissingArtifacts(groupId, artifactId, knownRefs)
3844
yield inserted
3945
}
4046
yield s"Inserted ${result.sum} missing poms"
@@ -53,9 +59,8 @@ class MavenCentralService(
5359
missingPomFiles <- missingVersions.mapSync(ref => mavenCentralClient.getPomFile(ref).map(_.map(ref -> _)))
5460
publishResult <- missingPomFiles.flatten.mapSync {
5561
case (mavenRef, (pomFile, creationDate)) =>
56-
// Add a small delay between publishes to avoid overwhelming the database connection pool
5762
for
58-
_ <- delayBetweenPublishes()
63+
_ <- delay(publishDelay)
5964
result <- publishProcess.publishPom(mavenRef.toString(), pomFile, creationDate, None)
6065
yield result
6166
}
@@ -64,36 +69,69 @@ class MavenCentralService(
6469
case _ => false
6570
}
6671

67-
private def delayBetweenPublishes(): Future[Unit] =
68-
// Small delay between publishes to avoid overwhelming the database connection pool
69-
after(100.millis, system.scheduler)(Future.successful(()))
70-
7172
def findMissing(): Future[String] =
72-
for
73-
// Load group IDs only, then known refs per group — avoid loading the entire artifacts table
74-
groupIds <- database.getGroupIds().map(_.sorted)
75-
// we sort just to estimate through the logs the percentage of progress
76-
result <- groupIds.mapSync(findAndIndexMissingArtifacts(_, None))
77-
yield s"Inserted ${result.sum} missing poms"
73+
def loop(page: Int, totalInserted: Int): Future[Int] =
74+
for
75+
batch <- database.getGroupIds(limit = groupIdPageSize, offset = page * groupIdPageSize)
76+
_ = logger.info(s"Processing group ID page $page (${batch.size} groups)")
77+
inserted <- batch.mapSync(g => findAndIndexMissingArtifacts(g, None)).map(_.sum)
78+
total = totalInserted + inserted
79+
result <-
80+
if batch.size == groupIdPageSize then delay(pageDelay).flatMap(_ => loop(page + 1, total))
81+
else Future.successful(total)
82+
yield result
83+
84+
loop(0, 0).map(n => s"Inserted $n missing poms")
7885

7986
private def findAndIndexMissingArtifacts(
8087
groupId: GroupId,
8188
artifactNameOpt: Option[Artifact.Name]
8289
): Future[Int] =
8390
for
84-
knownRefs <- database.getArtifactRefs(groupId).map(_.toSet)
91+
knownRefs <- loadKnownRefs(groupId)
8592
artifactIds <- mavenCentralClient.getAllArtifactIds(groupId)
8693
scalaArtifactIds = artifactIds.filter(artifact =>
8794
artifactNameOpt.forall(_ == artifact.name) && artifact.isScala && artifact.binaryVersion.isValid
8895
)
89-
result <- scalaArtifactIds
90-
.mapSync(id => findAndIndexMissingArtifacts(groupId, id, knownRefs))
91-
yield result.sum
96+
result <- processPages(scalaArtifactIds, artifactIdPageSize) { batch =>
97+
batch.mapSync(id => findAndIndexMissingArtifacts(groupId, id, knownRefs)).map(_.sum)
98+
}
99+
yield result
92100

93101
def syncOne(groupId: GroupId, artifactNameOpt: Option[Artifact.Name]): Future[String] =
94102
for result <- findAndIndexMissingArtifacts(groupId, artifactNameOpt)
95103
yield s"Inserted $result poms"
96104

105+
/** Load known refs for a group in pages to keep each DB query small. */
106+
private def loadKnownRefs(groupId: GroupId): Future[Set[Artifact.Reference]] =
107+
def loop(page: Int, acc: Set[Artifact.Reference]): Future[Set[Artifact.Reference]] =
108+
for
109+
batch <- database.getArtifactRefs(groupId, limit = artifactRefPageSize, offset = page * artifactRefPageSize)
110+
next = acc ++ batch
111+
result <-
112+
if batch.size == artifactRefPageSize then loop(page + 1, next)
113+
else Future.successful(next)
114+
yield result
115+
loop(0, Set.empty)
116+
117+
/** Process items in pages, with a short delay between full pages. */
118+
private def processPages[A](items: Seq[A], pageSize: Int)(process: Seq[A] => Future[Int]): Future[Int] =
119+
def loop(page: Int, total: Int): Future[Int] =
120+
val batch = items.slice(page * pageSize, (page + 1) * pageSize)
121+
if batch.isEmpty then Future.successful(total)
122+
else
123+
for
124+
inserted <- process(batch)
125+
next = total + inserted
126+
result <-
127+
if batch.size == pageSize then delay(pageDelay).flatMap(_ => loop(page + 1, next))
128+
else Future.successful(next)
129+
yield result
130+
loop(0, 0)
131+
132+
private def delay(duration: FiniteDuration): Future[Unit] =
133+
after(duration, system.scheduler)(Future.successful(()))
134+
97135
def republishArtifacts(): Future[String] =
98136
for
99137
projectStatuses <- database.getAllProjectsStatuses()

0 commit comments

Comments
 (0)