How does Apache Ignite supports partitioning? - c#

I am trying to experiment with data partition in Apache Ignite using .NET thin client.
In article https://apacheignite.readme.io/docs/cache-modes it's written that in partition mode "the overall data set is divided equally into partitions and all partitions are split equally between participating nodes". So I am expecting cache with 1000 records to be splitted beetween 3 Ignite nodes equally: 333(4) on each node. But when I start 3 instances of Ignite on local machine (using platforms\dotnet\bin\Apache.Ignite.exe) I can see only that 1000 records are replicated on all nodes: 1000 same records on each node. I tried to disable backups creation: 1000 records were created only on first node. Currently I use sequental Int32 values as cache key. But even when I ran LinqExample with colocated employes (with AffinityKey) data was't splitted beetween nodes.
I also tried to experiment with cache configuration:
var cacheConfiguration = new CacheClientConfiguration(_key, cacheEntity);
cacheConfiguration.CacheMode = CacheMode.Partitioned;
cacheConfiguration.Backups = 0;
cacheConfiguration.ReadFromBackup = false;
cacheConfiguration.RebalanceMode = CacheRebalanceMode.Sync;
cacheConfiguration.RebalanceOrder = 1;
cacheConfiguration.RebalanceThrottle = TimeSpan.FromSeconds(1);
cacheConfiguration.RebalanceDelay = TimeSpan.Zero;
cacheConfiguration.RebalanceBatchSize = 1024;
var cache = _igniteClient.CreateCache<int, TEntityType>(cacheConfiguration).WithExpiryPolicy(_expiryPolicy);
Perhaps I don't understand the main concept of data partitioning implemented in Apache Ignite or Apache.Ignite.exe needs some additional configuration to support data partitioning. Execuse me if it's a simple question.
PS. I am using DBeaver to check amount of records on each node. 3 ignite instances by default uses ports 10800, 10801, 10802 for .NET client requests. So I am using localhost:10800, localhost:10801, localhost:10802 adresses in DBeaver.

