Skip to content

Commit 431215a

Browse files
committed
Optimize saving player data
Saving all players in a single transaction takes the initial save of 100k players from over 3 minutes to under 20 seconds.
1 parent 638a2e1 commit 431215a

File tree

3 files changed

+27
-15
lines changed

3 files changed

+27
-15
lines changed

data/bolt.go

+10-8
Original file line numberDiff line numberDiff line change
@@ -71,18 +71,20 @@ func (b *BoltDB) LoadPlayers() ([]Player, error) {
7171
return players, nil
7272
}
7373

74-
func (b *BoltDB) SavePlayer(player Player) error {
74+
func (b *BoltDB) SavePlayers(players []Player) error {
7575
err := b.DB.Update(func(tx *bolt.Tx) error {
7676
playersBucket := tx.Bucket([]byte(playersBucketName))
7777

78-
serialized, err := json.Marshal(player)
79-
if err != nil {
80-
return err
81-
}
78+
for _, player := range players {
79+
serialized, err := json.Marshal(player)
80+
if err != nil {
81+
return err
82+
}
8283

83-
err = playersBucket.Put([]byte(player.Name), serialized)
84-
if err != nil {
85-
return err
84+
err = playersBucket.Put([]byte(player.Name), serialized)
85+
if err != nil {
86+
return err
87+
}
8688
}
8789

8890
return nil

game/manager.go

+16-6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"log/slog"
77
"sync"
88
"time"
9+
10+
"github.com/eleniums/mining-post/data"
911
)
1012

1113
const updateInterval = 10 * time.Second
@@ -79,6 +81,8 @@ func (m *Manager) Stop() error {
7981

8082
// Update happens on a regular time interval. This is the main game loop.
8183
func (m *Manager) update() {
84+
slog.Info("Game update starting...")
85+
8286
startTime := time.Now()
8387

8488
// stop the world while updating
@@ -89,6 +93,8 @@ func (m *Manager) update() {
8993
m.adjustMarketPrices()
9094

9195
// run updates for each player
96+
playerSaveData := make([]data.Player, len(m.players))
97+
playerSaveIndex := 0
9298
for _, player := range m.players {
9399
player.lock.Lock()
94100
defer player.lock.Unlock()
@@ -115,14 +121,18 @@ func (m *Manager) update() {
115121
if ranks[player.Rank].eligibleForPromotion(player) {
116122
player.Rank++
117123
player.Title = ranks[player.Rank].Name
118-
slog.Info("player was promoted to a new rank", "username", player.Name, "title", player.Title, "rank", player.Rank)
124+
slog.Info("Player was promoted to a new rank", "username", player.Name, "title", player.Title, "rank", player.Rank)
119125
}
120126

121-
// last of all, save player data
122-
err := m.db.SavePlayer(player.ToDB())
123-
if err != nil {
124-
slog.Error("Failed to save player data", "username", player.Name, ErrAttr(err))
125-
}
127+
// prepare player data to be saved
128+
playerSaveData[playerSaveIndex] = player.ToDB()
129+
playerSaveIndex++
130+
}
131+
132+
// save all player data
133+
err := m.db.SavePlayers(playerSaveData)
134+
if err != nil {
135+
slog.Error("Failed to save player data", ErrAttr(err))
126136
}
127137

128138
slog.Info("Game update finished", "playerCount", len(m.players), "elapsed", time.Since(startTime))

game/storage.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ type Storage interface {
88
Open(conn string) error
99
Close() error
1010
LoadPlayers() ([]data.Player, error)
11-
SavePlayer(player data.Player) error
11+
SavePlayers(players []data.Player) error
1212
}

0 commit comments

Comments
 (0)