private bool TryBecomeConductor() { try { _writeSeriesLocks.Add(_conductorLock, Pid); } catch (ArgumentException) { } long conductorPid; if (_writeSeriesLocks.TryGetValue(_conductorLock, out conductorPid)) { if (conductorPid == Pid) { LogConductorPid(Pid); return(true); } if (IsProcessAlive(conductorPid)) { return(false); } // TODO need atomic CAS operations on dictionary, however in this case it is not very important, we should not open/close repos many times _writeSeriesLocks[_conductorLock] = Pid; LogConductorPid(Pid); return(true); } throw new ApplicationException("Value must exist"); }
private async Task Upgrade <K, V>(UUID seriesId, PersistentSeries <K, V> series) { if (!series.IsWriter) { try { _writeSeriesLocks.Add(seriesId, Pid); series.IsWriter = true; LogAcquireLock(seriesId, series.Version); return; } catch (ArgumentException) { } } while (true) { // wait if a writer from the same repo releases lock var released = await series.LockReleaseEvent.WaitAsync(1000); if (released) { try { // TODO TryAdd atomic method _writeSeriesLocks.Add(seriesId, Pid); series.IsWriter = true; LogAcquireLock(seriesId, series.Version); break; } catch (ArgumentException) { Trace.WriteLine("Could not upgrade after lock release, some one jumped ahead of us"); } } else { int pid; if (_writeSeriesLocks.TryGetValue(seriesId, out pid)) { try { Process.GetProcessById(pid & ((1 << 16) - 1)); Trace.TraceWarning("Tried to steal a lock but the owner process was alive."); } catch (ArgumentException) { // pid is not running anymore, steal lock Trace.TraceWarning($"Current process {Pid} has stolen a lock left by a dead process {pid}. If you see this often then dispose SeriesRepository properly before application exit."); _writeSeriesLocks[seriesId] = Pid; series.IsWriter = true; LogAcquireLock(seriesId, series.Version); break; } } } } }