| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| namespace Apache.Ignite.Internal.Buffers |
| { |
| using System.Buffers; |
| using System.Collections.Concurrent; |
| using System.Diagnostics; |
| using System.Reflection; |
| |
| /// <summary> |
| /// Wrapper for the standard <see cref="ArrayPool{T}.Shared"/> with safety checks in debug mode. |
| /// </summary> |
| internal static class ByteArrayPool |
| { |
| #if DEBUG |
| /// <summary> |
| /// Gets the currently rented arrays. |
| /// </summary> |
| public static readonly ConcurrentDictionary<byte[], MethodBase> CurrentlyRentedArrays = new(); |
| |
| /// <summary> |
| /// Track pooled arrays in debug mode to detect double-return - the most dangerous scenario which can cause application-wide |
| /// memory corruption, when the same array is returned from the pool twice and used concurrently. |
| /// |
| /// In the future there should be some built-in ways to detect this: |
| /// https://github.com/dotnet/runtime/issues/7532. |
| /// </summary> |
| private static readonly System.Runtime.CompilerServices.ConditionalWeakTable<byte[], object?> ReturnedArrays = new(); |
| #endif |
| |
| /// <summary> |
| /// Retrieves a buffer that is at least the requested length. |
| /// </summary> |
| /// <param name="minimumLength">The minimum length of the array.</param> |
| /// <returns>An byte array that is at least <paramref name="minimumLength" /> in length.</returns> |
| public static byte[] Rent(int minimumLength) |
| { |
| var bytes = ArrayPool<byte>.Shared.Rent(minimumLength); |
| |
| #if DEBUG |
| var stackTrace = new StackTrace(); |
| var frame = stackTrace.GetFrame(1); |
| |
| CurrentlyRentedArrays.TryAdd(bytes, frame!.GetMethod()!); |
| ReturnedArrays.Remove(bytes); |
| #endif |
| |
| return bytes; |
| } |
| |
| /// <summary> |
| /// Returns an array to the pool that was previously obtained using the <see cref="Rent" /> method. |
| /// </summary> |
| /// <param name="array">A buffer to return to the pool that was previously obtained using the <see cref="Rent" /> method.</param> |
| public static void Return(byte[] array) |
| { |
| #if DEBUG |
| CurrentlyRentedArrays.TryRemove(array, out _); |
| |
| // Will throw when key exists. |
| ReturnedArrays.Add(array, null); |
| #endif |
| |
| ArrayPool<byte>.Shared.Return(array); |
| } |
| } |
| } |