Exemple #1
0
        /// <summary>
        /// Allocates a generic fragment with a specified length.
        /// </summary>
        /// <param name="size">The number of bytes to allocate.</param>
        /// <param name="tries">
        /// The number of fails before switching to another lane.
        /// If 0 the HighwaySettings.LaneAllocTries value is used.
        /// </param>
        /// <param name="awaitMS">The awaitMS for each try</param>
        /// <returns>A new fragment.</returns>
        /// <exception cref="System.ArgumentOutOfRangeException">
        /// If size is negative or greater than HighwaySettings.MAX_LANE_CAPACITY.
        /// </exception>
        /// <exception cref="System.MemoryLaneException">
        /// Code.NotInitialized: when the lanes are not initialized.
        /// Code.NewLaneAllocFail: after an unsuccessful attempt to allocate a fragment in a dedicated new lane.
        /// One should never see this one!
        /// </exception>
        /// <exception cref="ObjectDisposedException">If the MemoryCarriage is disposed.</exception>
        public F Alloc(int size, int tries = 0, int awaitMS = 5)
        {
            if (isDisposed)
            {
                throw new ObjectDisposedException("MemoryCarriage");
            }
            if (Lanes == null || Lanes.AllocatedSlots == 0)
            {
                throw new MemoryLaneException(MemoryLaneException.Code.NotInitialized);
            }
            if (size < 0 || size > HighwaySettings.MAX_LANE_CAPACITY)
            {
                throw new ArgumentOutOfRangeException("size");
            }
            if (tries == 0)
            {
                tries = settings.LaneAllocTries;
            }

            F   frag       = null;
            var lanesCount = Lanes.ItemsCount;

            // Start from the oldest lane and cycle all lanes a few times before making a new lane
            for (var laps = 0; laps < settings.LapsBeforeNewLane; laps++)
            {
                for (var i = 0; i < lanesCount; i++)
                {
                    var lane = Lanes[i];

                    if (lane != null && !lane.IsClosed && !lane.IsDisposed)
                    {
                        frag = createFragment(lane, size, tries, awaitMS);

                        if (frag != null)
                        {
                            Volatile.Write(ref lastAllocTickAnyLane, DateTime.Now.Ticks);
                            return(frag);
                        }
                    }
                }
            }

            // limits the concurrent lane allocations
            if (noluckGate.Wait(settings.NewLaneAllocationTimeoutMS))
            {
                // Try again, there is at least one new lane
                if (lanesCount < Lanes.ItemsCount)
                {
                    noluckGate.Release();
                    return(Alloc(size, tries, awaitMS));
                }
                else
                {
                    try
                    {
                        // [i] No luck, create a new lane and do not publish it before getting a fragment

                        var ccMakers     = settings.ConcurrentNewLaneAllocations - noluckGate.CurrentCount;
                        var nextCapacity = settings.NextCapacity(Lanes.AppendIndex + ccMakers);
                        var cap          = size > nextCapacity ? size : nextCapacity;
                        var ml           = allocLane(cap, true);

                        // Could be null if the MaxLanesCount or MaxBytesCount exceptions are ignored.
                        // The consumer can infer that by checking if the fragment is null.
                        if (ml != null)
                        {
                            frag = createFragment(ml, size, tries, awaitMS);

                            if (frag == null)
                            {
                                throw new MemoryLaneException(
                                          MemoryLaneException.Code.NewLaneAllocFail,
                                          string.Format("Failed to allocate {0} bytes on a dedicated lane.", size));
                            }

                            Lanes.Append(ml);
                            Volatile.Write(ref lastAllocTickAnyLane, DateTime.Now.Ticks);
                        }
                    }
                    finally { noluckGate.Release(); }
                }
            }

            return(frag);
        }