├── .gitignore
├── ExerciseCosmosDB
├── App.config
├── ExerciseCosmosDB.csproj
├── ExerciseCosmosDB.sln
├── Experiment.cs
├── IndexConfig
│ ├── index-all.json
│ ├── index-lazy-all.json
│ ├── index-lazy-id-only.json
│ ├── index-none.json
│ └── index-partial.json
├── Models
│ ├── CustomerDetails.cs
│ ├── Order.cs
│ ├── Order.json
│ ├── Order2.json
│ ├── OrderItem.cs
│ └── PaymentType.cs
├── Operations
│ ├── InsertDocument.cs
│ ├── Operation.cs
│ ├── QueryCollection.cs
│ ├── ReadCollection.cs
│ ├── ReadDocument.cs
│ └── index.json
└── Program.cs
├── LICENSE
├── LICENSE-CODE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 | .vscode
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | bld/
24 | [Bb]in/
25 | [Oo]bj/
26 | [Ll]og/
27 |
28 | # Visual Studio 2015/2017 cache/options directory
29 | .vs/
30 | # Uncomment if you have tasks that create the project's static files in wwwroot
31 | #wwwroot/
32 |
33 | # Visual Studio 2017 auto generated files
34 | Generated\ Files/
35 |
36 | # MSTest test Results
37 | [Tt]est[Rr]esult*/
38 | [Bb]uild[Ll]og.*
39 |
40 | # NUNIT
41 | *.VisualState.xml
42 | TestResult.xml
43 |
44 | # Build Results of an ATL Project
45 | [Dd]ebugPS/
46 | [Rr]eleasePS/
47 | dlldata.c
48 |
49 | # Benchmark Results
50 | BenchmarkDotNet.Artifacts/
51 |
52 | # .NET Core
53 | project.lock.json
54 | project.fragment.lock.json
55 | artifacts/
56 | **/Properties/launchSettings.json
57 |
58 | # StyleCop
59 | StyleCopReport.xml
60 |
61 | # Files built by Visual Studio
62 | *_i.c
63 | *_p.c
64 | *_i.h
65 | *.ilk
66 | *.meta
67 | *.obj
68 | *.iobj
69 | *.pch
70 | *.pdb
71 | *.ipdb
72 | *.pgc
73 | *.pgd
74 | *.rsp
75 | *.sbr
76 | *.tlb
77 | *.tli
78 | *.tlh
79 | *.tmp
80 | *.tmp_proj
81 | *.log
82 | *.vspscc
83 | *.vssscc
84 | .builds
85 | *.pidb
86 | *.svclog
87 | *.scc
88 |
89 | # Chutzpah Test files
90 | _Chutzpah*
91 |
92 | # Visual C++ cache files
93 | ipch/
94 | *.aps
95 | *.ncb
96 | *.opendb
97 | *.opensdf
98 | *.sdf
99 | *.cachefile
100 | *.VC.db
101 | *.VC.VC.opendb
102 |
103 | # Visual Studio profiler
104 | *.psess
105 | *.vsp
106 | *.vspx
107 | *.sap
108 |
109 | # Visual Studio Trace Files
110 | *.e2e
111 |
112 | # TFS 2012 Local Workspace
113 | $tf/
114 |
115 | # Guidance Automation Toolkit
116 | *.gpState
117 |
118 | # ReSharper is a .NET coding add-in
119 | _ReSharper*/
120 | *.[Rr]e[Ss]harper
121 | *.DotSettings.user
122 |
123 | # JustCode is a .NET coding add-in
124 | .JustCode
125 |
126 | # TeamCity is a build add-in
127 | _TeamCity*
128 |
129 | # DotCover is a Code Coverage Tool
130 | *.dotCover
131 |
132 | # AxoCover is a Code Coverage Tool
133 | .axoCover/*
134 | !.axoCover/settings.json
135 |
136 | # Visual Studio code coverage results
137 | *.coverage
138 | *.coveragexml
139 |
140 | # NCrunch
141 | _NCrunch_*
142 | .*crunch*.local.xml
143 | nCrunchTemp_*
144 |
145 | # MightyMoose
146 | *.mm.*
147 | AutoTest.Net/
148 |
149 | # Web workbench (sass)
150 | .sass-cache/
151 |
152 | # Installshield output folder
153 | [Ee]xpress/
154 |
155 | # DocProject is a documentation generator add-in
156 | DocProject/buildhelp/
157 | DocProject/Help/*.HxT
158 | DocProject/Help/*.HxC
159 | DocProject/Help/*.hhc
160 | DocProject/Help/*.hhk
161 | DocProject/Help/*.hhp
162 | DocProject/Help/Html2
163 | DocProject/Help/html
164 |
165 | # Click-Once directory
166 | publish/
167 |
168 | # Publish Web Output
169 | *.[Pp]ublish.xml
170 | *.azurePubxml
171 | # Note: Comment the next line if you want to checkin your web deploy settings,
172 | # but database connection strings (with potential passwords) will be unencrypted
173 | *.pubxml
174 | *.publishproj
175 |
176 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
177 | # checkin your Azure Web App publish settings, but sensitive information contained
178 | # in these scripts will be unencrypted
179 | PublishScripts/
180 |
181 | # NuGet Packages
182 | *.nupkg
183 | # The packages folder can be ignored because of Package Restore
184 | **/[Pp]ackages/*
185 | # except build/, which is used as an MSBuild target.
186 | !**/[Pp]ackages/build/
187 | # Uncomment if necessary however generally it will be regenerated when needed
188 | #!**/[Pp]ackages/repositories.config
189 | # NuGet v3's project.json files produces more ignorable files
190 | *.nuget.props
191 | *.nuget.targets
192 |
193 | # Microsoft Azure Build Output
194 | csx/
195 | *.build.csdef
196 |
197 | # Microsoft Azure Emulator
198 | ecf/
199 | rcf/
200 |
201 | # Windows Store app package directories and files
202 | AppPackages/
203 | BundleArtifacts/
204 | Package.StoreAssociation.xml
205 | _pkginfo.txt
206 | *.appx
207 |
208 | # Visual Studio cache files
209 | # files ending in .cache can be ignored
210 | *.[Cc]ache
211 | # but keep track of directories ending in .cache
212 | !*.[Cc]ache/
213 |
214 | # Others
215 | ClientBin/
216 | ~$*
217 | *~
218 | *.dbmdl
219 | *.dbproj.schemaview
220 | *.jfm
221 | *.pfx
222 | *.publishsettings
223 | orleans.codegen.cs
224 |
225 | # Including strong name files can present a security risk
226 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
227 | #*.snk
228 |
229 | # Since there are multiple workflows, uncomment next line to ignore bower_components
230 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
231 | #bower_components/
232 |
233 | # RIA/Silverlight projects
234 | Generated_Code/
235 |
236 | # Backup & report files from converting an old project file
237 | # to a newer Visual Studio version. Backup files are not needed,
238 | # because we have git ;-)
239 | _UpgradeReport_Files/
240 | Backup*/
241 | UpgradeLog*.XML
242 | UpgradeLog*.htm
243 | ServiceFabricBackup/
244 | *.rptproj.bak
245 |
246 | # SQL Server files
247 | *.mdf
248 | *.ldf
249 | *.ndf
250 |
251 | # Business Intelligence projects
252 | *.rdl.data
253 | *.bim.layout
254 | *.bim_*.settings
255 | *.rptproj.rsuser
256 |
257 | # Microsoft Fakes
258 | FakesAssemblies/
259 |
260 | # GhostDoc plugin setting file
261 | *.GhostDoc.xml
262 |
263 | # Node.js Tools for Visual Studio
264 | .ntvs_analysis.dat
265 | node_modules/
266 |
267 | # Visual Studio 6 build log
268 | *.plg
269 |
270 | # Visual Studio 6 workspace options file
271 | *.opt
272 |
273 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
274 | *.vbw
275 |
276 | # Visual Studio LightSwitch build output
277 | **/*.HTMLClient/GeneratedArtifacts
278 | **/*.DesktopClient/GeneratedArtifacts
279 | **/*.DesktopClient/ModelManifest.xml
280 | **/*.Server/GeneratedArtifacts
281 | **/*.Server/ModelManifest.xml
282 | _Pvt_Extensions
283 |
284 | # Paket dependency manager
285 | .paket/paket.exe
286 | paket-files/
287 |
288 | # FAKE - F# Make
289 | .fake/
290 |
291 | # JetBrains Rider
292 | .idea/
293 | *.sln.iml
294 |
295 | # CodeRush
296 | .cr/
297 |
298 | # Python Tools for Visual Studio (PTVS)
299 | __pycache__/
300 | *.pyc
301 |
302 | # Cake - Uncomment if you are using it
303 | # tools/**
304 | # !tools/packages.config
305 |
306 | # Tabs Studio
307 | *.tss
308 |
309 | # Telerik's JustMock configuration file
310 | *.jmconfig
311 |
312 | # BizTalk build output
313 | *.btp.cs
314 | *.btm.cs
315 | *.odx.cs
316 | *.xsd.cs
317 |
318 | # OpenCover UI analysis results
319 | OpenCover/
320 |
321 | # Azure Stream Analytics local run output
322 | ASALocalRun/
323 |
324 | # MSBuild Binary and Structured Log
325 | *.binlog
326 |
327 | # NVidia Nsight GPU debugger configuration file
328 | *.nvuser
329 |
330 | # MFractors (Xamarin productivity tool) working folder
331 | .mfractor/
332 |
333 | # Mac OS
334 | .DS_Store
335 |
--------------------------------------------------------------------------------
/ExerciseCosmosDB/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/ExerciseCosmosDB/ExerciseCosmosDB.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp6.0
6 | mslearn_monitor_azure_cosmos_db
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/ExerciseCosmosDB/ExerciseCosmosDB.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExerciseCosmosDB", "ExerciseCosmosDB.csproj", "{FDF43ED9-1D7A-4CDC-9029-B6B515559DE3}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Any CPU = Debug|Any CPU
9 | Release|Any CPU = Release|Any CPU
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {FDF43ED9-1D7A-4CDC-9029-B6B515559DE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
13 | {FDF43ED9-1D7A-4CDC-9029-B6B515559DE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
14 | {FDF43ED9-1D7A-4CDC-9029-B6B515559DE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
15 | {FDF43ED9-1D7A-4CDC-9029-B6B515559DE3}.Release|Any CPU.Build.0 = Release|Any CPU
16 | EndGlobalSection
17 | EndGlobal
18 |
--------------------------------------------------------------------------------
/ExerciseCosmosDB/Experiment.cs:
--------------------------------------------------------------------------------
1 | namespace MsLearnCosmosDB
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Collections.Concurrent;
6 | using System.Reflection;
7 | using System.Diagnostics;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using Microsoft.Azure.Documents.Client;
11 | using Microsoft.Azure.Documents;
12 |
13 | public class Experiment
14 | {
15 | private readonly DocumentClient client;
16 | private readonly DocumentCollection collection;
17 | private readonly Uri DocumentCollectionUri;
18 | private readonly ConfigurationOptions Options;
19 | private int PendingTaskCount;
20 | private long OperationCount;
21 | private ConcurrentDictionary requestUnitsConsumed = new ConcurrentDictionary();
22 |
23 | ///
24 | /// Initializes a new instance of the class.
25 | ///
26 | /// Client.
27 | /// Collection.
28 | /// Document collection URI.
29 | /// Configured options
30 | public Experiment(DocumentClient client, DocumentCollection collection, Uri documentCollectionUri, ConfigurationOptions options)
31 | {
32 | this.client = client;
33 | this.collection = collection;
34 | this.DocumentCollectionUri = documentCollectionUri;
35 | this.Options = options;
36 | this.OperationCount = 0;
37 | }
38 |
39 | ///
40 | /// Run the experiment. Pre-allocates customers and items so that there are multiple
41 | /// orders made by the same customer, and the same item is ordered multiple times.
42 | /// This is currently a fixed ratio but could be extended to configurable ones.
43 | ///
44 | /// The experiment task
45 | public async Task RunAsync()
46 | {
47 | Assembly assembly = Assembly.GetExecutingAssembly();
48 | Type operationType = assembly.GetType("MsLearnCosmosDB." + Options.Operation);
49 |
50 | if (operationType == null)
51 | {
52 | Console.WriteLine("Could not find operation of type: {0}", Options.Operation);
53 | Environment.Exit(-1);
54 | }
55 |
56 | Operation operation = (Operation)Activator.CreateInstance(operationType);
57 |
58 | if (operation.GetOperationType() == "Write")
59 | {
60 | Console.WriteLine("Setting up experiment...");
61 | int numCustomers = Math.Max(1, (Options.NumberOfOperations * 4) / 10);
62 | CustomerDetails.Allocate(numCustomers);
63 | int numItems = Math.Max(1, (Options.NumberOfOperations * 2) / 10);
64 | OrderItem.Allocate(numItems);
65 | }
66 |
67 | int taskCount;
68 |
69 | if (Options.Parallelism == -1)
70 | {
71 | // set TaskCount = 3 for each 1k RUs, minimum 1, maximum 250
72 | taskCount = Math.Max(Options.Throughput / 333, 1);
73 | taskCount = Math.Min(taskCount, 250);
74 | }
75 | else
76 | {
77 | taskCount = Options.Parallelism;
78 | }
79 |
80 | Console.WriteLine("Starting experiment with {0} tasks @ {1}", taskCount, DateTime.Now);
81 |
82 | PendingTaskCount = taskCount;
83 |
84 | int numberOfOperationsPerTask = Options.NumberOfOperations / taskCount;
85 | int remainingOperations = Options.NumberOfOperations - (numberOfOperationsPerTask * taskCount);
86 |
87 | var tasks = new List();
88 | tasks.Add(LogOutputStats(operation.GetOperationType()));
89 |
90 | for (var i = 0; i < taskCount; i++)
91 | {
92 | int numberOfOperations = numberOfOperationsPerTask;
93 | if (i == taskCount - 1)
94 | {
95 | numberOfOperations += remainingOperations;
96 | }
97 | tasks.Add(RunTask(operation, i, numberOfOperations));
98 | }
99 |
100 | await Task.WhenAll(tasks);
101 | }
102 |
103 | ///
104 | /// Runs the task.
105 | ///
106 | /// The task.
107 | /// Operation.
108 | /// Task identifier.
109 | /// Number of operations.
110 | private async Task RunTask(Operation operation, int taskId, int numberOfOperations)
111 | {
112 | requestUnitsConsumed[taskId] = 0;
113 |
114 | for (var i = 0; i < numberOfOperations; i++)
115 | {
116 | await operation.Execute(this, client, collection, DocumentCollectionUri, taskId, Options);
117 | }
118 |
119 | DecrementPendingTaskCount();
120 | }
121 |
122 | ///
123 | /// Logs the output stats.
124 | ///
125 | /// The output stats.
126 | /// Type.
127 | private async Task LogOutputStats(string type)
128 | {
129 | long lastCount = 0;
130 | double lastRequestUnits = 0;
131 | double lastSeconds = 0;
132 | double requestUnits = 0;
133 |
134 | Stopwatch watch = new Stopwatch();
135 | watch.Start();
136 |
137 | while (PendingTaskCount > 0)
138 | {
139 | await Task.Delay(TimeSpan.FromSeconds(1));
140 | double seconds = watch.Elapsed.TotalSeconds;
141 |
142 | requestUnits = 0;
143 | foreach (int taskId in requestUnitsConsumed.Keys)
144 | {
145 | requestUnits += requestUnitsConsumed[taskId];
146 | }
147 |
148 | long currentCount = OperationCount;
149 |
150 | LogOutput(type, currentCount, OperationCount, seconds, requestUnits);
151 |
152 | lastCount = OperationCount;
153 | lastSeconds = seconds;
154 | lastRequestUnits = requestUnits;
155 | }
156 |
157 | double totalSeconds = watch.Elapsed.TotalSeconds;
158 |
159 | Console.WriteLine();
160 | Console.WriteLine("----------------------------------------------------------------- ");
161 | LogOutput(type, lastCount, OperationCount, watch.Elapsed.TotalSeconds, requestUnits);
162 | Console.WriteLine("Total (consumed {0} RUs in {1} seconds)", Math.Round(requestUnits, 1), Math.Round(watch.Elapsed.TotalSeconds));
163 | Console.WriteLine("------------------------------------------------------------------");
164 | }
165 |
166 | ///
167 | /// Logs the output.
168 | ///
169 | /// Type.
170 | /// Count.
171 | /// Operations.
172 | /// Seconds.
173 | /// Request units.
174 | private void LogOutput(string type, long count, long operations, double seconds, double requestUnits)
175 | {
176 | double ruPerSecond = (requestUnits / seconds);
177 |
178 | Console.WriteLine("Performed {0} {1} operations @ {2} operations/s, {3} RU/s)",
179 | count,
180 | type,
181 | Math.Round(operations / seconds),
182 | Math.Round(ruPerSecond, 1));
183 | }
184 |
185 |
186 | ///
187 | /// Increments the operation count.
188 | ///
189 | public void IncrementOperationCount()
190 | {
191 | Interlocked.Increment(ref OperationCount);
192 | }
193 |
194 | ///
195 | /// Decrements the pending task count.
196 | ///
197 | public void DecrementPendingTaskCount()
198 | {
199 | Interlocked.Decrement(ref PendingTaskCount);
200 | }
201 |
202 | ///
203 | /// Updates the request units.
204 | ///
205 | /// Task identifier.
206 | /// Request units.
207 | public void UpdateRequestUnits(int taskId, double requestUnits)
208 | {
209 | requestUnitsConsumed[taskId] += requestUnits;
210 | }
211 |
212 | }
213 | }
--------------------------------------------------------------------------------
/ExerciseCosmosDB/IndexConfig/index-all.json:
--------------------------------------------------------------------------------
1 | {
2 | "indexingMode": "consistent",
3 | "automatic": true,
4 | "includedPaths": [
5 | {
6 | "path": "/*",
7 | "indexes": [
8 | {
9 | "kind": "Range",
10 | "dataType": "Number",
11 | "precision": -1
12 | },
13 | {
14 | "kind": "Hash",
15 | "dataType": "String",
16 | "precision": 3
17 | }
18 | ]
19 | }
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/ExerciseCosmosDB/IndexConfig/index-lazy-all.json:
--------------------------------------------------------------------------------
1 | {
2 | "indexingMode": "lazy",
3 | "automatic": true,
4 | "includedPaths": [
5 | {
6 | "path": "/*",
7 | "indexes": [
8 | {
9 | "kind": "Range",
10 | "dataType": "Number",
11 | "precision": -1
12 | },
13 | {
14 | "kind": "Hash",
15 | "dataType": "String",
16 | "precision": 3
17 | }
18 | ]
19 | }
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/ExerciseCosmosDB/IndexConfig/index-lazy-id-only.json:
--------------------------------------------------------------------------------
1 | {
2 | "indexingMode": "lazy",
3 | "automatic": true,
4 | "includedPaths": [
5 | {
6 | "path": "/Item/id/?"
7 | }
8 | ],
9 | "excludedPaths": [
10 | {
11 | "path": "/"
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/ExerciseCosmosDB/IndexConfig/index-none.json:
--------------------------------------------------------------------------------
1 | {
2 | "indexingMode": "none"
3 | }
4 |
--------------------------------------------------------------------------------
/ExerciseCosmosDB/IndexConfig/index-partial.json:
--------------------------------------------------------------------------------
1 | {
2 | "indexingMode": "consistent",
3 | "automatic": true,
4 | "includedPaths": [
5 | {
6 | "path": "/Item/id/?"
7 | },
8 | {
9 | "path": "/Customer/email/?"
10 | },
11 | {
12 | "path": "/OrderTime/?"
13 | },
14 | {
15 | "path": "/Merchant/?"
16 | },
17 | {
18 | "path": "/OrderStatus/?"
19 | }
20 | ],
21 | "excludedPaths": [
22 | {
23 | "path": "/"
24 | }
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/ExerciseCosmosDB/Models/CustomerDetails.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace MsLearnCosmosDB
4 | {
5 | public class CustomerDetails
6 | {
7 | public Guid id { get; set; }
8 | public string FirstName { get; set; }
9 | public string LastName { get; set; }
10 | public string Email { get; set; }
11 | public string StreetAddress { get; set; }
12 | public string ZipCode { get; set; }
13 | public string State { get; set; }
14 | static CustomerDetails[] Customers;
15 | static Random RandomIndex = new Random();
16 |
17 | ///
18 | /// Allocate the specified numCustomers.
19 | ///
20 | /// Number customers.
21 | public static void Allocate(int numCustomers)
22 | {
23 | Customers = new CustomerDetails[numCustomers];
24 | for (int i = 0; i < numCustomers; i++)
25 | {
26 | Customers[i] = NewCustomerDetails();
27 | }
28 | }
29 | public static CustomerDetails NewCustomerDetails()
30 | {
31 | Bogus.Faker customerDetailsGenerator = new Bogus.Faker().Rules(
32 | (faker, customerDetails) =>
33 | {
34 | customerDetails.id = faker.Random.Guid();
35 | customerDetails.FirstName = faker.Name.FirstName();
36 | customerDetails.LastName = faker.Name.LastName();
37 | customerDetails.Email = faker.Internet.Email(customerDetails.FirstName, customerDetails.LastName);
38 | customerDetails.StreetAddress = faker.Address.StreetAddress();
39 | customerDetails.State = faker.Address.StateAbbr();
40 | customerDetails.ZipCode = faker.Address.ZipCode();
41 | });
42 |
43 | return customerDetailsGenerator.Generate();
44 | }
45 |
46 | public static CustomerDetails GetRandomCustomer()
47 | {
48 | // Assumes that customers are being allocated in a single thread.
49 | return Customers[RandomIndex.Next(0, Customers.Length)];
50 | }
51 |
52 | }
53 |
54 | }
--------------------------------------------------------------------------------
/ExerciseCosmosDB/Models/Order.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using Newtonsoft.Json;
4 |
5 | namespace MsLearnCosmosDB
6 | {
7 | public class Order
8 | {
9 | [JsonProperty(PropertyName = "id")]
10 | public string OrderId { get; set; }
11 | public string OrderTime;
12 | public string OrderStatus { get; set; }
13 | public OrderItem Item { get; set; }
14 | public long Quantity { get; set; }
15 | public PaymentType PaymentInstrumentType { get; set; }
16 | public string PurchaseOrderNumber { get; set; }
17 | public CustomerDetails Customer { get; set; }
18 | public DateTime ShippingDate { get; set; }
19 | // padding for record size
20 | public byte[] Data { get; set; }
21 |
22 | static Order[] Orders;
23 |
24 | static int NextOrder = -1;
25 |
26 | public static void Allocate(int numOrders)
27 | {
28 | Orders = new Order[numOrders];
29 | for (int i = 0; i < numOrders; i++)
30 | {
31 | Orders[i] = Order.NewOrder();
32 | }
33 | }
34 |
35 | public static Order NewOrder()
36 | {
37 | Bogus.Faker orderGenerator = new Bogus.Faker().Rules(
38 | (faker, order) =>
39 | {
40 | order.OrderId = faker.Random.Guid().ToString();
41 | var now = DateTime.Now;
42 | order.OrderTime = now.ToShortTimeString();
43 | order.OrderStatus = "NEW";
44 | order.Item = OrderItem.GetRandomItem();
45 | order.Quantity = faker.Random.Long(1, 100);
46 | order.PaymentInstrumentType = faker.Random.Enum();
47 | order.PurchaseOrderNumber = faker.Random.Replace("###-#####-##");
48 | order.Customer = CustomerDetails.GetRandomCustomer();
49 | order.ShippingDate = now.Add(new TimeSpan(faker.Random.Int(0, 10), 0, 0, 0));
50 | order.Data = faker.Random.Bytes(10);
51 | });
52 |
53 | return orderGenerator.Generate();
54 | }
55 |
56 | public static Order Next()
57 | {
58 | int index = Interlocked.Increment(ref NextOrder);
59 |
60 | if (index >= Orders.Length)
61 | {
62 | throw new Exception("Order allocation exceeded");
63 | }
64 |
65 | return Orders[index];
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/ExerciseCosmosDB/Models/Order.json:
--------------------------------------------------------------------------------
1 | {
2 | "OrderTime": "4:21 PM",
3 | "id": "e152c6b5-2d9b-f232-6f58-de17190ecfec",
4 | "OrderStatus": "NEW",
5 | "Item": {
6 | "id": "52841410-7500-828d-e932-66f166e6f87f",
7 | "Title": "8vlyf0jyvexfv3f",
8 | "Category": "Books",
9 | "UPC": "74:8585:249",
10 | "Website": "https://pzr.khdftcp.com",
11 | "ReleaseDate": "2019-01-10T16:21:41.039088-08:00",
12 | "Condition": "NEW",
13 | "Merchant": "24/7",
14 | "ListPricePerItem": 13.41,
15 | "PurchasePrice": 12.76,
16 | "Currency": "USD"
17 | },
18 | "Quantity": 24,
19 | "PaymentInstrumentType": 1,
20 | "PurchaseOrderNumber": "422-40277-87",
21 | "Customer": {
22 | "id": "297b2be8-f31f-cd84-4013-5a9a13a8aae6",
23 | "FirstName": "Clair",
24 | "LastName": "Weber",
25 | "Email": "Clair.Weber@yahoo.com",
26 | "StreetAddress": "594 Stoltenberg Divide",
27 | "ZipCode": "93267-7740",
28 | "State": "VT"
29 | },
30 | "ShippingDate": "2019-01-16T16:21:41.65195-08:00",
31 | "Data": "2FgYt+9u0FiL4Q==",
32 | }
--------------------------------------------------------------------------------
/ExerciseCosmosDB/Models/Order2.json:
--------------------------------------------------------------------------------
1 | {
2 | "OrderTime": "4:21 PM",
3 | "id": "c0292ca2-c932-4e7f-a159-330dfd7d18e9",
4 | "OrderStatus": "NEW",
5 | "Item": {
6 | "id": "07f11c55-6a17-3521-9c62-8ec4bf12d75b",
7 | "Title": "aqyq0ir54234qz3",
8 | "Category": "Books",
9 | "UPC": "85:8913:018",
10 | "Website": "https://asu.vvkgmfo.com",
11 | "ReleaseDate": "2019-01-10T16:21:41.15317-08:00",
12 | "Condition": "NEW",
13 | "Merchant": "Producer",
14 | "ListPricePerItem": 26.4,
15 | "PurchasePrice": 23.73,
16 | "Currency": "USD"
17 | },
18 | "Quantity": 80,
19 | "PaymentInstrumentType": 2,
20 | "PurchaseOrderNumber": "095-59132-06",
21 | "Customer": {
22 | "id": "b7903b01-2aec-e85e-42b0-4b9f342a8560",
23 | "FirstName": "Garland",
24 | "LastName": "Murazik",
25 | "Email": "Garland33@gmail.com",
26 | "StreetAddress": "605 Ritchie Ferry",
27 | "ZipCode": "15719",
28 | "State": "IA"
29 | },
30 | "ShippingDate": "2019-01-13T16:21:42.487967-08:00",
31 | "Data": "BG4eT0bLt+W5Uw=="
32 | }
--------------------------------------------------------------------------------
/ExerciseCosmosDB/Models/OrderItem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Configuration;
3 |
4 | namespace MsLearnCosmosDB
5 | {
6 | public class OrderItem
7 | {
8 | public Guid id { get; set;}
9 | public string Title { get; set; }
10 | public string Category { get; set; }
11 | public string UPC { get; set; }
12 | public string Website { get; set; }
13 | public DateTime ReleaseDate { get; set; }
14 | public string Condition { get; set; }
15 | public string Merchant { get; set; }
16 | public double ListPricePerItem { get; set; }
17 | public double PurchasePrice { get; set; }
18 | public string Currency { get; set; }
19 | public static string[] Categories =
20 | {
21 | "Books",
22 | "Electronics",
23 | "Cosmetics",
24 | "Tools",
25 | "Kitchenware",
26 | "Office Supplies",
27 | "Whiteware"
28 | };
29 | public static float[] CategoryWeights = { 0.7F, 0.05F, 0.05F, 0.05F, 0.05F, 0.05F, 0.05F };
30 | static OrderItem[] Items;
31 | static Random RandomIndex = new Random();
32 |
33 | ///
34 | /// Allocate this instance.
35 | ///
36 | public static void Allocate(int numItems)
37 | {
38 | Items = new OrderItem[numItems];
39 | for (int i = 0; i < numItems; i++)
40 | {
41 | Items[i] = NewItem();
42 | }
43 | }
44 |
45 | public static OrderItem NewItem()
46 | {
47 | Bogus.Faker itemGenerator = new Bogus.Faker().Rules(
48 | (faker, item) =>
49 | {
50 | item.id = faker.Random.Guid();
51 | item.Title = faker.Random.AlphaNumeric(15);
52 | item.Category = faker.Random.WeightedRandom(Categories, CategoryWeights);
53 | item.Merchant = faker.Random.Word();
54 | item.UPC = faker.Random.Replace("##:####:###");
55 | item.Website = faker.Random.Replace("https://???.???????.com").ToLower();
56 |
57 | item.ReleaseDate = DateTime.Now;
58 | item.Condition = "NEW";
59 | item.ListPricePerItem = Math.Round((faker.Random.Double() * 100),2);
60 | item.PurchasePrice = Math.Round(item.ListPricePerItem * faker.Random.Double(0.8),2);
61 | item.Currency = "USD";
62 | });
63 |
64 | return itemGenerator.Generate();
65 | }
66 |
67 | public static OrderItem GetRandomItem()
68 | {
69 | // Assumes that customers are being allocated in a single thread.
70 | return Items[RandomIndex.Next(0, Items.Length)];
71 | }
72 |
73 |
74 | }
75 | }
--------------------------------------------------------------------------------
/ExerciseCosmosDB/Models/PaymentType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace MsLearnCosmosDB
3 | {
4 | public enum PaymentType
5 | {
6 | Visa,
7 | Mastercard,
8 | Paypal,
9 | Venmo,
10 | Bitcoin
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ExerciseCosmosDB/Operations/InsertDocument.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Net;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using Microsoft.Azure.Documents.Client;
7 | using Microsoft.Azure.Documents;
8 | using Newtonsoft.Json;
9 |
10 | namespace MsLearnCosmosDB
11 | {
12 |
13 | class InsertDocument : Operation
14 | {
15 | public string GetOperationType()
16 | {
17 | return "Write";
18 | }
19 |
20 | public async Task Execute(Experiment experiment, DocumentClient client, DocumentCollection collection, Uri documentCollectionUri, int taskId, ConfigurationOptions options)
21 | {
22 | var cancellationTokenService = new CancellationTokenSource();
23 | try
24 | {
25 | cancellationTokenService.CancelAfter(2500);
26 |
27 | Order order = Order.NewOrder();
28 |
29 | ResourceResponse response = await client.CreateDocumentAsync(documentCollectionUri, order, new RequestOptions() { }, false, cancellationTokenService.Token);
30 |
31 | if (options.Record)
32 | {
33 | Console.WriteLine("Order: {0}", JsonConvert.SerializeObject(order));
34 | }
35 | experiment.IncrementOperationCount();
36 | experiment.UpdateRequestUnits(taskId, response.RequestCharge);
37 | }
38 | catch (Exception e)
39 | {
40 | Trace.TraceError("Failed to write. Exception was {0}", e);
41 | if (e is DocumentClientException)
42 | {
43 | DocumentClientException de = (DocumentClientException)e;
44 | if (de.StatusCode == HttpStatusCode.Forbidden)
45 | {
46 | experiment.IncrementOperationCount();
47 | }
48 | }
49 | }
50 |
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/ExerciseCosmosDB/Operations/Operation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Microsoft.Azure.Documents;
4 | using Microsoft.Azure.Documents.Client;
5 |
6 | namespace MsLearnCosmosDB
7 | {
8 | public interface Operation
9 | {
10 | Task Execute(Experiment experiment, DocumentClient client, DocumentCollection collection, Uri documentCollectionUri, int taskId, ConfigurationOptions options);
11 |
12 | string GetOperationType();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ExerciseCosmosDB/Operations/QueryCollection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading.Tasks;
4 | using Microsoft.Azure.Documents.Client;
5 | using Microsoft.Azure.Documents;
6 | using Microsoft.Azure.Documents.Linq;
7 |
8 | namespace MsLearnCosmosDB
9 | {
10 | public class QueryCollection : Operation
11 | {
12 | public string GetOperationType()
13 | {
14 | return "Query";
15 | }
16 |
17 | public async Task Execute(Experiment experiment, DocumentClient client, DocumentCollection collection, Uri documentCollectionUri, int taskId, ConfigurationOptions options)
18 | {
19 | try
20 | {
21 | IDocumentQuery query = client.CreateDocumentQuery(documentCollectionUri, options.QueryString,
22 | new FeedOptions
23 | {
24 | PopulateQueryMetrics = true,
25 | MaxItemCount = -1,
26 | MaxDegreeOfParallelism = -1,
27 | EnableCrossPartitionQuery = true,
28 | EnableScanInQuery = true
29 | }).AsDocumentQuery();
30 |
31 | while (query.HasMoreResults)
32 | {
33 | FeedResponse response = await query.ExecuteNextAsync();
34 |
35 | experiment.UpdateRequestUnits(taskId, response.RequestCharge);
36 |
37 | if (options.Record)
38 | {
39 | var enumerator = response.GetEnumerator();
40 | while (enumerator.MoveNext())
41 | {
42 | var current = enumerator.Current;
43 | Console.WriteLine("Order {0}", current.ToString());
44 | }
45 | }
46 | }
47 | experiment.IncrementOperationCount();
48 | }
49 | catch (Exception e)
50 | {
51 | Console.WriteLine("Failed to read {0}. Exception was {1}", collection.SelfLink, e);
52 | if (e is DocumentClientException)
53 | {
54 | DocumentClientException de = (DocumentClientException)e;
55 | if (de.StatusCode == HttpStatusCode.Forbidden)
56 | {
57 | experiment.IncrementOperationCount();
58 | }
59 | }
60 | }
61 |
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/ExerciseCosmosDB/Operations/ReadCollection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Net;
4 | using System.Threading.Tasks;
5 | using Microsoft.Azure.Documents.Client;
6 | using Microsoft.Azure.Documents;
7 |
8 | namespace MsLearnCosmosDB
9 | {
10 | class ReadCollection: Operation
11 | {
12 | public string GetOperationType()
13 | {
14 | return "Read";
15 | }
16 |
17 | public async Task Execute(Experiment experiment, DocumentClient client, DocumentCollection collection, Uri documentCollectionUri, int taskId, ConfigurationOptions options)
18 | {
19 | try
20 | {
21 | ResourceResponse response = await client.ReadDocumentCollectionAsync(collection.SelfLink, new RequestOptions() {} );
22 | experiment.IncrementOperationCount();
23 | experiment.UpdateRequestUnits(taskId, response.RequestCharge);
24 | }
25 | catch (Exception e)
26 | {
27 | Trace.TraceError("Failed to read {0}. Exception was {1}", collection.SelfLink, e);
28 | if (e is DocumentClientException)
29 | {
30 | DocumentClientException de = (DocumentClientException)e;
31 | if (de.StatusCode == HttpStatusCode.Forbidden)
32 | {
33 | experiment.IncrementOperationCount();
34 | }
35 | }
36 | }
37 |
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/ExerciseCosmosDB/Operations/ReadDocument.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading.Tasks;
4 | using Microsoft.Azure.Documents.Client;
5 | using Microsoft.Azure.Documents;
6 |
7 | namespace MsLearnCosmosDB
8 | {
9 | public class ReadDocument : Operation
10 | {
11 | public string GetOperationType()
12 | {
13 | return "Query";
14 | }
15 |
16 | public async Task Execute(Experiment experiment, DocumentClient client, DocumentCollection collection, Uri documentCollectionUri, int taskId, ConfigurationOptions options)
17 | {
18 | try
19 | {
20 | RequestOptions requestOptions = new RequestOptions();
21 | requestOptions.PartitionKey = new PartitionKey(options.PartitionKey);
22 |
23 | var response = await client.ReadDocumentAsync(options.DocumentLink, requestOptions);
24 |
25 | experiment.IncrementOperationCount();
26 | experiment.UpdateRequestUnits(taskId, response.RequestCharge);
27 |
28 | if (options.Record)
29 | {
30 | Console.WriteLine("Order: {0}", response.Resource);
31 | }
32 | }
33 | catch (Exception e)
34 | {
35 | Console.WriteLine("Failed to read {0}. Exception was {1}", collection.SelfLink, e);
36 | if (e is DocumentClientException)
37 | {
38 | DocumentClientException de = (DocumentClientException)e;
39 | if (de.StatusCode == HttpStatusCode.Forbidden)
40 | {
41 | experiment.IncrementOperationCount();
42 | }
43 | }
44 | }
45 |
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/ExerciseCosmosDB/Operations/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "indexingMode": "consistent",
3 | "automatic": true,
4 | "includedPaths": [
5 | {
6 | "path": "/Item/*",
7 | "indexes": [
8 | {
9 | "kind": "Range",
10 | "dataType": "Number",
11 | "precision": -1
12 | },
13 | {
14 | "kind": "Hash",
15 | "dataType": "String",
16 | "precision": 3
17 | }
18 | ]
19 | }
20 | ],
21 | "excludedPaths": [{
22 | "path": "/OrderItem/Title",
23 | },
24 | {
25 | "path": "/OrderItem/Website",
26 | },
27 | {
28 | "path": "/OrderItem/ReleaseDate",
29 | },
30 | {
31 | "path": "/OrderItem/ListPricePerItem",
32 | },
33 | {
34 | "path": "/OrderItem/PurchasePrice",
35 | },
36 | {
37 | "path": "/OrderItem/Currency",
38 | },
39 | {
40 | "path": "/PaymentInstrumentType",
41 | },
42 | {
43 | "path": "/Quantity",
44 | },
45 | {
46 | "path": "/Customer/StreetAddress",
47 | }]
48 | }
49 |
--------------------------------------------------------------------------------
/ExerciseCosmosDB/Program.cs:
--------------------------------------------------------------------------------
1 | namespace MsLearnCosmosDB {
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Diagnostics;
5 | using System.Linq;
6 | using System.Net;
7 | using System.Threading.Tasks;
8 | using System.Threading;
9 | using System;
10 | using CommandLine;
11 | using Microsoft.Azure.Documents.Client;
12 | using Microsoft.Azure.Documents;
13 |
14 | public class ConfigurationOptions {
15 | [Option ('d', "database", Required = false, HelpText = "The database to exercise")]
16 | public string Database { get; set; }
17 |
18 | [Option ('c', "collection", Required = false, HelpText = "The collection to exercise")]
19 | public string Collection { get; set; }
20 |
21 | [Option('t', "throughput", Required = false, HelpText = "Throughput of the collection (in RU/s)")]
22 | public int Throughput { get; set; }
23 |
24 | [Option ('o', "operation", Required = false, HelpText = "Operation to run for experiment. Name of Operation class to load.")]
25 | public string Operation { get; set; }
26 |
27 | [Option ('n', "number", Required = false, HelpText = "Number of operations to run")]
28 | public int NumberOfOperations { get; set; }
29 |
30 | [Option('p', "parallelism", Required = false, HelpText = "Number of threads to start")]
31 | public int Parallelism { get; set; }
32 |
33 | [Option ('q', "query", Required = false, HelpText = "The query string to run")]
34 | public string QueryString { get; set; }
35 |
36 | [Option ('k', "key", Required = false, HelpText = "The value of the partition key to access")]
37 | public string PartitionKey { get; set; }
38 |
39 | [Option ('l', "link", Required = false, HelpText = "The collection or document link to access")]
40 | public string DocumentLink { get; set; }
41 |
42 | [Option('v', "verbose", Required = false, HelpText = "Log configuration and results (with reduced performance)")]
43 | public bool Verbose { get; set; }
44 |
45 | [Option('r', "record", Required = false, HelpText = "Print out records as they are read and written")]
46 | public bool Record { get; set; }
47 |
48 | void Log(string message, params string[] args)
49 | {
50 | if (Verbose)
51 | {
52 | Console.WriteLine(message, args);
53 | }
54 | }
55 | }
56 |
57 | ///
58 | /// This sample repeatedly runs an operation on a CosmosDB collection to demonstrate high performance throughput.
59 | ///
60 | public sealed class Program {
61 | private static string InstanceId = Dns.GetHostEntry("LocalHost").HostName + Process.GetCurrentProcess().Id;
62 |
63 | private static ConfigurationOptions Options;
64 |
65 | private static readonly ConnectionPolicy ConnectionPolicy = new ConnectionPolicy {
66 | ConnectionMode = ConnectionMode.Direct,
67 | ConnectionProtocol = Protocol.Tcp,
68 | RequestTimeout = new TimeSpan (1, 0, 0),
69 | MaxConnectionLimit = 1000,
70 | RetryOptions = new RetryOptions {
71 | MaxRetryAttemptsOnThrottledRequests = 10,
72 | MaxRetryWaitTimeInSeconds = 60
73 | }
74 | };
75 |
76 | private const int MinThreadPoolSize = 100;
77 | private DocumentClient client;
78 |
79 | ///
80 | /// Initialize a new instance of the class.
81 | ///
82 | /// The DocumentDB client instance.
83 | private Program (DocumentClient client) {
84 | this.client = client;
85 | }
86 |
87 | ///
88 | /// Main method for the sample.
89 | ///
90 | /// command line arguments.
91 | public static void Main (string[] args) {
92 |
93 | ThreadPool.SetMinThreads (MinThreadPoolSize, MinThreadPoolSize);
94 |
95 | ProcessArgs (args);
96 | }
97 |
98 | ///
99 | /// Processes arguments from config file and command line.
100 | /// Where both are set, command line takes precedence.
101 | ///
102 | /// String array of arguments passed in via the command line
103 | private static void ProcessArgs (string[] args) {
104 | CommandLine.Parser.Default.ParseArguments (args)
105 | .WithParsed (opts => HandleConfigFileAndRun (opts))
106 | .WithNotParsed ((errs) => HandleParseError (errs));
107 | }
108 |
109 | ///
110 | /// Handles settings from the config file and run.
111 | ///
112 | private static void HandleConfigFileAndRun (ConfigurationOptions opts) {
113 | string endpoint = Environment.GetEnvironmentVariable ("ENDPOINT");
114 | string authKey = Environment.GetEnvironmentVariable ("KEY");
115 |
116 | if ((endpoint == null) || (authKey == null)) {
117 | Console.WriteLine ("Error: ENDPOINT and KEY environment variables must be set");
118 | Environment.Exit (-1);
119 | }
120 |
121 | string DatabaseName = ConfigurationManager.AppSettings["DatabaseName"];
122 | string DataCollectionName = ConfigurationManager.AppSettings["CollectionName"];
123 | int CollectionThroughput = int.Parse(ConfigurationManager.AppSettings["CollectionThroughput"]);
124 | string PartitionKey = ConfigurationManager.AppSettings["CollectionPartitionKey"];
125 | string Operation = ConfigurationManager.AppSettings["Operation"];
126 | int DegreeOfParallelism = int.Parse(ConfigurationManager.AppSettings["DegreeOfParallelism"]);
127 | string QueryString = ConfigurationManager.AppSettings["QueryString"];
128 | int NumberOfOperations = int.Parse (ConfigurationManager.AppSettings["NumberOfOperations"]);
129 |
130 | Options = opts;
131 |
132 | if (Options.Database == null) {
133 | Options.Database = DatabaseName;
134 | }
135 |
136 | if (Options.Collection == null) {
137 | Options.Collection = DataCollectionName;
138 | }
139 |
140 | if (Options.Throughput == 0)
141 | {
142 | Options.Throughput = CollectionThroughput;
143 | }
144 |
145 | if (Options.PartitionKey == null)
146 | {
147 | Options.PartitionKey = PartitionKey;
148 | }
149 |
150 | if (Options.Operation == null) {
151 | Options.Operation = Operation;
152 | }
153 |
154 | if (Options.Parallelism == 0)
155 | {
156 | Options.Parallelism = DegreeOfParallelism;
157 | }
158 |
159 | if (Options.NumberOfOperations == 0) {
160 | Options.NumberOfOperations = NumberOfOperations;
161 | }
162 |
163 |
164 |
165 | Run(endpoint, authKey);
166 |
167 | }
168 |
169 | ///
170 | /// Handle error in command line arguments
171 | ///
172 | /// Errors in the command line arguments
173 | private static void HandleParseError (IEnumerable errs) {
174 | Environment.Exit (-1);
175 | }
176 |
177 | ///
178 | /// Runs this program with its parsed command line arguments
179 | ///
180 | /// Endpoint read from the environment
181 | /// Auth key read from the environment
182 | private static void Run (string endpoint, string authKey) {
183 |
184 | try {
185 | using (var client = new DocumentClient (
186 | new Uri (endpoint),
187 | authKey,
188 | ConnectionPolicy)) {
189 | var program = new Program (client);
190 | program.RunAsync ().Wait ();
191 | }
192 | }
193 |
194 | #if !DEBUG
195 | catch (Exception e) {
196 | // If the Exception is a DocumentClientException, the "StatusCode" value might help identity
197 | // the source of the problem.
198 | Console.WriteLine ("Experiment failed with exception:{0}", e);
199 | }
200 | #endif
201 | finally {
202 | //Console.WriteLine ("Press any key to exit...");
203 | //Console.ReadLine ();
204 | Console.WriteLine("CosmosDB experiment complete");
205 | }
206 |
207 | }
208 |
209 | ///
210 | /// Run the main body of the program: create the database and collection, if they do not exist,
211 | /// then run the specified experiment,
212 | /// cleaning up afterwards if configured.
213 | ///
214 | /// The task
215 | private async Task RunAsync () {
216 |
217 | Database database = GetDatabaseIfExists(Options.Database);
218 |
219 | if (bool.Parse(ConfigurationManager.AppSettings["ShouldCleanupOnStart"]) && database != null)
220 | {
221 | Console.WriteLine("Deleting database {0}", Options.Database);
222 | await client.DeleteDatabaseAsync(database.SelfLink);
223 | }
224 |
225 | if (bool.Parse(ConfigurationManager.AppSettings["ShouldCleanupOnStart"]) || database == null)
226 | {
227 | Console.WriteLine("Creating database {0}", Options.Database);
228 | database = await client.CreateDatabaseAsync(new Database { Id = Options.Database });
229 | }
230 |
231 | DocumentCollection dataCollection = GetCollectionIfExists(Options.Database, Options.Collection);
232 |
233 | if (dataCollection == null)
234 | {
235 | Console.WriteLine("Creating collection {0} with {1} RU/s", Options.Collection, Options.Throughput);
236 | dataCollection = await this.CreatePartitionedCollectionAsync(Options.Database, Options.Collection, Options.Throughput, Options.PartitionKey);
237 | }
238 |
239 | long currentCollectionThroughput = 0;
240 | currentCollectionThroughput = Options.Throughput;
241 |
242 | OfferV2 offer = (OfferV2) client.CreateOfferQuery ().Where (o => o.ResourceLink == dataCollection.SelfLink).AsEnumerable ().FirstOrDefault ();
243 | currentCollectionThroughput = offer.Content.OfferThroughput;
244 |
245 | Uri collectionUri = UriFactory.CreateDocumentCollectionUri (Options.Database, Options.Collection);
246 |
247 | if (Options.Verbose)
248 | {
249 |
250 | Console.WriteLine("Summary:");
251 | Console.WriteLine("--------------------------------------------------------------------- ");
252 | Console.WriteLine("Endpoint: {0}", client.ServiceEndpoint);
253 | Console.WriteLine("Collection : {0}.{1} at {2} RU/s with partition key {3}", Options.Database, Options.Collection, currentCollectionThroughput, Options.PartitionKey);
254 | Console.WriteLine("Operations : {0} {1}", Options.NumberOfOperations, Options.Operation);
255 | Console.WriteLine("Degree of parallelism*: {0}", Options.Parallelism);
256 | Console.WriteLine("--------------------------------------------------------------------- ");
257 | Console.WriteLine();
258 | }
259 |
260 | var experiment = new Experiment (client, dataCollection, collectionUri, Options);
261 | await experiment.RunAsync ();
262 |
263 | if (bool.Parse (ConfigurationManager.AppSettings["ShouldCleanupOnFinish"])) {
264 | Console.WriteLine ("Deleting Database {0}", Options.Database);
265 | await client.DeleteDatabaseAsync (UriFactory.CreateDatabaseUri (Options.Database));
266 | }
267 | }
268 |
269 | ///
270 | /// Get the collection if it exists, null if it doesn't. Assumes that the database does exist.
271 | ///
272 | /// The requested collection
273 | private DocumentCollection GetCollectionIfExists (string databaseName, string collectionName) {
274 |
275 | if (Options.Verbose)
276 | {
277 | Console.WriteLine("Checking to see if collection: {0} exists", collectionName);
278 | }
279 |
280 | return client.CreateDocumentCollectionQuery (UriFactory.CreateDatabaseUri (databaseName))
281 | .Where (c => c.Id == collectionName).AsEnumerable ().FirstOrDefault ();
282 | }
283 |
284 | ///
285 | /// Get the database if it exists, null if it doesn't
286 | ///
287 | /// The requested database
288 | private Database GetDatabaseIfExists (string databaseName) {
289 | if (Options.Verbose)
290 | {
291 | Console.WriteLine("Checking to see if database: {0} exists", databaseName);
292 | }
293 | var result = client.CreateDatabaseQuery ().Where (d => d.Id == databaseName).AsEnumerable ();
294 | return result.FirstOrDefault ();
295 | }
296 |
297 | ///
298 | /// Create a partitioned collection.
299 | ///
300 | /// The created collection.
301 | private async Task CreatePartitionedCollectionAsync (string databaseName, string collectionName, int throughput, string partitionKey) {
302 | DocumentCollection collection = new DocumentCollection ();
303 |
304 | collection.Id = collectionName;
305 | collection.PartitionKey.Paths.Add (partitionKey);
306 |
307 | // Show user cost of running this test
308 | double estimatedCostPerMonth = 0.06 * throughput;
309 | double estimatedCostPerHour = estimatedCostPerMonth / (24 * 30);
310 |
311 | if (Options.Verbose)
312 | {
313 | Console.WriteLine("The collection will cost an estimated ${0} per hour (${1} per month)", Math.Round(estimatedCostPerHour, 2), Math.Round(estimatedCostPerMonth, 2));
314 | }
315 |
316 | return await client.CreateDocumentCollectionAsync (
317 | UriFactory.CreateDatabaseUri (databaseName),
318 | collection,
319 | new RequestOptions { OfferThroughput = throughput });
320 | }
321 |
322 | }
323 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Attribution 4.0 International
2 |
3 | =======================================================================
4 |
5 | Creative Commons Corporation ("Creative Commons") is not a law firm and
6 | does not provide legal services or legal advice. Distribution of
7 | Creative Commons public licenses does not create a lawyer-client or
8 | other relationship. Creative Commons makes its licenses and related
9 | information available on an "as-is" basis. Creative Commons gives no
10 | warranties regarding its licenses, any material licensed under their
11 | terms and conditions, or any related information. Creative Commons
12 | disclaims all liability for damages resulting from their use to the
13 | fullest extent possible.
14 |
15 | Using Creative Commons Public Licenses
16 |
17 | Creative Commons public licenses provide a standard set of terms and
18 | conditions that creators and other rights holders may use to share
19 | original works of authorship and other material subject to copyright
20 | and certain other rights specified in the public license below. The
21 | following considerations are for informational purposes only, are not
22 | exhaustive, and do not form part of our licenses.
23 |
24 | Considerations for licensors: Our public licenses are
25 | intended for use by those authorized to give the public
26 | permission to use material in ways otherwise restricted by
27 | copyright and certain other rights. Our licenses are
28 | irrevocable. Licensors should read and understand the terms
29 | and conditions of the license they choose before applying it.
30 | Licensors should also secure all rights necessary before
31 | applying our licenses so that the public can reuse the
32 | material as expected. Licensors should clearly mark any
33 | material not subject to the license. This includes other CC-
34 | licensed material, or material used under an exception or
35 | limitation to copyright. More considerations for licensors:
36 | wiki.creativecommons.org/Considerations_for_licensors
37 |
38 | Considerations for the public: By using one of our public
39 | licenses, a licensor grants the public permission to use the
40 | licensed material under specified terms and conditions. If
41 | the licensor's permission is not necessary for any reason--for
42 | example, because of any applicable exception or limitation to
43 | copyright--then that use is not regulated by the license. Our
44 | licenses grant only permissions under copyright and certain
45 | other rights that a licensor has authority to grant. Use of
46 | the licensed material may still be restricted for other
47 | reasons, including because others have copyright or other
48 | rights in the material. A licensor may make special requests,
49 | such as asking that all changes be marked or described.
50 | Although not required by our licenses, you are encouraged to
51 | respect those requests where reasonable. More_considerations
52 | for the public:
53 | wiki.creativecommons.org/Considerations_for_licensees
54 |
55 | =======================================================================
56 |
57 | Creative Commons Attribution 4.0 International Public License
58 |
59 | By exercising the Licensed Rights (defined below), You accept and agree
60 | to be bound by the terms and conditions of this Creative Commons
61 | Attribution 4.0 International Public License ("Public License"). To the
62 | extent this Public License may be interpreted as a contract, You are
63 | granted the Licensed Rights in consideration of Your acceptance of
64 | these terms and conditions, and the Licensor grants You such rights in
65 | consideration of benefits the Licensor receives from making the
66 | Licensed Material available under these terms and conditions.
67 |
68 |
69 | Section 1 -- Definitions.
70 |
71 | a. Adapted Material means material subject to Copyright and Similar
72 | Rights that is derived from or based upon the Licensed Material
73 | and in which the Licensed Material is translated, altered,
74 | arranged, transformed, or otherwise modified in a manner requiring
75 | permission under the Copyright and Similar Rights held by the
76 | Licensor. For purposes of this Public License, where the Licensed
77 | Material is a musical work, performance, or sound recording,
78 | Adapted Material is always produced where the Licensed Material is
79 | synched in timed relation with a moving image.
80 |
81 | b. Adapter's License means the license You apply to Your Copyright
82 | and Similar Rights in Your contributions to Adapted Material in
83 | accordance with the terms and conditions of this Public License.
84 |
85 | c. Copyright and Similar Rights means copyright and/or similar rights
86 | closely related to copyright including, without limitation,
87 | performance, broadcast, sound recording, and Sui Generis Database
88 | Rights, without regard to how the rights are labeled or
89 | categorized. For purposes of this Public License, the rights
90 | specified in Section 2(b)(1)-(2) are not Copyright and Similar
91 | Rights.
92 |
93 | d. Effective Technological Measures means those measures that, in the
94 | absence of proper authority, may not be circumvented under laws
95 | fulfilling obligations under Article 11 of the WIPO Copyright
96 | Treaty adopted on December 20, 1996, and/or similar international
97 | agreements.
98 |
99 | e. Exceptions and Limitations means fair use, fair dealing, and/or
100 | any other exception or limitation to Copyright and Similar Rights
101 | that applies to Your use of the Licensed Material.
102 |
103 | f. Licensed Material means the artistic or literary work, database,
104 | or other material to which the Licensor applied this Public
105 | License.
106 |
107 | g. Licensed Rights means the rights granted to You subject to the
108 | terms and conditions of this Public License, which are limited to
109 | all Copyright and Similar Rights that apply to Your use of the
110 | Licensed Material and that the Licensor has authority to license.
111 |
112 | h. Licensor means the individual(s) or entity(ies) granting rights
113 | under this Public License.
114 |
115 | i. Share means to provide material to the public by any means or
116 | process that requires permission under the Licensed Rights, such
117 | as reproduction, public display, public performance, distribution,
118 | dissemination, communication, or importation, and to make material
119 | available to the public including in ways that members of the
120 | public may access the material from a place and at a time
121 | individually chosen by them.
122 |
123 | j. Sui Generis Database Rights means rights other than copyright
124 | resulting from Directive 96/9/EC of the European Parliament and of
125 | the Council of 11 March 1996 on the legal protection of databases,
126 | as amended and/or succeeded, as well as other essentially
127 | equivalent rights anywhere in the world.
128 |
129 | k. You means the individual or entity exercising the Licensed Rights
130 | under this Public License. Your has a corresponding meaning.
131 |
132 |
133 | Section 2 -- Scope.
134 |
135 | a. License grant.
136 |
137 | 1. Subject to the terms and conditions of this Public License,
138 | the Licensor hereby grants You a worldwide, royalty-free,
139 | non-sublicensable, non-exclusive, irrevocable license to
140 | exercise the Licensed Rights in the Licensed Material to:
141 |
142 | a. reproduce and Share the Licensed Material, in whole or
143 | in part; and
144 |
145 | b. produce, reproduce, and Share Adapted Material.
146 |
147 | 2. Exceptions and Limitations. For the avoidance of doubt, where
148 | Exceptions and Limitations apply to Your use, this Public
149 | License does not apply, and You do not need to comply with
150 | its terms and conditions.
151 |
152 | 3. Term. The term of this Public License is specified in Section
153 | 6(a).
154 |
155 | 4. Media and formats; technical modifications allowed. The
156 | Licensor authorizes You to exercise the Licensed Rights in
157 | all media and formats whether now known or hereafter created,
158 | and to make technical modifications necessary to do so. The
159 | Licensor waives and/or agrees not to assert any right or
160 | authority to forbid You from making technical modifications
161 | necessary to exercise the Licensed Rights, including
162 | technical modifications necessary to circumvent Effective
163 | Technological Measures. For purposes of this Public License,
164 | simply making modifications authorized by this Section 2(a)
165 | (4) never produces Adapted Material.
166 |
167 | 5. Downstream recipients.
168 |
169 | a. Offer from the Licensor -- Licensed Material. Every
170 | recipient of the Licensed Material automatically
171 | receives an offer from the Licensor to exercise the
172 | Licensed Rights under the terms and conditions of this
173 | Public License.
174 |
175 | b. No downstream restrictions. You may not offer or impose
176 | any additional or different terms or conditions on, or
177 | apply any Effective Technological Measures to, the
178 | Licensed Material if doing so restricts exercise of the
179 | Licensed Rights by any recipient of the Licensed
180 | Material.
181 |
182 | 6. No endorsement. Nothing in this Public License constitutes or
183 | may be construed as permission to assert or imply that You
184 | are, or that Your use of the Licensed Material is, connected
185 | with, or sponsored, endorsed, or granted official status by,
186 | the Licensor or others designated to receive attribution as
187 | provided in Section 3(a)(1)(A)(i).
188 |
189 | b. Other rights.
190 |
191 | 1. Moral rights, such as the right of integrity, are not
192 | licensed under this Public License, nor are publicity,
193 | privacy, and/or other similar personality rights; however, to
194 | the extent possible, the Licensor waives and/or agrees not to
195 | assert any such rights held by the Licensor to the limited
196 | extent necessary to allow You to exercise the Licensed
197 | Rights, but not otherwise.
198 |
199 | 2. Patent and trademark rights are not licensed under this
200 | Public License.
201 |
202 | 3. To the extent possible, the Licensor waives any right to
203 | collect royalties from You for the exercise of the Licensed
204 | Rights, whether directly or through a collecting society
205 | under any voluntary or waivable statutory or compulsory
206 | licensing scheme. In all other cases the Licensor expressly
207 | reserves any right to collect such royalties.
208 |
209 |
210 | Section 3 -- License Conditions.
211 |
212 | Your exercise of the Licensed Rights is expressly made subject to the
213 | following conditions.
214 |
215 | a. Attribution.
216 |
217 | 1. If You Share the Licensed Material (including in modified
218 | form), You must:
219 |
220 | a. retain the following if it is supplied by the Licensor
221 | with the Licensed Material:
222 |
223 | i. identification of the creator(s) of the Licensed
224 | Material and any others designated to receive
225 | attribution, in any reasonable manner requested by
226 | the Licensor (including by pseudonym if
227 | designated);
228 |
229 | ii. a copyright notice;
230 |
231 | iii. a notice that refers to this Public License;
232 |
233 | iv. a notice that refers to the disclaimer of
234 | warranties;
235 |
236 | v. a URI or hyperlink to the Licensed Material to the
237 | extent reasonably practicable;
238 |
239 | b. indicate if You modified the Licensed Material and
240 | retain an indication of any previous modifications; and
241 |
242 | c. indicate the Licensed Material is licensed under this
243 | Public License, and include the text of, or the URI or
244 | hyperlink to, this Public License.
245 |
246 | 2. You may satisfy the conditions in Section 3(a)(1) in any
247 | reasonable manner based on the medium, means, and context in
248 | which You Share the Licensed Material. For example, it may be
249 | reasonable to satisfy the conditions by providing a URI or
250 | hyperlink to a resource that includes the required
251 | information.
252 |
253 | 3. If requested by the Licensor, You must remove any of the
254 | information required by Section 3(a)(1)(A) to the extent
255 | reasonably practicable.
256 |
257 | 4. If You Share Adapted Material You produce, the Adapter's
258 | License You apply must not prevent recipients of the Adapted
259 | Material from complying with this Public License.
260 |
261 |
262 | Section 4 -- Sui Generis Database Rights.
263 |
264 | Where the Licensed Rights include Sui Generis Database Rights that
265 | apply to Your use of the Licensed Material:
266 |
267 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right
268 | to extract, reuse, reproduce, and Share all or a substantial
269 | portion of the contents of the database;
270 |
271 | b. if You include all or a substantial portion of the database
272 | contents in a database in which You have Sui Generis Database
273 | Rights, then the database in which You have Sui Generis Database
274 | Rights (but not its individual contents) is Adapted Material; and
275 |
276 | c. You must comply with the conditions in Section 3(a) if You Share
277 | all or a substantial portion of the contents of the database.
278 |
279 | For the avoidance of doubt, this Section 4 supplements and does not
280 | replace Your obligations under this Public License where the Licensed
281 | Rights include other Copyright and Similar Rights.
282 |
283 |
284 | Section 5 -- Disclaimer of Warranties and Limitation of Liability.
285 |
286 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
287 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
288 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
289 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
290 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
291 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
292 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
293 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
294 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
295 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
296 |
297 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
298 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
299 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
300 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
301 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
302 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
303 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
304 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
305 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
306 |
307 | c. The disclaimer of warranties and limitation of liability provided
308 | above shall be interpreted in a manner that, to the extent
309 | possible, most closely approximates an absolute disclaimer and
310 | waiver of all liability.
311 |
312 |
313 | Section 6 -- Term and Termination.
314 |
315 | a. This Public License applies for the term of the Copyright and
316 | Similar Rights licensed here. However, if You fail to comply with
317 | this Public License, then Your rights under this Public License
318 | terminate automatically.
319 |
320 | b. Where Your right to use the Licensed Material has terminated under
321 | Section 6(a), it reinstates:
322 |
323 | 1. automatically as of the date the violation is cured, provided
324 | it is cured within 30 days of Your discovery of the
325 | violation; or
326 |
327 | 2. upon express reinstatement by the Licensor.
328 |
329 | For the avoidance of doubt, this Section 6(b) does not affect any
330 | right the Licensor may have to seek remedies for Your violations
331 | of this Public License.
332 |
333 | c. For the avoidance of doubt, the Licensor may also offer the
334 | Licensed Material under separate terms or conditions or stop
335 | distributing the Licensed Material at any time; however, doing so
336 | will not terminate this Public License.
337 |
338 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
339 | License.
340 |
341 |
342 | Section 7 -- Other Terms and Conditions.
343 |
344 | a. The Licensor shall not be bound by any additional or different
345 | terms or conditions communicated by You unless expressly agreed.
346 |
347 | b. Any arrangements, understandings, or agreements regarding the
348 | Licensed Material not stated herein are separate from and
349 | independent of the terms and conditions of this Public License.
350 |
351 |
352 | Section 8 -- Interpretation.
353 |
354 | a. For the avoidance of doubt, this Public License does not, and
355 | shall not be interpreted to, reduce, limit, restrict, or impose
356 | conditions on any use of the Licensed Material that could lawfully
357 | be made without permission under this Public License.
358 |
359 | b. To the extent possible, if any provision of this Public License is
360 | deemed unenforceable, it shall be automatically reformed to the
361 | minimum extent necessary to make it enforceable. If the provision
362 | cannot be reformed, it shall be severed from this Public License
363 | without affecting the enforceability of the remaining terms and
364 | conditions.
365 |
366 | c. No term or condition of this Public License will be waived and no
367 | failure to comply consented to unless expressly agreed to by the
368 | Licensor.
369 |
370 | d. Nothing in this Public License constitutes or may be interpreted
371 | as a limitation upon, or waiver of, any privileges and immunities
372 | that apply to the Licensor or You, including from the legal
373 | processes of any jurisdiction or authority.
374 |
375 |
376 | =======================================================================
377 |
378 | Creative Commons is not a party to its public
379 | licenses. Notwithstanding, Creative Commons may elect to apply one of
380 | its public licenses to material it publishes and in those instances
381 | will be considered the “Licensor.” The text of the Creative Commons
382 | public licenses is dedicated to the public domain under the CC0 Public
383 | Domain Dedication. Except for the limited purpose of indicating that
384 | material is shared under a Creative Commons public license or as
385 | otherwise permitted by the Creative Commons policies published at
386 | creativecommons.org/policies, Creative Commons does not authorize the
387 | use of the trademark "Creative Commons" or any other trademark or logo
388 | of Creative Commons without its prior written consent including,
389 | without limitation, in connection with any unauthorized modifications
390 | to any of its public licenses or any other arrangements,
391 | understandings, or agreements concerning use of licensed material. For
392 | the avoidance of doubt, this paragraph does not form part of the
393 | public licenses.
394 |
395 | Creative Commons may be contacted at creativecommons.org.
--------------------------------------------------------------------------------
/LICENSE-CODE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) Microsoft Corporation
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
5 | associated documentation files (the "Software"), to deal in the Software without restriction,
6 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8 | subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial
11 | portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
14 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
15 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
16 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
17 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Introduction
3 |
4 | Sample code for Microsoft Learn.
5 |
6 | # Contributing
7 |
8 | This project welcomes contributions and suggestions. Most contributions require you to agree to a
9 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
10 | the rights to use your contribution. For details, visit https://cla.microsoft.com.
11 |
12 | When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
13 | a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
14 | provided by the bot. You will only need to do this once across all repos using our CLA.
15 |
16 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
17 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
18 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
19 |
20 | # Legal Notices
21 |
22 | Microsoft and any contributors grant you a license to the Microsoft documentation and other content
23 | in this repository under the [Creative Commons Attribution 4.0 International Public License](https://creativecommons.org/licenses/by/4.0/legalcode),
24 | see the [LICENSE](./LICENSE) file, and grant you a license to any code in the repository under the [MIT License](https://opensource.org/licenses/MIT), see the
25 | [LICENSE-CODE](./LICENSE-CODE) file.
26 |
27 | Microsoft, Windows, Microsoft Azure and/or other Microsoft products and services referenced in the documentation
28 | may be either trademarks or registered trademarks of Microsoft in the United States and/or other countries.
29 | The licenses for this project do not grant you rights to use any Microsoft names, logos, or trademarks.
30 | Microsoft's general trademark guidelines can be found at http://go.microsoft.com/fwlink/?LinkID=254653.
31 |
32 | Privacy information can be found at https://privacy.microsoft.com/en-us/
33 |
34 | Microsoft and any contributors reserve all others rights, whether under their respective copyrights, patents,
35 | or trademarks, whether by implication, estoppel or otherwise.
36 |
--------------------------------------------------------------------------------