Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update quarkus and Kotlin versions. Migrate away from kmongo. Code cleanup #1126

Merged
merged 2 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .mvn/wrapper/maven-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.8/apache-maven-3.9.8-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar
19 changes: 17 additions & 2 deletions adoptium-api-v3-persistence/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@

<dependencies>
<dependency>
<groupId>org.litote.kmongo</groupId>
<artifactId>kmongo-coroutine</artifactId>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-kotlin-coroutine</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jakarta-jsonp</artifactId>
</dependency>
<dependency>
<groupId>net.adoptium.api</groupId>
Expand All @@ -41,6 +45,17 @@
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test</artifactId>
<version>${kotlin.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ class DownloadStatsInterface {
return stats.groupBy { it.dateTime.toLocalDate() }
.map { grouped ->
StatEntry(
grouped.value.map { it.dateTime }.maxOrNull()!!,
grouped.value.map { it.count }.sum()
grouped.value.maxOf { it.dateTime },
grouped.value.sumOf { it.count }
)
}
.sortedBy { it.dateTime }
Expand Down Expand Up @@ -161,7 +161,7 @@ class DownloadStatsInterface {
private fun calculateMonthlyDiff(
stats: Collection<StatEntry>
): List<MonthlyDownloadDiff> {
val toTwoChar = { value: Int -> if (value < 10) "0" + value else value.toString() } // Returns in MM format
val toTwoChar = { value: Int -> if (value < 10) "0$value" else value.toString() } // Returns in MM format

return stats
.windowed(2, 1, false) {
Expand Down Expand Up @@ -244,38 +244,28 @@ class DownloadStatsInterface {
return stats
.groupBy { it.getId() }
.map { grouped -> grouped.value.maxByOrNull { it.date } }
.map { it!!.getMetric() }
.sum()
.sumOf { it!!.getMetric() }
}

private fun formTotalDownloads(stats: List<GitHubDownloadStatsDbEntry>, jvmImpl: JvmImpl): Long {
return stats
.groupBy { it.getId() }
.map { grouped -> grouped.value.maxByOrNull { it.date } }
.map { (it!!.jvmImplDownloads?.get(jvmImpl) ?: 0) }
.sum()
.sumOf { (it!!.jvmImplDownloads?.get(jvmImpl) ?: 0) }
}

suspend fun getTotalDownloadStats(): DownloadStats {
val dockerStats = getAllDockerStats()

val githubStats = getGithubStats()

val dockerPulls = dockerStats
.map { it.pulls }
.sum()
val dockerPulls = dockerStats.sumOf { it.pulls }

val githubDownloads = githubStats
.map { it.downloads }
.sum()
val githubDownloads = githubStats.sumOf { it.downloads }

val dockerBreakdown = dockerStats
.map { Pair(it.repo, it.pulls) }
.toMap()
val dockerBreakdown = dockerStats.associate { Pair(it.repo, it.pulls) }

val githubBreakdown = githubStats
.map { Pair(it.feature_version, it.downloads) }
.toMap()
val githubBreakdown = githubStats.associate { Pair(it.feature_version, it.downloads) }

val totalStats = TotalStats(dockerPulls, githubDownloads, dockerPulls + githubDownloads)
return DownloadStats(TimeSource.now(), totalStats, githubBreakdown, dockerBreakdown)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ package net.adoptium.api.v3
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import com.fasterxml.jackson.module.kotlin.KotlinModule

object JsonMapper {
val mapper: ObjectMapper = ObjectMapper()
val mapper: ObjectMapper = com.fasterxml.jackson.module.kotlin.jacksonObjectMapper()
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.registerModule(KotlinModule.Builder().build())
.registerModule(JavaTimeModule())
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ open class APIDataStoreImpl : APIDataStore {
private var updatedAt: UpdatedInfo
private var binaryRepos: AdoptRepos
private var releaseInfo: ReleaseInfo
open var schedule: ScheduledFuture<*>?
private var schedule: ScheduledFuture<*>?

// required as injection objects to the final field
open fun getSchedule() = schedule

companion object {
@JvmStatic
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package net.adoptium.api.v3.dataSources.persitence.mongo

import com.mongodb.client.model.InsertManyOptions
import com.mongodb.client.model.UpdateOptions
import com.mongodb.client.model.ReplaceOptions
import com.mongodb.kotlin.client.coroutine.MongoCollection
import jakarta.enterprise.context.ApplicationScoped
import jakarta.enterprise.inject.Model
import jakarta.inject.Inject
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.toList
import net.adoptium.api.v3.TimeSource
import net.adoptium.api.v3.dataSources.models.AdoptRepos
import net.adoptium.api.v3.dataSources.models.FeatureRelease
Expand All @@ -24,19 +27,18 @@ import org.bson.BsonDateTime
import org.bson.BsonDocument
import org.bson.BsonString
import org.bson.Document
import org.litote.kmongo.coroutine.CoroutineCollection
import org.slf4j.LoggerFactory
import java.time.ZonedDateTime

@ApplicationScoped
open class MongoApiPersistence @Inject constructor(mongoClient: MongoClient) : MongoInterface(), ApiPersistence {
private val githubReleaseMetadataCollection: CoroutineCollection<GHReleaseMetadata> = createCollection(mongoClient.database, GH_RELEASE_METADATA)
private val releasesCollection: CoroutineCollection<Release> = createCollection(mongoClient.database, RELEASE_DB)
private val gitHubStatsCollection: CoroutineCollection<GitHubDownloadStatsDbEntry> = createCollection(mongoClient.database, GITHUB_STATS_DB)
private val dockerStatsCollection: CoroutineCollection<DockerDownloadStatsDbEntry> = createCollection(mongoClient.database, DOCKER_STATS_DB)
private val releaseInfoCollection: CoroutineCollection<ReleaseInfo> = createCollection(mongoClient.database, RELEASE_INFO_DB)
private val updateTimeCollection: CoroutineCollection<UpdatedInfo> = createCollection(mongoClient.database, UPDATE_TIME_DB)
private val githubReleaseNotesCollection: CoroutineCollection<ReleaseNotes> = createCollection(mongoClient.database, GH_RELEASE_NOTES)
private val githubReleaseMetadataCollection: MongoCollection<GHReleaseMetadata> = createCollection(mongoClient.getDatabase(), GH_RELEASE_METADATA)
private val releasesCollection: MongoCollection<Release> = createCollection(mongoClient.getDatabase(), RELEASE_DB)
private val gitHubStatsCollection: MongoCollection<GitHubDownloadStatsDbEntry> = createCollection(mongoClient.getDatabase(), GITHUB_STATS_DB)
private val dockerStatsCollection: MongoCollection<DockerDownloadStatsDbEntry> = createCollection(mongoClient.getDatabase(), DOCKER_STATS_DB)
private val releaseInfoCollection: MongoCollection<ReleaseInfo> = createCollection(mongoClient.getDatabase(), RELEASE_INFO_DB)
private val updateTimeCollection: MongoCollection<UpdatedInfo> = createCollection(mongoClient.getDatabase(), UPDATE_TIME_DB)
private val githubReleaseNotesCollection: MongoCollection<ReleaseNotes> = createCollection(mongoClient.getDatabase(), GH_RELEASE_NOTES)

companion object {
@JvmStatic
Expand Down Expand Up @@ -119,7 +121,7 @@ open class MongoApiPersistence @Inject constructor(mongoClient: MongoClient) : M
val repoNames = dockerStatsCollection.distinct<String>("repo").toList()

return repoNames
.mapNotNull {
.map {
dockerStatsCollection
.find(Document("repo", it))
.sort(Document("date", -1))
Expand All @@ -137,31 +139,31 @@ open class MongoApiPersistence @Inject constructor(mongoClient: MongoClient) : M

override suspend fun setReleaseInfo(releaseInfo: ReleaseInfo) {
releaseInfoCollection.deleteMany(releaseVersionDbEntryMatcher())
releaseInfoCollection.updateOne(
releaseInfoCollection.replaceOne(
releaseVersionDbEntryMatcher(),
releaseInfo,
UpdateOptions().upsert(true)
ReplaceOptions().upsert(true)
)
}

// visible for testing
open suspend fun updateUpdatedTime(dateTime: ZonedDateTime, checksum: String, hashCode: Int) {
updateTimeCollection.updateOne(
updateTimeCollection.replaceOne(
Document(),
UpdatedInfo(dateTime, checksum, hashCode),
UpdateOptions().upsert(true)
ReplaceOptions().upsert(true)
)
updateTimeCollection.deleteMany(Document("time", BsonDocument("\$lt", BsonDateTime(dateTime.toInstant().toEpochMilli()))))
}

override suspend fun getUpdatedAt(): UpdatedInfo {
val info = updateTimeCollection.findOne()
val info = updateTimeCollection.find().firstOrNull()
// if we have no existing time, make it 5 mins ago, should only happen on first time the db is used
return info ?: UpdatedInfo(TimeSource.now().minusMinutes(5), "000", 0)
}

override suspend fun getReleaseInfo(): ReleaseInfo? {
return releaseInfoCollection.findOne(releaseVersionDbEntryMatcher())
return releaseInfoCollection.find(releaseVersionDbEntryMatcher()).firstOrNull()
}

private fun releaseVersionDbEntryMatcher() = Document("tip_version", BsonDocument("\$exists", BsonBoolean(true)))
Expand All @@ -181,20 +183,20 @@ open class MongoApiPersistence @Inject constructor(mongoClient: MongoClient) : M
private fun majorVersionMatcher(featureVersion: Int) = Document("version_data.major", featureVersion)

override suspend fun getGhReleaseMetadata(gitHubId: GitHubId): GHReleaseMetadata? {
return githubReleaseMetadataCollection.findOne(matchGithubId(gitHubId))
return githubReleaseMetadataCollection.find(matchGithubId(gitHubId)).firstOrNull()
}

override suspend fun setGhReleaseMetadata(ghReleaseMetadata: GHReleaseMetadata) {
githubReleaseMetadataCollection
.updateOne(
.replaceOne(
matchGithubId(ghReleaseMetadata.gitHubId),
ghReleaseMetadata,
UpdateOptions().upsert(true)
ReplaceOptions().upsert(true)
)
}

override suspend fun hasReleaseNotesForGithubId(gitHubId: GitHubId): Boolean {
return githubReleaseNotesCollection.findOne(Document("id", gitHubId.id)) != null
return githubReleaseNotesCollection.find(Document("id", gitHubId.id)).firstOrNull() != null
}

override suspend fun putReleaseNote(releaseNotes: ReleaseNotes) {
Expand All @@ -203,7 +205,7 @@ open class MongoApiPersistence @Inject constructor(mongoClient: MongoClient) : M
}

override suspend fun getReleaseNotes(vendor: Vendor, releaseName: String): ReleaseNotes? {
return githubReleaseNotesCollection.findOne(Document(
return githubReleaseNotesCollection.find(Document(
"\$and",
BsonArray(
listOf(
Expand All @@ -213,6 +215,7 @@ open class MongoApiPersistence @Inject constructor(mongoClient: MongoClient) : M
)
)
)
.firstOrNull()
}

private fun matchGithubId(gitHubId: GitHubId) = Document("gitHubId.id", gitHubId.id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,21 @@ package net.adoptium.api.v3.dataSources.persitence.mongo

import com.mongodb.ConnectionString
import com.mongodb.MongoClientSettings
import com.mongodb.kotlin.client.coroutine.MongoDatabase
import jakarta.enterprise.context.ApplicationScoped
import org.litote.kmongo.coroutine.CoroutineClient
import org.litote.kmongo.coroutine.CoroutineDatabase
import org.litote.kmongo.coroutine.coroutine
import org.litote.kmongo.reactivestreams.KMongo
import net.adoptium.api.v3.dataSources.persitence.mongo.codecs.JacksonCodecProvider
import net.adoptium.api.v3.dataSources.persitence.mongo.codecs.ZonedDateTimeCodecProvider
import org.bson.codecs.configuration.CodecRegistries
import org.slf4j.LoggerFactory


@ApplicationScoped
open class MongoClient {
open val database: CoroutineDatabase
open val client: CoroutineClient
private val database: MongoDatabase
private val client: com.mongodb.kotlin.client.coroutine.MongoClient

// required as injection objects to the final field
open fun getDatabase() = database

companion object {
@JvmStatic
Expand Down Expand Up @@ -65,14 +69,21 @@ open class MongoClient {
serverSelectionTimeoutMills = System.getenv("MONGODB_SERVER_SELECTION_TIMEOUT_MILLIS")
)
var settingsBuilder = MongoClientSettings.builder()
.codecRegistry(CodecRegistries.fromProviders(
MongoClientSettings.getDefaultCodecRegistry(),
ZonedDateTimeCodecProvider(),
JacksonCodecProvider()
)
)
.applyConnectionString(ConnectionString(connectionString))
val sslEnabled = System.getenv("MONGODB_SSL")?.toBoolean()
if (sslEnabled == true) {
val checkMongoHostName = System.getenv("DISABLE_MONGO_HOST_CHECK")?.toBoolean() ?: false

settingsBuilder = settingsBuilder.applyToSslSettings { it.enabled(true).invalidHostNameAllowed(checkMongoHostName) }
}
client = KMongo.createClient(settingsBuilder.build()).coroutine
client = com.mongodb.kotlin.client.coroutine.MongoClient.create(settingsBuilder.build())
database = client.getDatabase(dbName)
}

}
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
package net.adoptium.api.v3.dataSources.persitence.mongo

import com.mongodb.MongoCommandException
import com.mongodb.kotlin.client.coroutine.MongoCollection
import com.mongodb.kotlin.client.coroutine.MongoDatabase
import kotlinx.coroutines.runBlocking
import org.litote.kmongo.coroutine.CoroutineCollection
import org.litote.kmongo.coroutine.CoroutineDatabase

abstract class MongoInterface {

inline fun <reified T : Any> createCollection(database: CoroutineDatabase, collectionName: String): CoroutineCollection<T> {
return runBlocking {
if (!database.listCollectionNames().contains(collectionName)) {
// TODO add indexes
inline fun <reified T : Any> createCollection(database: MongoDatabase, collectionName: String): MongoCollection<T> {
runBlocking {
try {
database.createCollection(collectionName)
} catch (e: MongoCommandException) {
if (e.errorCode == 48) {
// collection already exists ... ignore
} else {
throw e
}
}
return@runBlocking database.getCollection<T>(collectionName)
}
return database.getCollection(collectionName, T::class.java)

}
}
Loading