Refactor concurrency handling to introduce STALE_HEARTBEAT_THRESHOLD_MS constant and utilize SweepstoreWorkerTicketSnapshot for improved state management

This commit is contained in:
ImBenji
2025-11-23 20:27:08 +00:00
parent 580f07c483
commit f8e8636677
4 changed files with 98 additions and 85 deletions

View File

@@ -8,6 +8,9 @@ import 'package:sweepstore/header.dart';
import 'package:sweepstore/helpers.dart';
import 'package:sweepstore/structures.dart';
// Stale Heartbeat threshold in milliseconds
const int STALE_HEARTBEAT_THRESHOLD_MS = 5000; // 5 seconds
int _randomId() {
// mix timestamp with random for better uniquness
// keep it positive to avoid signed int issues when storing
@@ -77,7 +80,7 @@ void spawnTicket(RandomAccessFile file, {
int identifier = ticketSnapshot.identifier;
bool identifier_unassigned = identifier == 0;
bool stale_heartbeat = (DateTime.now().millisecondsSinceEpoch32() - ticketSnapshot.workerHeartbeat) > 2000;
bool stale_heartbeat = (DateTime.now().millisecondsSinceEpoch32() - ticketSnapshot.workerHeartbeat) > STALE_HEARTBEAT_THRESHOLD_MS;
bool is_free = ticketSnapshot.ticketState == SweepstoreTicketState.FREE;
if (identifier_unassigned && stale_heartbeat && is_free) {
@@ -132,13 +135,15 @@ void spawnTicket(RandomAccessFile file, {
// Wait for approval - (Approval loop)
while (true) {
SweepstoreWorkerTicketSnapshot snapshot = myTicket.snapshot();
// Check we still own the ticket
if (myTicket.identifier != myIdentifier) {
String exceptionMessage = "CRITICAL: Lost ownership of ticket ${myTicket.ticketIndex}, was expecting identifier $myIdentifier but found ${myTicket.identifier}.";
if (snapshot.identifier != myIdentifier) {
String exceptionMessage = "CRITICAL: Lost ownership of ticket ${myTicket.ticketIndex}, was expecting identifier $myIdentifier but found ${snapshot.identifier}.";
throw Exception(exceptionMessage);
}
if (myTicket.ticketState == SweepstoreTicketState.APPROVED) {
if (snapshot.ticketState == SweepstoreTicketState.APPROVED) {
myTicket.write(
ticketState: SweepstoreTicketState.EXECUTING,
);
@@ -155,9 +160,9 @@ void spawnTicket(RandomAccessFile file, {
// Update heartbeat
int now = DateTime.now().millisecondsSinceEpoch32();
if (now - myTicket.workerHeartbeat > 700) {
if (now - snapshot.workerHeartbeat > 700) {
myTicket.write(
workerHeartbeat: DateTime.now().millisecondsSinceEpoch32()
workerHeartbeat: now
);
}
}
@@ -182,16 +187,17 @@ void initialiseMasterListener(RandomAccessFile file) async {
for (int i = 0; i < concurrencyHeader.numberOfWorkers; i++) {
SweepstoreWorkerTicket ticket = concurrencyHeader[i];
SweepstoreWorkerTicketSnapshot snapshot = ticket.snapshot();
if (ticket.ticketState == SweepstoreTicketState.WAITING) {
log("Found waiting ticket $i (Key Hash: ${ticket.keyHash})...");
if (snapshot.ticketState == SweepstoreTicketState.WAITING) {
log("Found waiting ticket $i (Key Hash: ${snapshot.keyHash})...");
// Approve the ticket
ticket.write(
ticketState: SweepstoreTicketState.APPROVED,
);
log("Approved ticket $i.");
} else if (ticket.ticketState == SweepstoreTicketState.COMPLETED) {
} else if (snapshot.ticketState == SweepstoreTicketState.COMPLETED) {
log("Ticket $i completed. Resetting ticket...");
// Reset the ticket
ticket.write(