Skip to content

Commit

Permalink
persistence: transaction support
Browse files Browse the repository at this point in the history
  • Loading branch information
hex-agon committed Jul 30, 2023
1 parent 510b60f commit d53943c
Show file tree
Hide file tree
Showing 19 changed files with 179 additions and 136 deletions.
15 changes: 8 additions & 7 deletions game-server/src/main/kotlin/work/fking/pangya/game/Bootstrap.kt
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,14 @@ object Bootstrap {

private fun setupPersistenceContext(jooq: DSLContext): PersistenceContext {
return PersistenceContext(
playerRepository = JooqPlayerRepository(jooq),
characterRepository = JooqCharacterRepository(jooq),
caddieRepository = JooqCaddieRepository(jooq),
inventoryRepository = JooqInventoryRepository(jooq),
equipmentRepository = JooqEquipmentRepository(jooq),
statisticsRepository = JooqStatisticsRepository(jooq),
achievementsRepository = JooqAchievementsRepository(jooq)
jooq = jooq,
playerRepository = JooqPlayerRepository(),
characterRepository = JooqCharacterRepository(),
caddieRepository = JooqCaddieRepository(),
inventoryRepository = JooqInventoryRepository(),
equipmentRepository = JooqEquipmentRepository(),
statisticsRepository = JooqStatisticsRepository(),
achievementsRepository = JooqAchievementsRepository()
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class EquipmentUpdatePacketHandler : ClientPacketHandler {
val character = buffer.readCharacter()
server.runTask(
UpdatePlayerCharacterPartsTask(
server = server,
persistenceCtx = server.persistenceCtx,
player = player,
character = character
)
Expand All @@ -60,7 +60,7 @@ class EquipmentUpdatePacketHandler : ClientPacketHandler {
}
server.runTask(
UpdatePlayerCaddieTask(
server = server,
persistenceCtx = server.persistenceCtx,
player = player,
caddie = caddie
)
Expand All @@ -74,7 +74,7 @@ class EquipmentUpdatePacketHandler : ClientPacketHandler {
val clubSet = player.inventory.findByUid(clubSetUid) ?: throw IllegalStateException("Player ${player.nickname} tried to equip a clubSet it does not own ($clubSetUid)")
server.runTask(
UpdatePlayerCometClubSetTask(
server = server,
persistenceCtx = server.persistenceCtx,
player = player,
comet = comet,
clubSet = clubSet
Expand All @@ -90,7 +90,7 @@ class EquipmentUpdatePacketHandler : ClientPacketHandler {
val character = player.characterRoster.findByUid(characterUid) ?: throw IllegalStateException("Player ${player.nickname} tried to equip a character it does not own")
server.runTask(
UpdatePlayerCharacterTask(
server = server,
persistenceCtx = server.persistenceCtx,
player = player,
character = character
)
Expand All @@ -101,7 +101,7 @@ class EquipmentUpdatePacketHandler : ClientPacketHandler {
val itemIffIds = IntArray(EQUIPPED_ITEMS_SIZE) { buffer.readIntLE() }
server.runTask(
UpdatePlayerEquippedItemsTask(
server = server,
persistenceCtx = server.persistenceCtx,
player = player,
itemIffIds = itemIffIds
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package work.fking.pangya.game.persistence

import org.jooq.DSLContext
import org.jooq.impl.DSL.value
import work.fking.pangya.game.persistence.jooq.tables.references.ACHIEVEMENT
import work.fking.pangya.game.persistence.jooq.tables.references.ACHIEVEMENT_MILESTONE
Expand All @@ -14,18 +13,18 @@ import java.util.stream.Collectors.groupingBy
import java.util.stream.Collectors.mapping

interface AchievementsRepository {
fun load(playerUid: Int): PlayerAchievements
fun createAchievements(playerUid: Int)
fun load(txCtx: TransactionalContext, playerUid: Int): PlayerAchievements
fun createAchievements(txCtx: TransactionalContext, playerUid: Int)
}

class InMemoryAchievementsRepository : AchievementsRepository {
override fun load(playerUid: Int): PlayerAchievements = PlayerAchievements(emptyList())
override fun createAchievements(playerUid: Int) {}
override fun load(txCtx: TransactionalContext, playerUid: Int): PlayerAchievements = PlayerAchievements(emptyList())
override fun createAchievements(txCtx: TransactionalContext, playerUid: Int) {}
}

class JooqAchievementsRepository(private val jooq: DSLContext) : AchievementsRepository {
override fun load(playerUid: Int): PlayerAchievements {
val achievements = jooq.select(
class JooqAchievementsRepository : AchievementsRepository {
override fun load(txCtx: TransactionalContext, playerUid: Int): PlayerAchievements {
val achievements = txCtx.jooq().select(
PLAYER_ACHIEVEMENT.UID,
PLAYER_ACHIEVEMENT.IFF_ID,
PLAYER_ACHIEVEMENT_MILESTONE.UID,
Expand Down Expand Up @@ -60,8 +59,8 @@ class JooqAchievementsRepository(private val jooq: DSLContext) : AchievementsRep
})
}

override fun createAchievements(playerUid: Int) {
jooq.transaction { tx ->
override fun createAchievements(txCtx: TransactionalContext, playerUid: Int) {
txCtx.jooq().transaction { tx ->
tx.dsl().insertInto(
PLAYER_ACHIEVEMENT,
PLAYER_ACHIEVEMENT.ACCOUNT_UID,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package work.fking.pangya.game.persistence

import org.jooq.DSLContext
import org.jooq.RecordMapper
import work.fking.pangya.game.persistence.jooq.keys.PLAYER_CADDIE_PKEY
import work.fking.pangya.game.persistence.jooq.tables.records.PlayerCaddieRecord
Expand All @@ -10,23 +9,23 @@ import work.fking.pangya.game.player.CaddieRoster
import java.util.concurrent.atomic.AtomicInteger

interface CaddieRepository {
fun loadRoster(playerUid: Int): CaddieRoster
fun save(playerUid: Int, caddie: Caddie): Caddie
fun loadRoster(txCtx: TransactionalContext, playerUid: Int): CaddieRoster
fun save(txCtx: TransactionalContext, playerUid: Int, caddie: Caddie): Caddie
}

class InMemoryCaddieRepository : CaddieRepository {
private val uidSequence = AtomicInteger(1)
private val playerCaddies = mutableMapOf<Int, MutableList<Caddie>>()

override fun loadRoster(playerUid: Int): CaddieRoster = CaddieRoster(playerCaddies[playerUid] ?: mutableListOf())
override fun loadRoster(txCtx: TransactionalContext, playerUid: Int): CaddieRoster = CaddieRoster(playerCaddies[playerUid] ?: mutableListOf())

override fun save(playerUid: Int, caddie: Caddie): Caddie {
override fun save(txCtx: TransactionalContext, playerUid: Int, caddie: Caddie): Caddie {
val characters = playerCaddies[playerUid] ?: mutableListOf()
return characters.find { it.uid == caddie.uid } ?: caddie.copy(uid = uidSequence.getAndIncrement())
}
}

class JooqCaddieRepository(private val jooq: DSLContext) : CaddieRepository {
class JooqCaddieRepository : CaddieRepository {
private val caddieMapper = RecordMapper<PlayerCaddieRecord, Caddie> {
Caddie(
uid = it.uid!!,
Expand All @@ -36,15 +35,15 @@ class JooqCaddieRepository(private val jooq: DSLContext) : CaddieRepository {
)
}

override fun loadRoster(playerUid: Int): CaddieRoster {
val caddies = jooq.selectFrom(PLAYER_CADDIE)
override fun loadRoster(txCtx: TransactionalContext, playerUid: Int): CaddieRoster {
val caddies = txCtx.jooq().selectFrom(PLAYER_CADDIE)
.where(PLAYER_CADDIE.ACCOUNT_UID.eq(playerUid))
.fetch(caddieMapper)
return CaddieRoster(caddies)
}

override fun save(playerUid: Int, caddie: Caddie): Caddie {
val insert = jooq.insertInto(PLAYER_CADDIE)
override fun save(txCtx: TransactionalContext, playerUid: Int, caddie: Caddie): Caddie {
val insert = txCtx.jooq().insertInto(PLAYER_CADDIE)

if (caddie.uid != -1) insert.set(PLAYER_CADDIE.UID, caddie.uid)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,23 @@ import java.util.concurrent.atomic.AtomicInteger


interface CharacterRepository {
fun loadRoster(playerUid: Int): CharacterRoster
fun save(playerUid: Int, character: Character): Character
fun loadRoster(txCtx: TransactionalContext, playerUid: Int): CharacterRoster
fun save(txCtx: TransactionalContext, playerUid: Int, character: Character): Character
}

class InMemoryCharacterRepository : CharacterRepository {
private val uidSequence = AtomicInteger(1)
private val playerCharacters = mutableMapOf<Int, MutableList<Character>>()

override fun loadRoster(playerUid: Int): CharacterRoster = CharacterRoster(playerCharacters[playerUid] ?: mutableListOf())
override fun loadRoster(txCtx: TransactionalContext, playerUid: Int): CharacterRoster = CharacterRoster(playerCharacters[playerUid] ?: mutableListOf())

override fun save(playerUid: Int, character: Character): Character {
override fun save(txCtx: TransactionalContext, playerUid: Int, character: Character): Character {
val characters = playerCharacters[playerUid] ?: mutableListOf()
return characters.find { it.uid == character.uid } ?: character.copy(uid = uidSequence.getAndIncrement())
}
}

class JooqCharacterRepository(private val jooq: DSLContext) : CharacterRepository {
class JooqCharacterRepository : CharacterRepository {
private val characterMapper = RecordMapper<PlayerCharacterRecord, Character> {
Character(
uid = it.uid!!,
Expand All @@ -43,15 +43,15 @@ class JooqCharacterRepository(private val jooq: DSLContext) : CharacterRepositor
)
}

override fun loadRoster(playerUid: Int): CharacterRoster {
val characters = jooq.selectFrom(PLAYER_CHARACTER)
override fun loadRoster(txCtx: TransactionalContext, playerUid: Int): CharacterRoster {
val characters = txCtx.jooq().selectFrom(PLAYER_CHARACTER)
.where(PLAYER_CHARACTER.ACCOUNT_UID.eq(playerUid))
.fetch(characterMapper)
return CharacterRoster(characters)
}

override fun save(playerUid: Int, character: Character): Character {
val insert = jooq.insertInto(PLAYER_CHARACTER)
override fun save(txCtx: TransactionalContext, playerUid: Int, character: Character): Character {
val insert = txCtx.jooq().insertInto(PLAYER_CHARACTER)

if (character.uid != -1) insert.set(PLAYER_CHARACTER.UID, character.uid)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
package work.fking.pangya.game.persistence

import org.jooq.DSLContext
import org.jooq.RecordMapper
import work.fking.pangya.game.persistence.jooq.keys.PLAYER_EQUIPMENT_PKEY
import work.fking.pangya.game.persistence.jooq.tables.records.PlayerEquipmentRecord
import work.fking.pangya.game.persistence.jooq.tables.references.PLAYER_EQUIPMENT
import work.fking.pangya.game.player.Equipment

interface EquipmentRepository {
fun load(playerUid: Int): Equipment
fun save(playerUid: Int, equipment: Equipment)
fun load(txCtx: TransactionalContext, playerUid: Int): Equipment
fun save(txCtx: TransactionalContext, playerUid: Int, equipment: Equipment)
}

class InMemoryEquipmentRepository : EquipmentRepository {
private val equipments = mutableMapOf<Int, Equipment>()

override fun load(playerUid: Int): Equipment = Equipment(
override fun load(txCtx: TransactionalContext, playerUid: Int): Equipment = Equipment(
clubSetUid = 200,
characterUid = 100,
cometIffId = 0x14000000
)

override fun save(playerUid: Int, equipment: Equipment) {
override fun save(txCtx: TransactionalContext, playerUid: Int, equipment: Equipment) {
}
}

class JooqEquipmentRepository(private val jooq: DSLContext) : EquipmentRepository {
class JooqEquipmentRepository : EquipmentRepository {
private val equipmentMapper = RecordMapper<PlayerEquipmentRecord, Equipment> {
Equipment(
itemIffIds = it.itemIffIds,
Expand All @@ -36,14 +35,14 @@ class JooqEquipmentRepository(private val jooq: DSLContext) : EquipmentRepositor
)
}

override fun load(playerUid: Int): Equipment {
return jooq.selectFrom(PLAYER_EQUIPMENT)
override fun load(txCtx: TransactionalContext, playerUid: Int): Equipment {
return txCtx.jooq().selectFrom(PLAYER_EQUIPMENT)
.where(PLAYER_EQUIPMENT.ACCOUNT_UID.eq(playerUid))
.fetchOne(equipmentMapper) ?: throw IllegalStateException("could not load equipment for playerId=$playerUid")
}

override fun save(playerUid: Int, equipment: Equipment) {
jooq.insertInto(PLAYER_EQUIPMENT)
override fun save(txCtx: TransactionalContext, playerUid: Int, equipment: Equipment) {
txCtx.jooq().insertInto(PLAYER_EQUIPMENT)
.set(PLAYER_EQUIPMENT.ACCOUNT_UID, playerUid)
.set(PLAYER_EQUIPMENT.ITEM_IFF_IDS, equipment.itemIffIds)
.set(PLAYER_EQUIPMENT.CHARACTER_UID, equipment.characterUid)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package work.fking.pangya.game.persistence

import org.jooq.DSLContext
import org.jooq.RecordMapper
import work.fking.pangya.game.persistence.jooq.keys.PLAYER_INVENTORY_ITEM_PKEY
import work.fking.pangya.game.persistence.jooq.tables.records.PlayerInventoryItemRecord
Expand All @@ -10,8 +9,8 @@ import work.fking.pangya.game.player.Item
import java.util.concurrent.atomic.AtomicInteger

interface InventoryRepository {
fun load(playerUid: Int): Inventory
fun saveItem(playerUid: Int, item: Item): Item
fun load(txCtx: TransactionalContext, playerUid: Int): Inventory
fun saveItem(txCtx: TransactionalContext, playerUid: Int, item: Item): Item
}

class InMemoryInventoryRepository : InventoryRepository {
Expand All @@ -25,18 +24,18 @@ class InMemoryInventoryRepository : InventoryRepository {
)
}

override fun load(playerUid: Int): Inventory {
override fun load(txCtx: TransactionalContext, playerUid: Int): Inventory {
return Inventory(findInventory(playerUid))
}

override fun saveItem(playerUid: Int, item: Item): Item {
override fun saveItem(txCtx: TransactionalContext, playerUid: Int, item: Item): Item {
val persistedItem = item.copy(uid = uidSequence.getAndIncrement())
findInventory(playerUid).add(persistedItem)
return persistedItem
}
}

class JooqInventoryRepository(private val jooq: DSLContext) : InventoryRepository {
class JooqInventoryRepository : InventoryRepository {
private val itemMapper = RecordMapper<PlayerInventoryItemRecord, Item> {
Item(
uid = it.uid!!,
Expand All @@ -46,15 +45,15 @@ class JooqInventoryRepository(private val jooq: DSLContext) : InventoryRepositor
)
}

override fun load(playerUid: Int): Inventory {
val items = jooq.selectFrom(PLAYER_INVENTORY_ITEM)
override fun load(txCtx: TransactionalContext, playerUid: Int): Inventory {
val items = txCtx.jooq().selectFrom(PLAYER_INVENTORY_ITEM)
.where(PLAYER_INVENTORY_ITEM.ACCOUNT_UID.eq(playerUid))
.fetch(itemMapper)
return Inventory(items)
}

override fun saveItem(playerUid: Int, item: Item): Item {
val insert = jooq.insertInto(PLAYER_INVENTORY_ITEM)
override fun saveItem(txCtx: TransactionalContext, playerUid: Int, item: Item): Item {
val insert = txCtx.jooq().insertInto(PLAYER_INVENTORY_ITEM)

if (item.uid != -1) insert.set(PLAYER_INVENTORY_ITEM.UID, item.uid)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,35 @@
package work.fking.pangya.game.persistence

import org.jooq.DSLContext

data class PersistenceContext(
val jooq: DSLContext?,
val playerRepository: PlayerRepository = InMemoryPlayerRepository(),
val characterRepository: CharacterRepository = InMemoryCharacterRepository(),
val caddieRepository: CaddieRepository = InMemoryCaddieRepository(),
val inventoryRepository: InventoryRepository = InMemoryInventoryRepository(),
val equipmentRepository: EquipmentRepository = InMemoryEquipmentRepository(),
val statisticsRepository: StatisticsRepository = InMemoryStatisticsRepository(),
val achievementsRepository: AchievementsRepository = InMemoryAchievementsRepository()
)
) {

/**
* Returns a transactional context without an active transaction.
*/
fun noTxContext() = TransactionalContext(jooq)

/**
* Returns a transactional context with an active transaction.
*/
fun transactional(transactional: (txContext: TransactionalContext) -> Unit) {
if (jooq != null) {
jooq.transaction { tx -> transactional(TransactionalContext(tx.dsl())) }
} else {
transactional(TransactionalContext())
}
}
}

data class TransactionalContext(private val jooq: DSLContext? = null) {
fun jooq(): DSLContext = jooq ?: throw IllegalStateException("no jooq context available")
}
Loading

0 comments on commit d53943c

Please sign in to comment.