Skip to content

Commit

Permalink
Update quarkus and Kotlin versions. Migrate away from kmongo. Code cl…
Browse files Browse the repository at this point in the history
…eanup
  • Loading branch information
johnoliver committed Aug 20, 2024
1 parent 4b1ff39 commit 7c57def
Show file tree
Hide file tree
Showing 90 changed files with 596 additions and 389 deletions.
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

0 comments on commit 7c57def

Please sign in to comment.