To get the number of entries per node, use included Visor tool.
Go to Ignite bin directory
Start ignitevisorcmd
Use open to connect to a cluster
Type cache -a
Generated report will include table with node specifics:
Nodes for: person-cache-1(#c0)
+====================================================================================================================+
| Node ID8(#), IP | CPUs | Heap Used | CPU Load | Up Time | Size (Primary / Backup) | Hi/Mi/Rd/Wr |
+====================================================================================================================+
| 1F81F615(#n0), 127.0.0.1 | 12 | 10.26 % | 0.00 % | 00:08:15.394 | Total: 513 (513 / 0) | Hi: 0 |
| | | | | | Heap: 0 (0 / <n/a>) | Mi: 0 |
| | | | | | Off-Heap: 513 (513 / 0) | Rd: 0 |
| | | | | | Off-Heap Memory: <n/a> | Wr: 0 |
+-----------------------------+------+-----------+----------+--------------+---------------------------+-------------+
| FBCF3B0F(#n1), 127.0.0.1 | 12 | 15.23 % | 0.00 % | 00:07:46.647 | Total: 486 (486 / 0) | Hi: 0 |
| | | | | | Heap: 0 (0 / <n/a>) | Mi: 0 |
| | | | | | Off-Heap: 486 (486 / 0) | Rd: 0 |
| | | | | | Off-Heap Memory: <n/a> | Wr: 0 |
+--------------------------------------------------------------------------------------------------------------------+
According to Size(Primary/...) 999 entries are split between two nodes, with 513 entries on the first node and 486 on the second node.
Check "Primary" and not "Total"; "Total" is sum of primary entries and replicated entries from other nodes. Shown setup does not have replication, so it is equal to "Primary".
If a cluster had three nodes, and a cache had 2 replicas (so 3 copies in total), then the "Total" number on one node will be close to a total number of entries (as each node contains all entries, either as a primary node or backup node for two other nodes), "Primary" would be approximately 1/3 of the total and "Backup" would be 2/3.

Related

Efficient way to concatenate strings using c# [duplicate]

This question already has answers here:
Most efficient way to concatenate strings?
(18 answers)
Closed last month.
I have following code snippet that will append filename with current timestamp and it's working fine.
Just want to make sure this is best way to append strings in c# 10, if not then how we can we make below code more efficient?
ex: testfile.txt ->o/p testfile_timestamp.txt
string[] strName = formFile.FileName.Split('.');
string updatedFilename = strName[0] + "_"
+ DateTime.Now.ToUniversalTime().ToString("THHmmssfff") + "." +
strName[strName.Length - 1];
How about this:
// Just a stupid method name for demo, you'll find a better one :)
public static string DatifyFileName(string fileName)
{
// Use well tested Framework method to get filename without extension
var nameWithoutExtension = System.IO.Path.GetFileNameWithoutExtension(fileName);
// Use well tested Framework method to get extension
var extension = System.IO.Path.GetExtension(fileName);
// interpolate to get the desired output.
return $"{nameWithoutExtension}_{DateTime.Now.ToUniversalTime().ToString("THHmmssfff")}{extension}";
}
Or if you are familiar with Span<char>:
public static string DatifyFileName(ReadOnlySpan<char> fileName)
{
var lastDotIndex = fileName.LastIndexOf('.');
//Maybe : if( lastDotIndex < 0 ) throw ArgumentException("no extension found");
var nameWithoutExtension = fileName[..lastDotIndex];
var extension = fileName[lastDotIndex..];
return $"{nameWithoutExtension}_{DateTime.Now.ToUniversalTime().ToString("THHmmssfff")}{extension}";
}
Fiddle
And just to give some fire to the discussion :D ...
BenchmarkDotNet=v0.13.3, OS=Windows 10 (10.0.19044.2364/21H2/November2021Update)
Intel Core i9-10885H CPU 2.40GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK=7.0.101
[Host] : .NET 7.0.1 (7.0.122.56804), X64 RyuJIT AVX2
DefaultJob : .NET 7.0.1 (7.0.122.56804), X64 RyuJIT AVX2
| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|----------------- |-----------:|---------:|---------:|------:|--------:|-------:|----------:|------------:|
| Interpolated | 906.7 ns | 16.92 ns | 16.61 ns | 1.08 | 0.02 | 0.0458 | 384 B | 1.66 |
| InterpolatedSpan | 842.0 ns | 13.06 ns | 12.22 ns | 1.00 | 0.00 | 0.0277 | 232 B | 1.00 |
| StringBuilder | 1,010.8 ns | 6.70 ns | 5.94 ns | 1.20 | 0.02 | 0.1068 | 904 B | 3.90 |
| Original | 960.0 ns | 18.68 ns | 19.19 ns | 1.14 | 0.03 | 0.0734 | 616 B | 2.66 |
// * Hints *
Outliers
Benchmark.StringBuilder: Default -> 1 outlier was removed (1.03 us)
Benchmark.Original: Default -> 2 outliers were removed (1.03 us, 1.06 us)
// * Legends *
Mean : Arithmetic mean of all measurements
Error : Half of 99.9% confidence interval
StdDev : Standard deviation of all measurements
Ratio : Mean of the ratio distribution ([Current]/[Baseline])
RatioSD : Standard deviation of the ratio distribution ([Current]/[Baseline])
Gen0 : GC Generation 0 collects per 1000 operations
Allocated : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B)
Alloc Ratio : Allocated memory ratio distribution ([Current]/[Baseline])
1 ns : 1 Nanosecond (0.000000001 sec)
Strings are immutable. whenever you modify any string, it is recreated in the memory. Hence to overcome this you should always use StringBuilder. Sample code shown below:
string[] strName = formFile.FileName.Split('.');
StringBuilder updatedFilename = new StringBuilder();
updatedFilename.Append(strName[0]);
updatedFilename.Append("_");
updatedFilename.Append(DateTime.Now.ToUniversalTime().ToString("THHmmssfff"));
updatedFilename.Append(".");
updatedFilename.Append(strName[strName.Length - 1]);
// You can get this using `ToString()` method
string filename = updatedFilename.ToString();

UnionBy() EF Core

I have this ef query that give me the following result
IQueryable<A>
| Id | count |
| 1 | 5 |
| 2 | 6 |
IQueryable<B>
| Id | count |
| 1 | 1 |
| 2 | 2 |
| 3 | 9 |
When I do
IQueryable<Something> C = A.union(B)
Result that I got is this
| Id | count |
| 1 | 5 |
| 2 | 6 |
| 1 | 1 |
| 2 | 2 |
| 3 | 9 |
Whish is logical.
What I want is a UnionBy(Id)
IQueryable<Something> C = A.unionBy(B,c=>c.Id)
and this work perfectly in my case
| Id | count |
| 1 | 5 | -- FROM A
| 2 | 6 | -- FROM A
| 3 | 9 | -- FROM B
If the Query A or B are already executed by that I mean a ToList() was made it work perfectly and I have no problem in anyway.
But in my case, both queries are not executed and thus using this function result in.
System.InvalidOperationException query could not be translated.
the alternative is to use a GroupBy however I have no idea how to replacte UnionBy behavior with the GroupBy
FYI: the query works perfectly using the IQueryable.Union
and it's mandatory in my case that the request stay in IQueryable and not executed until later
UPDATE
⚠️ The solution that I'm looking for must stay in IQueryable without a toList() execution
"query could not be translated" usually means that EF doesn't support a certain LINQ or language construct as it can't translate it into SQL. One way to make this work is to force the evaluation of the expression client-side by adding e.g. ToList() or likes on the query parts before executing the UnionBy:
IQueryable<Something> C = A.ToList().UnionBy(B.ToList(),c=>c.Id);
The solution is simple you filtre A From B using the following
IQueryable<Something> C = A.Union(B.where(b=> A.All(a=>a.Id != b.Id))

C# - Convert a string of Key value pair separated by '=' to Dictionary

I'm extracting data from an API which gives me some information in JSON. However, one of the values gives me:
{X0=80,X1=80,X2=80,X3=80,X4=80,X5=80,X6=80,X7=80,X8=80,X9=80,X10=80,X11=80,X12=80,X13=80,X14=80,X15=80,X16=80,X17=80,X18=80,X19=80,X20=80,X21=80,X22=80,X23=80,X24=80,X25=80,X26=80,X27=80,X28=80,X29=80,X30=80,X31=80,X32=80,X33=80,X34=80,X35=80,X36=80,X37=80,X38=80,X39=80,X40=80,X41=80,X42=80,X43=80,X44=80,X45=80,X46=80,X47=80,X48=80,X49=80,X50=80,X51=80,X52=80,X53=80,X54=80,X55=80,X56=80,X57=80,X58=80,X59=80,X60=80,X61=80,X62=80}
I am trying to decode this for use in a C# Console Application (.NET).
My main question is, what would be the best way to extract this string into a dictionary or array? I am not sure if I have worded this correctly, so please correct me if I'm wrong!
Thanks!
You can use Linq with Trim, Split, Select, ToDictionary
var result = json.Trim('{', '}')
.Split(',')
.Select(x => x.Split('='))
.ToDictionary(x => x[0], x => int.Parse(x[1]));
Console.WriteLine(string.Join("\r\n", result.Select(x => x.Key + " : " + x.Value)));
Full Demo Here
And just because i'm bored
Benchmarks
Mode : Release (64Bit)
Test Framework : .NET Framework 4.7.1
Operating System : Microsoft Windows 10 Pro
Version : 10.0.17134
CPU Name : Intel(R) Core(TM) i7-3770K CPU # 3.50GHz
Description : Intel64 Family 6 Model 58 Stepping 9
Cores (Threads) : 4 (8) : Architecture : x64
Clock Speed : 3901 MHz : Bus Speed : 100 MHz
L2Cache : 1 MB : L3Cache : 8 MB
Benchmarks Runs : Inputs (1) * Scales (3) * Benchmarks (3) * Runs (100) = 900
Results
--- Random Set ----------------------------------------------------------------------
| Value | Average | Fastest | Cycles | Garbage | Test | Gain |
--- Scale 100 -------------------------------------------------------- Time 0.229 ---
| Split | 0.058 ms | 0.043 ms | 207,064 | 48.000 KB | Base | 0.00 % |
| JsonReplace | 0.077 ms | 0.064 ms | 273,556 | 24.000 KB | Pass | -32.38 % |
| Regex | 0.270 ms | 0.235 ms | 950,504 | 80.000 KB | Pass | -364.87 % |
--- Scale 1,000 ------------------------------------------------------ Time 0.633 ---
| Split | 0.490 ms | 0.446 ms | 1,718,180 | 495.102 KB | Base | 0.00 % |
| JsonReplace | 0.671 ms | 0.596 ms | 2,352,043 | 195.078 KB | Pass | -36.86 % |
| Regex | 2.544 ms | 2.293 ms | 8,897,994 | 731.125 KB | Pass | -419.00 % |
--- Scale 10,000 ----------------------------------------------------- Time 5.005 ---
| Split | 5.247 ms | 4.673 ms | 18,363,748 | 4.843 MB | Base | 0.00 % |
| JsonReplace | 6.782 ms | 5.488 ms | 23,721,593 | 1.829 MB | Pass | -29.25 % |
| Regex | 31.840 ms | 27.008 ms | 111,277,134 | 6.637 MB | Pass | -506.80 % |
-------------------------------------------------------------------------------------
Data
private string GenerateData(int scale)
{
var ary = Enumerable.Range(0, scale)
.Select(x => $"X{x}={Rand.Next()}")
.ToList();
return $"{{{string.Join(",", ary)}}}";
}
Split
public class Split : Benchmark<string, Dictionary<string,int>>
{
protected override Dictionary<string,int> InternalRun()
{
return Input.Trim('{', '}')
.Split(',')
.Select(x => x.Split('='))
.ToDictionary(x => x[0], x => int.Parse(x[1]));
}
}
Regex
Credited to emsimpson92 using Cast
public class Regex : Benchmark<string, Dictionary<string,int>>
{
protected override Dictionary<string,int> InternalRun()
{
var regex = new System.Text.RegularExpressions.Regex("(?<key>[^,]+)=(?<value>[^,]+)");
var matchCollection = regex.Matches(Input.Trim('{', '}'));
return matchCollection.Cast<Match>()
.ToDictionary(
x => x.Groups["key"].Value,
x => int.Parse(x.Groups["value"].Value));
}
}
JsonReplace
Credited to Hanzalah Adalan Modified to work with string.replace
public unsafe class JsonReplace : Benchmark<string, Dictionary<string,int>>
{
protected override Dictionary<string,int> InternalRun()
{
return JsonConvert.DeserializeObject<Dictionary<string,int>>(Input.Replace("=", ":"));
}
}
Additional Resources
String.Trim Method
Returns a new string in which all leading and trailing occurrences of
a set of specified characters from the current String object are
removed.
String.Split Method (String[], StringSplitOptions)
Splits a string into substrings based on the strings in an array. You
can specify whether the substrings include empty array elements.
Enumerable.Select Method (IEnumerable, Func)
Projects each element of a sequence into a new form.
Enumerable.ToDictionary Method (IEnumerable, Func)
Creates a Dictionary from an IEnumerable according to
a specified key selector function.
This can be done with Regex The following pattern will capture keys and values in 2 separate groups (?<key>[^,]+)=(?<value>[^,]+)
Demo
Once you have your MatchCollection, run a foreach loop through it, and add each element to a dictionary.
Var myAwesomeDictionary = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string,string>>(_yourJsonStringHere);

List of object into a data structure or datatable with collation

I have got a List with the following object
// Properties
long InstID
long SheetID
String[] Names
Double[] Values
The populated list contains the following items
InstID | SheetID | Names | Values |
-----------------------------------------------------------------
8 | 100 | 2,3,4,5 | 200, 300, 400, 500 |
9 | 100 | 2,3,4,5 | 2000,3000,4000,5000 |
8 | 101 | 2,3,4,5 | 201, 301, 401, 501 |
9 | 101 | 2,3,4,500 | 2001, 3001, 4001, 5001 |
I want to make use of this list and create a data structure with the following Columns and Rows
The columns Names
-----------------
SheetID
InstID_Name
Rows
-----
Instrument Values
Using the list above the output should look as below
SheetID |8_2 |8_3 |8_4 |8_5 |9_2 |9_3 |9_4 | 9_5 |
-------------------------------------------------------------------------
100 |200 |300 |400 |500 |2000 |3000 |4000 |5000 |
101 |201 |301 |401 |501 |2001 |3001 |4001 |5001 |
What I have tried
I have tried to create a datatable and try to loop through the list to create the columns and populate the rows. This seems very convoluted, I am hoping to get some ideas on how to implement this. If there is anything in .Net framework which will make this task easier.
Thanks in advance.

Determine node level in tree command output

I'm attempting to populate a C# TreeView from the output of the DOS Tree command(tree /F /A > treeList.txt). I need to determine the level of each node in the text file line by line and store it as an integer. Is there a way that this can be determined through Regex expressions? Below is an example of the output from the Tree command:
Folder PATH listing
Volume serial number is ****-****
C:.
| info.txt
| treeList.txt
|
+---Folder1
| +---Sub1
| | | info.txt
| | | info2.txt
| | | info3.txt
| | |
| | \---Sub
| | | info.txt
| | |
| | \---Sub
| | info.txt
| | info2.txt
| |
| +---Sub2
| \---Sub3
+---Folder2
| | info.txt
| | info2.txt
| |
| +---Sub1
| | info.txt
| |
| +---Sub2
| +---Sub3
| | info.txt
| |
| \---Sub4
+---Folder3
| \---Sub1
+---Folder4
| +---Sub1
| \---Sub2
| info.txt
| info2.txt
|
\---Folder5
info.txt
This is an example of the output I'm trying to achieve:
info.txt 0
treeList.txt 0
Folder1 0
Sub1 1
info.txt 2
info2.txt 2
info3.txt 2
Sub 2
info.txt 3
Sub 3
info.txt 4
info2.txt 4
Folder2 0
And so on...
Any assistance or guidance is greatly appreciated.
I have an idea. You may want to replace in every line of the tree's string every special character of the tree by replacing:
[|\\-\+]
and after that count spaces between beginning of the line and name of the file or folder.
Number of spaces will tell You how deep you are in lvl.
Then You also may divide number of spaces by 3 and You will get aproximately a number of lvl.
What do You think?
Expression used to split text at beginning of node:
((?:[a-zA-Z0-9][+'-_ ()a-zA-Z0-9.]*))
Code used to determine Node level:
List<TreeItem> items=new List<TreeItem>();
int lineNum=0;
string line;
// Read the file
StreamReader file=new StreamReader("<Path>");
while((line=file.ReadLine())!=null) {
string[] parts=Regex.Split(line,"((?:[a-zA-Z0-9][+'-_ ()a-zA-Z0-9.]*))");
if(parts.Length>1) {
//Node level is determined by the number of characters preceding node text
items.Add(new TreeItem(parts[1],(parts[0].Length/4)-1));
}
lineNum++;
}
file.Close();

Categories

Resources