forked from Alachisoft/NCache-Solutions
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTester.cs
More file actions
241 lines (194 loc) · 10.6 KB
/
Tester.cs
File metadata and controls
241 lines (194 loc) · 10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
// Copyright (c) 2020 Alachisoft
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using Alachisoft.NCache.Client;
using Alachisoft.NCache.Runtime.Dependencies;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace Alachisoft.NCache.Samples
{
internal class Tester
{
// This test shows data in the cache is removed when the corresponding database contents are changed
internal static void Test1()
{
Console.WriteLine("Conducting test1\n");
Initialize();
UpdateTest();
}
// This test shows that in case of node removal from a running cache, the re-distributed data in
// partitioned and/or por topologies is removed when the corresponding database contents are changed,
// demonstrating the persistance of state during data transfer between surviving nodes
internal static void Test2()
{
Console.WriteLine("Conducting test2\n");
Initialize();
Console.WriteLine("Stop one node in cache and then press any key");
Console.ReadKey();
UpdateTest();
}
// Initialize method called in Test1 and Test2 to initialize the data, the cache handle and the database client
private static void Initialize()
{
// In case the resources aren't already initialized in a previous test
if (!_initialized)
{
Console.WriteLine($"Initializing data");
InitializeData();
Console.WriteLine($"Initializing database and seeding data");
InitializeDatabase();
Console.WriteLine($"Initializing cache");
InitializeCache();
_initialized = true;
}
Console.WriteLine($"Inserting {_customerCount} items in {_cacheId}");
InsertItemsInCacheWithDependency();
Console.WriteLine($"Number of items in cache before update: {_cache.Count}");
}
// UpdateTest is called in Test1 and Test2 to demonstrate the working of CosmosDbNotificationDependency on the server side
private static void UpdateTest()
{
UpdateDatabase();
Thread.Sleep(10000);
Console.WriteLine($"Number of items in {_cacheId} after update: {_cache.Count}");
}
// Simulates a large number of customer instances to be added to cache and database
private static void InitializeData()
{
int j = 0;
_customers = new Bogus.Faker<Customer>()
.RuleFor(i => i.Id, (fake) => $"{j++}")
.RuleFor(i => i.ContactName, (fake) => fake.Person.FullName)
.RuleFor(i => i.Address, (fake) => fake.Address.StreetAddress())
.RuleFor(i => i.City, (fake) => fake.Address.City())
.RuleFor(i => i.Country, (fake) => fake.Address.Country())
.RuleFor(i => i.CompanyName, (fake) => fake.Company.CompanyName())
.Generate(_customerCount);
}
// We start the Cosmos Db SQL API client and, if necessary, create the database as well as the monitored and leases
// collections
private static void InitializeDatabase()
{
_client = new DocumentClient(
serviceEndpoint: new Uri(_endPoint),
authKeyOrResourceToken: _authKey,
handler: _cosmosDbHandler,
connectionPolicy: _cosmosDBConnectionPolicy);
Database database = _client.CreateDatabaseIfNotExistsAsync(
new Database { Id = _databaseName }).GetAwaiter().GetResult().Resource;
DocumentCollection monitoredCollection = new DocumentCollection
{
Id = _monitoredCollection
};
monitoredCollection.PartitionKey.Paths.Add("/id");
DocumentCollection leaseCollection = new DocumentCollection
{
Id = _leaseCollection
};
leaseCollection.PartitionKey.Paths.Add("/id");
monitoredCollection = _client.CreateDocumentCollectionIfNotExistsAsync(UriFactory.CreateDatabaseUri(_databaseName), monitoredCollection, new RequestOptions { OfferThroughput = 10000 }).GetAwaiter().GetResult().Resource;
leaseCollection = _client.CreateDocumentCollectionIfNotExistsAsync(UriFactory.CreateDatabaseUri(_databaseName), leaseCollection, new RequestOptions { OfferThroughput = 10000 }).GetAwaiter().GetResult().Resource;
List<Task> tasks = new List<Task>();
foreach (var customer in _customers)
{
tasks.Add(_client.UpsertDocumentAsync(monitoredCollection.DocumentsLink, customer, new RequestOptions { PartitionKey = new PartitionKey(customer.Id) }, disableAutomaticIdGeneration: true));
}
Task.WhenAll(tasks).Wait();
}
// Initialize the cache using the cache Id and the parameters given in the client.ncconf file given in the project folder
private static void InitializeCache()
{
_cache = CacheManager.GetCache(_cacheId);
}
// We insert the created list of customers to the cache together with the CosmosDbNotificationDependency instances as
// dependencies. The insertion is done in bulk to save on network latency times
private static void InsertItemsInCacheWithDependency()
{
_cache.Clear();
Dictionary<string, CacheItem> insertItems = new Dictionary<string, CacheItem>();
foreach (var customer in _customers)
{
IDictionary<string, string> parameters = new Dictionary<string, string>();
parameters.Add("Key", customer.Id);
parameters.Add("CacheId", _cacheId);
parameters.Add("EndPoint", _endPoint);
parameters.Add("AuthKey", _authKey);
parameters.Add("DatabaseName", _databaseName);
parameters.Add("MonitoredCollection", _monitoredCollection);
parameters.Add("LeaseEndPoint", _endPoint);
parameters.Add("LeaseAuthKey", _authKey);
parameters.Add("LeaseDatabaseName", _databaseName);
parameters.Add("LeaseCollection", _leaseCollection);
CacheItem item = new CacheItem(customer);
item.Dependency = new CustomDependency(_providerName, parameters);
insertItems.Add(customer.Id, item);
};
_cache.InsertBulk(insertItems);
}
// We upsert updated customers to the database to demonstrate the CosmosDbNotificationDependency logic is working
private static void UpdateDatabase()
{
List<Task> tasks = new List<Task>();
foreach (var customer in _customers)
{
customer.Address += 1;
Task t = _client.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(_databaseName, _monitoredCollection, customer.Id), customer, new RequestOptions { PartitionKey = new PartitionKey(customer.Id) });
tasks.Add(t);
}
Task.WhenAll(tasks).Wait();
}
// The cache handle we will use to communicate with the clustered cache
private static ICache _cache;
// The Cosmos Db SQL API client used to add data in the database
private static DocumentClient _client = null;
// The endpoint URI of Azure Cosmos DB SQL API
private static readonly string _endPoint = ConfigurationManager.AppSettings["EndPoint"];
// The authorization key of Azure Cosmos DB SQL API
private static readonly string _authKey = ConfigurationManager.AppSettings["AuthKey"];
// The id of the monitored collection
private static readonly string _monitoredCollection = ConfigurationManager.AppSettings["MonitoredCollection"];
// The id of the lease collection where the change feed metadata is kept
private static readonly string _leaseCollection = ConfigurationManager.AppSettings["LeaseCollection"];
// The id of the database where the monitored collection and lease collection reside
private static readonly string _databaseName = ConfigurationManager.AppSettings["DatabaseName"];
// The number of customers we are going to add to the cache and database to test
// CosmosDbNotificationDependency
private static readonly int _customerCount = int.Parse(ConfigurationManager.AppSettings["InstanceCount"]);
// The id of the clustered cache. The value in the appSettings section should have a corresponding entry in the
// client.ncconf value given in the project folder. The default given is 'pora'
private static string _cacheId = ConfigurationManager.AppSettings["CacheID"];
//The name of the provider deployed on cache server. The default value is 'CosmosDbNotificationDependency'
private static string _providerName = ConfigurationManager.AppSettings["ProviderName"];
// The list of custom instances to add to the database and cache
private static List<Customer> _customers;
// We disable certificate validation for demonstration purposes only and should NOT be used in production environments
private static readonly HttpClientHandler _cosmosDbHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (a, b, c, d) => true
};
// The connection policy attribute when initializing the Azure Cosmos Db SQL client
private static readonly ConnectionPolicy _cosmosDBConnectionPolicy = new ConnectionPolicy
{
EnableEndpointDiscovery = false
};
// In case Test1 and Test2 are run one after the other in the same application run, the _initialized field
// makes sure we don't waste time re-initializing the customer list, database and cache
private static bool _initialized = false;
}
}