/// <summary> /// Initializes a new instance of the <see cref="BucketCircularArray{T}"/> class. /// </summary> /// <param name="size">The maximum number of buckets to store.</param> public BucketCircularArray(int size) { AtomicReferenceArray <T> buckets = new AtomicReferenceArray <T>(size + 1); // + 1 as extra room for the add/remove BucketCircularArrayListState listState = new BucketCircularArrayListState(buckets, 0, 0); this.state = new AtomicReference <BucketCircularArrayListState>(listState); }
/// <summary> /// Appends an item to the end of the circular array. /// </summary> /// <param name="item">The item to add.</param> public void AddLast(T item) { BucketCircularArrayListState currentState = this.state.Value; BucketCircularArrayListState newState = currentState.AddBucket(item); // use CompareAndSet to set in case multiple threads are attempting (which shouldn't be the case // because since AddLast will ONLY be called by a single thread at a time due to protection // provided in GetCurrentBucket) if (this.state.CompareAndSet(currentState, newState)) { // we succeeded return; } else { // we failed, someone else was adding or removing // instead of trying again and risking multiple AddLast concurrently (which shouldn't be the case) // we'll just return and let the other thread 'win' and if the timing is off the next call to GetCurrentBucket will fix things return; } }
/// <summary> /// Clears the array. /// </summary> public void Clear() { while (true) { // it should be very hard to not succeed the first pass thru since this is typically is only called from // a single thread protected by a tryLock, but there is at least 1 other place (at time of writing this comment) // where reset can be called from (CircuitBreaker.markSuccess after circuit was tripped) so it can // in an edge-case conflict. // // Instead of trying to determine if someone already successfully called clear() and we should skip // we will have both calls reset the circuit, even if that means losing data added in between the two // depending on thread scheduling. // // The rare scenario in which that would occur, we'll accept the possible data loss while clearing it // since the code has stated its desire to clear() anyways. BucketCircularArrayListState current = this.state.Value; BucketCircularArrayListState newState = current.Clear(); if (this.state.CompareAndSet(current, newState)) { return; } } }