├── .gitattributes
├── .gitignore
├── .nuget
├── NuGet.Config
├── NuGet.exe
└── NuGet.targets
├── Amazon.ElastiCacheCluster
├── Amazon.ElastiCacheCluster.csproj
├── Amazon.ElastiCacheCluster.nuspec
├── ClusterClient.cs
├── ClusterConfigSettings.cs
├── ConfigurationPoller.cs
├── DiscoveryNode.cs
├── ElastiCacheClusterConfig.cs
├── Factories
│ ├── DefaultConfigNodeFactory.cs
│ └── IConfigNodeFactory.cs
├── Helpers
│ ├── AddrUtil.cs
│ └── TextSocketHelper.cs
├── Operations
│ ├── ConfigGetOperation.cs
│ ├── GetHelper.cs
│ ├── GetOperation.cs
│ └── IConfigOperation.cs
├── Pools
│ ├── AutoBinaryPool.cs
│ └── AutoServerPool.cs
├── Properties
│ └── AssemblyInfo.cs
├── awskey.snk
└── packages.config
├── ClusterClientAppTester
├── App.config
├── ClusterClientAppTester.csproj
├── Form1.Designer.cs
├── Form1.cs
├── Form1.resx
├── Program.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
└── packages.config
├── ElastiCacheClusterConfig.sln
├── LICENSE.txt
├── LocalSimulationTests
├── ConfigTests.cs
├── LocalSimulationTests.csproj
├── NodeFactory.cs
├── Properties
│ └── AssemblyInfo.cs
├── TestNode.cs
└── packages.config
├── NOTICE.txt
├── README.md
└── packages
└── repositories.config
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 |
9 | # Build results
10 |
11 | [Dd]ebug/
12 | [Rr]elease/
13 | x64/
14 | build/
15 | [Bb]in/
16 | [Oo]bj/
17 |
18 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
19 | !packages/*/build/
20 |
21 | # MSTest test Results
22 | [Tt]est[Rr]esult*/
23 | [Bb]uild[Ll]og.*
24 |
25 | *_i.c
26 | *_p.c
27 | *.ilk
28 | *.meta
29 | *.obj
30 | *.pch
31 | *.pdb
32 | *.pgc
33 | *.pgd
34 | *.rsp
35 | *.sbr
36 | *.tlb
37 | *.tli
38 | *.tlh
39 | *.tmp
40 | *.tmp_proj
41 | *.log
42 | *.vspscc
43 | *.vssscc
44 | .builds
45 | *.pidb
46 | *.log
47 | *.scc
48 |
49 | # Visual C++ cache files
50 | ipch/
51 | *.aps
52 | *.ncb
53 | *.opensdf
54 | *.sdf
55 | *.cachefile
56 |
57 | # Visual Studio profiler
58 | *.psess
59 | *.vsp
60 | *.vspx
61 |
62 | # Guidance Automation Toolkit
63 | *.gpState
64 |
65 | # ReSharper is a .NET coding add-in
66 | _ReSharper*/
67 | *.[Rr]e[Ss]harper
68 |
69 | # TeamCity is a build add-in
70 | _TeamCity*
71 |
72 | # DotCover is a Code Coverage Tool
73 | *.dotCover
74 |
75 | # NCrunch
76 | *.ncrunch*
77 | .*crunch*.local.xml
78 |
79 | # Installshield output folder
80 | [Ee]xpress/
81 |
82 | # DocProject is a documentation generator add-in
83 | DocProject/buildhelp/
84 | DocProject/Help/*.HxT
85 | DocProject/Help/*.HxC
86 | DocProject/Help/*.hhc
87 | DocProject/Help/*.hhk
88 | DocProject/Help/*.hhp
89 | DocProject/Help/Html2
90 | DocProject/Help/html
91 |
92 | # Click-Once directory
93 | publish/
94 |
95 | # Publish Web Output
96 | *.Publish.xml
97 |
98 | # NuGet Packages Directory
99 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
100 | #packages/
101 |
102 | # Windows Azure Build Output
103 | csx
104 | *.build.csdef
105 |
106 | # Windows Store app package directory
107 | AppPackages/
108 |
109 | # Others
110 | sql/
111 | *.Cache
112 | ClientBin/
113 | [Ss]tyle[Cc]op.*
114 | ~$*
115 | *~
116 | *.dbmdl
117 | *.[Pp]ublish.xml
118 | *.pfx
119 | *.publishsettings
120 |
121 | # RIA/Silverlight projects
122 | Generated_Code/
123 |
124 | # Backup & report files from converting an old project file to a newer
125 | # Visual Studio version. Backup files are not needed, because we have git ;-)
126 | _UpgradeReport_Files/
127 | Backup*/
128 | UpgradeLog*.XML
129 | UpgradeLog*.htm
130 |
131 | # SQL Server files
132 | App_Data/*.mdf
133 | App_Data/*.ldf
134 |
135 |
136 | #LightSwitch generated files
137 | GeneratedArtifacts/
138 | _Pvt_Extensions/
139 | ModelManifest.xml
140 |
141 | # =========================
142 | # Windows detritus
143 | # =========================
144 |
145 | # Windows image file caches
146 | Thumbs.db
147 | ehthumbs.db
148 |
149 | # Folder config file
150 | Desktop.ini
151 |
152 | # Recycle Bin used on file shares
153 | $RECYCLE.BIN/
154 |
155 | # Mac desktop service store files
156 | .DS_Store
157 |
--------------------------------------------------------------------------------
/.nuget/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.nuget/NuGet.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awslabs/elasticache-cluster-config-net/30996c7f37dbb978f7d25f926847852a1d6ea50f/.nuget/NuGet.exe
--------------------------------------------------------------------------------
/.nuget/NuGet.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(MSBuildProjectDirectory)\..\
5 |
6 |
7 | false
8 |
9 |
10 | false
11 |
12 |
13 | true
14 |
15 |
16 | false
17 |
18 |
19 |
20 |
21 |
22 |
26 |
27 |
28 |
29 |
30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget"))
31 |
32 |
33 |
34 |
35 | $(SolutionDir).nuget
36 |
37 |
38 |
39 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName.Replace(' ', '_')).config
40 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName).config
41 |
42 |
43 |
44 | $(MSBuildProjectDirectory)\packages.config
45 | $(PackagesProjectConfig)
46 |
47 |
48 |
49 |
50 | $(NuGetToolsPath)\NuGet.exe
51 | @(PackageSource)
52 |
53 | "$(NuGetExePath)"
54 | mono --runtime=v4.0.30319 "$(NuGetExePath)"
55 |
56 | $(TargetDir.Trim('\\'))
57 |
58 | -RequireConsent
59 | -NonInteractive
60 |
61 | "$(SolutionDir) "
62 | "$(SolutionDir)"
63 |
64 |
65 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir)
66 | $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols
67 |
68 |
69 |
70 | RestorePackages;
71 | $(BuildDependsOn);
72 |
73 |
74 |
75 |
76 | $(BuildDependsOn);
77 | BuildPackage;
78 |
79 |
80 |
81 |
82 |
83 |
84 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
99 |
100 |
103 |
104 |
105 |
106 |
108 |
109 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
141 |
142 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/Amazon.ElastiCacheCluster.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Release
6 | AnyCPU
7 | {1255EBD3-0340-4AF6-A5F2-3D97D8709546}
8 | Library
9 | Properties
10 | Amazon.ElastiCacheCluster
11 | Amazon.ElastiCacheCluster
12 | v3.5
13 | 512
14 |
15 | ..\..\..\reInvent2014Demos\ZipCodes\
16 | true
17 |
18 |
19 | true
20 | full
21 | false
22 | bin\Debug\
23 |
24 |
25 | prompt
26 | 4
27 | true
28 |
29 |
30 | pdbonly
31 | true
32 | bin\Release\
33 |
34 |
35 | prompt
36 | 4
37 | true
38 | bin\Release\Amazon.ElastiCacheCluster.XML
39 |
40 |
41 | true
42 |
43 |
44 | awskey.snk
45 |
46 |
47 |
48 | ..\packages\EnyimMemcached.2.12\lib\net35\Enyim.Caching.dll
49 | True
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
86 |
87 |
88 |
89 |
96 |
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/Amazon.ElastiCacheCluster.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $id$
5 | $version$
6 | $title$
7 | $author$
8 | $author$
9 | http://media.amazonwebservices.com/aws_singlebox_01.png
10 | http://aws.amazon.com/apache2.0
11 | https://github.com/awslabs/elasticache-cluster-config-net
12 | false
13 | $description$
14 | Copyright 2014
15 | AWS Amazon cloud elasticache clusterclient aws amazon ElastiCacheCluster elasticacheclusterconfig cluster config clusterconfig elasticachenetclusterclient ElastiCache
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/ClusterClient.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | using System;
16 | using System.Collections.Generic;
17 | using System.Linq;
18 | using System.Text;
19 | using Enyim.Caching;
20 |
21 | namespace Amazon.ElastiCacheCluster
22 | {
23 | ///
24 | /// Used to instantiate MemcachedClients with auto discovery enabled.
25 | /// Only use these for easy creation because the ability to get information from the config object is lost
26 | ///
27 | public static class ClusterClient
28 | {
29 | ///
30 | /// Creates a MemcachedClient using the settings found in the app.config section "clusterclient"
31 | ///
32 | /// A new MemcachedClient configured for auto discovery
33 | public static MemcachedClient CreateClient()
34 | {
35 | return new MemcachedClient(new ElastiCacheClusterConfig());
36 | }
37 |
38 | ///
39 | /// Creates a MemcachedClient using the settings found in the app.config section specified
40 | ///
41 | /// A section in app.config that has a endpoint field
42 | /// A new MemcachedClient configured for auto discovery
43 | public static MemcachedClient CreateClient(string section)
44 | {
45 | return new MemcachedClient(new ElastiCacheClusterConfig(section));
46 | }
47 |
48 | ///
49 | /// Creates a MemcachedClient using the default settings with the endpoint and port specified
50 | ///
51 | /// The url for the cluster endpoint containing .cfg.
52 | /// The port to access the cluster on
53 | /// A new MemcachedClient configured for auto discovery
54 | public static MemcachedClient CreateClient(string endpoint, int port)
55 | {
56 | return new MemcachedClient(new ElastiCacheClusterConfig(endpoint, port));
57 | }
58 |
59 | ///
60 | /// Creates a MemcachedClient using the Client config provided
61 | ///
62 | /// The config to instantiate the client with
63 | /// A new MemcachedClient configured for auto discovery
64 | public static MemcachedClient CreateClient(ElastiCacheClusterConfig config)
65 | {
66 | return new MemcachedClient(config);
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/ClusterConfigSettings.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Portions copyright 2010 Attila Kiskó, enyim.com. Please see LICENSE.txt
5 | * for applicable license terms and NOTICE.txt for applicable notices.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License").
8 | * You may not use this file except in compliance with the License.
9 | * A copy of the License is located at
10 | *
11 | * http://aws.amazon.com/apache2.0
12 | *
13 | * or in the "license" file accompanying this file. This file is distributed
14 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
15 | * express or implied. See the License for the specific language governing
16 | * permissions and limitations under the License.
17 | */
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Linq;
21 | using System.Text;
22 | using System.Configuration;
23 | using Enyim.Caching.Configuration;
24 | using Enyim.Caching.Memcached;
25 | using Amazon.ElastiCacheCluster.Factories;
26 |
27 | namespace Amazon.ElastiCacheCluster
28 | {
29 | ///
30 | /// A config settings object used to configure the client config
31 | ///
32 | public class ClusterConfigSettings : ConfigurationSection
33 | {
34 | ///
35 | /// An object that produces nodes for the Discovery Node, mainly used for testing
36 | ///
37 | public IConfigNodeFactory NodeFactory { get; set; }
38 |
39 | #region Constructors
40 |
41 | ///
42 | /// For config manager
43 | ///
44 | public ClusterConfigSettings() { }
45 |
46 | ///
47 | /// Used to initialize a setup with a host and port
48 | ///
49 | /// Cluster hostname
50 | /// Cluster port
51 | public ClusterConfigSettings(string hostname, int port)
52 | {
53 | if (string.IsNullOrEmpty(hostname))
54 | throw new ArgumentNullException("hostname");
55 | if (port <= 0)
56 | throw new ArgumentException("Port cannot be less than or equal to zero");
57 |
58 | this.ClusterEndPoint.HostName = hostname;
59 | this.ClusterEndPoint.Port = port;
60 | }
61 |
62 | #endregion
63 |
64 | #region Config Settings
65 |
66 | ///
67 | /// Class containing information about the cluster host and port
68 | ///
69 | [ConfigurationProperty("endpoint", IsRequired = true)]
70 | public Endpoint ClusterEndPoint
71 | {
72 | get { return (Endpoint)base["endpoint"]; }
73 | set { base["endpoint"] = value; }
74 | }
75 |
76 | ///
77 | /// Class containing information about the node configuration
78 | ///
79 | [ConfigurationProperty("node", IsRequired = false)]
80 | public NodeSettings ClusterNode
81 | {
82 | get { return (NodeSettings)base["node"]; }
83 | set { base["node"] = value; }
84 | }
85 |
86 | ///
87 | /// Class containing information about the poller configuration
88 | ///
89 | [ConfigurationProperty("poller", IsRequired = false)]
90 | public PollerSettings ClusterPoller
91 | {
92 | get { return (PollerSettings)base["poller"]; }
93 | set { base["poller"] = value; }
94 | }
95 |
96 | ///
97 | /// Endpoint that contains the hostname and port for auto discovery
98 | ///
99 | public class Endpoint : ConfigurationElement
100 | {
101 | ///
102 | /// The hostname of the cluster containing ".cfg."
103 | ///
104 | [ConfigurationProperty("hostname", IsRequired = true)]
105 | public String HostName
106 | {
107 | get
108 | {
109 | return (String)this["hostname"];
110 | }
111 | set
112 | {
113 | this["hostname"] = value;
114 | }
115 | }
116 |
117 | ///
118 | /// The port of the endpoint
119 | ///
120 | [ConfigurationProperty("port", IsRequired = true)]
121 | public int Port
122 | {
123 | get
124 | {
125 | return (int)this["port"];
126 | }
127 | set
128 | {
129 | this["port"] = value;
130 | }
131 | }
132 | }
133 |
134 | ///
135 | /// Settings used for the discovery node
136 | ///
137 | public class NodeSettings : ConfigurationElement
138 | {
139 | ///
140 | /// How many tries the node should use to get a config
141 | ///
142 | [ConfigurationProperty("nodeTries", DefaultValue = -1, IsRequired = false)]
143 | public int NodeTries
144 | {
145 | get { return (int)base["nodeTries"]; }
146 | set { base["nodeTries"] = value; }
147 | }
148 |
149 | ///
150 | /// The delay between tries for the config in miliseconds
151 | ///
152 | [ConfigurationProperty("nodeDelay", DefaultValue = -1, IsRequired = false)]
153 | public int NodeDelay
154 | {
155 | get { return (int)base["nodeDelay"]; }
156 | set { base["nodeDelay"] = value; }
157 | }
158 | }
159 |
160 | ///
161 | /// Settins used for the configuration poller
162 | ///
163 | public class PollerSettings : ConfigurationElement
164 | {
165 | ///
166 | /// The delay between polls in miliseconds
167 | ///
168 | [ConfigurationProperty("intervalDelay", DefaultValue = -1, IsRequired = false)]
169 | public int IntervalDelay
170 | {
171 | get { return (int)base["intervalDelay"]; }
172 | set { base["intervalDelay"] = value; }
173 | }
174 | }
175 |
176 | #endregion
177 |
178 | #region MemcachedConfig
179 |
180 | ///
181 | /// Gets or sets the configuration of the socket pool.
182 | ///
183 | [ConfigurationProperty("socketPool", IsRequired = false)]
184 | public SocketPoolElement SocketPool
185 | {
186 | get { return (SocketPoolElement)base["socketPool"]; }
187 | set { base["socketPool"] = value; }
188 | }
189 |
190 | ///
191 | /// Gets or sets the configuration of the authenticator.
192 | ///
193 | [ConfigurationProperty("authentication", IsRequired = false)]
194 | public AuthenticationElement Authentication
195 | {
196 | get { return (AuthenticationElement)base["authentication"]; }
197 | set { base["authentication"] = value; }
198 | }
199 |
200 | ///
201 | /// Gets or sets the which will be used to assign items to Memcached nodes.
202 | ///
203 | [ConfigurationProperty("locator", IsRequired = false)]
204 | public ProviderElement NodeLocator
205 | {
206 | get { return (ProviderElement)base["locator"]; }
207 | set { base["locator"] = value; }
208 | }
209 |
210 | ///
211 | /// Gets or sets the which will be used to convert item keys for Memcached.
212 | ///
213 | [ConfigurationProperty("keyTransformer", IsRequired = false)]
214 | public ProviderElement KeyTransformer
215 | {
216 | get { return (ProviderElement)base["keyTransformer"]; }
217 | set { base["keyTransformer"] = value; }
218 | }
219 |
220 | ///
221 | /// Gets or sets the which will be used serialzie or deserialize items.
222 | ///
223 | [ConfigurationProperty("transcoder", IsRequired = false)]
224 | public ProviderElement Transcoder
225 | {
226 | get { return (ProviderElement)base["transcoder"]; }
227 | set { base["transcoder"] = value; }
228 | }
229 |
230 | ///
231 | /// Gets or sets the which will be used monitor the performance of the client.
232 | ///
233 | [ConfigurationProperty("performanceMonitor", IsRequired = false)]
234 | public ProviderElement PerformanceMonitor
235 | {
236 | get { return (ProviderElement)base["performanceMonitor"]; }
237 | set { base["performanceMonitor"] = value; }
238 | }
239 |
240 | ///
241 | /// Gets or sets the type of the communication between client and server.
242 | ///
243 | [ConfigurationProperty("protocol", IsRequired = false, DefaultValue = MemcachedProtocol.Binary)]
244 | public MemcachedProtocol Protocol
245 | {
246 | get { return (MemcachedProtocol)base["protocol"]; }
247 | set { base["protocol"] = value; }
248 | }
249 |
250 | #endregion
251 |
252 | }
253 | }
254 |
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/ConfigurationPoller.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | using System;
16 | using System.Collections.Generic;
17 | using System.Linq;
18 | using System.Text;
19 | using System.Timers;
20 |
21 | namespace Amazon.ElastiCacheCluster
22 | {
23 | ///
24 | /// A poller used to reconfigure the client servers when updates occur to the cluster configuration
25 | ///
26 | internal class ConfigurationPoller
27 | {
28 | private static readonly Enyim.Caching.ILog log = Enyim.Caching.LogManager.GetLogger(typeof(ConfigurationPoller));
29 |
30 | #region Defaults
31 |
32 | // Poll once every minute
33 | private static readonly int DEFAULT_INTERVAL_DELAY = 60000;
34 |
35 | #endregion
36 |
37 | private Timer timer;
38 | private int intervalDelay;
39 | private ElastiCacheClusterConfig config;
40 |
41 | #region Constructors
42 |
43 | ///
44 | /// Creates a poller for Auto Discovery with the default intervals
45 | ///
46 | /// The memcached client to update servers for
47 | public ConfigurationPoller(ElastiCacheClusterConfig config)
48 | : this(config, DEFAULT_INTERVAL_DELAY) { }
49 |
50 | ///
51 | /// Creates a poller for Auto Discovery with the defined itnerval, delay, tries, and try delay for polling
52 | ///
53 | /// The memcached client to update servers for
54 | /// The amount of time between polling operations in miliseconds
55 | public ConfigurationPoller(ElastiCacheClusterConfig config, int intervalDelay)
56 | {
57 | this.intervalDelay = intervalDelay < 0 ? DEFAULT_INTERVAL_DELAY : intervalDelay;
58 | this.config = config;
59 |
60 | this.timer = new Timer(this.intervalDelay);
61 | this.timer.Elapsed += this.pollOnTimedEvent;
62 | }
63 |
64 | #endregion
65 |
66 | #region Polling Methods
67 |
68 | internal void StartTimer()
69 | {
70 | log.Debug("Starting timer");
71 | this.pollOnTimedEvent(null, null);
72 | this.timer.Start();
73 | }
74 |
75 | ///
76 | /// Used by the poller's timer to update the cluster configuration if a new version is available
77 | ///
78 | internal void pollOnTimedEvent(Object source, ElapsedEventArgs evnt)
79 | {
80 | log.Debug("Polling...");
81 | try
82 | {
83 | var oldVersion = config.DiscoveryNode.ClusterVersion;
84 | var endPoints = config.DiscoveryNode.GetEndPointList();
85 | if (oldVersion != config.DiscoveryNode.ClusterVersion ||
86 | (this.config.Pool.nodeLocator != null && endPoints.Count != this.config.Pool.nodeLocator.GetWorkingNodes().Count()))
87 | {
88 | log.DebugFormat("Updating endpoints to have {0} nodes", endPoints.Count);
89 | this.config.Pool.UpdateLocator(endPoints);
90 | }
91 | }
92 | catch(Exception e)
93 | {
94 | try
95 | {
96 | log.Debug("Error updating endpoints, going to attempt to reresolve configuration endpoint.", e);
97 | config.DiscoveryNode.ResolveEndPoint();
98 |
99 | var oldVersion = config.DiscoveryNode.ClusterVersion;
100 | var endPoints = config.DiscoveryNode.GetEndPointList();
101 | if (oldVersion != config.DiscoveryNode.ClusterVersion ||
102 | (this.config.Pool.nodeLocator != null && endPoints.Count != this.config.Pool.nodeLocator.GetWorkingNodes().Count()))
103 | {
104 | log.DebugFormat("Updating endpoints to have {0} nodes", endPoints.Count);
105 | this.config.Pool.UpdateLocator(endPoints);
106 | }
107 | }
108 | catch (Exception ex)
109 | {
110 | log.Debug("Error updating endpoints. Setting endpoints to empty collection of nodes.", ex);
111 |
112 | /*
113 | * We were not able to retrieve the current node configuration. This is most likely because the application
114 | * is running in development outside of EC2. ElastiCache clusters are only accessible from an EC2 instance
115 | * with the right security permissions.
116 | */
117 | this.config.Pool.UpdateLocator(new List());
118 | }
119 | }
120 | }
121 |
122 | #endregion
123 |
124 | ///
125 | /// Disposes the background thread that is used for polling the configs
126 | ///
127 | public void StopPolling()
128 | {
129 | log.Debug("Destroying poller thread");
130 | if (this.timer != null)
131 | this.timer.Dispose();
132 | }
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/DiscoveryNode.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | using System;
16 | using System.Collections.Generic;
17 | using System.Linq;
18 | using System.Text;
19 |
20 | using System.Net;
21 | using System.Configuration;
22 | using Enyim.Caching.Configuration;
23 | using Enyim.Caching.Memcached;
24 | using Amazon.ElastiCacheCluster.Helpers;
25 | using Amazon.ElastiCacheCluster.Operations;
26 | using Amazon.ElastiCacheCluster.Pools;
27 | using Enyim.Caching.Memcached.Results;
28 | using Enyim.Caching.Memcached.Protocol;
29 |
30 | namespace Amazon.ElastiCacheCluster
31 | {
32 | ///
33 | /// A class that manages the discovery of endpoints inside of an ElastiCache cluster
34 | ///
35 | public class DiscoveryNode
36 | {
37 | #region Static ReadOnlys
38 |
39 | private static readonly Enyim.Caching.ILog log = Enyim.Caching.LogManager.GetLogger(typeof(DiscoveryNode));
40 |
41 | internal static readonly int DEFAULT_TRY_COUNT = 5;
42 | internal static readonly int DEFAULT_TRY_DELAY = 1000;
43 |
44 | #endregion
45 |
46 | ///
47 | /// The version of memcached running on the Nodes
48 | ///
49 | public Version NodeVersion { get; private set; }
50 |
51 | ///
52 | /// The version of the cluster configuration
53 | ///
54 | public int ClusterVersion { get; private set; }
55 |
56 | ///
57 | /// The number of nodes running inside of the cluster
58 | ///
59 | public int NodesInCluster { get { return this.nodes.Count; } }
60 |
61 | #region Private Fields
62 |
63 | private IPEndPoint EndPoint;
64 |
65 | private IMemcachedNode Node;
66 |
67 | private ElastiCacheClusterConfig config;
68 |
69 | private List nodes = new List();
70 |
71 | private ConfigurationPoller poller;
72 |
73 | private string hostname;
74 | private int port;
75 |
76 | private int tries;
77 | private int delay;
78 |
79 | private Object nodesLock, endpointLock, clusterLock;
80 |
81 | #endregion
82 |
83 | #region Constructors
84 |
85 | ///
86 | /// The node used to discover endpoints in an ElastiCache cluster
87 | ///
88 | /// The config of the client to access the SocketPool
89 | /// The host name of the cluster with .cfg. in name
90 | /// The port of the cluster
91 | internal DiscoveryNode(ElastiCacheClusterConfig config, string hostname, int port)
92 | : this(config, hostname, port, DEFAULT_TRY_COUNT, DEFAULT_TRY_DELAY) { }
93 |
94 | ///
95 | /// The node used to discover endpoints in an ElastiCache cluster
96 | ///
97 | /// The config of the client to access the SocketPool
98 | /// The host name of the cluster with .cfg. in name
99 | /// The port of the cluster
100 | /// The number of tries for requesting config info
101 | /// The time, in miliseconds, to wait between tries
102 | internal DiscoveryNode(ElastiCacheClusterConfig config, string hostname, int port, int tries, int delay)
103 | {
104 | #region Param Checks
105 |
106 | if (config == null)
107 | throw new ArgumentNullException("config");
108 | if (string.IsNullOrEmpty(hostname))
109 | throw new ArgumentNullException("hostname");
110 | if (port <= 0)
111 | throw new ArgumentException("Port cannot be 0 or less");
112 | if (tries < 1)
113 | throw new ArgumentException("Must atleast try once");
114 | if (delay < 0)
115 | throw new ArgumentException("The delay can't be negative");
116 | if (hostname.IndexOf(".cfg", StringComparison.OrdinalIgnoreCase) < 0)
117 | throw new ArgumentException("The hostname is not able to use Auto Discovery");
118 |
119 | #endregion
120 |
121 | #region Setting Members
122 |
123 | this.hostname = hostname;
124 | this.port = port;
125 | this.config = config;
126 | this.ClusterVersion = 0;
127 | this.tries = tries;
128 | this.delay = delay;
129 |
130 | this.clusterLock = new Object();
131 | this.endpointLock = new Object();
132 | this.nodesLock = new Object();
133 |
134 | #endregion
135 |
136 | this.ResolveEndPoint();
137 | }
138 |
139 | #endregion
140 |
141 | #region Poller Methods
142 |
143 | ///
144 | /// Used to start a poller that checks for changes in the cluster client configuration
145 | ///
146 | internal void StartPoller()
147 | {
148 | this.config.Pool.UpdateLocator(new List(new IPEndPoint[] { this.EndPoint }));
149 | this.poller = new ConfigurationPoller(this.config);
150 | this.poller.StartTimer();
151 | }
152 |
153 | ///
154 | /// Used to start a poller that checks for changes in the cluster client configuration
155 | ///
156 | /// Time between pollings, in miliseconds
157 | internal void StartPoller(int intervalDelay)
158 | {
159 | this.poller = new ConfigurationPoller(this.config, intervalDelay);
160 | this.poller.StartTimer();
161 | }
162 |
163 | #endregion
164 |
165 | #region Config Info
166 | ///
167 | /// Parses the string NodeConfig into a list of IPEndPoints for configuration
168 | ///
169 | /// A list of IPEndPoints for config to use
170 | internal List GetEndPointList()
171 | {
172 | try
173 | {
174 | var endpoints = AddrUtil.HashEndPointList(this.GetNodeConfig());
175 |
176 | lock (nodesLock)
177 | {
178 | var nodesToRemove = new HashSet();
179 | foreach (var node in this.nodes)
180 | {
181 | if (!endpoints.Contains(node.EndPoint))
182 | nodesToRemove.Add(node);
183 | }
184 | foreach (var node in nodesToRemove)
185 | {
186 | this.nodes.Remove(node);
187 | }
188 |
189 | foreach (var point in endpoints)
190 | {
191 | if (this.nodes.FirstOrDefault(x => x.EndPoint.Equals(point)) == null)
192 | {
193 | this.nodes.Add(this.config.nodeFactory.CreateNode(point, this.config.SocketPool));
194 | }
195 | }
196 | }
197 |
198 | return endpoints;
199 | }
200 | catch (Exception ex)
201 | {
202 | // Error getting the list of endpoints. Most likely this is due to the
203 | // client being used outside of EC2.
204 | log.Debug("Error getting endpoints list", ex);
205 | throw;
206 | }
207 | }
208 |
209 | ///
210 | /// Gets the Node configuration from "config get cluster" if it's new or "get AmazonElastiCache:cluster" if it's older than
211 | /// 1.4.14
212 | ///
213 | /// A string in the format "hostname1|ip1|port1 hostname2|ip2|port2 ..."
214 | internal string GetNodeConfig()
215 | {
216 | var tries = this.tries;
217 | var nodeVersion = this.GetNodeVersion();
218 | var older = new Version("1.4.14");
219 | var waiting = true;
220 | string message = "";
221 | string[] items = null;
222 |
223 | IGetOperation command = nodeVersion.CompareTo(older) < 0 ?
224 | command = new GetOperation("AmazonElastiCache:cluster") :
225 | command = new ConfigGetOperation("cluster");
226 |
227 | while (waiting && tries > 0)
228 | {
229 | tries--;
230 | try
231 | {
232 | lock (nodesLock)
233 | {
234 | // This avoids timing out from requesting the config from the endpoint
235 | foreach (var node in this.nodes.ToArray())
236 | {
237 | try
238 | {
239 | var result = node.Execute(command);
240 |
241 | if (result.Success)
242 | {
243 | var configCommand = command as IConfigOperation;
244 | items = Encoding.UTF8.GetString(configCommand.ConfigResult.Data.Array, configCommand.ConfigResult.Data.Offset, configCommand.ConfigResult.Data.Count).Split('\n');
245 | waiting = false;
246 | break;
247 | }
248 | else
249 | {
250 | message = result.Message;
251 | }
252 | }
253 | catch (Exception ex)
254 | {
255 | message = ex.Message;
256 | }
257 | }
258 | }
259 |
260 | if (waiting)
261 | System.Threading.Thread.Sleep(this.delay);
262 |
263 | }
264 | catch (Exception ex)
265 | {
266 | message = ex.Message;
267 | System.Threading.Thread.Sleep(this.delay);
268 | }
269 | }
270 |
271 | if (waiting)
272 | {
273 | throw new TimeoutException(String.Format("Could not get config of version " + this.NodeVersion.ToString() + ". Tries: {0} Delay: {1}. " + message, this.tries, this.delay));
274 | }
275 |
276 | lock (clusterLock)
277 | {
278 | if (this.ClusterVersion < Convert.ToInt32(items[0]))
279 | this.ClusterVersion = Convert.ToInt32(items[0]);
280 | }
281 | return items[1];
282 | }
283 |
284 | ///
285 | /// Finds the version of Memcached the Elasticache setup is running on
286 | ///
287 | /// Version of memcahced running on nodes
288 | internal Version GetNodeVersion()
289 | {
290 | if (this.NodeVersion != null)
291 | {
292 | return this.NodeVersion;
293 | }
294 |
295 | if (!string.IsNullOrEmpty(this.Node.ToString()) && this.Node.ToString().Equals("TestingAWSInternal"))
296 | {
297 | this.NodeVersion = new Version("1.4.14");
298 | return this.NodeVersion;
299 | }
300 |
301 | IStatsOperation statcommand = new Enyim.Caching.Memcached.Protocol.Text.StatsOperation(null);
302 | var statresult = this.Node.Execute(statcommand);
303 |
304 | string version;
305 | if (statcommand.Result != null && statcommand.Result.TryGetValue("version", out version))
306 | {
307 | this.NodeVersion = new Version(version);
308 | return this.NodeVersion;
309 | }
310 | else
311 | {
312 | log.Error("Could not call stats on Node endpoint");
313 | throw new CommandNotSupportedException("The node does not have a version in stats.");
314 | }
315 | }
316 |
317 | ///
318 | /// Tries to resolve the endpoint ip, used if the connection fails
319 | ///
320 | /// The resolved endpoint as an ip and port
321 | internal IPEndPoint ResolveEndPoint()
322 | {
323 | IPHostEntry entry = null;
324 | var waiting = true;
325 | var tryCount = this.tries;
326 | string message = "";
327 |
328 | while (tryCount > 0 && waiting)
329 | {
330 | try
331 | {
332 | tryCount--;
333 | entry = Dns.GetHostEntry(hostname);
334 | if (entry.AddressList.Length > 0)
335 | {
336 | waiting = false;
337 | }
338 | }
339 | catch (Exception ex)
340 | {
341 | message = ex.Message;
342 | System.Threading.Thread.Sleep(this.delay);
343 | }
344 | }
345 |
346 |
347 | if (waiting || entry == null)
348 | {
349 | log.Error("Could not resolve hostname to ip");
350 | throw new TimeoutException(String.Format("Could not resolve hostname to Ip after trying the specified amount: {0}. " + message, this.tries));
351 | }
352 |
353 | log.DebugFormat("Resolved configuration endpoint {0} to {1}.", hostname, entry.AddressList[0]);
354 |
355 | lock (endpointLock)
356 | {
357 | this.EndPoint = new IPEndPoint(entry.AddressList[0], port);
358 | }
359 |
360 | lock (nodesLock)
361 | {
362 | if (this.Node != null)
363 | {
364 | try
365 | {
366 | this.Node.Dispose();
367 | }
368 | catch { }
369 | }
370 | this.Node = this.config.nodeFactory.CreateNode(this.EndPoint, this.config.SocketPool);
371 | this.nodes.Clear();
372 | this.nodes.Add(this.Node);
373 | }
374 | return this.EndPoint;
375 | }
376 |
377 | #endregion
378 |
379 | ///
380 | /// Stops the current poller
381 | ///
382 | public void Dispose()
383 | {
384 | if (this.poller != null)
385 | this.poller.StopPolling();
386 | }
387 | }
388 | }
389 |
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/ElastiCacheClusterConfig.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Portions copyright 2010 Attila Kiskó, enyim.com. Please see LICENSE.txt
5 | * for applicable license terms and NOTICE.txt for applicable notices.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License").
8 | * You may not use this file except in compliance with the License.
9 | * A copy of the License is located at
10 | *
11 | * http://aws.amazon.com/apache2.0
12 | *
13 | * or in the "license" file accompanying this file. This file is distributed
14 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
15 | * express or implied. See the License for the specific language governing
16 | * permissions and limitations under the License.
17 | */
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Net;
21 | using Enyim.Caching.Memcached;
22 | using Enyim.Reflection;
23 | using Enyim.Caching.Memcached.Protocol.Binary;
24 | using Enyim.Caching.Configuration;
25 | using Amazon.ElastiCacheCluster.Pools;
26 | using Amazon.ElastiCacheCluster.Factories;
27 | using System.Configuration;
28 |
29 | namespace Amazon.ElastiCacheCluster
30 | {
31 | ///
32 | /// Configuration class for auto discovery
33 | ///
34 | public class ElastiCacheClusterConfig : IMemcachedClientConfiguration
35 | {
36 | // these are lazy initialized in the getters
37 | private Type nodeLocator;
38 | private ITranscoder transcoder;
39 | private IMemcachedKeyTransformer keyTransformer;
40 |
41 | internal ClusterConfigSettings setup;
42 | internal AutoServerPool Pool;
43 | internal IConfigNodeFactory nodeFactory;
44 |
45 | ///
46 | /// The node used to check the cluster's configuration
47 | ///
48 | public DiscoveryNode DiscoveryNode { get; private set; }
49 |
50 | #region Constructors
51 |
52 | ///
53 | /// Initializes a MemcahcedClient config with auto discovery enabled from the app.config clusterclient section
54 | ///
55 | public ElastiCacheClusterConfig()
56 | : this(null as ClusterConfigSettings) { }
57 |
58 | ///
59 | /// Initializes a MemcahcedClient config with auto discovery enabled from the app.config with the specified section
60 | ///
61 | /// The section to get config settings from
62 | public ElastiCacheClusterConfig(string section)
63 | : this(ConfigurationManager.GetSection(section) as ClusterConfigSettings) { }
64 |
65 | ///
66 | /// Initializes a MemcahcedClient config with auto discovery enabled
67 | ///
68 | /// The hostname of the cluster containing ".cfg."
69 | /// The port to connect to for communication
70 | public ElastiCacheClusterConfig(string hostname, int port)
71 | : this(new ClusterConfigSettings(hostname, port)) { }
72 |
73 | ///
74 | /// Initializes a MemcahcedClient config with auto discovery enabled using the setup provided
75 | ///
76 | /// The setup to get conifg settings from
77 | public ElastiCacheClusterConfig(ClusterConfigSettings setup)
78 | {
79 | if (setup == null)
80 | {
81 | try
82 | {
83 | setup = ConfigurationManager.GetSection("clusterclient") as ClusterConfigSettings;
84 | if (setup == null)
85 | {
86 | throw new ConfigurationErrorsException("Could not instantiate from app.config, setup was null");
87 | }
88 | }
89 | catch (Exception ex)
90 | {
91 | throw new ConfigurationErrorsException("Could not instantiate from app.config\n" + ex.Message);
92 | }
93 | }
94 |
95 | if (setup.ClusterEndPoint == null)
96 | throw new ArgumentException("Cluster Settings are null");
97 | if (String.IsNullOrEmpty(setup.ClusterEndPoint.HostName))
98 | throw new ArgumentNullException("hostname");
99 | if (setup.ClusterEndPoint.Port <= 0)
100 | throw new ArgumentException("Port cannot be 0 or less");
101 |
102 | this.setup = setup;
103 | this.Servers = new List();
104 |
105 | this.Protocol = setup.Protocol;
106 |
107 | if (setup.KeyTransformer == null)
108 | this.KeyTransformer = new DefaultKeyTransformer();
109 | else
110 | this.KeyTransformer = setup.KeyTransformer.CreateInstance() ?? new DefaultKeyTransformer();
111 |
112 | this.SocketPool = (ISocketPoolConfiguration)setup.SocketPool ?? new SocketPoolConfiguration();
113 | this.Authentication = (IAuthenticationConfiguration)setup.Authentication ?? new AuthenticationConfiguration();
114 |
115 | this.nodeFactory = setup.NodeFactory ?? new DefaultConfigNodeFactory();
116 | this.nodeLocator = setup.NodeLocator != null ? setup.NodeLocator.Type : typeof(DefaultNodeLocator);
117 |
118 | if (setup.Transcoder != null)
119 | {
120 | this.transcoder = setup.Transcoder.CreateInstance() ?? new DefaultTranscoder();
121 | }
122 |
123 | if (setup.ClusterEndPoint.HostName.IndexOf(".cfg", StringComparison.OrdinalIgnoreCase) >= 0)
124 | {
125 | if (setup.ClusterNode != null)
126 | {
127 | var _tries = setup.ClusterNode.NodeTries > 0 ? setup.ClusterNode.NodeTries : DiscoveryNode.DEFAULT_TRY_COUNT;
128 | var _delay = setup.ClusterNode.NodeDelay >= 0 ? setup.ClusterNode.NodeDelay : DiscoveryNode.DEFAULT_TRY_DELAY;
129 | this.DiscoveryNode = new DiscoveryNode(this, setup.ClusterEndPoint.HostName, setup.ClusterEndPoint.Port, _tries, _delay);
130 | }
131 | else
132 | this.DiscoveryNode = new DiscoveryNode(this, setup.ClusterEndPoint.HostName, setup.ClusterEndPoint.Port);
133 | }
134 | else
135 | {
136 | throw new ArgumentException("The provided endpoint does not support auto discovery");
137 | }
138 | }
139 |
140 | #endregion
141 |
142 | #region Members
143 |
144 | ///
145 | /// Gets a list of each representing a Memcached server in the pool.
146 | ///
147 | public IList Servers { get; private set; }
148 |
149 | ///
150 | /// Gets the configuration of the socket pool.
151 | ///
152 | public ISocketPoolConfiguration SocketPool { get; private set; }
153 |
154 | ///
155 | /// Gets the authentication settings.
156 | ///
157 | public IAuthenticationConfiguration Authentication { get; set; }
158 |
159 | ///
160 | /// Gets or sets the which will be used to convert item keys for Memcached.
161 | ///
162 | public IMemcachedKeyTransformer KeyTransformer
163 | {
164 | get { return this.keyTransformer ?? (this.keyTransformer = new DefaultKeyTransformer()); }
165 | set { this.keyTransformer = value; }
166 | }
167 |
168 | ///
169 | /// Gets or sets the Type of the which will be used to assign items to Memcached nodes.
170 | ///
171 | /// If both and are assigned then the latter takes precedence.
172 | public Type NodeLocator
173 | {
174 | get { return this.nodeLocator; }
175 | set
176 | {
177 | ConfigurationHelper.CheckForInterface(value, typeof(IMemcachedNodeLocator));
178 | this.nodeLocator = value;
179 | }
180 | }
181 |
182 | ///
183 | /// Gets or sets the NodeLocatorFactory instance which will be used to create a new IMemcachedNodeLocator instances.
184 | ///
185 | /// If both and are assigned then the latter takes precedence.
186 | public IProviderFactory NodeLocatorFactory { get; set; }
187 |
188 | ///
189 | /// Gets or sets the which will be used serialize or deserialize items.
190 | ///
191 | public ITranscoder Transcoder
192 | {
193 | get { return this.transcoder ?? (this.transcoder = new DefaultTranscoder()); }
194 | set { this.transcoder = value; }
195 | }
196 |
197 | ///
198 | /// Gets or sets the instance which will be used monitor the performance of the client.
199 | ///
200 | public IPerformanceMonitor PerformanceMonitor { get; set; }
201 |
202 | ///
203 | /// Gets or sets the type of the communication between client and server.
204 | ///
205 | public MemcachedProtocol Protocol { get; set; }
206 |
207 | #endregion
208 |
209 | #region [ interface ]
210 |
211 | IList IMemcachedClientConfiguration.Servers
212 | {
213 | get { return this.Servers; }
214 | }
215 |
216 | ISocketPoolConfiguration IMemcachedClientConfiguration.SocketPool
217 | {
218 | get { return this.SocketPool; }
219 | }
220 |
221 | IAuthenticationConfiguration IMemcachedClientConfiguration.Authentication
222 | {
223 | get { return this.Authentication; }
224 | }
225 |
226 | IMemcachedKeyTransformer IMemcachedClientConfiguration.CreateKeyTransformer()
227 | {
228 | return this.KeyTransformer;
229 | }
230 |
231 | IMemcachedNodeLocator IMemcachedClientConfiguration.CreateNodeLocator()
232 | {
233 | var f = this.NodeLocatorFactory;
234 | if (f != null) return f.Create();
235 |
236 | return this.NodeLocator == null
237 | ? new DefaultNodeLocator()
238 | : (IMemcachedNodeLocator)FastActivator.Create(this.NodeLocator);
239 | }
240 |
241 | ITranscoder IMemcachedClientConfiguration.CreateTranscoder()
242 | {
243 | return this.Transcoder;
244 | }
245 |
246 | IServerPool IMemcachedClientConfiguration.CreatePool()
247 | {
248 | switch (this.Protocol)
249 | {
250 | case MemcachedProtocol.Text:
251 | this.Pool = new AutoServerPool(this, new Enyim.Caching.Memcached.Protocol.Text.TextOperationFactory());
252 | break;
253 | case MemcachedProtocol.Binary:
254 | this.Pool = new AutoBinaryPool(this);
255 | break;
256 | default:
257 | throw new ArgumentOutOfRangeException("Unknown protocol: " + (int)this.Protocol);
258 | }
259 |
260 | return this.Pool;
261 | }
262 |
263 | IPerformanceMonitor IMemcachedClientConfiguration.CreatePerformanceMonitor()
264 | {
265 | return this.PerformanceMonitor;
266 | }
267 |
268 | #endregion
269 | }
270 | }
271 |
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/Factories/DefaultConfigNodeFactory.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | using Enyim.Caching.Configuration;
16 | using Enyim.Caching.Memcached;
17 | using System;
18 | using System.Collections.Generic;
19 | using System.Linq;
20 | using System.Net;
21 | using System.Text;
22 |
23 | namespace Amazon.ElastiCacheCluster.Factories
24 | {
25 | internal class DefaultConfigNodeFactory : IConfigNodeFactory
26 | {
27 | public IMemcachedNode CreateNode(IPEndPoint endpoint, ISocketPoolConfiguration config)
28 | {
29 | return new MemcachedNode(endpoint, config);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/Factories/IConfigNodeFactory.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | using Enyim.Caching.Configuration;
16 | using Enyim.Caching.Memcached;
17 | using System;
18 | using System.Collections.Generic;
19 | using System.Linq;
20 | using System.Net;
21 | using System.Text;
22 |
23 | namespace Amazon.ElastiCacheCluster.Factories
24 | {
25 | public interface IConfigNodeFactory
26 | {
27 | IMemcachedNode CreateNode(IPEndPoint endpoint, ISocketPoolConfiguration config);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/Helpers/AddrUtil.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | using System;
16 | using System.Collections.Generic;
17 | using System.Linq;
18 | using System.Net;
19 | using System.Text;
20 |
21 | namespace Amazon.ElastiCacheCluster.Helpers
22 | {
23 | ///
24 | /// A class used to parse configs of Auto Discovery
25 | ///
26 | internal static class AddrUtil
27 | {
28 | ///
29 | /// Creates a list of endpoints from a string returned in the config request
30 | ///
31 | /// Format: host1|ip1|port1 host2|ip2|port2 ...
32 | /// List of the endpoints parsed to ip:port endpoints for connections
33 | public static List HashEndPointList(string endpoints)
34 | {
35 | List list = new List();
36 | foreach (var node in endpoints.Split(' '))
37 | {
38 | string[] parts = node.Split('|');
39 | IPAddress ip;
40 | if (IPAddress.TryParse(parts[1], out ip))
41 | {
42 | list.Add(new IPEndPoint(ip, Convert.ToInt32(parts[2])));
43 | }
44 | }
45 | return list;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/Helpers/TextSocketHelper.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awslabs/elasticache-cluster-config-net/30996c7f37dbb978f7d25f926847852a1d6ea50f/Amazon.ElastiCacheCluster/Helpers/TextSocketHelper.cs
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/Operations/ConfigGetOperation.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | using Enyim.Caching.Memcached.Protocol;
16 | using Enyim.Caching.Memcached.Protocol.Text;
17 | using System;
18 | using System.Collections.Generic;
19 | using System.Globalization;
20 | using System.Linq;
21 | using System.Text;
22 | using Enyim.Caching.Memcached.Results;
23 | using Enyim.Caching.Memcached.Results.Extensions;
24 | using Enyim.Caching.Memcached;
25 | using Amazon.ElastiCacheCluster.Helpers;
26 |
27 | namespace Amazon.ElastiCacheCluster.Operations
28 | {
29 | ///
30 | /// Used to get auto discovery information from ElastiCache endpoints version 1.4.14 or higher
31 | ///
32 | internal class ConfigGetOperation : SingleItemOperation, IGetOperation, IConfigOperation
33 | {
34 | private CacheItem result;
35 |
36 | ///
37 | /// Creates a config get for ElastiCache
38 | ///
39 | ///
40 | public ConfigGetOperation(string key) : base(key) { }
41 |
42 | protected override IList> GetBuffer()
43 | {
44 | var command = "config get " + this.Key + TextSocketHelper.CommandTerminator;
45 |
46 | return TextSocketHelper.GetCommandBuffer(command);
47 | }
48 |
49 | protected override Enyim.Caching.Memcached.Results.IOperationResult ReadResponse(PooledSocket socket)
50 | {
51 | string description = TextSocketHelper.ReadResponse(socket);
52 |
53 | if (String.Compare(description, "END", StringComparison.Ordinal) == 0)
54 | return null;
55 |
56 | if (description.Length < 7 || String.Compare(description, 0, "CONFIG ", 0, 7, StringComparison.Ordinal) != 0)
57 | throw new MemcachedClientException("No CONFIG response received.\r\n" + description);
58 |
59 | string[] parts = description.Split(' ');
60 |
61 | /****** Format ********
62 | *
63 | * CONFIG
64 | * 0 1 2 3
65 | *
66 | */
67 |
68 | ushort flags = UInt16.Parse(parts[2], CultureInfo.InvariantCulture);
69 | int length = Int32.Parse(parts[3], CultureInfo.InvariantCulture);
70 |
71 | byte[] allNodes = new byte[length];
72 | byte[] eod = new byte[2];
73 |
74 | socket.Read(allNodes, 0, length);
75 | socket.Read(eod, 0, 2); // data is terminated by \r\n
76 |
77 | this.result = new CacheItem(flags, new ArraySegment(allNodes, 0, length));
78 | this.ConfigResult = this.result;
79 |
80 | string response = TextSocketHelper.ReadResponse(socket);
81 |
82 | if (String.Compare(response, "END", StringComparison.Ordinal) != 0)
83 | throw new MemcachedClientException("No END was received.");
84 |
85 | var result = new TextOperationResult();
86 | return result.Pass();
87 | }
88 |
89 | protected override bool ReadResponseAsync(PooledSocket socket, Action next)
90 | {
91 | throw new System.NotSupportedException();
92 | }
93 |
94 | ///
95 | /// The CacheItem result of a "config get *key*" request
96 | ///
97 | public CacheItem Result
98 | {
99 | get { return result; }
100 | }
101 |
102 | public CacheItem ConfigResult { get; set; }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/Operations/GetHelper.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awslabs/elasticache-cluster-config-net/30996c7f37dbb978f7d25f926847852a1d6ea50f/Amazon.ElastiCacheCluster/Operations/GetHelper.cs
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/Operations/GetOperation.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awslabs/elasticache-cluster-config-net/30996c7f37dbb978f7d25f926847852a1d6ea50f/Amazon.ElastiCacheCluster/Operations/GetOperation.cs
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/Operations/IConfigOperation.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | using System;
16 | using System.Collections.Generic;
17 | using System.Linq;
18 | using System.Text;
19 | using Enyim.Caching.Memcached;
20 |
21 | namespace Amazon.ElastiCacheCluster.Operations
22 | {
23 | public interface IConfigOperation
24 | {
25 | CacheItem ConfigResult { get; set; }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/Pools/AutoBinaryPool.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Portions copyright 2010 Attila Kiskó, enyim.com. Please see LICENSE.txt
5 | * for applicable license terms and NOTICE.txt for applicable notices.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License").
8 | * You may not use this file except in compliance with the License.
9 | * A copy of the License is located at
10 | *
11 | * http://aws.amazon.com/apache2.0
12 | *
13 | * or in the "license" file accompanying this file. This file is distributed
14 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
15 | * express or implied. See the License for the specific language governing
16 | * permissions and limitations under the License.
17 | */
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Diagnostics;
21 | using System.Net;
22 | using System.Threading;
23 | using Enyim.Caching.Configuration;
24 | using Enyim.Collections;
25 | using System.Security;
26 | using Enyim.Caching.Memcached;
27 | using Enyim.Caching.Memcached.Protocol.Binary;
28 |
29 | namespace Amazon.ElastiCacheCluster.Pools
30 | {
31 | ///
32 | /// Server pool implementing the binary protocol.
33 | ///
34 | internal class AutoBinaryPool : AutoServerPool
35 | {
36 | ISaslAuthenticationProvider authenticationProvider;
37 | IMemcachedClientConfiguration configuration;
38 |
39 | public AutoBinaryPool(IMemcachedClientConfiguration configuration)
40 | : base(configuration, new BinaryOperationFactory())
41 | {
42 | this.authenticationProvider = GetProvider(configuration);
43 | this.configuration = configuration;
44 | }
45 |
46 | protected override IMemcachedNode CreateNode(IPEndPoint endpoint)
47 | {
48 | if (endpoint == null)
49 | throw new ArgumentNullException("endpoint");
50 | return new BinaryNode(endpoint, this.configuration.SocketPool, this.authenticationProvider);
51 | }
52 |
53 | private static ISaslAuthenticationProvider GetProvider(IMemcachedClientConfiguration configuration)
54 | {
55 | // create&initialize the authenticator, if any
56 | // we'll use this single instance everywhere, so it must be thread safe
57 | IAuthenticationConfiguration auth = configuration.Authentication;
58 | if (auth != null)
59 | {
60 | Type t = auth.Type;
61 | var provider = (t == null) ? null : Enyim.Reflection.FastActivator.Create(t) as ISaslAuthenticationProvider;
62 |
63 | if (provider != null)
64 | {
65 | provider.Initialize(auth.Parameters);
66 | return provider;
67 | }
68 | }
69 |
70 | return null;
71 | }
72 |
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/Pools/AutoServerPool.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Portions copyright 2010 Attila Kiskó, enyim.com. Please see LICENSE.txt
5 | * for applicable license terms and NOTICE.txt for applicable notices.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License").
8 | * You may not use this file except in compliance with the License.
9 | * A copy of the License is located at
10 | *
11 | * http://aws.amazon.com/apache2.0
12 | *
13 | * or in the "license" file accompanying this file. This file is distributed
14 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
15 | * express or implied. See the License for the specific language governing
16 | * permissions and limitations under the License.
17 | */
18 | using System;
19 | using System.Linq;
20 | using System.Collections.Generic;
21 | using System.Collections.ObjectModel;
22 | using System.Net;
23 | using System.Threading;
24 | using Enyim.Caching.Configuration;
25 | using Enyim.Caching.Memcached;
26 |
27 | namespace Amazon.ElastiCacheCluster.Pools
28 | {
29 | ///
30 | /// A server pool just like the default that enables safely changing the servers of the locator
31 | ///
32 | internal class AutoServerPool : IServerPool, IDisposable
33 | {
34 | private static readonly Enyim.Caching.ILog log = Enyim.Caching.LogManager.GetLogger(typeof(DefaultServerPool));
35 |
36 | private IMemcachedNode[] allNodes;
37 |
38 | private IMemcachedClientConfiguration configuration;
39 | private IOperationFactory factory;
40 | internal IMemcachedNodeLocator nodeLocator;
41 |
42 | private object DeadSync = new Object();
43 | private System.Threading.Timer resurrectTimer;
44 | private bool isTimerActive;
45 | private long deadTimeoutMsec;
46 | private bool isDisposed;
47 | private event Action nodeFailed;
48 |
49 | ///
50 | /// Creates a server pool for auto discovery
51 | ///
52 | /// The client configuration using the pool
53 | /// The factory used to create operations on demand
54 | public AutoServerPool(IMemcachedClientConfiguration configuration, IOperationFactory opFactory)
55 | {
56 | if (configuration == null) throw new ArgumentNullException("socketConfig");
57 | if (opFactory == null) throw new ArgumentNullException("opFactory");
58 |
59 | this.configuration = configuration;
60 | this.factory = opFactory;
61 |
62 | this.deadTimeoutMsec = (long)this.configuration.SocketPool.DeadTimeout.TotalMilliseconds;
63 | }
64 |
65 | ~AutoServerPool()
66 | {
67 | try { ((IDisposable)this).Dispose(); }
68 | catch { }
69 | }
70 |
71 | protected virtual IMemcachedNode CreateNode(IPEndPoint endpoint)
72 | {
73 | return new MemcachedNode(endpoint, this.configuration.SocketPool);
74 | }
75 |
76 | private void rezCallback(object state)
77 | {
78 | var isDebug = log.IsDebugEnabled;
79 |
80 | if (isDebug) log.Debug("Checking the dead servers.");
81 |
82 | // how this works:
83 | // 1. timer is created but suspended
84 | // 2. Locate encounters a dead server, so it starts the timer which will trigger after deadTimeout has elapsed
85 | // 3. if another server goes down before the timer is triggered, nothing happens in Locate (isRunning == true).
86 | // however that server will be inspected sooner than Dead Timeout.
87 | // S1 died S2 died dead timeout
88 | // |----*--------*------------*-
89 | // | |
90 | // timer start both servers are checked here
91 | // 4. we iterate all the servers and record it in another list
92 | // 5. if we found a dead server whihc responds to Ping(), the locator will be reinitialized
93 | // 6. if at least one server is still down (Ping() == false), we restart the timer
94 | // 7. if all servers are up, we set isRunning to false, so the timer is suspended
95 | // 8. GOTO 2
96 | lock (this.DeadSync)
97 | {
98 | if (this.isDisposed)
99 | {
100 | if (log.IsWarnEnabled) log.Warn("IsAlive timer was triggered but the pool is already disposed. Ignoring.");
101 |
102 | return;
103 | }
104 |
105 | var nodes = this.allNodes;
106 | var aliveList = new List(nodes.Length);
107 | var changed = false;
108 | var deadCount = 0;
109 |
110 | for (var i = 0; i < nodes.Length; i++)
111 | {
112 | var n = nodes[i];
113 | if (n.IsAlive)
114 | {
115 | if (isDebug) log.DebugFormat("Alive: {0}", n.EndPoint);
116 |
117 | aliveList.Add(n);
118 | }
119 | else
120 | {
121 | if (isDebug) log.DebugFormat("Dead: {0}", n.EndPoint);
122 |
123 | if (n.Ping())
124 | {
125 | changed = true;
126 | aliveList.Add(n);
127 |
128 | if (isDebug) log.Debug("Ping ok.");
129 | }
130 | else
131 | {
132 | if (isDebug) log.Debug("Still dead.");
133 |
134 | deadCount++;
135 | }
136 | }
137 | }
138 |
139 | // reinit the locator
140 | if (changed)
141 | {
142 | if (isDebug) log.Debug("Reinitializing the locator.");
143 |
144 | this.nodeLocator.Initialize(aliveList);
145 | }
146 |
147 | // stop or restart the timer
148 | if (deadCount == 0)
149 | {
150 | if (isDebug) log.Debug("deadCount == 0, stopping the timer.");
151 |
152 | this.isTimerActive = false;
153 | }
154 | else
155 | {
156 | if (isDebug) log.DebugFormat("deadCount == {0}, starting the timer.", deadCount);
157 |
158 | this.resurrectTimer.Change(this.deadTimeoutMsec, Timeout.Infinite);
159 | }
160 | }
161 | }
162 |
163 | private void NodeFail(IMemcachedNode node)
164 | {
165 | var isDebug = log.IsDebugEnabled;
166 | if (isDebug) log.DebugFormat("Node {0} is dead.", node.EndPoint);
167 |
168 | // the timer is stopped until we encounter the first dead server
169 | // when we have one, we trigger it and it will run after DeadTimeout has elapsed
170 | lock (this.DeadSync)
171 | {
172 | if (this.isDisposed)
173 | {
174 | if (log.IsWarnEnabled) log.Warn("Got a node fail but the pool is already disposed. Ignoring.");
175 |
176 | return;
177 | }
178 |
179 | // bubble up the fail event to the client
180 | var fail = this.nodeFailed;
181 | if (fail != null)
182 | fail(node);
183 |
184 | // re-initialize the locator
185 | var newLocator = this.configuration.CreateNodeLocator();
186 | newLocator.Initialize(allNodes.Where(n => n.IsAlive).ToArray());
187 | Interlocked.Exchange(ref this.nodeLocator, newLocator);
188 |
189 | // the timer is stopped until we encounter the first dead server
190 | // when we have one, we trigger it and it will run after DeadTimeout has elapsed
191 | if (!this.isTimerActive)
192 | {
193 | if (isDebug) log.Debug("Starting the recovery timer.");
194 |
195 | if (this.resurrectTimer == null)
196 | this.resurrectTimer = new Timer(this.rezCallback, null, this.deadTimeoutMsec, Timeout.Infinite);
197 | else
198 | this.resurrectTimer.Change(this.deadTimeoutMsec, Timeout.Infinite);
199 |
200 | this.isTimerActive = true;
201 |
202 | if (isDebug) log.Debug("Timer started.");
203 | }
204 | }
205 | }
206 |
207 | #region [ IServerPool ]
208 |
209 | IMemcachedNode IServerPool.Locate(string key)
210 | {
211 | var node = this.nodeLocator.Locate(key);
212 |
213 | return node;
214 | }
215 |
216 | IOperationFactory IServerPool.OperationFactory
217 | {
218 | get { return this.factory; }
219 | }
220 |
221 | IEnumerable IServerPool.GetWorkingNodes()
222 | {
223 | return this.nodeLocator.GetWorkingNodes();
224 | }
225 |
226 | void IServerPool.Start()
227 | {
228 | this.allNodes = this.configuration.Servers.
229 | Select(ip =>
230 | {
231 | var node = this.CreateNode(ip);
232 | node.Failed += this.NodeFail;
233 |
234 | return node;
235 | }).
236 | ToArray();
237 |
238 | // initialize the locator
239 | var locator = this.configuration.CreateNodeLocator();
240 | locator.Initialize(allNodes);
241 |
242 | this.nodeLocator = locator;
243 |
244 | var config = this.configuration as ElastiCacheClusterConfig;
245 | if (config.setup.ClusterPoller.IntervalDelay < 0)
246 | config.DiscoveryNode.StartPoller();
247 | else
248 | config.DiscoveryNode.StartPoller(config.setup.ClusterPoller.IntervalDelay);
249 | }
250 |
251 | event Action IServerPool.NodeFailed
252 | {
253 | add { this.nodeFailed += value; }
254 | remove { this.nodeFailed -= value; }
255 | }
256 |
257 | #endregion
258 | #region [ IDisposable ]
259 |
260 | void IDisposable.Dispose()
261 | {
262 | GC.SuppressFinalize(this);
263 |
264 | lock (this.DeadSync)
265 | {
266 | if (this.isDisposed) return;
267 |
268 | this.isDisposed = true;
269 |
270 | // dispose the locator first, maybe it wants to access
271 | // the nodes one last time
272 | var nd = this.nodeLocator as IDisposable;
273 | if (nd != null)
274 | try { nd.Dispose(); }
275 | catch (Exception e) { if (log.IsErrorEnabled) log.Error(e); }
276 |
277 | this.nodeLocator = null;
278 |
279 | for (var i = 0; i < this.allNodes.Length; i++)
280 | try { this.allNodes[i].Dispose(); }
281 | catch (Exception e) { if (log.IsErrorEnabled) log.Error(e); }
282 |
283 | // stop the timer
284 | if (this.resurrectTimer != null)
285 | using (this.resurrectTimer)
286 | this.resurrectTimer.Change(Timeout.Infinite, Timeout.Infinite);
287 |
288 | this.allNodes = null;
289 | this.resurrectTimer = null;
290 | }
291 | }
292 |
293 | #endregion
294 |
295 | ///
296 | /// Used to update the servers for Auto discovery
297 | ///
298 | /// The connections to all the cluster nodes
299 | public void UpdateLocator(List endPoints)
300 | {
301 | var newLocator = this.configuration.CreateNodeLocator();
302 |
303 | var nodes = endPoints.Select(ip =>
304 | {
305 | var node = this.CreateNode(ip);
306 | node.Failed += this.NodeFail;
307 |
308 | return node;
309 | }).ToArray();
310 |
311 | var aliveList = new List(nodes.Length);
312 | var deadList = new List(nodes.Length);
313 | foreach (var node in nodes)
314 | {
315 | var result = this.allNodes.Where(n => n.EndPoint.Equals(node.EndPoint)).ToList();
316 |
317 | if (result.Count > 0 && !result[0].IsAlive)
318 | {
319 | deadList.Add(result[0]);
320 | continue;
321 | }
322 |
323 | aliveList.Add(node);
324 | }
325 |
326 | newLocator.Initialize(aliveList);
327 |
328 | // Retain All Nodes List With IsAlive Status
329 | var allNodesList = new List(nodes.Length);
330 | allNodesList.AddRange(aliveList);
331 | allNodesList.AddRange(deadList);
332 |
333 | this.allNodes = allNodesList.ToArray();
334 |
335 | Interlocked.Exchange(ref this.nodeLocator, newLocator);
336 | }
337 | }
338 | }
339 |
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2008-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use
4 | * this file except in compliance with the License. A copy of the License is located at
5 | *
6 | * http://aws.amazon.com/apache2.0
7 | *
8 | * or in the "license" file accompanying this file.
9 | * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
10 | * CONDITIONS OF ANY KIND, either express or implied. See the License for the
11 | * specific language governing permissions and limitations under the License.
12 | * *****************************************************************************
13 | * __ _ _ ___
14 | * ( )( \/\/ )/ __)
15 | * /__\ \ / \__ \
16 | * (_)(_) \/\/ (___/
17 | *
18 | *
19 | */
20 | using System.Reflection;
21 | using System.Runtime.CompilerServices;
22 | using System.Runtime.InteropServices;
23 |
24 | // General Information about an assembly is controlled through the following
25 | // set of attributes. Change these attribute values to modify the information
26 | // associated with an assembly.
27 | [assembly: AssemblyTitle("AmazonElastiCacheClusterConfig")]
28 | [assembly: AssemblyDescription("A configuration object to enable auto discovery in Enyim for ElastiCache")]
29 | [assembly: AssemblyConfiguration("")]
30 | [assembly: AssemblyCompany("Amazon.com, Inc")]
31 | [assembly: AssemblyProduct("AmazonElastiCacheClusterConfig")]
32 | [assembly: AssemblyCopyright("Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2014-2016")]
33 | [assembly: AssemblyTrademark("")]
34 | [assembly: AssemblyCulture("")]
35 |
36 | // Setting ComVisible to false makes the types in this assembly not visible
37 | // to COM components. If you need to access a type in this assembly from
38 | // COM, set the ComVisible attribute to true on that type.
39 | [assembly: ComVisible(false)]
40 |
41 | // The following GUID is for the ID of the typelib if this project is exposed to COM
42 | [assembly: Guid("526dcd43-9e27-40fe-aed6-5d72ad69b7cd")]
43 |
44 | // Version information for an assembly consists of the following four values:
45 | //
46 | // Major Version
47 | // Minor Version
48 | // Build Number
49 | // Revision
50 | //
51 | // You can specify all the values or you can default the Build and Revision Numbers
52 | // by using the '*' as shown below:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("1.0.1.0")]
55 | [assembly: AssemblyFileVersion("1.0.1.0")]
56 |
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/awskey.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awslabs/elasticache-cluster-config-net/30996c7f37dbb978f7d25f926847852a1d6ea50f/Amazon.ElastiCacheCluster/awskey.snk
--------------------------------------------------------------------------------
/Amazon.ElastiCacheCluster/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/ClusterClientAppTester/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/ClusterClientAppTester/ClusterClientAppTester.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {085886E5-3D56-4E41-941A-611EDD2A31D4}
8 | WinExe
9 | Properties
10 | ClusterClientAppTester
11 | ClusterClientAppTester
12 | v3.5
13 | 512
14 |
15 | ..\
16 | true
17 |
18 |
19 | AnyCPU
20 | true
21 | full
22 | false
23 | bin\Debug\
24 | DEBUG;TRACE
25 | prompt
26 | 4
27 |
28 |
29 | AnyCPU
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 |
39 | False
40 | ..\packages\EnyimMemcached.2.12\lib\net35\Enyim.Caching.dll
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | Form
55 |
56 |
57 | Form1.cs
58 |
59 |
60 |
61 |
62 | Form1.cs
63 |
64 |
65 | ResXFileCodeGenerator
66 | Resources.Designer.cs
67 | Designer
68 |
69 |
70 | True
71 | Resources.resx
72 | True
73 |
74 |
75 |
76 | SettingsSingleFileGenerator
77 | Settings.Designer.cs
78 |
79 |
80 | True
81 | Settings.settings
82 | True
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | {1255ebd3-0340-4af6-a5f2-3d97d8709546}
91 | Amazon.ElastiCacheCluster
92 |
93 |
94 |
95 |
96 |
97 |
98 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
99 |
100 |
101 |
102 |
109 |
--------------------------------------------------------------------------------
/ClusterClientAppTester/Form1.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace ClusterClientAppTester
2 | {
3 | partial class Form1
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.components = new System.ComponentModel.Container();
32 | this.groupBox1 = new System.Windows.Forms.GroupBox();
33 | this.ButtonOlder = new System.Windows.Forms.Button();
34 | this.TextOlder = new System.Windows.Forms.TextBox();
35 | this.label2 = new System.Windows.Forms.Label();
36 | this.TextPort = new System.Windows.Forms.TextBox();
37 | this.label1 = new System.Windows.Forms.Label();
38 | this.ButtonInstantiate = new System.Windows.Forms.Button();
39 | this.groupBox2 = new System.Windows.Forms.GroupBox();
40 | this.label4 = new System.Windows.Forms.Label();
41 | this.label3 = new System.Windows.Forms.Label();
42 | this.TextValue = new System.Windows.Forms.TextBox();
43 | this.TextKey = new System.Windows.Forms.TextBox();
44 | this.ButtonAdd = new System.Windows.Forms.Button();
45 | this.groupBox3 = new System.Windows.Forms.GroupBox();
46 | this.LabelValue = new System.Windows.Forms.Label();
47 | this.label6 = new System.Windows.Forms.Label();
48 | this.TextGetKey = new System.Windows.Forms.TextBox();
49 | this.label5 = new System.Windows.Forms.Label();
50 | this.ButtonGet = new System.Windows.Forms.Button();
51 | this.label7 = new System.Windows.Forms.Label();
52 | this.LabelStatus = new System.Windows.Forms.Label();
53 | this.ProgressBarStatus = new System.Windows.Forms.ProgressBar();
54 | this.ButtonExit = new System.Windows.Forms.Button();
55 | this.ProgressPoller = new System.Windows.Forms.ProgressBar();
56 | this.label8 = new System.Windows.Forms.Label();
57 | this.groupBox4 = new System.Windows.Forms.GroupBox();
58 | this.LabelVersion = new System.Windows.Forms.Label();
59 | this.TimerPoller = new System.Windows.Forms.Timer(this.components);
60 | this.groupBox1.SuspendLayout();
61 | this.groupBox2.SuspendLayout();
62 | this.groupBox3.SuspendLayout();
63 | this.groupBox4.SuspendLayout();
64 | this.SuspendLayout();
65 | //
66 | // groupBox1
67 | //
68 | this.groupBox1.Controls.Add(this.ButtonOlder);
69 | this.groupBox1.Controls.Add(this.TextOlder);
70 | this.groupBox1.Controls.Add(this.label2);
71 | this.groupBox1.Controls.Add(this.TextPort);
72 | this.groupBox1.Controls.Add(this.label1);
73 | this.groupBox1.Controls.Add(this.ButtonInstantiate);
74 | this.groupBox1.Location = new System.Drawing.Point(12, 12);
75 | this.groupBox1.Name = "groupBox1";
76 | this.groupBox1.Size = new System.Drawing.Size(317, 125);
77 | this.groupBox1.TabIndex = 0;
78 | this.groupBox1.TabStop = false;
79 | this.groupBox1.Text = "Connection Tests";
80 | //
81 | // ButtonOlder
82 | //
83 | this.ButtonOlder.Location = new System.Drawing.Point(159, 85);
84 | this.ButtonOlder.Name = "ButtonOlder";
85 | this.ButtonOlder.Size = new System.Drawing.Size(133, 23);
86 | this.ButtonOlder.TabIndex = 7;
87 | this.ButtonOlder.Text = "Instantiate From Params";
88 | this.ButtonOlder.UseVisualStyleBackColor = true;
89 | this.ButtonOlder.Click += new System.EventHandler(this.ButtonOlder_Click);
90 | //
91 | // TextOlder
92 | //
93 | this.TextOlder.Location = new System.Drawing.Point(6, 48);
94 | this.TextOlder.Name = "TextOlder";
95 | this.TextOlder.Size = new System.Drawing.Size(172, 20);
96 | this.TextOlder.TabIndex = 6;
97 | this.TextOlder.Text = "versiontesting.4mpstz.cfg.use1.cache.amazonaws.com";
98 | //
99 | // label2
100 | //
101 | this.label2.AutoSize = true;
102 | this.label2.Location = new System.Drawing.Point(199, 29);
103 | this.label2.Name = "label2";
104 | this.label2.Size = new System.Drawing.Size(74, 13);
105 | this.label2.TabIndex = 4;
106 | this.label2.Text = "Endpoint Port:";
107 | //
108 | // TextPort
109 | //
110 | this.TextPort.Location = new System.Drawing.Point(202, 48);
111 | this.TextPort.Name = "TextPort";
112 | this.TextPort.Size = new System.Drawing.Size(41, 20);
113 | this.TextPort.TabIndex = 3;
114 | this.TextPort.Text = "11211";
115 | //
116 | // label1
117 | //
118 | this.label1.AutoSize = true;
119 | this.label1.Location = new System.Drawing.Point(6, 29);
120 | this.label1.Name = "label1";
121 | this.label1.Size = new System.Drawing.Size(83, 13);
122 | this.label1.TabIndex = 2;
123 | this.label1.Text = "Endpoint Name:";
124 | //
125 | // ButtonInstantiate
126 | //
127 | this.ButtonInstantiate.Location = new System.Drawing.Point(6, 85);
128 | this.ButtonInstantiate.Name = "ButtonInstantiate";
129 | this.ButtonInstantiate.Size = new System.Drawing.Size(147, 23);
130 | this.ButtonInstantiate.TabIndex = 0;
131 | this.ButtonInstantiate.Text = "Instantiate From App.Config";
132 | this.ButtonInstantiate.UseVisualStyleBackColor = true;
133 | this.ButtonInstantiate.Click += new System.EventHandler(this.ButtonInstantiate_Click);
134 | //
135 | // groupBox2
136 | //
137 | this.groupBox2.Controls.Add(this.label4);
138 | this.groupBox2.Controls.Add(this.label3);
139 | this.groupBox2.Controls.Add(this.TextValue);
140 | this.groupBox2.Controls.Add(this.TextKey);
141 | this.groupBox2.Controls.Add(this.ButtonAdd);
142 | this.groupBox2.Location = new System.Drawing.Point(335, 12);
143 | this.groupBox2.Name = "groupBox2";
144 | this.groupBox2.Size = new System.Drawing.Size(235, 125);
145 | this.groupBox2.TabIndex = 1;
146 | this.groupBox2.TabStop = false;
147 | this.groupBox2.Text = "Initial Add";
148 | //
149 | // label4
150 | //
151 | this.label4.AutoSize = true;
152 | this.label4.Location = new System.Drawing.Point(109, 29);
153 | this.label4.Name = "label4";
154 | this.label4.Size = new System.Drawing.Size(37, 13);
155 | this.label4.TabIndex = 4;
156 | this.label4.Text = "Value:";
157 | //
158 | // label3
159 | //
160 | this.label3.AutoSize = true;
161 | this.label3.Location = new System.Drawing.Point(3, 29);
162 | this.label3.Name = "label3";
163 | this.label3.Size = new System.Drawing.Size(28, 13);
164 | this.label3.TabIndex = 3;
165 | this.label3.Text = "Key:";
166 | //
167 | // TextValue
168 | //
169 | this.TextValue.Location = new System.Drawing.Point(112, 48);
170 | this.TextValue.Name = "TextValue";
171 | this.TextValue.Size = new System.Drawing.Size(100, 20);
172 | this.TextValue.TabIndex = 2;
173 | this.TextValue.Text = "Hello World";
174 | //
175 | // TextKey
176 | //
177 | this.TextKey.Location = new System.Drawing.Point(6, 48);
178 | this.TextKey.Name = "TextKey";
179 | this.TextKey.Size = new System.Drawing.Size(90, 20);
180 | this.TextKey.TabIndex = 1;
181 | this.TextKey.Text = "Test";
182 | //
183 | // ButtonAdd
184 | //
185 | this.ButtonAdd.Enabled = false;
186 | this.ButtonAdd.Location = new System.Drawing.Point(6, 96);
187 | this.ButtonAdd.Name = "ButtonAdd";
188 | this.ButtonAdd.Size = new System.Drawing.Size(89, 23);
189 | this.ButtonAdd.TabIndex = 0;
190 | this.ButtonAdd.Text = "Add to Cache";
191 | this.ButtonAdd.UseVisualStyleBackColor = true;
192 | this.ButtonAdd.Click += new System.EventHandler(this.ButtonAdd_Click);
193 | //
194 | // groupBox3
195 | //
196 | this.groupBox3.Controls.Add(this.LabelValue);
197 | this.groupBox3.Controls.Add(this.label6);
198 | this.groupBox3.Controls.Add(this.TextGetKey);
199 | this.groupBox3.Controls.Add(this.label5);
200 | this.groupBox3.Controls.Add(this.ButtonGet);
201 | this.groupBox3.Location = new System.Drawing.Point(12, 144);
202 | this.groupBox3.Name = "groupBox3";
203 | this.groupBox3.Size = new System.Drawing.Size(317, 109);
204 | this.groupBox3.TabIndex = 2;
205 | this.groupBox3.TabStop = false;
206 | this.groupBox3.Text = "Initial Get";
207 | //
208 | // LabelValue
209 | //
210 | this.LabelValue.AutoSize = true;
211 | this.LabelValue.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
212 | this.LabelValue.Location = new System.Drawing.Point(139, 46);
213 | this.LabelValue.Name = "LabelValue";
214 | this.LabelValue.Size = new System.Drawing.Size(0, 25);
215 | this.LabelValue.TabIndex = 4;
216 | //
217 | // label6
218 | //
219 | this.label6.AutoSize = true;
220 | this.label6.Location = new System.Drawing.Point(141, 20);
221 | this.label6.Name = "label6";
222 | this.label6.Size = new System.Drawing.Size(37, 13);
223 | this.label6.TabIndex = 3;
224 | this.label6.Text = "Value:";
225 | //
226 | // TextGetKey
227 | //
228 | this.TextGetKey.Location = new System.Drawing.Point(9, 37);
229 | this.TextGetKey.Name = "TextGetKey";
230 | this.TextGetKey.ReadOnly = true;
231 | this.TextGetKey.Size = new System.Drawing.Size(100, 20);
232 | this.TextGetKey.TabIndex = 2;
233 | this.TextGetKey.Text = "Test";
234 | //
235 | // label5
236 | //
237 | this.label5.AutoSize = true;
238 | this.label5.Location = new System.Drawing.Point(9, 20);
239 | this.label5.Name = "label5";
240 | this.label5.Size = new System.Drawing.Size(28, 13);
241 | this.label5.TabIndex = 1;
242 | this.label5.Text = "Key:";
243 | //
244 | // ButtonGet
245 | //
246 | this.ButtonGet.Enabled = false;
247 | this.ButtonGet.Location = new System.Drawing.Point(6, 80);
248 | this.ButtonGet.Name = "ButtonGet";
249 | this.ButtonGet.Size = new System.Drawing.Size(75, 23);
250 | this.ButtonGet.TabIndex = 0;
251 | this.ButtonGet.Text = "Get Value";
252 | this.ButtonGet.UseVisualStyleBackColor = true;
253 | this.ButtonGet.Click += new System.EventHandler(this.ButtonGet_Click);
254 | //
255 | // label7
256 | //
257 | this.label7.AutoSize = true;
258 | this.label7.Location = new System.Drawing.Point(12, 275);
259 | this.label7.Name = "label7";
260 | this.label7.Size = new System.Drawing.Size(40, 13);
261 | this.label7.TabIndex = 3;
262 | this.label7.Text = "Status:";
263 | //
264 | // LabelStatus
265 | //
266 | this.LabelStatus.AutoSize = true;
267 | this.LabelStatus.Location = new System.Drawing.Point(58, 275);
268 | this.LabelStatus.Name = "LabelStatus";
269 | this.LabelStatus.Size = new System.Drawing.Size(93, 13);
270 | this.LabelStatus.TabIndex = 4;
271 | this.LabelStatus.Text = "Waiting on action.";
272 | //
273 | // ProgressBarStatus
274 | //
275 | this.ProgressBarStatus.Location = new System.Drawing.Point(11, 300);
276 | this.ProgressBarStatus.Name = "ProgressBarStatus";
277 | this.ProgressBarStatus.Size = new System.Drawing.Size(140, 23);
278 | this.ProgressBarStatus.TabIndex = 5;
279 | //
280 | // ButtonExit
281 | //
282 | this.ButtonExit.Location = new System.Drawing.Point(495, 300);
283 | this.ButtonExit.Name = "ButtonExit";
284 | this.ButtonExit.Size = new System.Drawing.Size(75, 23);
285 | this.ButtonExit.TabIndex = 6;
286 | this.ButtonExit.Text = "Exit";
287 | this.ButtonExit.UseVisualStyleBackColor = true;
288 | this.ButtonExit.Click += new System.EventHandler(this.ButtonExit_Click);
289 | //
290 | // ProgressPoller
291 | //
292 | this.ProgressPoller.Location = new System.Drawing.Point(40, 48);
293 | this.ProgressPoller.Maximum = 60;
294 | this.ProgressPoller.Name = "ProgressPoller";
295 | this.ProgressPoller.Size = new System.Drawing.Size(157, 23);
296 | this.ProgressPoller.Step = 1;
297 | this.ProgressPoller.TabIndex = 7;
298 | //
299 | // label8
300 | //
301 | this.label8.AutoSize = true;
302 | this.label8.Location = new System.Drawing.Point(40, 29);
303 | this.label8.Name = "label8";
304 | this.label8.Size = new System.Drawing.Size(145, 13);
305 | this.label8.TabIndex = 8;
306 | this.label8.Text = "Wait 1 minute to check poller";
307 | //
308 | // groupBox4
309 | //
310 | this.groupBox4.Controls.Add(this.LabelVersion);
311 | this.groupBox4.Controls.Add(this.ProgressPoller);
312 | this.groupBox4.Controls.Add(this.label8);
313 | this.groupBox4.Location = new System.Drawing.Point(336, 144);
314 | this.groupBox4.Name = "groupBox4";
315 | this.groupBox4.Size = new System.Drawing.Size(234, 109);
316 | this.groupBox4.TabIndex = 9;
317 | this.groupBox4.TabStop = false;
318 | this.groupBox4.Text = "Poller Test";
319 | //
320 | // LabelVersion
321 | //
322 | this.LabelVersion.AutoSize = true;
323 | this.LabelVersion.Location = new System.Drawing.Point(6, 80);
324 | this.LabelVersion.Name = "LabelVersion";
325 | this.LabelVersion.Size = new System.Drawing.Size(0, 13);
326 | this.LabelVersion.TabIndex = 9;
327 | //
328 | // TimerPoller
329 | //
330 | this.TimerPoller.Interval = 1000;
331 | this.TimerPoller.Tick += new System.EventHandler(this.TimerPoller_Tick);
332 | //
333 | // Form1
334 | //
335 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
336 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
337 | this.ClientSize = new System.Drawing.Size(582, 335);
338 | this.Controls.Add(this.groupBox4);
339 | this.Controls.Add(this.ButtonExit);
340 | this.Controls.Add(this.ProgressBarStatus);
341 | this.Controls.Add(this.LabelStatus);
342 | this.Controls.Add(this.label7);
343 | this.Controls.Add(this.groupBox3);
344 | this.Controls.Add(this.groupBox2);
345 | this.Controls.Add(this.groupBox1);
346 | this.MaximizeBox = false;
347 | this.Name = "Form1";
348 | this.ShowIcon = false;
349 | this.Text = "Cluster Client Tests";
350 | this.groupBox1.ResumeLayout(false);
351 | this.groupBox1.PerformLayout();
352 | this.groupBox2.ResumeLayout(false);
353 | this.groupBox2.PerformLayout();
354 | this.groupBox3.ResumeLayout(false);
355 | this.groupBox3.PerformLayout();
356 | this.groupBox4.ResumeLayout(false);
357 | this.groupBox4.PerformLayout();
358 | this.ResumeLayout(false);
359 | this.PerformLayout();
360 |
361 | }
362 |
363 | #endregion
364 |
365 | private System.Windows.Forms.GroupBox groupBox1;
366 | private System.Windows.Forms.Label label2;
367 | private System.Windows.Forms.TextBox TextPort;
368 | private System.Windows.Forms.Label label1;
369 | private System.Windows.Forms.Button ButtonInstantiate;
370 | private System.Windows.Forms.GroupBox groupBox2;
371 | private System.Windows.Forms.Button ButtonAdd;
372 | private System.Windows.Forms.Label label4;
373 | private System.Windows.Forms.Label label3;
374 | private System.Windows.Forms.TextBox TextValue;
375 | private System.Windows.Forms.TextBox TextKey;
376 | private System.Windows.Forms.GroupBox groupBox3;
377 | private System.Windows.Forms.Label LabelValue;
378 | private System.Windows.Forms.Label label6;
379 | private System.Windows.Forms.TextBox TextGetKey;
380 | private System.Windows.Forms.Label label5;
381 | private System.Windows.Forms.Button ButtonGet;
382 | private System.Windows.Forms.Label label7;
383 | private System.Windows.Forms.Label LabelStatus;
384 | private System.Windows.Forms.ProgressBar ProgressBarStatus;
385 | private System.Windows.Forms.TextBox TextOlder;
386 | private System.Windows.Forms.Button ButtonOlder;
387 | private System.Windows.Forms.Button ButtonExit;
388 | private System.Windows.Forms.ProgressBar ProgressPoller;
389 | private System.Windows.Forms.Label label8;
390 | private System.Windows.Forms.GroupBox groupBox4;
391 | private System.Windows.Forms.Timer TimerPoller;
392 | private System.Windows.Forms.Label LabelVersion;
393 | }
394 | }
395 |
396 |
--------------------------------------------------------------------------------
/ClusterClientAppTester/Form1.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | using System;
16 | using System.Collections.Generic;
17 | using System.ComponentModel;
18 | using System.Data;
19 | using System.Drawing;
20 | using System.Linq;
21 | using System.Text;
22 | using System.Windows.Forms;
23 |
24 | using Enyim.Caching;
25 | using Amazon.ElastiCacheCluster;
26 | using Enyim.Caching.Memcached;
27 |
28 | namespace ClusterClientAppTester
29 | {
30 | public partial class Form1 : Form
31 | {
32 | private MemcachedClient mem;
33 | private ElastiCacheClusterConfig config;
34 |
35 | public Form1()
36 | {
37 | InitializeComponent();
38 | }
39 |
40 | public void ErrorAlert(string error)
41 | {
42 | MessageBox.Show(error);
43 | }
44 |
45 | private void ButtonInstantiate_Click(object sender, EventArgs e)
46 | {
47 | try
48 | {
49 | this.LabelStatus.Text = "Instantiating";
50 |
51 | // Instantiates config from app.config in the clusterclient section
52 | this.config = new ElastiCacheClusterConfig();
53 |
54 | mem = new MemcachedClient(this.config);
55 |
56 | #region UI Stuff
57 |
58 | this.TimerPoller.Enabled = false;
59 | this.ProgressPoller.Value = 0;
60 | this.TimerPoller.Enabled = true;
61 |
62 | if (mem == null)
63 | {
64 | this.LabelStatus.Text = "MemcachedClient returned a null object";
65 | }
66 | else
67 | {
68 | this.ButtonAdd.Enabled = true;
69 | this.ButtonGet.Enabled = true;
70 | this.LabelStatus.Text = "Instantiation Success";
71 | this.ProgressBarStatus.Value = 25;
72 | }
73 |
74 | #endregion
75 | }
76 | catch (Exception ex)
77 | {
78 | this.LabelStatus.Text = ex.Message;
79 | }
80 | }
81 |
82 | private void ButtonOlder_Click(object sender, EventArgs e)
83 | {
84 | try
85 | {
86 | this.LabelStatus.Text = "Instantiating";
87 |
88 | // Instantiates client with default settings and uses the hostname and port provided
89 | this.config = new ElastiCacheClusterConfig(this.TextOlder.Text, Convert.ToInt32(this.TextPort.Text));
90 |
91 | this.mem = new MemcachedClient(this.config);
92 |
93 | #region UI Stuff
94 |
95 | this.TimerPoller.Enabled = false;
96 | this.ProgressPoller.Value = 0;
97 | this.TimerPoller.Enabled = true;
98 |
99 | if (mem == null)
100 | {
101 | this.LabelStatus.Text = "MemcachedClient returned a null object";
102 | }
103 | else
104 | {
105 | this.ButtonAdd.Enabled = true;
106 | this.ButtonGet.Enabled = true;
107 | this.LabelStatus.Text = "Old Instantiation Success";
108 | this.ProgressBarStatus.Value = 25;
109 | }
110 |
111 | #endregion
112 | }
113 | catch (Exception ex)
114 | {
115 | this.LabelStatus.Text = ex.Message;
116 | }
117 | }
118 |
119 | private void ButtonAdd_Click(object sender, EventArgs e)
120 | {
121 | try
122 | {
123 | this.LabelStatus.Text = "Storing";
124 |
125 | // Stores the same as an Enyim client, just that the nodes are already set through the config object
126 | if (mem.Store(StoreMode.Set, this.TextKey.Text, this.TextValue.Text))
127 | {
128 | #region UI Stuff
129 |
130 | this.TextGetKey.Text = this.TextKey.Text;
131 | this.LabelStatus.Text = "Storing Success";
132 | if (this.ProgressBarStatus.Value < 50)
133 | {
134 | this.ProgressBarStatus.Value = 50;
135 | }
136 |
137 | #endregion
138 | }
139 | else
140 | {
141 | this.LabelStatus.Text = "Failed to store";
142 | }
143 | }
144 | catch (Exception ex)
145 | {
146 | this.LabelStatus.Text = ex.Message;
147 | }
148 | }
149 |
150 | private void ButtonGet_Click(object sender, EventArgs e)
151 | {
152 | try
153 | {
154 | this.LabelStatus.Text = "Getting";
155 |
156 | // Gets the value the same way as a normal Enyim client from the dynamic nodes provided from the config
157 | object val;
158 | if (!mem.TryGet(TextGetKey.Text, out val))
159 | {
160 |
161 | #region UI Stuff
162 |
163 | this.LabelStatus.Text = "Failed to get";
164 | }
165 | else
166 | {
167 | this.LabelValue.Text = val as string;
168 | this.LabelStatus.Text = "Getting Success";
169 | if (this.ProgressBarStatus.Value < 75)
170 | {
171 | this.ProgressBarStatus.Value = 75;
172 | }
173 | }
174 |
175 | #endregion
176 | }
177 | catch (Exception ex)
178 | {
179 | this.LabelStatus.Text = ex.Message;
180 | }
181 | }
182 |
183 | private void ButtonExit_Click(object sender, EventArgs e)
184 | {
185 | if (mem != null)
186 | this.mem.Dispose();
187 | Application.Exit();
188 | }
189 |
190 | private void TimerPoller_Tick(object sender, EventArgs e)
191 | {
192 | this.LabelVersion.Text = String.Format("Config version is: {0} ", this.config.DiscoveryNode.ClusterVersion)
193 | + String.Format("Number of nodes: {0}", this.config.DiscoveryNode.NodesInCluster);
194 | this.ProgressPoller.PerformStep();
195 | if (this.ProgressPoller.Value == 60)
196 | {
197 | this.ProgressPoller.Value = 0;
198 | this.ProgressBarStatus.Value = 100;
199 | this.LabelStatus.Text = "Poller cycle completed.";
200 | }
201 |
202 | }
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/ClusterClientAppTester/Form1.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | 17, 17
122 |
123 |
124 | True
125 |
126 |
--------------------------------------------------------------------------------
/ClusterClientAppTester/Program.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | using System;
16 | using System.Collections.Generic;
17 | using System.Linq;
18 | using System.Windows.Forms;
19 |
20 | namespace ClusterClientAppTester
21 | {
22 | static class Program
23 | {
24 | private static Form1 form;
25 | ///
26 | /// The main entry point for the application.
27 | ///
28 | [STAThread]
29 | static void Main()
30 | {
31 | try
32 | {
33 | Application.EnableVisualStyles();
34 | Application.SetCompatibleTextRenderingDefault(false);
35 |
36 | AppDomain currentDomain = AppDomain.CurrentDomain;
37 | currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
38 |
39 | Program.form = new Form1();
40 | Application.Run(Program.form);
41 | }
42 | catch (Exception ex)
43 | {
44 | System.IO.File.WriteAllText("log.txt", ex.Message);
45 | Program.form.ErrorAlert(ex.Message);
46 | }
47 | }
48 |
49 | static void MyHandler(object sender, UnhandledExceptionEventArgs args)
50 | {
51 | Exception e = (Exception)args.ExceptionObject;
52 | System.IO.File.WriteAllText("log.txt", e.Message);
53 | Program.form.Name = e.Message;
54 | Program.form.ErrorAlert(e.Message);
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/ClusterClientAppTester/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("ClusterClientAppTester")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("ClusterClientAppTester")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("fdd8eaec-ac53-479d-8703-7f84e890701e")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/ClusterClientAppTester/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.18444
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace ClusterClientAppTester.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ClusterClientAppTester.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/ClusterClientAppTester/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/ClusterClientAppTester/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.18444
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace ClusterClientAppTester.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/ClusterClientAppTester/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ClusterClientAppTester/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/ElastiCacheClusterConfig.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.30626.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amazon.ElastiCacheCluster", "Amazon.ElastiCacheCluster\Amazon.ElastiCacheCluster.csproj", "{1255EBD3-0340-4AF6-A5F2-3D97D8709546}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClusterClientAppTester", "ClusterClientAppTester\ClusterClientAppTester.csproj", "{085886E5-3D56-4E41-941A-611EDD2A31D4}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LocalSimulationTests", "LocalSimulationTests\LocalSimulationTests.csproj", "{4348C13C-0E60-47C2-B86E-8D1FBB4060D5}"
11 | EndProject
12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{8A597A8A-8879-4589-80C6-3FA1B4BDE518}"
13 | ProjectSection(SolutionItems) = preProject
14 | .nuget\NuGet.Config = .nuget\NuGet.Config
15 | .nuget\NuGet.exe = .nuget\NuGet.exe
16 | .nuget\NuGet.targets = .nuget\NuGet.targets
17 | EndProjectSection
18 | EndProject
19 | Global
20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
21 | Debug|Any CPU = Debug|Any CPU
22 | Release|Any CPU = Release|Any CPU
23 | EndGlobalSection
24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
25 | {1255EBD3-0340-4AF6-A5F2-3D97D8709546}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26 | {1255EBD3-0340-4AF6-A5F2-3D97D8709546}.Debug|Any CPU.Build.0 = Debug|Any CPU
27 | {1255EBD3-0340-4AF6-A5F2-3D97D8709546}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {1255EBD3-0340-4AF6-A5F2-3D97D8709546}.Release|Any CPU.Build.0 = Release|Any CPU
29 | {085886E5-3D56-4E41-941A-611EDD2A31D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
30 | {085886E5-3D56-4E41-941A-611EDD2A31D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
31 | {085886E5-3D56-4E41-941A-611EDD2A31D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
32 | {085886E5-3D56-4E41-941A-611EDD2A31D4}.Release|Any CPU.Build.0 = Release|Any CPU
33 | {4348C13C-0E60-47C2-B86E-8D1FBB4060D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
34 | {4348C13C-0E60-47C2-B86E-8D1FBB4060D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
35 | {4348C13C-0E60-47C2-B86E-8D1FBB4060D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
36 | {4348C13C-0E60-47C2-B86E-8D1FBB4060D5}.Release|Any CPU.Build.0 = Release|Any CPU
37 | EndGlobalSection
38 | GlobalSection(SolutionProperties) = preSolution
39 | HideSolutionNode = FALSE
40 | EndGlobalSection
41 | EndGlobal
42 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 |
4 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
5 |
6 | 1. Definitions.
7 |
8 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
9 |
10 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
11 |
12 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
13 |
14 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
15 |
16 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
17 |
18 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
19 |
20 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
21 |
22 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
23 |
24 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
25 |
26 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
27 |
28 | 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
29 |
30 | 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
31 |
32 | 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
33 |
34 | 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
35 | 2. You must cause any modified files to carry prominent notices stating that You changed the files; and
36 | 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
37 | 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
38 |
39 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
40 |
41 | 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
42 |
43 | 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
44 |
45 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
46 |
47 | 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
48 |
49 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
50 |
51 | END OF TERMS AND CONDITIONS
52 |
--------------------------------------------------------------------------------
/LocalSimulationTests/ConfigTests.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | using System;
16 | using System.Configuration;
17 | using Microsoft.VisualStudio.TestTools.UnitTesting;
18 | using Amazon.ElastiCacheCluster;
19 | using Enyim.Caching;
20 |
21 | namespace LocalSimulationTests
22 | {
23 | [TestClass]
24 | public class ConfigTests
25 | {
26 | ElastiCacheClusterConfig config;
27 | MemcachedClient client;
28 |
29 | [TestMethod]
30 | public void ConfigTest()
31 | {
32 | // The url below is used to bypass the .cfg. contraint of the hostname for testing locally
33 | ClusterConfigSettings settings = new ClusterConfigSettings("www.cfg.org", 11211);
34 | settings.NodeFactory = new NodeFactory();
35 | config = new ElastiCacheClusterConfig(settings);
36 | this.config.DiscoveryNode.Dispose();
37 | }
38 |
39 | [TestMethod]
40 | public void InitialRequestTest()
41 | {
42 | // The url below is used to bypass the .cfg. contraint of the hostname for testing locally
43 | ClusterConfigSettings settings = new ClusterConfigSettings("www.cfg.org", 11211);
44 | settings.NodeFactory = new NodeFactory();
45 | config = new ElastiCacheClusterConfig(settings);
46 |
47 | client = new MemcachedClient(config);
48 |
49 | Assert.AreEqual(new Version("1.4.14"), config.DiscoveryNode.NodeVersion);
50 | Assert.AreEqual(1, config.DiscoveryNode.ClusterVersion);
51 | Assert.AreEqual(3, config.DiscoveryNode.NodesInCluster);
52 |
53 | this.config.DiscoveryNode.Dispose();
54 | client.Dispose();
55 | }
56 |
57 | [TestMethod]
58 | public void PollerTesting()
59 | {
60 | //Poller is set to poll every second to make this test faster
61 | ClusterConfigSettings settings = new ClusterConfigSettings("www.cfg.org", 11211);
62 | settings.NodeFactory = new NodeFactory();
63 | settings.ClusterPoller.IntervalDelay = 1000;
64 | config = new ElastiCacheClusterConfig(settings);
65 |
66 | client = new MemcachedClient(config);
67 |
68 | // Buffer time to wait, this can fail occasionally because delays can occur in the poller or timer
69 | System.Threading.Thread.Sleep(3000);
70 | Assert.AreEqual(3, config.DiscoveryNode.ClusterVersion);
71 | Assert.AreEqual(1, config.DiscoveryNode.NodesInCluster);
72 |
73 | this.config.DiscoveryNode.Dispose();
74 | client.Dispose();
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/LocalSimulationTests/LocalSimulationTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {4348C13C-0E60-47C2-B86E-8D1FBB4060D5}
7 | Library
8 | Properties
9 | LocalSimulationTests
10 | LocalSimulationTests
11 | v3.5
12 | 512
13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 10.0
15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
17 | False
18 | UnitTest
19 |
20 | ..\
21 | true
22 |
23 |
24 | true
25 | full
26 | false
27 | bin\Debug\
28 | DEBUG;TRACE
29 | prompt
30 | 4
31 |
32 |
33 | pdbonly
34 | true
35 | bin\Release\
36 | TRACE
37 | prompt
38 | 4
39 |
40 |
41 |
42 | ..\packages\EnyimMemcached.2.12\lib\net35\Enyim.Caching.dll
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | {1255ebd3-0340-4af6-a5f2-3d97d8709546}
68 | Amazon.ElastiCacheCluster
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | False
79 |
80 |
81 | False
82 |
83 |
84 | False
85 |
86 |
87 | False
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
98 |
99 |
100 |
101 |
108 |
--------------------------------------------------------------------------------
/LocalSimulationTests/NodeFactory.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | using System;
16 | using System.Collections.Generic;
17 | using System.Linq;
18 | using System.Text;
19 | using Amazon.ElastiCacheCluster.Factories;
20 | using Enyim.Caching.Memcached;
21 |
22 | namespace LocalSimulationTests
23 | {
24 | public class NodeFactory : IConfigNodeFactory
25 | {
26 | TestNode node;
27 |
28 | public NodeFactory()
29 | {
30 | this.node = new TestNode();
31 | }
32 |
33 | public IMemcachedNode CreateNode(System.Net.IPEndPoint endpoint, Enyim.Caching.Configuration.ISocketPoolConfiguration config)
34 | {
35 | return node;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/LocalSimulationTests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("LocalSimulationTests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("LocalSimulationTests")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("67675e7a-9380-4882-8b1d-f4345703e8d5")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/LocalSimulationTests/TestNode.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | using System;
16 | using System.Collections.Generic;
17 | using System.Linq;
18 | using System.Text;
19 | using Enyim.Caching.Memcached;
20 | using Enyim.Caching.Memcached.Protocol;
21 | using System.Net;
22 | using Amazon.ElastiCacheCluster.Operations;
23 | using Enyim.Caching.Memcached.Results;
24 |
25 | namespace LocalSimulationTests
26 | {
27 | public class TestNode : IMemcachedNode
28 | {
29 | private IPEndPoint end;
30 | public IPEndPoint EndPoint { get { return end; } set { this.end = value; } }
31 |
32 | private int requestNum = 1;
33 |
34 | public Enyim.Caching.Memcached.Results.IOperationResult Execute(IOperation op)
35 | {
36 | IConfigOperation getOp = op as IConfigOperation;
37 |
38 | byte[] bytes;
39 |
40 | switch (requestNum)
41 | {
42 | case 1:
43 | bytes = Encoding.UTF8.GetBytes(String.Format("{0}\r\ncluster.0001.use1.cache.amazon.aws.com|10.10.10.1|11211 cluster.0002.use1.cache.amazon.aws.com|10.10.10.2|11211 cluster.0003.use1.cache.amazon.aws.com|10.10.10.3|11211\r\n", this.requestNum));
44 | break;
45 | case 2:
46 | bytes = Encoding.UTF8.GetBytes(String.Format("{0}\r\ncluster.0002.use1.cache.amazon.aws.com|10.10.10.2|11211 cluster.0003.use1.cache.amazon.aws.com|10.10.10.3|11211\r\n", this.requestNum));
47 | break;
48 | default:
49 | bytes = Encoding.UTF8.GetBytes(String.Format("{0}\r\ncluster.0001.use1.cache.amazon.aws.com|10.10.10.1|11211\r\n", this.requestNum));
50 | break;
51 | }
52 | this.requestNum++;
53 |
54 | var arr = new ArraySegment(bytes);
55 | getOp.ConfigResult = new CacheItem(0, arr);
56 |
57 | var result = new PooledSocketResult();
58 | result.Success = true;
59 | return result;
60 | }
61 |
62 | public override string ToString()
63 | {
64 | return "TestingAWSInternal";
65 | }
66 |
67 | public bool ExecuteAsync(IOperation op, Action next)
68 | {
69 | throw new NotImplementedException();
70 | }
71 |
72 | public event Action Failed;
73 |
74 | public bool IsAlive
75 | {
76 | get { throw new NotImplementedException(); }
77 | }
78 |
79 | public bool Ping()
80 | {
81 | throw new NotImplementedException();
82 | }
83 |
84 | public void Dispose()
85 | {
86 | throw new NotImplementedException();
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/LocalSimulationTests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/NOTICE.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awslabs/elasticache-cluster-config-net/30996c7f37dbb978f7d25f926847852a1d6ea50f/NOTICE.txt
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Amazon ElastiCache Cluster Configuration for .NET
2 |
3 | Amazon ElastiCache Cluster Configuration is an enhanced .NET library that supports connecting to an Amazon ElastiCache cluster for Auto Discovery. This client library is an extension built upon Enyim and is released under the [Apache 2.0 License](http://aws.amazon.com/apache2.0/).
4 |
5 | ## Usage
6 |
7 | To use Amazon ElastiCache with Auto Discovery, the ElastiCacheClusterConfig object must be passed to the MemcachedClient object. An ElastiCacheClusterConfig can be created from the App.config if there is a clusterclient section or you can pass a different section.
8 |
9 | var client = new MemcachedClient(new ElastiCacheClusterConfig());
10 |
11 | ElastiCacheClusterConfig can also be instantiated by providing it an AutoConfigSetup or simply provide the hostname and port like so:
12 |
13 | var client = new MemcachedClient(new ElastiCacheClusterConfig("hostname", 11211));
14 |
15 | Once instantiation occurs in this way, MemcachedClient can be used the same way as the [Enyim Client](https://github.com/enyim/EnyimMemcached). The only difference is a background process polls the cluster and updates nodes when changes occur.
16 |
17 | ## App.config
18 | The ElastiCacheClusterConfig object can be configured from an application's App.config file. Here is a sample App.config that configures the Amazon ElastiCache configuration URL and the polling interval at which the client will check for changes to the cluster.
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | The rest of the app.config configuration items for Enyim can be found [here](https://github.com/enyim/EnyimMemcached/wiki/MemcachedClient-Configuration#appconfig).
34 |
35 | ## Enyim Client
36 | Because this binary is used as a configuration object for the Enyim MemcachedClient, usage beyond instantiation is all exactly the same so refer to [this wiki](https://github.com/enyim/EnyimMemcached/wiki) or [this google group](https://groups.google.com/forum/#!forum/enyim-memcached) on how to use the actual client.
37 |
38 | ## Wiki
39 | The wiki found [here](https://github.com/awslabs/elasticache-cluster-config-net/wiki) goes into more detail on the usage of the ElastiCacheClusterConfig object as well as how the project takes advantage of Auto Discovery.
40 |
41 | ## Requirements
42 |
43 | You'll need .NET Framework 3.5 or later to use the precompiled binaries. To build the client, you'll need Visual Studio 2010 or higher.
44 |
--------------------------------------------------------------------------------
/packages/repositories.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------