/// <summary> /// Increment shared instance id and return a process buffer with new Wpid /// </summary> /// <returns></returns> public ProcessConfigRecord CreateNew() { using (var txn = Environment.BeginTransaction()) { while (true) { // ReSharper disable once ImpureMethodCallOnReadonlyValueField var newInsatnceId = unchecked ((uint)SharedRecord._processBuffer.InterlockedIncrementInt32(ProcessConfigRecord.SharedInstanceIdCounterOffset)); try { // We try to increment instance id instead of reuse existing // At some point after running for very very long time it might overflow // and start from zero again - this is fine. if (_processDb.TryGet(txn, ref newInsatnceId, out BufferRef bufferRef)) { continue; } bufferRef = Allocate(txn, 0, out var fromFreeList, null); _processDb.Put(txn, newInsatnceId, bufferRef, TransactionPutOptions.NoOverwrite); txn.Commit(); if (!fromFreeList) { Environment.Sync(true); } var result = _buckets[bufferRef]; if (fromFreeList) { // in Delete we clear the buffer after commit, there is small chance a process died after commit but before cleaning result.Clear(0, result.Length); } else { Debug.Assert(result.IsFilledWithValue(0), "a new ProcessConfig buffer must be clean."); } result.WriteInt64(ProcessConfigRecord.WpidOffset, Wpid.Create(newInsatnceId)); var record = new ProcessConfigRecord(result); return(record); } catch (Exception ex) { txn.Abort(); Trace.TraceError(ex.ToString()); throw; } } } }
public ProcessConfigStorage(string directoryPath) : base(directoryPath, StartupConfig.ProcessConfigEnvFlags, default, ProcessConfigRecord.BufferSize, 1024L * 1024 * 1024) // 1GB is way too much but it takes no resources above actually used { // BRA dbs and _env are set in base class // InstanceId -> BufferRef _processDb = Environment.OpenDatabase("_processConfig", new DatabaseConfig(DbFlags.Create | DbFlags.IntegerKey)); _buckets = new SharedMemoryBuckets(directoryPath, ProcessConfigRecord.BufferSize, 0); using (var txn = Environment.BeginTransaction()) { try { uint sharedInstanceId = 0; if (_processDb.TryGet(txn, ref sharedInstanceId, out BufferRef sharedBufferRef)) { txn.Abort(); } else { sharedBufferRef = Allocate(txn, 0, out var fromFreeList, null); _processDb.Put(txn, sharedInstanceId, sharedBufferRef, TransactionPutOptions.NoOverwrite); txn.Commit(); if (!fromFreeList) { Environment.Sync(true); } } SharedRecord = new ProcessConfigRecord(_buckets[sharedBufferRef]); } catch (Exception ex) { txn.Abort(); Trace.TraceError(ex.ToString()); throw; } } }
public bool Delete(ProcessConfigRecord processConfigRecord) { if (!processConfigRecord.IsValid) { return(false); } using (var txn = Environment.BeginTransaction()) { var wpid = processConfigRecord.Wpid; // Debug.Assert(!IsWpidAlive(processConfigRecord)); uint insatnceId = wpid.InstanceId; try { // We try to increment instance id instead of reuse existing // At some point after running for very very long time it might overflow // and start from zero again - this is fine. if (!_processDb.TryGet(txn, ref insatnceId, out BufferRef bufferRef)) { // was already deleted // TODO (?) throw? review txn.Abort(); return(false); } Free(txn, bufferRef); _processDb.Delete(txn, insatnceId); txn.Commit(); var db = _buckets[bufferRef]; db.Clear(0, db.Length); return(true); } catch (Exception ex) { txn.Abort(); Trace.TraceError(ex.ToString()); throw; } } }