Defer container UPDATEs until we've finished the current statement

Postgres would otherwise deadlock forever. I'm not sure why this worked
when testing - perhaps we always had fewer than BATCH_SIZE rows?

Signed-off-by: Graham <gpe@openrs2.org>
bzip2
Graham 4 years ago
parent 42c3c4c120
commit b1ccd9371d
  1. 57
      archive/src/main/kotlin/org/openrs2/archive/key/KeyBruteForcer.kt

@ -15,6 +15,13 @@ import javax.inject.Singleton
public class KeyBruteForcer @Inject constructor( public class KeyBruteForcer @Inject constructor(
private val database: Database private val database: Database
) { ) {
private data class ValidatedKey(
val keyId: Long,
val containerId: Long,
val uncompressedLength: Int,
val uncompressedChecksum: Int
)
/* /*
* The code for writing to the containers and keys tables ensures that the * The code for writing to the containers and keys tables ensures that the
* row IDs are allocated monotonically (by forbidding any other * row IDs are allocated monotonically (by forbidding any other
@ -94,6 +101,7 @@ public class KeyBruteForcer @Inject constructor(
while (true) { while (true) {
val pair = nextContainer(connection, lastContainerId) ?: break val pair = nextContainer(connection, lastContainerId) ?: break
val (containerId, data) = pair val (containerId, data) = pair
var validatedKey: ValidatedKey? = null
connection.prepareStatement( connection.prepareStatement(
""" """
@ -113,12 +121,17 @@ public class KeyBruteForcer @Inject constructor(
val k3 = rows.getInt(5) val k3 = rows.getInt(5)
val key = XteaKey(k0, k1, k2, k3) val key = XteaKey(k0, k1, k2, k3)
if (validateKey(connection, data, key, keyId, containerId)) { validatedKey = validateKey(data, key, keyId, containerId)
if (validatedKey != null) {
break break
} }
} }
} }
if (validatedKey != null) {
updateContainers(connection, listOf(validatedKey!!))
}
lastContainerId = containerId lastContainerId = containerId
} }
} }
@ -187,6 +200,7 @@ public class KeyBruteForcer @Inject constructor(
while (true) { while (true) {
val pair = nextKey(connection, lastKeyId) ?: break val pair = nextKey(connection, lastKeyId) ?: break
val (keyId, key) = pair val (keyId, key) = pair
val validatedKeys = mutableListOf<ValidatedKey>()
connection.prepareStatement( connection.prepareStatement(
""" """
@ -203,11 +217,16 @@ public class KeyBruteForcer @Inject constructor(
val containerId = rows.getLong(1) val containerId = rows.getLong(1)
val data = rows.getBytes(2) val data = rows.getBytes(2)
validateKey(connection, data, key, keyId, containerId) val validatedKey = validateKey(data, key, keyId, containerId)
if (validatedKey != null) {
validatedKeys += validatedKey
}
} }
} }
} }
updateContainers(connection, validatedKeys)
lastKeyId = keyId lastKeyId = keyId
} }
@ -253,34 +272,42 @@ public class KeyBruteForcer @Inject constructor(
} }
private fun validateKey( private fun validateKey(
connection: Connection,
data: ByteArray, data: ByteArray,
key: XteaKey, key: XteaKey,
keyId: Long, keyId: Long,
containerId: Long containerId: Long
): Boolean { ): ValidatedKey? {
Unpooled.wrappedBuffer(data).use { buf -> Unpooled.wrappedBuffer(data).use { buf ->
Js5Compression.uncompressIfKeyValid(buf, key).use { uncompressed -> Js5Compression.uncompressIfKeyValid(buf, key).use { uncompressed ->
if (uncompressed == null) { return if (uncompressed != null) {
return false ValidatedKey(keyId, containerId, uncompressed.readableBytes(), uncompressed.crc32())
} else {
null
}
}
}
}
private fun updateContainers(connection: Connection, keys: List<ValidatedKey>) {
if (keys.isEmpty()) {
return
} }
connection.prepareStatement( connection.prepareStatement(
""" """
UPDATE containers UPDATE containers
SET key_id = ?, uncompressed_length = ?, uncompressed_crc32 = ? SET key_id = ?, uncompressed_length = ?, uncompressed_crc32 = ?
WHERE id = ? WHERE id = ?""".trimIndent()
""".trimIndent()
).use { stmt -> ).use { stmt ->
stmt.setLong(1, keyId) for (key in keys) {
stmt.setInt(2, uncompressed.readableBytes()) stmt.setLong(1, key.keyId)
stmt.setInt(3, uncompressed.crc32()) stmt.setInt(2, key.uncompressedLength)
stmt.setLong(4, containerId) stmt.setInt(3, key.uncompressedChecksum)
stmt.execute() stmt.setLong(4, key.containerId)
stmt.addBatch()
} }
return true stmt.executeBatch()
}
} }
} }

Loading…
Cancel
Save