Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

VBucket support

- VBucketNodeLocator
- keyTransformer, nodeLocator and trascoder providers can now be instantiated by a factory so custom initialization is possible. (this brings a breaking change in the config file: their attributes are now elements)
- ported some hashes from hashkit
- unit tests are missing
  • Loading branch information...
commit ff351fade1ed927c7c421082b14da9dfafc883d6 1 parent 7321456
@enyim authored
Showing with 1,109 additions and 117 deletions.
  1. +7 −19 Enyim.Caching/App.config
  2. +1 −1  Enyim.Caching/Configuration/AuthenticationElement.cs
  3. +34 −0 Enyim.Caching/Configuration/ConfigurationElementException.cs
  4. +42 −0 Enyim.Caching/Configuration/ConfigurationHelper.cs
  5. +1 −33 Enyim.Caching/Configuration/EndPointElement.cs
  6. +6 −6 Enyim.Caching/Configuration/IMemcachedClientConfiguration.cs
  7. +54 −0 Enyim.Caching/Configuration/IVBucketConfiguration.cs
  8. +86 −0 Enyim.Caching/Configuration/JsonVBucketConfig.cs
  9. +9 −11 Enyim.Caching/Configuration/MemcachedClientConfiguration.cs
  10. +18 −29 Enyim.Caching/Configuration/MemcachedClientSection.cs
  11. +111 −0 Enyim.Caching/Configuration/ProviderElement.cs
  12. +11 −0 Enyim.Caching/Enyim.Caching.csproj
  13. +30 −0 Enyim.Caching/FastActivator.cs
  14. +26 −5 Enyim.Caching/FnvHash.cs
  15. +172 −0 Enyim.Caching/HashkitCrc32.cs
  16. +143 −0 Enyim.Caching/HashkitMurmur.cs
  17. +108 −0 Enyim.Caching/HashkitOneAtATime.cs
  18. +38 −0 Enyim.Caching/IUIntHashAlgorithm.cs
  19. +1 −1  Enyim.Caching/Memcached/IMemcachedNodeLocator.cs
  20. +34 −0 Enyim.Caching/Memcached/IProviderFactory.cs
  21. +5 −11 Enyim.Caching/Memcached/ServerPool.cs
  22. +104 −0 Enyim.Caching/Memcached/VBucketNodeLocator.cs
  23. +67 −0 Enyim.Caching/Memcached/VBucketNodeLocatorFactory.cs
  24. +1 −1  Enyim.Caching/MemcachedClient.cs
