2.Garnet 配置

1.Options

Garnet中所有可配置的选项

2.RedisOptions

Garnet兼容redis配置文件,以及部分配置项包括:“bind”,“port”,“maxmemory” 等等。

3.RedisConfigSerializer Redis配置序列化器

 while ((line = reader.ReadLine()) != null)
 {
     lineCount++;

     // Ignore whitespaces and comments
     if (string.IsNullOrWhiteSpace(line) || line.TrimStart().StartsWith('#'))
         continue;

     // Expected line format: keyword argument1 argument2 ... argumentN
     var sepIdx = line.IndexOf(' ');
     if (sepIdx == -1)
         throw new RedisSerializationException(
             $"Unable to deserialize {nameof(RedisOptions)} object. Line {lineCount} not in expected format (keyword argument1 argument2 ... argumentN).");

     // Ignore key when no matching property found 
     var key = line.Substring(0, sepIdx);
     if (!KeyToProperty.Value.ContainsKey(key))
     {
         logger?.LogWarning($"Redis configuration option not supported: {key}.");
         continue;
     }

     var value = line.Substring(sepIdx + 1);

     // Get matching property & the underlying option type (T in Option<T>)
     var prop = KeyToProperty.Value[key];
     var optType = prop.PropertyType.GenericTypeArguments.First();

     // Try to deserialize the value
     if (!TryChangeType(value, typeof(string), optType, out var newVal))
     {
         // If unsuccessful and if underlying option type is an array, try to deserialize array by elements
         if (optType.IsArray)
         {
             // Split the values in the serialized array
             var values = value.Split(' ');

             // Instantiate a new array
             var elemType = optType.GetElementType();
             newVal = Array.CreateInstance(elemType, values.Length);

             // Try deserializing and setting array elements
             for (var i = 0; i < values.Length; i++)
             {
                 if (!TryChangeType(values[i], typeof(string), elemType, out var elem))
                     throw new RedisSerializationException(
                         $"Unable to deserialize {nameof(RedisOptions)} object. Unable to convert object of type {typeof(string)} to object of type {elemType}. (Line: {lineCount}; Key: {key}; Property: {prop.Name}).");


                 ((Array)newVal).SetValue(elem, i);
             }
         }
         else
         {
             throw new RedisSerializationException(
                 $"Unable to deserialize {nameof(RedisOptions)} object. Unable to convert object of type {typeof(string)} to object of type {optType}. (Line: {lineCount}; Key: {key}; Property: {prop.Name}).");
         }
     }

     // Create a new Option<T> object
     var newOpt = Activator.CreateInstance(prop.PropertyType);

     // Set the underlying option value
     var valueProp = prop.PropertyType.GetProperty(nameof(Option<object>.Value));
     valueProp.SetValue(newOpt, newVal);

     // Set the options property to the new option object
     prop.SetValue(options, newOpt);

     // Append usage warning, if defined
     var redisOptionAttr = (RedisOptionAttribute)prop.GetCustomAttributes(typeof(RedisOptionAttribute), false).First();
     if (!string.IsNullOrEmpty(redisOptionAttr.UsageWarning))
     {
         logger?.LogWarning($"Redis configuration option usage warning ({key}): {redisOptionAttr.UsageWarning}");
     }
 }

使用while循环逐行读取文件流,并且转换为RedisOptions实体,转换失败的字段也会报出RedisSerializationException异常。这里面有一个比较又意思设计:

[RedisOption("bind", nameof(Options.Address), BindWarning, typeof(ArrayToFirstItemTransformer<string>))]
public Option<string[]> Bind { get; set; }

RedisOptions中字段类型使用了Option进行包裹,因此在序列化的时候稍微麻烦一点。

4.IConfigProvider 配置提供器

/// <summary>
/// Interface for importing / exporting options from different configuration file types
/// </summary>
internal interface IConfigProvider
{
    /// <summary>
    /// Import an Options object from path using a stream provider
    /// </summary>
    /// <param name="path">Path to the config file containing the serialized object</param>
    /// <param name="streamProvider">Stream provider to use when reading from the path</param>
    /// <param name="options">Options object to populate with deserialized options</param>
    /// <param name="logger">Logger</param>
    /// <returns>True if import succeeded</returns>
    bool TryImportOptions(string path, IStreamProvider streamProvider, Options options, ILogger logger);

    /// <summary>
    /// Export an Options object to path using a stream provider
    /// </summary>
    /// <param name="path">Path to the config file to write into</param>
    /// <param name="streamProvider">Stream provider to use when writing to the path</param>
    /// <param name="options">Options object to serialize</param>
    /// <param name="logger">Logger</param>
    /// <returns>True if export succeeded</returns>
    bool TryExportOptions(string path, IStreamProvider streamProvider, Options options, ILogger logger);
}

RedisConfigProvider与GarnetConfigProvider共同继承IConfigProvider用来导出或者导入配置项,GarnetConfigProvider用于提供Options,导出方法中使用了JsonConvert用来序列化Options;RedisConfigProvider则用于提供RedisOptions,导出方法中使用了RedisConfigSerializer 用来序列化RedisOptions。

5.IGarnetCustomTransformer 自定义转换器

/// <summary>
/// Defines an interface for custom transformers that transform a RedisOptions property value to an Options property value and vice versa
/// The custom transformer is specified by the RedisOptionAttribute decorating the RedisOptions property
/// </summary>
/// <typeparam name="TIn">RedisOptions property value type</typeparam>
/// <typeparam name="TOut">Options property value type</typeparam>
internal interface IGarnetCustomTransformer<TIn, TOut>
{
    /// <summary>
    /// Transforms a RedisOptions property value to an Options property value
    /// </summary>
    /// <param name="input">RedisOptions property value</param>
    /// <param name="output">Options property value</param>
    /// <param name="errorMessage">Error message, empty if no error occurred</param>
    /// <returns>True if transform successful</returns>
    bool Transform(TIn input, out TOut output, out string errorMessage);

    /// <summary>
    /// Transforms an Options property value back to a RedisOptions property value
    /// </summary>
    /// <param name="input">Options property value</param>
    /// <param name="output">RedisOptions property value</param>
    /// <param name="errorMessage">Error message, empty if no error occurred</param>
    /// <returns>True if transform successful</returns>
    bool TransformBack(TOut input, out TIn output, out string errorMessage);
}

用于将RedisOptions属性值转换为Options属性值,反之亦然

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值