public void RemoveKeyIfStillThere(TWeakOwningKey weakOwningKey) { lock (mLock) { WeakOwningKeyToContained.Remove(weakOwningKey); } }
public TContained GetAndBuildIfAbsent(TWeakOwningKey weakOwningKey, Func <TContained> buildANewOne) { lock (mLock) // key - it builds *inside* the lock { return(WeakOwningKeyToContained.GetValue(weakOwningKey, k => buildANewOne())); } }
public TSharedContained GetFromWeakOwningKey(TWeakOwningKey weakOwningKey) // resource key is more a guard at this stage that you were ever an intentional client. { lock (mLock) { return(WeakOwningKeyToContained.GetValue(weakOwningKey, _ => throw new Exception("No - assumption of this wider container that key existence implies membership always - grave coding or assumption error in container.")).Item1); } }
public TContained GetValue(TWeakOwningKey weakOwningKey) { lock (mLock) { return(WeakOwningKeyToContained.GetValue(weakOwningKey, _ => throw new Exception("No - assumption of this wider container that key existence implies membership always - grave coding or assumption error in container."))); } }
public void Add(TWeakOwningKey weakOwningKey, TContained contained) { lock (mLock) { WeakOwningKeyToContained.Add(weakOwningKey, contained); } }
public TContained SwapOutValueWithExistingAsAtomicOperation(TWeakOwningKey weakOwningKey, TContained replacementValue) { lock (mLock) // key - it builds *inside* the lock { var preReplacementValue = WeakOwningKeyToContained.GetValue(weakOwningKey, _ => throw new Exception("No - assumption of this wider container that key existence implies membership always - grave coding or assumption error in container.")); WeakOwningKeyToContained.Remove(weakOwningKey); // the add doesn't allow a duplicate WeakOwningKeyToContained.Add(weakOwningKey, replacementValue); return(preReplacementValue); } }
// This would be 'always' if Shared were made a hard direct reference public void AddKeyIfValueAvailable(TWeakOwningKey weakOwningKey) { lock (mLock) { if (PossibleRecovery.TryGetTarget(out var currentContained)) { var newKeyHolderID = Guid.NewGuid(); var newKeyHolder = NewWeakOwningKeyLifeWatcher(mLock, IDToWeakOfOwningKey, newKeyHolderID); IDToWeakOfOwningKey.Add(newKeyHolderID, new WeakReference <TWeakOwningKey>(weakOwningKey)); WeakOwningKeyToContained.Add(weakOwningKey, Tuple.Create(currentContained, newKeyHolder)); } } }
public void AddUnrepresentedKeyWithRecreateIfMissing(TWeakOwningKey weakOwningKey, Func <TSharedContained> toCreateIfMissing) { var newKeyHolderID = Guid.NewGuid(); var newKeyHolder = NewWeakOwningKeyLifeWatcher(mLock, IDToWeakOfOwningKey, newKeyHolderID); lock (mLock) { if (PossibleRecovery.TryGetTarget(out var currentContained)) { WeakOwningKeyToContained.Add(weakOwningKey, Tuple.Create(currentContained, newKeyHolder)); // can fail/grenade IDToWeakOfOwningKey.Add(newKeyHolderID, new WeakReference <TWeakOwningKey>(weakOwningKey)); } else { currentContained = toCreateIfMissing(); PossibleRecovery.SetTarget(currentContained); WeakOwningKeyToContained.Add(weakOwningKey, Tuple.Create(currentContained, newKeyHolder)); // can fail/grenade IDToWeakOfOwningKey.Add(newKeyHolderID, new WeakReference <TWeakOwningKey>(weakOwningKey)); } } }
// At first glance, this may look redundant - why not return Option<TContained> then the caller build it to the new key and insert it? // Then, realize that the use case may have others come in from different threads with the same key!! // Currently, holding the full lock thwarts this outright, the next guy will simply find the value. // Perhaps another would be to extend the container to have a per-weak-owning-key lockable. // Or WeakOwningKeyToContained containing Either<Func<TContained>, TContained> and have the left portion have a closed-over 'wait' // However, because ergonomically .Match(x => x(), x => x) will be inside lock (mLock) so the wait and PulseAll may have to be off of mLock // Minor performance matter but the Wait then has to be a loop as all are awakened. // // Better would be to have the 'Either' but simply factor the primary lock and have everyone return an 'either' out of it. public TContained GetAndIfAbsentBuildSplitInjectAndOuterReturnInsideTheLock(TWeakOwningKey weakOwningKey, Func <InjectAndOuterReturn <TContained> > getToInjectAndOuterReturn) { lock (mLock) // key - it builds *inside* the lock { var ifNotInitiallyFoundThisIsInjectAndOuterReturn = None <InjectAndOuterReturn <TContained> >(); var r = WeakOwningKeyToContained.GetValue(weakOwningKey, k => { // weakOwningKey/k (which should be identical) are irrelevant. var toInjectAndOuterReturn = getToInjectAndOuterReturn(); ifNotInitiallyFoundThisIsInjectAndOuterReturn = Some(toInjectAndOuterReturn); // mark outer code that this path was taken and has a return that's different to what's to be injected return(toInjectAndOuterReturn.ToInject); }); // Really, the to-inject decision is made inside of the underlying container's lock - this could be outside of mLock FWIW return (ifNotInitiallyFoundThisIsInjectAndOuterReturn.Match( x => x.ToReturn, // injected, use the inject-return () => r // found first time, return *that* )); } }
public AddKeyResult AddKeyIfNotAlreadyPresentWithRecreateIfMissing(TWeakOwningKey weakOwningKey, Func <TSharedContained> toCreateIfMissing) { //var newKeyHolderID = Guid.NewGuid(); //var newKeyHolder = NewWeakOwningKeyLifeWatcher(mLock, IDToWeakOfOwningKey, newKeyHolderID); lock (mLock) { if (PossibleRecovery.TryGetTarget(out var currentContained)) { if (WeakOwningKeyToContained.TryGetValue(weakOwningKey, out var existing)) { // already exists - do nothing return(new AddKeyResult(addedWeakOwningKeyAsNew: false, createdIfMissing: false)); // one way or another, it was already there } else { var newKeyHolderID = Guid.NewGuid(); var newKeyHolder = NewWeakOwningKeyLifeWatcher(mLock, IDToWeakOfOwningKey, newKeyHolderID); WeakOwningKeyToContained.Add(weakOwningKey, Tuple.Create(currentContained, newKeyHolder)); // should never fail - no existing IDToWeakOfOwningKey.Add(newKeyHolderID, new WeakReference <TWeakOwningKey>(weakOwningKey)); return(new AddKeyResult(addedWeakOwningKeyAsNew: true, createdIfMissing: false)); } } else { if (WeakOwningKeyToContained.TryGetValue(weakOwningKey, out var existing)) { // already exists - do nothing throw new Exception("Contradiction - Recovery value doesn't exist but value slot does!"); } else { currentContained = toCreateIfMissing(); PossibleRecovery.SetTarget(currentContained); var newKeyHolderID = Guid.NewGuid(); var newKeyHolder = NewWeakOwningKeyLifeWatcher(mLock, IDToWeakOfOwningKey, newKeyHolderID); WeakOwningKeyToContained.Add(weakOwningKey, Tuple.Create(currentContained, newKeyHolder)); // can fail/grenade IDToWeakOfOwningKey.Add(newKeyHolderID, new WeakReference <TWeakOwningKey>(weakOwningKey)); return(new AddKeyResult(addedWeakOwningKeyAsNew: true, createdIfMissing: true)); } } /* * if (PossibleRecovery.TryGetTarget(out var currentContained)) * { * IDToWeakOfOwningKey.Add(newKeyHolderID, new WeakReference<TWeakOwningKey>(weakOwningKey)); * * * } * else * { * IDToWeakOfOwningKey.Add(newKeyHolderID, new WeakReference<TWeakOwningKey>(weakOwningKey)); * * * currentContained = toCreateIfMissing(); * PossibleRecovery.SetTarget(currentContained); * } * * if (WeakOwningKeyToContained.TryGetValue(weakOwningKey, out var existing)) * { // already exists * WeakOwningKeyToContained.Remove() * } * else * { * WeakOwningKeyToContained.Add(weakOwningKey, Tuple.Create(currentContained, newKeyHolder)); * } */ } }
public TContained GetAndBuildIfAbsent(TWeakOwningKey weakOwningKey, Func <TContained> buildANewOne) { // internally locks return(WeakOwningKeyToContained.GetValue(weakOwningKey, k => buildANewOne())); }
public void Add(TWeakOwningKey weakOwningKey, TContained contained) { // this internally locks WeakOwningKeyToContained.Add(weakOwningKey, contained); }