|
|
@ -21,6 +21,9 @@ import java.io.IOException |
|
|
|
import java.sql.Connection |
|
|
|
import java.sql.Connection |
|
|
|
import java.sql.SQLException |
|
|
|
import java.sql.SQLException |
|
|
|
import java.sql.Types |
|
|
|
import java.sql.Types |
|
|
|
|
|
|
|
import java.time.Instant |
|
|
|
|
|
|
|
import java.time.OffsetDateTime |
|
|
|
|
|
|
|
import java.time.ZoneOffset |
|
|
|
import javax.inject.Inject |
|
|
|
import javax.inject.Inject |
|
|
|
import javax.inject.Singleton |
|
|
|
import javax.inject.Singleton |
|
|
|
|
|
|
|
|
|
|
@ -60,14 +63,16 @@ public class CacheImporter @Inject constructor( |
|
|
|
override val encrypted: Boolean |
|
|
|
override val encrypted: Boolean |
|
|
|
) : Container(data) |
|
|
|
) : Container(data) |
|
|
|
|
|
|
|
|
|
|
|
public suspend fun import(store: Store) { |
|
|
|
public suspend fun import(store: Store, game: String, build: Int?, timestamp: Instant?) { |
|
|
|
database.execute { connection -> |
|
|
|
database.execute { connection -> |
|
|
|
prepare(connection) |
|
|
|
prepare(connection) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val gameId = getGameId(connection, game) |
|
|
|
|
|
|
|
|
|
|
|
// import master index |
|
|
|
// import master index |
|
|
|
val masterIndex = createMasterIndex(store) |
|
|
|
val masterIndex = createMasterIndex(store) |
|
|
|
try { |
|
|
|
try { |
|
|
|
addMasterIndex(connection, masterIndex) |
|
|
|
addMasterIndex(connection, masterIndex, gameId, build, timestamp) |
|
|
|
} finally { |
|
|
|
} finally { |
|
|
|
masterIndex.release() |
|
|
|
masterIndex.release() |
|
|
|
} |
|
|
|
} |
|
|
@ -116,13 +121,15 @@ public class CacheImporter @Inject constructor( |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public suspend fun importMasterIndex(buf: ByteBuf) { |
|
|
|
public suspend fun importMasterIndex(buf: ByteBuf, game: String, build: Int?, timestamp: Instant?) { |
|
|
|
Js5Compression.uncompress(buf.slice()).use { uncompressed -> |
|
|
|
Js5Compression.uncompress(buf.slice()).use { uncompressed -> |
|
|
|
val masterIndex = MasterIndex(Js5MasterIndex.read(uncompressed.slice()), buf) |
|
|
|
val masterIndex = MasterIndex(Js5MasterIndex.read(uncompressed.slice()), buf) |
|
|
|
|
|
|
|
|
|
|
|
database.execute { connection -> |
|
|
|
database.execute { connection -> |
|
|
|
prepare(connection) |
|
|
|
prepare(connection) |
|
|
|
addMasterIndex(connection, masterIndex) |
|
|
|
|
|
|
|
|
|
|
|
val gameId = getGameId(connection, game) |
|
|
|
|
|
|
|
addMasterIndex(connection, masterIndex, gameId, build, timestamp) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -131,7 +138,8 @@ public class CacheImporter @Inject constructor( |
|
|
|
masterIndex: Js5MasterIndex, |
|
|
|
masterIndex: Js5MasterIndex, |
|
|
|
buf: ByteBuf, |
|
|
|
buf: ByteBuf, |
|
|
|
gameId: Int, |
|
|
|
gameId: Int, |
|
|
|
build: Int |
|
|
|
build: Int, |
|
|
|
|
|
|
|
timestamp: Instant |
|
|
|
): List<ByteBuf?> { |
|
|
|
): List<ByteBuf?> { |
|
|
|
return database.execute { connection -> |
|
|
|
return database.execute { connection -> |
|
|
|
prepare(connection) |
|
|
|
prepare(connection) |
|
|
@ -149,7 +157,7 @@ public class CacheImporter @Inject constructor( |
|
|
|
stmt.execute() |
|
|
|
stmt.execute() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
addMasterIndex(connection, MasterIndex(masterIndex, buf)) |
|
|
|
addMasterIndex(connection, MasterIndex(masterIndex, buf), gameId, build, timestamp) |
|
|
|
|
|
|
|
|
|
|
|
connection.prepareStatement( |
|
|
|
connection.prepareStatement( |
|
|
|
""" |
|
|
|
""" |
|
|
@ -293,17 +301,33 @@ public class CacheImporter @Inject constructor( |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private fun addMasterIndex(connection: Connection, masterIndex: MasterIndex) { |
|
|
|
private fun addMasterIndex( |
|
|
|
|
|
|
|
connection: Connection, |
|
|
|
|
|
|
|
masterIndex: MasterIndex, |
|
|
|
|
|
|
|
gameId: Int, |
|
|
|
|
|
|
|
build: Int? = null, |
|
|
|
|
|
|
|
timestamp: Instant? = null |
|
|
|
|
|
|
|
) { |
|
|
|
val containerId = addContainer(connection, masterIndex) |
|
|
|
val containerId = addContainer(connection, masterIndex) |
|
|
|
val savepoint = connection.setSavepoint() |
|
|
|
val savepoint = connection.setSavepoint() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO(gpe): override game_id/build/timestamp if they're null? |
|
|
|
connection.prepareStatement( |
|
|
|
connection.prepareStatement( |
|
|
|
""" |
|
|
|
""" |
|
|
|
INSERT INTO master_indexes (container_id) |
|
|
|
INSERT INTO master_indexes (container_id, game_id, build, timestamp) |
|
|
|
VALUES (?) |
|
|
|
VALUES (?, ?, ?, ?) |
|
|
|
""".trimIndent() |
|
|
|
""".trimIndent() |
|
|
|
).use { stmt -> |
|
|
|
).use { stmt -> |
|
|
|
stmt.setLong(1, containerId) |
|
|
|
stmt.setLong(1, containerId) |
|
|
|
|
|
|
|
stmt.setObject(2, gameId, Types.INTEGER) |
|
|
|
|
|
|
|
stmt.setObject(3, build, Types.INTEGER) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (timestamp != null) { |
|
|
|
|
|
|
|
val offsetDateTime = OffsetDateTime.ofInstant(timestamp, ZoneOffset.UTC) |
|
|
|
|
|
|
|
stmt.setObject(4, offsetDateTime, Types.TIMESTAMP_WITH_TIMEZONE) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
stmt.setNull(4, Types.TIMESTAMP_WITH_TIMEZONE) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
stmt.execute() |
|
|
|
stmt.execute() |
|
|
@ -541,6 +565,26 @@ public class CacheImporter @Inject constructor( |
|
|
|
return ids |
|
|
|
return ids |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private fun getGameId(connection: Connection, name: String): Int { |
|
|
|
|
|
|
|
connection.prepareStatement( |
|
|
|
|
|
|
|
""" |
|
|
|
|
|
|
|
SELECT id |
|
|
|
|
|
|
|
FROM games |
|
|
|
|
|
|
|
WHERE name = ? |
|
|
|
|
|
|
|
""".trimIndent() |
|
|
|
|
|
|
|
).use { stmt -> |
|
|
|
|
|
|
|
stmt.setString(1, name) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stmt.executeQuery().use { rows -> |
|
|
|
|
|
|
|
if (!rows.next()) { |
|
|
|
|
|
|
|
throw Exception("Game not found") |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return rows.getInt(1) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public companion object { |
|
|
|
public companion object { |
|
|
|
public const val BATCH_SIZE: Int = 1024 |
|
|
|
public const val BATCH_SIZE: Int = 1024 |
|
|
|
} |
|
|
|
} |
|
|
|