diff --git a/api/build.gradle.kts b/api/build.gradle.kts index a4b1b6d..229f287 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -44,4 +44,15 @@ tasks.test { } kotlin { jvmToolchain(21) +} + +application { + mainClass.set("com.jaytux.simd.MainKt") +} + +tasks.withType { + manifest { + attributes["Main-Class"] = application.mainClass + } + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } \ No newline at end of file diff --git a/api/src/main/kotlin/Main.kt b/api/src/main/kotlin/Main.kt index b0960e2..4f0a563 100644 --- a/api/src/main/kotlin/Main.kt +++ b/api/src/main/kotlin/Main.kt @@ -10,25 +10,38 @@ import io.ktor.server.netty.* import kotlinx.coroutines.runBlocking fun main(args: Array) { - if(args.size > 3 && args[1] == "-reload") { - val xmlFile = args[2] - val jsonFile = args[3] - dbSetup(xmlFile, jsonFile) + println("Arguments (${args.size}): [${args.joinToString(", ")}]") + + if(args.size >= 3 && args[0] == "-reload") { + val xmlFile = args[1] + val jsonFile = args[2] + val force = args.size > 3 && args[3] == "-force" + dbSetup(xmlFile, jsonFile, force) } else if(args.size >= 1 && args[1] == "-h") { - println("Usage: ${args[0]} -reload (to reload the database)") - println(" ${args[0]} (to start the server)") + println("Usage: -reload (to reload the database)") + println(" -reload -force (to force reload the database; overwriting data even if the database has newer data)") + println(" -h (to show this help message)") + println(" (no arguments) (to start the server)") } else { EngineMain.main(args) } } -fun dbSetup(xmlFile: String, jsonFile: String) { +fun dbSetup(xmlFile: String, jsonFile: String, force: Boolean = false) { runBlocking { val xml = Loader.loadXml("/home/jay/intrinsics/data.xml") val perf = Loader.loadJson("/home/jay/intrinsics/perf2.js") - Loader.importToDb(xml, perf) + + val current = Loader.DatedVersion.fromPrefs() + if(force || (xml.version.version isNewerThan current.version)) { + Database.reset() + Loader.importToDb(xml, perf) + } + if(!(xml.version.version isNewerThan current.version)) { + System.err.println("The XML file (${xml.version}) is not more up-to-date than the database ($current). Use -force to force importing.") + } } } @@ -37,19 +50,4 @@ fun Application.module() { configureSerialization() configureHTTP() configureRouting() -} - -// API: (everything except /details/ is paginated per 100) -// - GET /all (list of SIMD intrinsics (name + ID)) -// - GET /cpuid (list of CPUID values) -// - GET /tech (list of techs) -// - GET /category (list of categories) -// - GET /types (list of types) -// - GET /search (search for SIMD intrinsics); query params: -// - name (string, optional, partial matching) -// - return (string, optional, full match) -// - cpuid (string, optional, full match) -// - tech (string, optional, full match) -// - category (string, optional, full match) -// - desc (string, optional, partial matching) -// - GET /details/ (details of a SIMD intrinsic) \ No newline at end of file +} \ No newline at end of file diff --git a/api/src/main/kotlin/data/Database.kt b/api/src/main/kotlin/data/Database.kt index 391f8ae..d42e3a6 100644 --- a/api/src/main/kotlin/data/Database.kt +++ b/api/src/main/kotlin/data/Database.kt @@ -4,6 +4,7 @@ import com.jaytux.simd.DotEnv import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.SchemaUtils import org.jetbrains.exposed.sql.transactions.transaction +import java.util.prefs.Preferences object Database { val db by lazy { @@ -22,6 +23,7 @@ object Database { } fun reset() { + db transaction { SchemaUtils.drop(Techs, CppTypes, Categories, CPUIDs, Intrinsics, IntrinsicArguments, IntrinsicInstructions, Platforms, Performances) diff --git a/api/src/main/kotlin/data/Loader.kt b/api/src/main/kotlin/data/Loader.kt index d1c9945..c00332b 100644 --- a/api/src/main/kotlin/data/Loader.kt +++ b/api/src/main/kotlin/data/Loader.kt @@ -11,11 +11,57 @@ import org.jetbrains.exposed.sql.insert import org.jetbrains.exposed.sql.transactions.transaction import java.io.File import org.json.JSONObject +import org.junit.jupiter.api.DisplayNameGenerator.Simple +import java.text.DateFormat +import java.text.SimpleDateFormat +import java.util.Date +import java.util.prefs.Preferences +import java.time.Instant object Loader { - data class XmlIntrinsic(val name: String, val tech: String, val retType: String, val retVar: String?, val args: List>, val desc: String, val op: String?, val insn: List>, val cpuid: String?, val category: String) + private val cache = Preferences.userNodeForPackage(this::class.java) + private val intelDateTimeFormat = SimpleDateFormat("MM/dd/yyyy") + private val dateFormat = SimpleDateFormat("dd-MMMM-yyyy") + + data class XmlIntrinsic(val name: String, val tech: String, val retType: String, val retVar: String?, + val args: List>, val desc: String, val op: String?, + val insn: List>, val cpuid: String?, val category: String + ) + + data class Version(val major: Int, val minor: Int, val patch: Int) { + override fun toString(): String = "$major.$minor.$patch" + + infix fun isNewerThan(other: Version): Boolean { + if(major > other.major) return true + if(major == other.major && minor > other.minor) return true + if(major == other.major && minor == other.minor && patch > other.patch) return true + return false + } + + companion object { + fun fromString(version: String): Version { + val parts = version.split(".") + return Version(parts[0].toInt(), parts[1].toInt(), parts[2].toInt()) + } + } + } + + data class DatedVersion(val version: Version, val releaseDate: Date, val updateDate: Date) { + override fun toString(): String = "$version (remote released ${dateFormat.format(releaseDate)}; local updated ${dateFormat.format(updateDate)})" + + companion object { + fun fromPrefs(): DatedVersion { + val v = cache.get("version", null)?.let { Version.fromString(it) } ?: Version(0, 0, 0) + val r = cache.get("release", null)?.let { dateFormat.parse(it) } ?: Date.from(Instant.ofEpochMilli(0)) + val u = cache.get("update", null)?.let { dateFormat.parse(it) } ?: Date.from(Instant.ofEpochMilli(0)) + + return DatedVersion(v, r, u) + } + } + } data class XmlData( + val version: DatedVersion, val types: Set, val techs: Set, val cpuids: Set, val categories: Set, val intrinsics: List ) @@ -24,6 +70,12 @@ object Loader { data class JsonData(val platforms: Set, val data: Map>) + private suspend fun updateVersion(version: DatedVersion) = coroutineScope { + cache.put("version", version.version.toString()) + cache.put("release", dateFormat.format(version.releaseDate)) + cache.put("update", dateFormat.format(version.updateDate)) + } + suspend fun loadXml(xmlFile: String): XmlData = coroutineScope { val xml = Ksoup.parseXml(File(xmlFile).readText(Charsets.UTF_8)) @@ -35,6 +87,28 @@ object Loader { val errors = mutableListOf() + val (version, release) = xml.getElementsByTag("intrinsics_list").firstOrNull()?.let { + val version = it.attribute("version")?.value?.let { v -> Version.fromString(v) } + if(version == null) { + errors += "Missing version attribute in intrinsics_list element" + return@let null + } + val date = it.attribute("date")?.value?.let { d -> intelDateTimeFormat.parse(d) } + if(date == null) { + errors += "Missing release_date attribute in intrinsics_list element" + return@let null + } + + version to date + } ?: Version(0, 0, 0) to Date() + + if(errors.isNotEmpty()) { + errors.forEach { System.err.println(it) } + throw Exception("XML file is (partially) invalid") + } + + val update = Date() + xml.getElementsByTag("intrinsic").forEachIndexed { i, it -> val name = it.attribute("name")?.value if(name == null) { @@ -123,7 +197,10 @@ object Loader { throw Exception("XML file is (partially) invalid") } - XmlData(types = cppTypes, techs = techs, cpuids = cpuids, categories = categories, intrinsics = intrins) + XmlData(version = DatedVersion(version, release, update), + types = cppTypes, techs = techs, cpuids = cpuids, categories = categories, + intrinsics = intrins + ) } suspend fun loadJson(jsonFile: String): JsonData = coroutineScope { @@ -201,5 +278,6 @@ object Loader { } } } + updateVersion(xml.version) } } \ No newline at end of file diff --git a/api/src/main/resources/logback.xml b/api/src/main/resources/logback.xml index 1591528..2e46a79 100644 --- a/api/src/main/resources/logback.xml +++ b/api/src/main/resources/logback.xml @@ -4,6 +4,10 @@ %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + +