- 
                Notifications
    
You must be signed in to change notification settings  - Fork 841
 
Migrate HybridCache from aspnetcore to extensions #5391
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
          
     Merged
      
      
    
  
     Merged
                    Changes from 5 commits
      Commits
    
    
            Show all changes
          
          
            10 commits
          
        
        Select commit
          Hold shift + click to select a range
      
      349d769
              
                migrate hybridcache from dotnet/aspnetcore
              
              
                mgravell e845d63
              
                fix additional DEBUG build warnings
              
              
                mgravell f118bfe
              
                pragma S3251 (ignored partial for debug API)
              
              
                mgravell 7776bdc
              
                nowarn LA0003
              
              
                mgravell 389975e
              
                PR nits
              
              
                mgravell fb09156
              
                - add depenency chain, workflow, etc
              
              
                mgravell 632df82
              
                mark HybridCache as "dev" for now
              
              
                mgravell da7a86d
              
                improve readme
              
              
                mgravell b207cae
              
                Merge branch 'dev' into hybrid_cache
              
              
                mgravell b38fcb8
              
                Merge branch 'dev' into hybrid_cache
              
              
                mgravell File filter
Filter by extension
Conversations
          Failed to load comments.   
        
        
          
      Loading
        
  Jump to
        
          Jump to file
        
      
      
          Failed to load files.   
        
        
          
      Loading
        
  Diff view
Diff view
There are no files selected for viewing
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
            Binary file not shown.
          
    
        
          
  
    
      
          
            62 changes: 62 additions & 0 deletions
          
          62 
        
  src/Libraries/Microsoft.Extensions.Caching.Hybrid/HybridCacheBuilderExtensions.cs
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| 
     | 
||
| using System.Diagnostics.CodeAnalysis; | ||
| using Microsoft.Extensions.Caching.Hybrid; | ||
| using Microsoft.Shared.Diagnostics; | ||
| 
     | 
||
| namespace Microsoft.Extensions.DependencyInjection; | ||
| 
     | 
||
| /// <summary> | ||
| /// Configuration extension methods for <see cref="IHybridCacheBuilder"/> / <see cref="HybridCache"/>. | ||
| /// </summary> | ||
| public static class HybridCacheBuilderExtensions | ||
| { | ||
| /// <summary> | ||
| /// Serialize values of type <typeparamref name="T"/> with the specified serializer from <paramref name="serializer"/>. | ||
| /// </summary> | ||
| /// <typeparam name="T">The type to be serialized.</typeparam> | ||
| /// <returns>The <see cref="IHybridCacheBuilder"/> instance.</returns> | ||
| public static IHybridCacheBuilder AddSerializer<T>(this IHybridCacheBuilder builder, IHybridCacheSerializer<T> serializer) | ||
| { | ||
| _ = Throw.IfNull(builder).Services.AddSingleton<IHybridCacheSerializer<T>>(serializer); | ||
| return builder; | ||
| } | ||
| 
     | 
||
| /// <summary> | ||
| /// Serialize values of type <typeparamref name="T"/> with the serializer of type <typeparamref name="TImplementation"/>. | ||
| /// </summary> | ||
| /// <typeparam name="T">The type to be serialized.</typeparam> | ||
| /// <typeparam name="TImplementation">The serializer to use for this type.</typeparam> | ||
| /// <returns>The <see cref="IHybridCacheBuilder"/> instance.</returns> | ||
| public static IHybridCacheBuilder AddSerializer<T, | ||
| [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TImplementation>(this IHybridCacheBuilder builder) | ||
| where TImplementation : class, IHybridCacheSerializer<T> | ||
| { | ||
| _ = Throw.IfNull(builder).Services.AddSingleton<IHybridCacheSerializer<T>, TImplementation>(); | ||
| return builder; | ||
| } | ||
| 
     | 
||
| /// <summary> | ||
| /// Add <paramref name="factory"/> as an additional serializer factory, which can provide serializers for multiple types. | ||
| /// </summary> | ||
| /// <returns>The <see cref="IHybridCacheBuilder"/> instance.</returns> | ||
| public static IHybridCacheBuilder AddSerializerFactory(this IHybridCacheBuilder builder, IHybridCacheSerializerFactory factory) | ||
| { | ||
| _ = Throw.IfNull(builder).Services.AddSingleton<IHybridCacheSerializerFactory>(factory); | ||
| return builder; | ||
| } | ||
| 
     | 
||
| /// <summary> | ||
| /// Add a factory of type <typeparamref name="TImplementation"/> as an additional serializer factory, which can provide serializers for multiple types. | ||
| /// </summary> | ||
| /// <typeparam name="TImplementation">The type of the serializer factory.</typeparam> | ||
| /// <returns>The <see cref="IHybridCacheBuilder"/> instance.</returns> | ||
| public static IHybridCacheBuilder AddSerializerFactory< | ||
| [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TImplementation>(this IHybridCacheBuilder builder) | ||
| where TImplementation : class, IHybridCacheSerializerFactory | ||
| { | ||
| _ = Throw.IfNull(builder).Services.AddSingleton<IHybridCacheSerializerFactory, TImplementation>(); | ||
| return builder; | ||
| } | ||
| } | 
        
          
  
    
      
          
            44 changes: 44 additions & 0 deletions
          
          44 
        
  src/Libraries/Microsoft.Extensions.Caching.Hybrid/HybridCacheOptions.cs
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| 
     | 
||
| namespace Microsoft.Extensions.Caching.Hybrid; | ||
| 
     | 
||
| /// <summary> | ||
| /// Options for configuring the default <see cref="HybridCache"/> implementation. | ||
| /// </summary> | ||
| public class HybridCacheOptions | ||
| { | ||
| private const int ShiftBytesToMibiBytes = 20; | ||
| 
     | 
||
| /// <summary> | ||
| /// Gets or sets the default global options to be applied to <see cref="HybridCache"/> operations; if options are | ||
| /// specified at the individual call level, the non-null values are merged (with the per-call | ||
| /// options being used in preference to the global options). If no value is specified for a given | ||
| /// option (globally or per-call), the implementation may choose a reasonable default. | ||
| /// </summary> | ||
| public HybridCacheEntryOptions? DefaultEntryOptions { get; set; } | ||
| 
     | 
||
| /// <summary> | ||
| /// Gets or sets a value indicating whether compression for this <see cref="HybridCache"/> instance is disabled. | ||
| /// </summary> | ||
| public bool DisableCompression { get; set; } | ||
| 
     | 
||
| /// <summary> | ||
| /// Gets or sets the maximum size of cache items; attempts to store values over this size will be logged | ||
| /// and the value will not be stored in cache. | ||
| /// </summary> | ||
| /// <remarks>The default value is 1 MiB.</remarks> | ||
| public long MaximumPayloadBytes { get; set; } = 1 << ShiftBytesToMibiBytes; // 1MiB | ||
| 
     | 
||
| /// <summary> | ||
| /// Gets or sets the maximum permitted length (in characters) of keys; attempts to use keys over this size will be logged. | ||
| /// </summary> | ||
| /// <remark>The default value is 1024 characters.</remark> | ||
| public int MaximumKeyLength { get; set; } = 1024; // characters | ||
| 
     | 
||
| /// <summary> | ||
| /// Gets or sets a value indicating whether to use "tags" data as dimensions on metric reporting; if enabled, care should be used to ensure that | ||
| /// tags do not contain data that should not be visible in metrics systems. | ||
| /// </summary> | ||
| public bool ReportTagMetrics { get; set; } | ||
| } | 
        
          
  
    
      
          
            44 changes: 44 additions & 0 deletions
          
          44 
        
  src/Libraries/Microsoft.Extensions.Caching.Hybrid/HybridCacheServiceExtensions.cs
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| 
     | 
||
| using System; | ||
| using Microsoft.Extensions.Caching.Hybrid; | ||
| using Microsoft.Extensions.Caching.Hybrid.Internal; | ||
| using Microsoft.Extensions.DependencyInjection.Extensions; | ||
| using Microsoft.Shared.Diagnostics; | ||
| 
     | 
||
| namespace Microsoft.Extensions.DependencyInjection; | ||
| 
     | 
||
| /// <summary> | ||
| /// Configuration extension methods for <see cref="HybridCache"/>. | ||
| /// </summary> | ||
| public static class HybridCacheServiceExtensions | ||
| { | ||
| /// <summary> | ||
| /// Adds support for multi-tier caching services. | ||
| /// </summary> | ||
| /// <returns>A builder instance that allows further configuration of the <see cref="HybridCache"/> system.</returns> | ||
| public static IHybridCacheBuilder AddHybridCache(this IServiceCollection services, Action<HybridCacheOptions> setupAction) | ||
| { | ||
| _ = Throw.IfNull(setupAction); | ||
| _ = AddHybridCache(services); | ||
| _ = services.Configure(setupAction); | ||
| return new HybridCacheBuilder(services); | ||
| } | ||
| 
     | 
||
| /// <summary> | ||
| /// Adds support for multi-tier caching services. | ||
| /// </summary> | ||
| /// <returns>A builder instance that allows further configuration of the <see cref="HybridCache"/> system.</returns> | ||
| public static IHybridCacheBuilder AddHybridCache(this IServiceCollection services) | ||
| { | ||
| _ = Throw.IfNull(services); | ||
| services.TryAddSingleton(TimeProvider.System); | ||
| _ = services.AddOptions().AddMemoryCache(); | ||
| services.TryAddSingleton<IHybridCacheSerializerFactory, DefaultJsonSerializerFactory>(); | ||
| services.TryAddSingleton<IHybridCacheSerializer<string>>(InbuiltTypeSerializer.Instance); | ||
| services.TryAddSingleton<IHybridCacheSerializer<byte[]>>(InbuiltTypeSerializer.Instance); | ||
| services.TryAddSingleton<HybridCache, DefaultHybridCache>(); | ||
| return new HybridCacheBuilder(services); | ||
| } | ||
| } | 
        
          
  
    
      
          
            17 changes: 17 additions & 0 deletions
          
          17 
        
  src/Libraries/Microsoft.Extensions.Caching.Hybrid/IHybridCacheBuilder.cs
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| 
     | 
||
| using Microsoft.Extensions.DependencyInjection; | ||
| 
     | 
||
| namespace Microsoft.Extensions.Caching.Hybrid; | ||
| 
     | 
||
| /// <summary> | ||
| /// Helper API for configuring <see cref="HybridCache"/>. | ||
| /// </summary> | ||
| public interface IHybridCacheBuilder | ||
| { | ||
| /// <summary> | ||
| /// Gets the services collection associated with this instance. | ||
| /// </summary> | ||
| IServiceCollection Services { get; } | ||
| } | 
        
          
  
    
      
          
            94 changes: 94 additions & 0 deletions
          
          94 
        
  src/Libraries/Microsoft.Extensions.Caching.Hybrid/Internal/BufferChunk.cs
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| 
     | 
||
| using System; | ||
| using System.Buffers; | ||
| using System.Diagnostics; | ||
| using System.Runtime.CompilerServices; | ||
| 
     | 
||
| namespace Microsoft.Extensions.Caching.Hybrid.Internal; | ||
| 
     | 
||
| // Used to convey buffer status; like ArraySegment<byte>, but Offset is always | ||
| // zero, and we use the most significant bit of the length (usually the sign flag, | ||
| // but we do not need to support negative length) to track whether or not | ||
| // to recycle this value. | ||
| internal readonly struct BufferChunk | ||
| { | ||
| private const int FlagReturnToPool = (1 << 31); | ||
| 
     | 
||
| private readonly int _lengthAndPoolFlag; | ||
| 
     | 
||
| public byte[]? Array { get; } // null for default | ||
                
      
                  RussKie marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| public int Length => _lengthAndPoolFlag & ~FlagReturnToPool; | ||
| 
     | 
||
| public bool ReturnToPool => (_lengthAndPoolFlag & FlagReturnToPool) != 0; | ||
| 
     | 
||
| public byte[] ToArray() | ||
| { | ||
| var length = Length; | ||
| if (length == 0) | ||
| { | ||
| return []; | ||
| } | ||
| 
     | 
||
| var copy = new byte[length]; | ||
| Buffer.BlockCopy(Array!, 0, copy, 0, length); | ||
                
      
                  RussKie marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| return copy; | ||
| 
     | 
||
| // Note on nullability of Array; the usage here is that a non-null array | ||
| // is always provided during construction, so the only null scenario is for default(BufferChunk). | ||
| // Since the constructor explicitly accesses array.Length, any null array passed to the constructor | ||
| // will cause an exception, even in release (the Debug.Assert only covers debug) - although in | ||
| // reality we do not expect this to ever occur (internal type, usage checked, etc). In the case of | ||
| // default(BufferChunk), we know that Length will be zero, which means we will hit the [] case. | ||
                
      
                  mgravell marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| } | ||
| 
     | 
||
| public BufferChunk(byte[] array) | ||
| { | ||
| Debug.Assert(array is not null, "expected valid array input"); | ||
                
      
                  RussKie marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| Array = array; | ||
| _lengthAndPoolFlag = array!.Length; | ||
| 
     | 
||
| // assume not pooled, if exact-sized | ||
| // (we don't expect array.Length to be negative; we're really just saying | ||
| // "we expect the result of assigning array.Length to _lengthAndPoolFlag | ||
| // to give the expected Length *and* not have the MSB set; we're just | ||
| // checking that we haven't fat-fingered our MSB logic) | ||
| Debug.Assert(!ReturnToPool, "do not return right-sized arrays"); | ||
| Debug.Assert(Length == array.Length, "array length not respected"); | ||
                
      
                  RussKie marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| } | ||
| 
     | 
||
| public BufferChunk(byte[] array, int length, bool returnToPool) | ||
| { | ||
| Debug.Assert(array is not null, "expected valid array input"); | ||
| Debug.Assert(length >= 0, "expected valid length"); | ||
| Array = array; | ||
| _lengthAndPoolFlag = length | (returnToPool ? FlagReturnToPool : 0); | ||
| Debug.Assert(ReturnToPool == returnToPool, "return-to-pool not respected"); | ||
| Debug.Assert(Length == length, "length not respected"); | ||
| } | ||
| 
     | 
||
| internal void RecycleIfAppropriate() | ||
| { | ||
| if (ReturnToPool) | ||
| { | ||
| ArrayPool<byte>.Shared.Return(Array!); | ||
| } | ||
| 
     | 
||
| Unsafe.AsRef(in this) = default; // anti foot-shotgun double-return guard; not 100%, but worth doing | ||
| Debug.Assert(Array is null && !ReturnToPool, "expected clean slate after recycle"); | ||
| } | ||
| 
     | 
||
| // get the data as a ROS; for note on null-logic of Array!, see comment in ToArray | ||
| internal ReadOnlySequence<byte> AsSequence() => Length == 0 ? default : new ReadOnlySequence<byte>(Array!, 0, Length); | ||
                
      
                  RussKie marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| internal BufferChunk DoNotReturnToPool() | ||
| { | ||
| var copy = this; | ||
| Unsafe.AsRef(in copy._lengthAndPoolFlag) &= ~FlagReturnToPool; | ||
| Debug.Assert(copy.Length == Length, "same length expected"); | ||
| Debug.Assert(!copy.ReturnToPool, "do not return to pool"); | ||
| return copy; | ||
| } | ||
| } | ||
      
      Oops, something went wrong.
        
    
  
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
Uh oh!
There was an error while loading. Please reload this page.