View
26 Enyim.Caching/App.config
@@ -4,8 +4,6 @@
<sectionGroup name="enyim.com">
<section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching" />
</sectionGroup>
-
- <section name="northscale" type="NorthScale.Store.Configuration.NorthScaleClientSection, NorthScale.Store" />
</configSections>
<!--
@@ -13,8 +11,7 @@
Note: you must have the enyim.com/memcached section if you're using the parameterless constructor of EnyimMemcachedClient.
-->
<enyim.com>
- <!-- binary protocol needs more reallife testing so if you're not
- comfortable with it, change it back to protocol="Text" -->
+ <!-- you can use protocol="Text" if your memcached is < 1.3 but you should probably upgrade -->
<memcached protocol="Binary">
<servers>
<!-- make sure you use the same ordering of nodes in every configuration you have -->
@@ -24,22 +21,13 @@
<add address="127.0.0.1" port="20008" />
</servers>
<socketPool minPoolSize="10" maxPoolSize="100" connectionTimeout="00:10:00" deadTimeout="00:02:00" />
+
+ <!-- uncomment the section below if your memcached instance requires authentication
+
+ <authentication type="Enyim.Caching.Memcached.PlainTextAuthenticator" zone="AUTHZ" userName="user name" password="password" />
+
+ -->
</memcached>
</enyim.com>
- <!--
- Use this section as a template if you're connecting to NorthScale Mecached Servers.
- Note: you must have the top-level northscale section if you're using the parameterless constructor of NorthScaleClient.
- -->
- <northscale transcoder="Enyim.Caching.Memcached.DefaultTranscoder, Enyim.Caching">
- <!-- bucket is optional and can be specified in the constructor,
- so you can use the same configuration to connect to different buckets in the cluster -->
- <servers bucket="enyim">
- <!-- provide at least 2-3 urls from your cluster -->
- <add uri="http://192.168.2.100:8080/pools/default" />
- <add uri="http://192.168.2.102:8080/pools/default" />
- </servers>
- <socketPool minPoolSize="10" maxPoolSize="100" connectionTimeout="00:00:10" />
- </northscale>
-
</configuration>
View
2  Enyim.Caching/Configuration/AuthenticationElement.cs
@@ -10,7 +10,7 @@ namespace Enyim.Caching.Configuration
/// </summary>
public sealed class AuthenticationElement : ConfigurationElement, IAuthenticationConfiguration
{
- // TODO make this element play nice with the configuratino system (allow saving, etc.)
+ // TODO make this element play nice with the configuration system (allow saving, etc.)
private Dictionary<string, object> parameters = new Dictionary<string, object>();
/// <summary>
View
34 Enyim.Caching/Configuration/ConfigurationElementException.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Configuration;
+
+namespace Enyim.Caching.Configuration
+{
+ internal class ConfigurationElementException : ConfigurationErrorsException
+ {
+ public ConfigurationElementException(string message, ConfigurationElement element) : this(message, null, element) { }
+ public ConfigurationElementException(string message, Exception inner, ConfigurationElement element) : base(message, inner, element.ElementInformation.Source, element.ElementInformation.LineNumber) { }
+ }
+}
+
+#region [ License information ]
+/* ************************************************************
+ *
+ * Copyright (c) 2010 Attila Kiskó, enyim.com
+ *
+ * Licensed 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.
+ *
+ * ************************************************************/
+#endregion
View
42 Enyim.Caching/Configuration/ConfigurationHelper.cs
@@ -1,4 +1,6 @@
using System;
+using System.Linq;
+using System.Net;
namespace Enyim.Caching.Configuration
{
@@ -6,9 +8,49 @@ public static class ConfigurationHelper
{
public static void CheckForInterface(Type type, Type interfaceType)
{
+ if (type == null || interfaceType == null) return;
+
if (Array.IndexOf<Type>(type.GetInterfaces(), interfaceType) == -1)
throw new System.Configuration.ConfigurationErrorsException("The type " + type.AssemblyQualifiedName + " must implement " + interfaceType.AssemblyQualifiedName);
}
+
+ internal static IPEndPoint ResolveToEndPoint(string value)
+ {
+ if (String.IsNullOrEmpty(value))
+ throw new ArgumentNullException("value");
+
+ var parts = value.Split(':');
+ if (parts.Length != 2)
+ throw new ArgumentException("host:port is expected", "value");
+
+ int port;
+ if (!Int32.TryParse(parts[1], out port))
+ throw new ArgumentException("Cannot parse port: " + parts[1], "value");
+
+ return ResolveToEndPoint(parts[0], port);
+ }
+
+ internal static IPEndPoint ResolveToEndPoint(string host, int port)
+ {
+ if (String.IsNullOrEmpty(host))
+ throw new ArgumentNullException("host");
+
+ IPAddress address;
+
+ // parse as an IP address
+ if (!IPAddress.TryParse(host, out address))
+ {
+ // not an ip, resolve from dns
+ // TODO we need to find a way to specify whihc ip should be used when the host has several
+ var entry = System.Net.Dns.GetHostEntry(host);
+ address = entry.AddressList.FirstOrDefault(ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork);
+
+ if (address == null)
+ throw new ArgumentException(String.Format("Could not resolve host '{0}'.", host));
+ }
+
+ return new IPEndPoint(address, port);
+ }
}
}
View
34 Enyim.Caching/Configuration/EndPointElement.cs
@@ -36,39 +36,7 @@ public int Port
/// </summary>
public System.Net.IPEndPoint EndPoint
{
- get
- {
- if (this.endpoint == null)
- {
- IPAddress address;
-
- if (!IPAddress.TryParse(this.Address, out address))
- {
- IPHostEntry entry = System.Net.Dns.GetHostEntry(this.Address);
- IPAddress[] list = entry.AddressList;
-
- if (list.Length == 0)
- throw new ConfigurationErrorsException(String.Format("Could not resolve host '{0}'.", this.Address));
-
- // get the first IPv4 address from the list (not sure how memcached works against ipv6 addresses whihc are not localhost)
- for (int i = 0; i < list.Length; i++)
- {
- if (list[i].AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
- {
- address = list[i];
- break;
- }
- }
-
- if (address == null)
- throw new ConfigurationErrorsException(String.Format("Host '{0}' does not have an IPv4 address.", this.Address));
- }
-
- this.endpoint = new System.Net.IPEndPoint(address, this.Port);
- }
-
- return this.endpoint;
- }
+ get { return this.endpoint ?? (this.endpoint = ConfigurationHelper.ResolveToEndPoint(this.Address, this.Port)); }
}
#region [ T:IPAddressValidator ]
View
12 Enyim.Caching/Configuration/IMemcachedClientConfiguration.cs
@@ -26,19 +26,19 @@ public interface IMemcachedClientConfiguration
IAuthenticationConfiguration Authentication { get; }
/// <summary>
- /// Gets or sets the type of the <see cref="T:Enyim.Caching.Memcached.IMemcachedKeyTransformer"/> which will be used to convert item keys for Memcached.
+ /// Creates an <see cref="T:Enyim.Caching.Memcached.IMemcachedKeyTransformer"/> instance which will be used to convert item keys for Memcached.
/// </summary>
- Type KeyTransformer { get; set; }
+ IMemcachedKeyTransformer CreateKeyTransformer();
/// <summary>
- /// Gets or sets the type of the <see cref="T:Enyim.Caching.Memcached.IMemcachedNodeLocator"/> which will be used to assign items to Memcached nodes.
+ /// Creates an <see cref="T:Enyim.Caching.Memcached.IMemcachedNodeLocator"/> instance which will be used to assign items to Memcached nodes.
/// </summary>
- Type NodeLocator { get; set; }
+ IMemcachedNodeLocator CreateNodeLocator();
/// <summary>
- /// Gets or sets the type of the <see cref="T:Enyim.Caching.Memcached.ITranscoder"/> which will be used serialzie or deserialize items.
+ /// Creates an <see cref="T:Enyim.Caching.Memcached.ITranscoder"/> instance which will be used to serialize or deserialize items.
/// </summary>
- Type Transcoder { get; set; }
+ ITranscoder CreateTranscoder();
/// <summary>
/// Gets or sets the type of the communication between client and server.
View
54 Enyim.Caching/Configuration/IVBucketConfiguration.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Security.Cryptography;
+using System.Net;
+using System.Web.Script.Serialization;
+using System.Collections.ObjectModel;
+using System.Web;
+
+namespace Enyim.Caching.Configuration
+{
+ public interface IVBucketConfiguration
+ {
+ HashAlgorithm CreateHashAlgorithm();
+ IList<IPEndPoint> Servers { get; }
+ IList<VBucket> Buckets { get; }
+ }
+
+ public struct VBucket
+ {
+ private int master;
+ private int[] replicas;
+
+ public VBucket(int master, int[] replicas)
+ {
+ this.master = master;
+ this.replicas = replicas;
+ }
+
+ public int Master { get { return this.master; } }
+ public int[] Replicas { get { return this.replicas; } }
+ }
+}
+
+#region [ License information ]
+/* ************************************************************
+ *
+ * Copyright (c) 2010 Attila Kiskó, enyim.com
+ *
+ * Licensed 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.
+ *
+ * ************************************************************/
+#endregion
View
86 Enyim.Caching/Configuration/JsonVBucketConfig.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Security.Cryptography;
+using System.Net;
+using System.Web.Script.Serialization;
+using Enyim.Caching.Configuration;
+
+namespace Enyim.Caching.Configuration
+{
+ /// <summary>
+ /// Parses a json formatted vbucket config.
+ /// </summary>
+ public class JsonVBucketConfig : IVBucketConfiguration
+ {
+ private Func<HashAlgorithm> factory;
+ private IPEndPoint[] servers;
+ private VBucket[] buckets;
+
+ public JsonVBucketConfig(string json)
+ {
+ var config = new JavaScriptSerializer().Deserialize<_JsonConfig>(json);
+
+ if (config.numReplicas < 0)
+ throw new ArgumentException("Invalid numReplicas: " + config.numReplicas, "json");
+
+ if (hashFactory.TryGetValue(config.hashAlgorithm, out this.factory))
+ throw new ArgumentException("Unknown hash algorithm: " + config.hashAlgorithm, "json");
+
+ this.servers = config.serverList.Select(endpoint => ConfigurationHelper.ResolveToEndPoint(endpoint)).ToArray();
+ this.buckets = config.vBucketMap.Select((bucket, index) =>
+ {
+ if (bucket == null || bucket.Length != config.numReplicas + 1)
+ throw new ArgumentException("Invalid bucket definition at index " + index, "json");
+
+ return new VBucket(bucket[0], bucket.Skip(1).Take(config.numReplicas)/* .Where(v => v > -1) */.ToArray());
+ }).ToArray();
+ }
+
+ #region [ _JsonConfig ]
+
+ private class _JsonConfig
+ {
+ public string hashAlgorithm;
+ public int numReplicas;
+ public string[] serverList;
+ public int[][] vBucketMap;
+ }
+
+ #endregion
+ #region [ IVBucketConfiguration ]
+
+ HashAlgorithm IVBucketConfiguration.CreateHashAlgorithm()
+ {
+ return factory();
+ }
+
+ IList<IPEndPoint> IVBucketConfiguration.Servers
+ {
+ get { return this.servers; }
+ }
+
+ IList<VBucket> IVBucketConfiguration.Buckets
+ {
+ get { return this.buckets; }
+ }
+
+ #endregion
+ #region [ hashFactory ]
+
+ private static readonly Dictionary<string, Func<HashAlgorithm>> hashFactory = new Dictionary<string, Func<HashAlgorithm>>(StringComparer.OrdinalIgnoreCase)
+ {
+ { String.Empty, () => new HashkitOneAtATime() },
+ { "default", () => new HashkitOneAtATime() },
+ { "crc", () => new HashkitCrc32() },
+ { "fnv1_32", () => new Enyim.FNV1() },
+ { "fnv1_64", () => new Enyim.FNV1a() },
+ { "fnv1a_32", () => new Enyim.FNV64() },
+ { "fnv1a_64", () => new Enyim.FNV64a() },
+ { "murmur", () => new HashkitMurmur() }
+ };
+
+ #endregion
+ }
+}
View
20 Enyim.Caching/Configuration/MemcachedClientConfiguration.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Net;
using Enyim.Caching.Memcached;
+using Enyim.Reflection;
namespace Enyim.Caching.Configuration
{
@@ -17,7 +18,7 @@ public class MemcachedClientConfiguration : IMemcachedClientConfiguration
private Type nodeLocator;
private Type transcoder;
private MemcachedProtocol protocol;
-
+
/// <summary>
/// Initializes a new instance of the <see cref="T:MemcachedClientConfiguration"/> class.
/// </summary>
@@ -27,7 +28,7 @@ public MemcachedClientConfiguration()
this.socketPool = new SocketPoolConfiguration();
this.authentication = new AuthenticationConfiguration();
- this.Protocol = MemcachedProtocol.Text;
+ this.Protocol = MemcachedProtocol.Binary;
}
/// <summary>
@@ -122,22 +123,19 @@ IAuthenticationConfiguration IMemcachedClientConfiguration.Authentication
get { return this.authentication; }
}
- Type IMemcachedClientConfiguration.KeyTransformer
+ IMemcachedKeyTransformer IMemcachedClientConfiguration.CreateKeyTransformer()
{
- get { return this.KeyTransformer; }
- set { this.KeyTransformer = value; }
+ return (IMemcachedKeyTransformer)FastActivator2.Create(this.KeyTransformer);
}
- Type IMemcachedClientConfiguration.NodeLocator
+ IMemcachedNodeLocator IMemcachedClientConfiguration.CreateNodeLocator()
{
- get { return this.NodeLocator; }
- set { this.NodeLocator = value; }
+ return (IMemcachedNodeLocator)FastActivator2.Create(this.NodeLocator);
}
- Type IMemcachedClientConfiguration.Transcoder
+ ITranscoder IMemcachedClientConfiguration.CreateTranscoder()
{
- get { return this.Transcoder; }
- set { this.Transcoder = value; }
+ return (ITranscoder)FastActivator2.Create(this.Transcoder);
}
MemcachedProtocol IMemcachedClientConfiguration.Protocol
View
47 Enyim.Caching/Configuration/MemcachedClientSection.cs
@@ -5,6 +5,7 @@
using System.Net;
using System.Web.Configuration;
using Enyim.Caching.Memcached;
+using Enyim.Reflection;
namespace Enyim.Caching.Configuration
{
@@ -42,33 +43,24 @@ public AuthenticationElement Authentication
set { base["authentication"] = value; }
}
- /// <summary>
- /// Gets or sets the type of the <see cref="T:Enyim.Caching.Memcached.IMemcachedKeyTransformer"/> which will be used to convert item keys for Memcached.
- /// </summary>
- [ConfigurationProperty("keyTransformer", IsRequired = false), TypeConverter(typeof(TypeNameConverter)), InterfaceValidator(typeof(Enyim.Caching.Memcached.IMemcachedKeyTransformer))]
- public Type KeyTransformer
+ [ConfigurationProperty("locator", IsRequired = false)]
+ public ProviderElement<IMemcachedNodeLocator> NodeLocator
{
- get { return (Type)base["keyTransformer"]; }
- set { base["keyTransformer"] = value; }
+ get { return (ProviderElement<IMemcachedNodeLocator>)base["locator"]; }
+ set { base["locator"] = value; }
}
- /// <summary>
- /// Gets or sets the type of the <see cref="T:Enyim.Caching.Memcached.IMemcachedNodeLocator"/> which will be used to assign items to Memcached nodes.
- /// </summary>
- [ConfigurationProperty("nodeLocator", IsRequired = false), TypeConverter(typeof(TypeNameConverter)), InterfaceValidator(typeof(Enyim.Caching.Memcached.IMemcachedNodeLocator))]
- public Type NodeLocator
+ [ConfigurationProperty("keyTransformer", IsRequired = false)]
+ public ProviderElement<IMemcachedKeyTransformer> KeyTransformer
{
- get { return (Type)base["nodeLocator"]; }
- set { base["nodeLocator"] = value; }
+ get { return (ProviderElement<IMemcachedKeyTransformer>)base["keyTransformer"]; }
+ set { base["keyTransformer"] = value; }
}
- /// <summary>
- /// Gets or sets the type of the <see cref="T:Enyim.Caching.Memcached.ITranscoder"/> which will be used serialzie or deserialize items.
- /// </summary>
- [ConfigurationProperty("transcoder", IsRequired = false), TypeConverter(typeof(TypeNameConverter)), InterfaceValidator(typeof(Enyim.Caching.Memcached.ITranscoder))]
- public Type Transcoder
+ [ConfigurationProperty("transcoder", IsRequired = false)]
+ public ProviderElement<ITranscoder> Transcoder
{
- get { return (Type)base["transcoder"]; }
+ get { return (ProviderElement<ITranscoder>)base["transcoder"]; }
set { base["transcoder"] = value; }
}
@@ -106,22 +98,19 @@ ISocketPoolConfiguration IMemcachedClientConfiguration.SocketPool
get { return this.SocketPool; }
}
- Type IMemcachedClientConfiguration.KeyTransformer
+ IMemcachedKeyTransformer IMemcachedClientConfiguration.CreateKeyTransformer()
{
- get { return this.KeyTransformer; }
- set { this.KeyTransformer = value; }
+ return this.KeyTransformer.CreateInstance() ?? new DefaultKeyTransformer();
}
- Type IMemcachedClientConfiguration.NodeLocator
+ IMemcachedNodeLocator IMemcachedClientConfiguration.CreateNodeLocator()
{
- get { return this.NodeLocator; }
- set { this.NodeLocator = value; }
+ return this.NodeLocator.CreateInstance() ?? new DefaultNodeLocator();
}
- Type IMemcachedClientConfiguration.Transcoder
+ ITranscoder IMemcachedClientConfiguration.CreateTranscoder()
{
- get { return this.Transcoder; }
- set { this.Transcoder = value; }
+ return this.Transcoder.CreateInstance() ?? new DefaultTranscoder();
}
IAuthenticationConfiguration IMemcachedClientConfiguration.Authentication
View
111 Enyim.Caching/Configuration/ProviderElement.cs
@@ -0,0 +1,111 @@
+using System;
+using System.ComponentModel;
+using System.Configuration;
+using System.Collections.Generic;
+using Enyim.Caching.Memcached;
+using Enyim.Reflection;
+
+namespace Enyim.Caching.Configuration
+{
+ /// <summary>
+ /// This element defines the IMemcachedNodeLocator used by the client.
+ /// </summary>
+ /// <remarks>This deprecates the nodeLocator attribute (which will be removed later).</remarks>
+ public sealed class ProviderElement<T> : ConfigurationElement
+ where T : class
+ {
+ // TODO make this element play nice with the configuration system (allow saving, etc.)
+ private Dictionary<string, string> parameters = new Dictionary<string, string>();
+ private IProviderFactory<T> factoryInstance;
+
+ /// <summary>
+ /// Gets or sets the type of the provider.
+ /// </summary>
+ [ConfigurationProperty("type", IsRequired = false), TypeConverter(typeof(TypeNameConverter))]
+ public Type Type
+ {
+ get { return (Type)base["type"]; }
+ set
+ {
+ ConfigurationHelper.CheckForInterface(value, typeof(T));
+ base["type"] = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the type of the provider factory.
+ /// </summary>
+ [ConfigurationProperty("factory", IsRequired = false), TypeConverter(typeof(TypeNameConverter))]
+ public Type Factory
+ {
+ get { return (Type)base["factory"]; }
+ set
+ {
+ ConfigurationHelper.CheckForInterface(value, typeof(IProviderFactory<T>));
+
+ base["factory"] = value;
+ }
+ }
+
+ protected override bool OnDeserializeUnrecognizedAttribute(string name, string value)
+ {
+ ConfigurationProperty property = new ConfigurationProperty(name, typeof(string), value);
+ base[property] = value;
+
+ this.parameters[name] = value;
+
+ return true;
+ }
+
+ /// <summary>
+ /// Creates the provider by using the factory (if present) or directly instantiating by type name
+ /// </summary>
+ /// <returns></returns>
+ public T CreateInstance()
+ {
+ //check if we have a factory
+ if (this.factoryInstance == null)
+ {
+ var type = this.Factory;
+ if (type != null)
+ {
+ this.factoryInstance = (IProviderFactory<T>)Activator.CreateInstance(type);
+ this.factoryInstance.Initialize(this.parameters);
+ }
+ }
+
+ // no factory, use the provider type
+ if (this.factoryInstance == null)
+ {
+ var type = this.Type;
+
+ if (type == null)
+ return null;
+
+ return (T)FastActivator2.Create(type);
+ }
+
+ return factoryInstance.Create();
+ }
+ }
+}
+
+#region [ License information ]
+/* ************************************************************
+ *
+ * Copyright (c) 2010 Attila Kiskó, enyim.com
+ *
+ * Licensed 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.
+ *
+ * ************************************************************/
+#endregion
View
11 Enyim.Caching/Enyim.Caching.csproj
@@ -57,11 +57,21 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Configuration\AuthenticationConfiguration.cs" />
+ <Compile Include="Configuration\ConfigurationElementException.cs" />
<Compile Include="Configuration\ConfigurationHelper.cs" />
<Compile Include="Configuration\AuthenticationElement.cs" />
+ <Compile Include="Configuration\ProviderElement.cs" />
<Compile Include="Configuration\IAuthenticationConfiguration.cs" />
+ <Compile Include="Configuration\IVBucketConfiguration.cs" />
+ <Compile Include="Configuration\JsonVBucketConfig.cs" />
<Compile Include="Configuration\SocketPoolConfiguration.cs" />
+ <Compile Include="HashkitCrc32.cs" />
+ <Compile Include="HashkitMurmur.cs" />
+ <Compile Include="HashkitOneAtATime.cs" />
+ <Compile Include="IUIntHashAlgorithm.cs" />
<Compile Include="Memcached\Authentication\PlainTextAuthenticator.cs" />
+ <Compile Include="Memcached\VBucketNodeLocatorFactory.cs" />
+ <Compile Include="Memcached\IProviderFactory.cs" />
<Compile Include="Memcached\IAuthenticator.cs" />
<Compile Include="Memcached\IMemcachedNode.cs" />
<Compile Include="Memcached\IServerPool.cs" />
@@ -132,6 +142,7 @@
<Compile Include="Memcached\ThrowHelper.cs" />
<Compile Include="Memcached\Transcoders\CacheItem.cs" />
<Compile Include="Memcached\Transcoders\ITranscoder.cs" />
+ <Compile Include="Memcached\VBucketNodeLocator.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Memcached\ServerPool.cs" />
<Compile Include="Memcached\StoreMode.cs" />
View
30 Enyim.Caching/FastActivator.cs
@@ -5,9 +5,39 @@
using System.Reflection.Emit;
using System.Text;
using System.Threading;
+using System.Linq.Expressions;
namespace Enyim.Reflection
{
+ public static class FastActivator2
+ {
+ private static class F1<T>
+ {
+ public static readonly Func<T> Factory = Expression.Lambda<Func<T>>(Expression.New(typeof(T))).Compile();
+ }
+
+ public static T Create<T>()
+ {
+ return F1<T>.Factory();
+ }
+
+ private static Dictionary<Type, Func<object>> factoryCache = new Dictionary<Type, Func<object>>();
+
+ public static object Create(Type type)
+ {
+ Func<object> f;
+
+ if (!factoryCache.TryGetValue(type, out f))
+ lock (factoryCache)
+ if (!factoryCache.TryGetValue(type, out f))
+ {
+ factoryCache[type] = f = Expression.Lambda<Func<object>>(Expression.New(type)).Compile();
+ }
+
+ return f();
+ }
+ }
+
/// <summary>
/// <para>Implements a very fast object factory for dynamic object creation. Dynamically generates a factory class which will use the new() constructor of the requested type.</para>
/// <para>Much faster than using Activator at the price of the first invocation being significantly slower than subsequent calls.</para>
View
31 Enyim.Caching/FnvHash.cs
@@ -10,7 +10,7 @@ namespace Enyim
/// Calculation found at http://lists.danga.com/pipermail/memcached/2007-April/003846.html, but
/// it is pretty much available everywhere
/// </remarks>
- public class FNV64 : System.Security.Cryptography.HashAlgorithm
+ public class FNV64 : System.Security.Cryptography.HashAlgorithm, IUIntHashAlgorithm
{
protected const ulong Init = 0xcbf29ce484222325L;
protected const ulong Prime = 0x100000001b3L;
@@ -23,8 +23,6 @@ public class FNV64 : System.Security.Cryptography.HashAlgorithm
public FNV64()
{
base.HashSizeValue = 64;
-
- this.Initialize();
}
/// <summary>
@@ -58,6 +56,18 @@ protected override byte[] HashFinal()
{
return BitConverter.GetBytes(this.CurrentHashValue);
}
+
+ #region [ IUIntHashAlgorithm ]
+
+ uint IUIntHashAlgorithm.ComputeHash(byte[] data)
+ {
+ this.Initialize();
+ this.HashCore(data, 0, data.Length);
+
+ return (uint)this.CurrentHashValue;
+ }
+
+ #endregion
}
/// <summary>
@@ -84,7 +94,7 @@ protected override void HashCore(byte[] array, int ibStart, int cbSize)
/// <summary>
/// Implements an FNV1 hash algorithm.
/// </summary>
- public class FNV1 : HashAlgorithm
+ public class FNV1 : HashAlgorithm, IUIntHashAlgorithm
{
protected const uint Prime = 16777619;
protected const uint Init = 2166136261;
@@ -100,7 +110,6 @@ public class FNV1 : HashAlgorithm
public FNV1()
{
this.HashSizeValue = 32;
- this.Initialize();
}
/// <summary>
@@ -134,6 +143,18 @@ protected override byte[] HashFinal()
{
return BitConverter.GetBytes(this.CurrentHashValue);
}
+
+ #region [ IUIntHashAlgorithm ]
+
+ uint IUIntHashAlgorithm.ComputeHash(byte[] data)
+ {
+ this.Initialize();
+ this.HashCore(data, 0, data.Length);
+
+ return this.CurrentHashValue;
+ }
+
+ #endregion
}
/// <summary>
View
172 Enyim.Caching/HashkitCrc32.cs
@@ -0,0 +1,172 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Security.Cryptography;
+
+namespace Enyim
+{
+ /// <summary>
+ /// CRC-32 implementation. Compatible with libhashkit.
+ /// </summary>
+ internal class HashkitCrc32 : HashAlgorithm, IUIntHashAlgorithm
+ {
+ private bool shouldReset;
+ private uint currentHash;
+
+ public HashkitCrc32()
+ {
+ this.HashSizeValue = 32;
+ this.shouldReset = true;
+ }
+
+ public override void Initialize()
+ {
+ // ComputeHash calls Initialize
+ // so this way we keep the CurrentValue until the next hash calculation
+ this.shouldReset = true;
+ }
+
+ protected override void HashCore(byte[] array, int ibStart, int cbSize)
+ {
+ if (array == null) throw new ArgumentNullException("array");
+ if (ibStart < 0 || ibStart > array.Length) throw new ArgumentOutOfRangeException("ibStart");
+ if (ibStart + cbSize > array.Length) throw new ArgumentOutOfRangeException("length");
+
+ if (this.shouldReset)
+ {
+ this.currentHash = UInt32.MaxValue;
+ this.shouldReset = false;
+ }
+ else
+ this.currentHash ^= UInt32.MaxValue;
+
+ this.UnsafeHashCore(array, ibStart, cbSize);
+ }
+
+ private void FinalizeHash()
+ {
+ // strangely libhaskit truncates CRC-32 to 15 bits. we'll do the same to be on the safe side.
+ this.currentHash = ((~this.currentHash) >> 16) & 0x7fff;
+ }
+
+ protected override byte[] HashFinal()
+ {
+ this.FinalizeHash();
+
+ return BitConverter.GetBytes((uint)currentHash);
+ }
+
+ public uint CurrentHash { get { return this.currentHash; } }
+
+ #region [ UnsafeHashCore ]
+
+ private unsafe void UnsafeHashCore(byte[] buffer, int offset, int count)
+ {
+ fixed (byte* ptr = buffer)
+ {
+ byte* current = ptr + offset;
+
+ while (count > 0)
+ {
+ this.currentHash = CrcTable[(byte)(this.currentHash ^ (*current))] ^ (this.currentHash >> 8);
+
+ count--;
+ current++;
+ }
+ }
+ }
+
+ #endregion
+ #region [ CrcTable ]
+ private static readonly uint[] CrcTable = new uint[]
+ {
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419,
+ 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
+ 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07,
+ 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
+ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856,
+ 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
+ 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
+ 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
+ 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A,
+ 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599,
+ 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190,
+ 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
+ 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E,
+ 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
+ 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
+ 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3,
+ 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
+ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
+ 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
+ 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010,
+ 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17,
+ 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6,
+ 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
+ 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
+ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344,
+ 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
+ 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A,
+ 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1,
+ 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
+ 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
+ 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE,
+ 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
+ 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C,
+ 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B,
+ 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
+ 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1,
+ 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
+ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
+ 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
+ 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66,
+ 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
+ 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8,
+ 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
+ 0x2D02EF8D
+ };
+ #endregion
+ #region [ IUIntHash ]
+
+ uint IUIntHashAlgorithm.ComputeHash(byte[] data)
+ {
+ this.Initialize();
+
+ this.HashCore(data, 0, data.Length);
+ this.FinalizeHash();
+
+ return this.currentHash;
+ }
+
+ #endregion
+ }
+}
+
+#region [ License information ]
+/* ************************************************************
+ *
+ * Copyright (c) 2010 Attila Kiskó, enyim.com
+ *
+ * Licensed 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.
+ *
+ * ************************************************************/
+#endregion
View
143 Enyim.Caching/HashkitMurmur.cs
@@ -0,0 +1,143 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Security.Cryptography;
+
+namespace Enyim
+{
+ /// <summary>
+ /// Murmur hash. Uses the same seed values as libhashkit.
+ /// </summary>
+ /// <remarks>Does not support block based hashing.</remarks>
+ internal class HashkitMurmur : HashAlgorithm, IUIntHashAlgorithm
+ {
+ public HashkitMurmur()
+ {
+ this.HashSizeValue = 32;
+ }
+
+ public override bool CanTransformMultipleBlocks
+ {
+ get { return false; }
+ }
+
+ public override void Initialize() { }
+
+ protected override void HashCore(byte[] array, int ibStart, int cbSize)
+ {
+ if (array == null) throw new ArgumentNullException("array");
+ if (ibStart < 0 || ibStart > array.Length) throw new ArgumentOutOfRangeException("ibStart");
+ if (ibStart + cbSize > array.Length) throw new ArgumentOutOfRangeException("cbSize");
+
+ this.CurrentHash = HashkitMurmur.UnsafeHashCore(array, ibStart, cbSize);
+ }
+
+ protected override byte[] HashFinal()
+ {
+ return BitConverter.GetBytes(this.CurrentHash);
+ }
+
+ public uint CurrentHash { get; private set; }
+
+ #region [ UnsafeHashCore ]
+
+ // this could be rewritten to support streams tho
+ // cache the tail of the buffer if its length is not mod4 then merge with the next buffer (this is a perf hit since we cannot do our pointer magics)
+ // then the swicth and the last XORs could be moved into TransformFinal
+ // -- or --
+ // just cache tail and if we have a cache dvalue and the next block is not mod4 long then throw an exception (thus only allow random length blocks for the last one)
+ static unsafe uint UnsafeHashCore(byte[] data, int offset, int length)
+ {
+ const uint M = 0x5bd1e995;
+ const int R = 24;
+
+ uint seed = (uint)(0xdeadbeef * length);
+ uint hash = (uint)(seed ^ length);
+
+ int count = length >> 2;
+
+ fixed (byte* start = &(data[offset]))
+ {
+ uint* ptrUInt = (uint*)start;
+
+ while (count > 0)
+ {
+ uint current = *ptrUInt;
+
+ current = (uint)(current * M);
+ current ^= current >> R;
+ current = (uint)(current * M);
+ hash = (uint)(hash * M);
+ hash ^= current;
+
+ count--;
+ ptrUInt++;
+ }
+
+ switch (length & 3)
+ {
+ case 3:
+ // reverse the last 3 bytes and convert it to an uint
+ // so cast the last to into an UInt16 and get the 3rd as a byte
+ // ABC --> CBA; (UInt16)(AB) --> BA
+ //h ^= (uint)(*ptrByte);
+ //h ^= (uint)(ptrByte[1] << 8);
+ hash ^= (*(UInt16*)ptrUInt);
+ hash ^= (uint)(((byte*)ptrUInt)[2] << 16);
+ hash *= M;
+ break;
+
+ case 2:
+ hash ^= (*(UInt16*)ptrUInt);
+ hash *= M;
+ break;
+
+ case 1:
+ hash ^= (*((byte*)ptrUInt));
+ hash *= M;
+ break;
+ }
+ }
+
+ hash ^= hash >> 13;
+ hash *= M;
+ hash ^= hash >> 15;
+
+ return hash;
+ }
+ #endregion
+ #region [ IUIntHash ]
+
+ uint IUIntHashAlgorithm.ComputeHash(byte[] data)
+ {
+ this.Initialize();
+
+ this.HashCore(data, 0, data.Length);
+
+ return this.CurrentHash;
+ }
+
+ #endregion
+ }
+}
+
+#region [ License information ]
+/* ************************************************************
+ *
+ * Copyright (c) 2010 Attila Kiskó, enyim.com
+ *
+ * Licensed 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.
+ *
+ * ************************************************************/
+#endregion
View
108 Enyim.Caching/HashkitOneAtATime.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Security.Cryptography;
+
+namespace Enyim
+{
+ /// <summary>
+ /// This is Jenkin's "One at A time Hash".
+ /// http://en.wikipedia.org/wiki/Jenkins_hash_function
+ ///
+ /// Coming from libhashkit.
+ /// </summary>
+ /// <remarks>Does not support block based hashing.</remarks>
+ internal class HashkitOneAtATime : HashAlgorithm, IUIntHashAlgorithm
+ {
+ public HashkitOneAtATime()
+ {
+ this.HashSizeValue = 32;
+ }
+
+ public override bool CanTransformMultipleBlocks
+ {
+ get { return false; }
+ }
+
+ public override void Initialize() { }
+
+ protected override void HashCore(byte[] array, int ibStart, int cbSize)
+ {
+ if (array == null) throw new ArgumentNullException("array");
+ if (ibStart < 0 || ibStart > array.Length) throw new ArgumentOutOfRangeException("ibStart");
+ if (ibStart + cbSize > array.Length) throw new ArgumentOutOfRangeException("cbSize");
+
+ HashkitOneAtATime.UnsafeHashCore(array, ibStart, cbSize);
+ }
+
+ protected override byte[] HashFinal()
+ {
+ return BitConverter.GetBytes(this.CurrentHash);
+ }
+
+ public uint CurrentHash { get; private set; }
+
+ #region [ UnsafeHashCore ]
+
+ // see the murmur hash about stream support
+ private static unsafe uint UnsafeHashCore(byte[] data, int offset, int count)
+ {
+ uint hash = 0;
+
+ fixed (byte* start = &(data[offset]))
+ {
+ var ptr = start;
+
+ while (count > 0)
+ {
+ hash += *ptr;
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+
+ count--;
+ ptr++;
+ }
+ }
+
+ hash += (hash << 3);
+ hash ^= (hash >> 11);
+ hash += (hash << 15);
+
+ return hash;
+ }
+ #endregion
+ #region [ IUIntHash ]
+
+ uint IUIntHashAlgorithm.ComputeHash(byte[] data)
+ {
+ this.Initialize();
+
+ this.HashCore(data, 0, data.Length);
+
+ return this.CurrentHash;
+ }
+
+ #endregion
+ }
+}
+
+#region [ License information ]
+/* ************************************************************
+ *
+ * Copyright (c) 2010 Attila Kiskó, enyim.com
+ *
+ * Licensed 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.
+ *
+ * ************************************************************/
+#endregion
View
38 Enyim.Caching/IUIntHashAlgorithm.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Security.Cryptography;
+using System.Net;
+using System.Web.Script.Serialization;
+using System.Collections.ObjectModel;
+using System.Web;
+using Enyim.Caching.Memcached;
+
+namespace Enyim
+{
+ internal interface IUIntHashAlgorithm
+ {
+ uint ComputeHash(byte[] data);
+ }
+}
+
+#region [ License information ]
+/* ************************************************************
+ *
+ * Copyright (c) 2010 Attila Kiskó, enyim.com
+ *
+ * Licensed 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.
+ *
+ * ************************************************************/
+#endregion
View
2  Enyim.Caching/Memcached/IMemcachedNodeLocator.cs
@@ -3,7 +3,7 @@
namespace Enyim.Caching.Memcached
{
/// <summary>
- /// Defines a locator class whihc maps item keys to memcached servers.
+ /// Defines a locator class which maps item keys to memcached servers.
/// </summary>
public interface IMemcachedNodeLocator
{
View
34 Enyim.Caching/Memcached/IProviderFactory.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+
+namespace Enyim.Caching.Memcached
+{
+ /// <summary>
+ /// Provides a way for custom initalization of the providers (locators, transcoders, key transformers)
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ public interface IProviderFactory<T>
+ {
+ void Initialize(Dictionary<string, string> parameters);
+ T Create();
+ }
+}
+
+#region [ License information ]
+/* ************************************************************
+ *
+ * Copyright (c) 2010 Attila Kiskó, enyim.com
+ *
+ * Licensed 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.
+ *
+ * ************************************************************/
+#endregion
View
16 Enyim.Caching/Memcached/ServerPool.cs
@@ -39,16 +39,12 @@ public DefaultServerPool(IMemcachedClientConfiguration configuration)
this.isAliveTimer = new Timer(callback_isAliveTimer, null, (int)this.configuration.SocketPool.DeadTimeout.TotalMilliseconds, (int)this.configuration.SocketPool.DeadTimeout.TotalMilliseconds);
// create the key transformer instance
- Type t = this.configuration.KeyTransformer;
- this.keyTransformer = (t == null) ? new DefaultKeyTransformer() : (IMemcachedKeyTransformer)Enyim.Reflection.FastActivator.CreateInstance(t);
+ this.keyTransformer = this.configuration.CreateKeyTransformer() ?? new DefaultKeyTransformer();
// create the item transcoder instance
- t = this.configuration.Transcoder;
- this.transcoder = (t == null) ? new DefaultTranscoder() : (ITranscoder)Enyim.Reflection.FastActivator.CreateInstance(t);
+ this.transcoder = this.configuration.CreateTranscoder() ?? new DefaultTranscoder();
}
- //public event Action<PooledSocket> SocketConnected;
-
/// <summary>
/// This will start the pool: initializes the nodelocator, warms up the socket pools, etc.
/// </summary>
@@ -72,12 +68,10 @@ private void RebuildIndexes()
try
{
- Type ltype = this.configuration.NodeLocator;
-
- IMemcachedNodeLocator l = ltype == null ? new DefaultNodeLocator() : (IMemcachedNodeLocator)Enyim.Reflection.FastActivator.CreateInstance(ltype);
- l.Initialize(this.workingServers);
+ var newLocator = this.configuration.CreateNodeLocator();
+ newLocator.Initialize(this.workingServers);
- this.nodeLocator = l;
+ Interlocked.Exchange(ref this.nodeLocator, newLocator);
this.publicWorkingServers = null;
}
View
104 Enyim.Caching/Memcached/VBucketNodeLocator.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Security.Cryptography;
+using System.Net;
+using System.Web.Script.Serialization;
+using System.Collections.ObjectModel;
+using System.Web;
+using Enyim.Caching.Configuration;
+using System.Configuration;
+using System.IO;
+
+namespace Enyim.Caching.Memcached
+{
+ /// <summary>
+ /// Implements a vbucket based node locator.
+ /// </summary>
+ public class VBucketNodeLocator : IMemcachedNodeLocator
+ {
+ private IVBucketConfiguration config;
+ private int mask;
+
+ public VBucketNodeLocator(IVBucketConfiguration config)
+ {
+ this.config = config;
+
+ var log = Math.Log(this.config.Buckets.Count, 2);
+ if (log != (int)log)
+ throw new ArgumentException("Buckets.Count must be a power of 2!");
+
+ this.mask = config.Buckets.Count - 1;
+ }
+
+ [ThreadStatic]
+ private static HashAlgorithm currentAlgo;
+
+ private HashAlgorithm GetAlgo()
+ {
+ // we cache the HashAlgorithm instance per thread
+ // they are reinitialized before every ComputeHash but we avoid creating then GCing them every time we need
+ // to find something (which will happen a lot)
+ // we cannot use ThreadStatic for asp.net (requests can change threads) so the hasher will be recreated for every request
+ // (we could use an object pool but talk about overkill)
+ var ctx = HttpContext.Current;
+ if (ctx == null)
+ return currentAlgo ?? (currentAlgo = this.config.CreateHashAlgorithm());
+
+ var algo = ctx.Items["**VBucket.CurrentAlgo"] as HashAlgorithm;
+ if (algo == null)
+ ctx.Items["**VBucket.CurrentAlgo"] = algo = this.config.CreateHashAlgorithm();
+
+ return algo;
+ }
+
+ #region [ IMemcachedNodeLocator ]
+
+ private IMemcachedNode[] nodes;
+
+ void IMemcachedNodeLocator.Initialize(IList<IMemcachedNode> nodes)
+ {
+ this.nodes = nodes.ToArray();
+ }
+
+ IMemcachedNode IMemcachedNodeLocator.Locate(string key)
+ {
+ var ha = this.GetAlgo();
+
+ //little shortcut for some hashes; we skip the uint -> byte[] -> uint conversion
+ var iuha = ha as IUIntHashAlgorithm;
+ var keyBytes = Encoding.UTF8.GetBytes(key);
+
+ uint keyHash = (iuha == null)
+ ? keyHash = BitConverter.ToUInt32(ha.ComputeHash(keyBytes), 0)
+ : iuha.ComputeHash(keyBytes);
+
+ int index = (int)(keyHash & this.mask);
+
+ return this.nodes[this.config.Buckets[index].Master];
+ }
+
+ #endregion
+ }
+}
+
+#region [ License information ]
+/* ************************************************************
+ *
+ * Copyright (c) 2010 Attila Kiskó, enyim.com
+ *
+ * Licensed 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.
+ *
+ * ************************************************************/
+#endregion
View
67 Enyim.Caching/Memcached/VBucketNodeLocatorFactory.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Security.Cryptography;
+using System.Net;
+using System.Web.Script.Serialization;
+using System.Collections.ObjectModel;
+using System.Web;
+using Enyim.Caching.Configuration;
+using System.Configuration;
+using System.IO;
+
+namespace Enyim.Caching.Memcached
+{
+ /// <summary>
+ /// Factory for the vbucket based locator.
+ /// </summary>
+ /// <remarks>You need to use this in the configuration file because this is the only way pass parameters to the VBucketNodeLocator.
+ ///
+ /// <locator factory="Enyim.Caching.Memcached.VBucketNodeLocatorFactory" configFile="vbucket.json" />
+ ///
+ /// </remarks>
+ public class VBucketNodeLocatorFactory : IProviderFactory<IMemcachedNodeLocator>
+ {
+ private IVBucketConfiguration config;
+
+ void IProviderFactory<IMemcachedNodeLocator>.Initialize(Dictionary<string, string> parameters)
+ {
+ string configFile;
+
+ if (!parameters.TryGetValue("configFile", out configFile))
+ throw new ConfigurationErrorsException("VBucketNodeLocatorFactory expects configFile");
+
+ var json = File.ReadAllText(configFile);
+ if (String.IsNullOrEmpty(json))
+ throw new ConfigurationErrorsException("Config file " + configFile + " is empty.");
+
+ this.config = new JsonVBucketConfig(json);
+ }
+
+ IMemcachedNodeLocator IProviderFactory<IMemcachedNodeLocator>.Create()
+ {
+ return new VBucketNodeLocator(this.config);
+ }
+ }
+}
+
+#region [ License information ]
+/* ************************************************************
+ *
+ * Copyright (c) 2010 Attila Kiskó, enyim.com
+ *
+ * Licensed 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.
+ *
+ * ************************************************************/
+#endregion
View
2  Enyim.Caching/MemcachedClient.cs
@@ -82,7 +82,7 @@ private static ISaslAuthenticationProvider GetProvider(IMemcachedClientConfigura
if (auth != null)
{
Type t = auth.Type;
- var provider = (t == null) ? null : Enyim.Reflection.FastActivator.CreateInstance(t) as ISaslAuthenticationProvider;
+ var provider = (t == null) ? null : Enyim.Reflection.FastActivator2.Create(t) as ISaslAuthenticationProvider;
if (provider != null)
{
Please sign in to comment.
Something went wrong with that request. Please try again.