tryAcquireLock method

Future<int?> tryAcquireLock()

Acquire: write PID -> mtime = now. Returns the pre-acquire mtime (for rollback), or null if blocked / lost a race.

Implementation

Future<int?> tryAcquireLock() async {
  int? mtimeMs;
  int? holderPid;

  try {
    final results = await Future.wait([
      statMtimeMs(_lockPath),
      readFileOrNull(_lockPath),
    ]);
    mtimeMs = results[0] as int?;
    final raw = results[1] as String?;
    if (raw != null) {
      final parsed = int.tryParse(raw.trim());
      holderPid = parsed;
    }
  } catch (_) {
    // ENOENT — no prior lock.
  }

  if (mtimeMs != null &&
      DateTime.now().millisecondsSinceEpoch - mtimeMs < _holderStaleMs) {
    if (holderPid != null && isProcessRunning(holderPid)) {
      logDebug(
        '[autoDream] lock held by live PID $holderPid '
        '(mtime ${((DateTime.now().millisecondsSinceEpoch - mtimeMs) / 1000).round()}s ago)',
      );
      return null;
    }
    // Dead PID or unparseable body — reclaim.
  }

  // Memory dir may not exist yet.
  await mkdirRecursive(getAutoMemPath());
  await writeFile(_lockPath, pid.toString());

  // Two reclaimers both write -> last wins the PID. Loser bails on re-read.
  String? verify;
  try {
    verify = await readFileOrNull(_lockPath);
  } catch (_) {
    return null;
  }
  if (verify == null || int.tryParse(verify.trim()) != pid) return null;

  return mtimeMs ?? 0;
}