From 4fa67c37fc72be70e17e73bf4f8e456deccfef4e Mon Sep 17 00:00:00 2001 From: Graham Date: Thu, 4 Feb 2021 20:45:41 +0000 Subject: [PATCH] Improve code for merging an old and new master index together Signed-off-by: Graham --- .../openrs2/archive/cache/CacheImporter.kt | 117 +++++++++++++++--- 1 file changed, 97 insertions(+), 20 deletions(-) diff --git a/archive/src/main/kotlin/org/openrs2/archive/cache/CacheImporter.kt b/archive/src/main/kotlin/org/openrs2/archive/cache/CacheImporter.kt index 84255837..f9ab606b 100644 --- a/archive/src/main/kotlin/org/openrs2/archive/cache/CacheImporter.kt +++ b/archive/src/main/kotlin/org/openrs2/archive/cache/CacheImporter.kt @@ -76,7 +76,7 @@ public class CacheImporter @Inject constructor( // import master index val masterIndex = createMasterIndex(store) try { - addMasterIndex(connection, masterIndex, gameId, build, timestamp, name, description) + addMasterIndex(connection, masterIndex, gameId, build, timestamp, name, description, false) } finally { masterIndex.release() } @@ -140,7 +140,7 @@ public class CacheImporter @Inject constructor( prepare(connection) val gameId = getGameId(connection, game) - addMasterIndex(connection, masterIndex, gameId, build, timestamp, name, description) + addMasterIndex(connection, masterIndex, gameId, build, timestamp, name, description, false) } } } @@ -169,7 +169,7 @@ public class CacheImporter @Inject constructor( stmt.execute() } - addMasterIndex(connection, MasterIndex(masterIndex, buf), gameId, build, timestamp, name, null) + addMasterIndex(connection, MasterIndex(masterIndex, buf), gameId, build, timestamp, name, null, true) connection.prepareStatement( """ @@ -320,49 +320,126 @@ public class CacheImporter @Inject constructor( build: Int?, timestamp: Instant?, name: String?, - description: String? + description: String?, + overwrite: Boolean ) { val containerId = addContainer(connection, masterIndex) + var exists: Boolean + + var newBuild: Int? + var newTimestamp: Instant? + var newName: String? + var newDescription: String? + + connection.prepareStatement( + """ + SELECT game_id, build, timestamp, name, description + FROM master_indexes + WHERE container_id = ? + FOR UPDATE + """.trimIndent() + ).use { stmt -> + stmt.setLong(1, containerId) + + stmt.executeQuery().use { rows -> + exists = rows.next() + + if (exists && !overwrite) { + val oldGameId = rows.getInt(1) + + var oldBuild: Int? = rows.getInt(2) + if (rows.wasNull()) { + oldBuild = null + } + + val oldTimestamp: Instant? = rows.getTimestamp(3)?.toInstant() + val oldName: String? = rows.getString(4) + val oldDescription: String? = rows.getString(5) + + check(oldGameId == gameId) + + if (oldBuild != null && build != null) { + check(oldBuild == build) + newBuild = oldBuild + } else if (oldBuild != null) { + newBuild = oldBuild + } else { + newBuild = build + } + + if (oldTimestamp != null && timestamp != null) { + newTimestamp = if (oldTimestamp.isBefore(timestamp)) { + oldTimestamp + } else { + timestamp + } + } else if (oldTimestamp != null) { + newTimestamp = oldTimestamp + } else { + newTimestamp = timestamp + } + + if (oldName != null && name != null) { + newName = "$oldName/$name" + } else if (oldName != null) { + newName = oldName + } else { + newName = name + } + + if (oldDescription != null && description != null) { + newDescription = "$oldDescription\n\n$description" + } else if (oldDescription != null) { + newDescription = oldDescription + } else { + newDescription = description + } + } else { + newBuild = build + newTimestamp = timestamp + newName = name + newDescription = description + } + } + } - // TODO(gpe): combine name/description instead of overwriting one with the other? - // or a mechanism to control priority? connection.prepareStatement( """ INSERT INTO master_indexes (container_id, game_id, build, timestamp, name, description) VALUES (?, ?, ?, ?, ?, ?) ON CONFLICT (container_id) DO UPDATE SET - build = COALESCE(EXCLUDED.build, master_indexes.build), - timestamp = COALESCE( - LEAST(EXCLUDED.timestamp, master_indexes.timestamp), - EXCLUDED.timestamp, - master_indexes.timestamp - ), - name = COALESCE(EXCLUDED.name, master_indexes.name), - description = COALESCE(EXCLUDED.description, master_indexes.description) + game_id = EXCLUDED.game_id, + build = EXCLUDED.build, + timestamp = EXCLUDED.timestamp, + name = EXCLUDED.name, + description = EXCLUDED.description """.trimIndent() ).use { stmt -> stmt.setLong(1, containerId) stmt.setInt(2, gameId) - stmt.setObject(3, build, Types.INTEGER) + stmt.setObject(3, newBuild, Types.INTEGER) - if (timestamp != null) { - val offsetDateTime = OffsetDateTime.ofInstant(timestamp, ZoneOffset.UTC) + if (newTimestamp != null) { + val offsetDateTime = OffsetDateTime.ofInstant(newTimestamp, ZoneOffset.UTC) stmt.setObject(4, offsetDateTime, Types.TIMESTAMP_WITH_TIMEZONE) } else { stmt.setNull(4, Types.TIMESTAMP_WITH_TIMEZONE) } - stmt.setString(5, name) - stmt.setString(6, description) + stmt.setString(5, newName) + stmt.setString(6, newDescription) stmt.execute() } + if (exists) { + return + } + connection.prepareStatement( """ INSERT INTO master_index_archives (container_id, archive_id, crc32, version) VALUES (?, ?, ?, ?) - ON CONFLICT DO NOTHING """.trimIndent() ).use { stmt -> for ((i, entry) in masterIndex.index.entries.withIndex()) {