Optimise files on start
This commit is contained in:
parent
19aa91eff2
commit
ef966b0aa3
@ -8,14 +8,26 @@
|
||||
import Foundation
|
||||
|
||||
|
||||
protocol DiskWriter {
|
||||
protocol DiskWriter: AnyObject {
|
||||
|
||||
var storageFile: FileHandle { get }
|
||||
var storageFile: FileHandle { get set }
|
||||
|
||||
var storageFileUrl: URL { get }
|
||||
}
|
||||
|
||||
extension DiskWriter {
|
||||
|
||||
func replaceFile(data: String) throws {
|
||||
let data = data.data(using: .utf8)!
|
||||
try storageFile.close()
|
||||
try data.write(to: storageFileUrl)
|
||||
storageFile = try FileHandle(forUpdating: storageFileUrl)
|
||||
if #available(macOS 10.15.4, *) {
|
||||
try storageFile.seekToEnd()
|
||||
} else {
|
||||
storageFile.seekToEndOfFile()
|
||||
}
|
||||
}
|
||||
|
||||
static func prepareFile(at url: URL) throws -> FileHandle {
|
||||
if !FileManager.default.fileExists(atPath: url.path) {
|
||||
|
@ -16,7 +16,7 @@ final class PlayerManagement: DiskWriter {
|
||||
/// A reverse mapping between generated access tokens and player name
|
||||
private var playerNameForToken = [SessionToken: PlayerName]()
|
||||
|
||||
let storageFile: FileHandle
|
||||
var storageFile: FileHandle
|
||||
|
||||
let storageFileUrl: URL
|
||||
|
||||
@ -25,7 +25,8 @@ final class PlayerManagement: DiskWriter {
|
||||
|
||||
storageFileUrl = url
|
||||
storageFile = try Self.prepareFile(at: url)
|
||||
|
||||
|
||||
var redundantEntries = 0
|
||||
try readLinesFromDisk().forEach { line in
|
||||
let parts = line.components(separatedBy: ":")
|
||||
// Token may contain the separator
|
||||
@ -37,12 +38,29 @@ final class PlayerManagement: DiskWriter {
|
||||
let token = parts.dropFirst().joined(separator: ":")
|
||||
if token == "" {
|
||||
playerPasswordHashes[name] = nil
|
||||
} else {
|
||||
playerPasswordHashes[name] = token
|
||||
redundantEntries += 2 // One for creation, one for deletion
|
||||
return
|
||||
}
|
||||
if playerPasswordHashes[name] != nil {
|
||||
redundantEntries += 1
|
||||
}
|
||||
playerPasswordHashes[name] = token
|
||||
}
|
||||
|
||||
print("Loaded \(playerPasswordHashes.count) players")
|
||||
let playerCount = playerPasswordHashes.count
|
||||
let totalEntries = playerCount + redundantEntries
|
||||
let percentage = playerCount * 100 / totalEntries
|
||||
print("Loaded \(playerCount) players from \(totalEntries) entries (\(percentage) % useful)")
|
||||
if percentage < 80 && redundantEntries > 10 {
|
||||
try optimizePlayerFile()
|
||||
}
|
||||
}
|
||||
|
||||
private func optimizePlayerFile() throws {
|
||||
print("Optimizing player file...")
|
||||
let lines = playerPasswordHashes.map { $0.key + ":" + $0.value + "\n" }.joined()
|
||||
try replaceFile(data: lines)
|
||||
print("Done.")
|
||||
}
|
||||
|
||||
private func save(password: PasswordHash, forPlayer player: PlayerName) -> Bool {
|
||||
|
@ -13,7 +13,7 @@ final class TableManagement: DiskWriter {
|
||||
private var tables = [TableId : ManageableTable]()
|
||||
|
||||
/// The handle to the file where the tables are persisted
|
||||
let storageFile: FileHandle
|
||||
var storageFile: FileHandle
|
||||
|
||||
/// The url to the file where the tables are persisted
|
||||
let storageFileUrl: URL
|
||||
@ -30,6 +30,7 @@ final class TableManagement: DiskWriter {
|
||||
storageFile = try Self.prepareFile(at: url)
|
||||
|
||||
var entries = [TableId : (name: TableName, isPublic: Bool, players: [PlayerName])]()
|
||||
var redundantEntries = 0
|
||||
try readLinesFromDisk().forEach { line in
|
||||
// Each line has parts: ID | NAME | PLAYER, PLAYER, ...
|
||||
let parts = line.components(separatedBy: ":")
|
||||
@ -43,14 +44,37 @@ final class TableManagement: DiskWriter {
|
||||
let players = parts[3].components(separatedBy: ",")
|
||||
if name == "" {
|
||||
entries[id] = nil
|
||||
} else {
|
||||
entries[id] = (name, isPublic, players)
|
||||
redundantEntries += 2 // One for creation, one for deletion
|
||||
return
|
||||
}
|
||||
if entries[id] != nil {
|
||||
redundantEntries += 1
|
||||
}
|
||||
entries[id] = (name, isPublic, players)
|
||||
}
|
||||
entries.forEach { id, tableData in
|
||||
tables[id] = WaitingTable(id: id, name: tableData.name, isPublic: tableData.isPublic, players: tableData.players)
|
||||
}
|
||||
print("Loaded \(tables.count) tables")
|
||||
let totalEntries = entries.count + redundantEntries
|
||||
let percentage = entries.count * 100 / totalEntries
|
||||
print("Loaded \(tables.count) tables from \(totalEntries) entries (\(percentage) % useful)")
|
||||
if percentage < 80 && redundantEntries > 10 {
|
||||
try optimizeTableFile()
|
||||
}
|
||||
}
|
||||
|
||||
private func optimizeTableFile() throws {
|
||||
print("Optimizing tables file...")
|
||||
let lines = tables.values.map(entry).joined(separator: "\n") + "\n"
|
||||
try replaceFile(data: lines)
|
||||
print("Done.")
|
||||
}
|
||||
|
||||
private func entry(for table: ManageableTable) -> String {
|
||||
let visible = table.isPublic ? "public" : "private"
|
||||
let players = table.playerNames
|
||||
.joined(separator: ",")
|
||||
return [table.id, table.name, visible, players].joined(separator: ":")
|
||||
}
|
||||
|
||||
/**
|
||||
@ -62,11 +86,7 @@ final class TableManagement: DiskWriter {
|
||||
*/
|
||||
@discardableResult
|
||||
private func writeTableToDisk(table: ManageableTable) -> Bool {
|
||||
let visible = table.isPublic ? "public" : "private"
|
||||
let players = table.playerNames
|
||||
.joined(separator: ",")
|
||||
let entry = [table.id, table.name, visible, players]
|
||||
.joined(separator: ":")
|
||||
let entry = entry(for: table)
|
||||
return writeToDisk(line: entry)
|
||||
}
|
||||
|
||||
@ -187,6 +207,9 @@ final class TableManagement: DiskWriter {
|
||||
}
|
||||
tables[newTable.id] = newTable
|
||||
newTable.sendUpdateToAllPlayers()
|
||||
if newTable is FinishedTable || newTable is DealingTable {
|
||||
writeTableToDisk(table: newTable)
|
||||
}
|
||||
return .success
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user