Skip to content

Commit 7353f35

Browse files
authored
Merge pull request #151 from Tynab/develop
Develop
2 parents 95a8dbb + d0cb0ea commit 7353f35

File tree

14 files changed

+2244
-28
lines changed

14 files changed

+2244
-28
lines changed

README.md

Lines changed: 115 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
- [YANTask](#yantask)
2828
- [YANProcess](#yanprocess)
2929
- [YANExpression](#yanexpression)
30+
- [YANLib.Snowflake](#yanlibsnowflake)
3031
- [Performance Benchmarks](#-performance-benchmarks)
3132
- [Code Examples](#-code-examples)
3233
- [Project Architecture](#-project-architecture)
@@ -361,6 +362,56 @@ var person = new Person { Name = "John", Age = 30 };
361362
string name = (string)func(person); // Returns "John"
362363
```
363364

365+
### YANLib.Snowflake
366+
367+
A robust implementation of the Snowflake ID algorithm for generating distributed, time-ordered unique identifiers in C# applications.
368+
369+
#### Key Features
370+
371+
- 64-bit unique ID generation
372+
- Alphabetic and alphanumeric string representations
373+
- Time-ordered IDs for easy sorting
374+
- Distributed system support with worker and datacenter IDs
375+
- Component extraction from existing IDs
376+
- Predefined bit allocation strategies for different use cases
377+
- Customizable bit allocation for specialized scaling needs
378+
379+
```csharp
380+
// Create an ID generator with worker ID 1 and datacenter ID 1
381+
var generator = new IdGenerator(1, 1);
382+
383+
// Generate a numeric ID
384+
long id = generator.NextId();
385+
// Example: 6982190104624234496
386+
387+
// Generate an alphabetic ID (base-26, A-Z)
388+
string alphabeticId = generator.NextIdAlphabetic();
389+
// Example: "BPNHEBKDMGLCQ"
390+
391+
// Generate an alphanumeric ID (base-36, 0-9, A-Z)
392+
string alphanumericId = generator.NextIdAlphanumeric();
393+
// Example: "1Z9DHPKW0S"
394+
395+
// Create a generator with a predefined bit allocation strategy
396+
// MoreDistributed: 10 bits for worker ID (0-1023), 10 bits for datacenter ID (0-1023), 3 bits for sequence (0-7)
397+
var distributedGenerator = new IdGenerator(100, 200, BitAllocationStrategy.MoreDistributed);
398+
399+
// HighVolume: 2 bits for worker ID (0-3), 2 bits for datacenter ID (0-3), 19 bits for sequence (0-524,287)
400+
var highVolumeGenerator = new IdGenerator(1, 1, BitAllocationStrategy.HighVolume);
401+
402+
// Extract components from an ID
403+
var components = IdGenerator.ExtractIdComponents(id);
404+
DateTime timestamp = components.Timestamp;
405+
long workerId = components.WorkerId;
406+
long datacenterId = components.DatacenterId;
407+
408+
// Extract components using the same strategy used to generate the ID
409+
var strategicComponents = IdGenerator.ExtractIdComponents(
410+
distributedGenerator.NextId(),
411+
BitAllocationStrategy.MoreDistributed
412+
);
413+
```
414+
364415

365416
## 📊 Performance Benchmarks
366417

@@ -468,6 +519,61 @@ public Customer PrepareCustomerData(Customer customer)
468519
}
469520
```
470521

522+
### Unique ID Generation with Snowflake
523+
524+
```csharp
525+
public class IdService
526+
{
527+
private readonly IdGenerator _userIdGenerator;
528+
private readonly IdGenerator _orderIdGenerator;
529+
private readonly IdGenerator _highVolumeGenerator;
530+
531+
public IdService()
532+
{
533+
// Create separate generators for different entity types
534+
_userIdGenerator = new IdGenerator(1, 1);
535+
_orderIdGenerator = new IdGenerator(2, 1);
536+
537+
// Create a high-volume generator with custom bit allocation
538+
// 2 bits for worker ID, 2 bits for datacenter ID, 19 bits for sequence
539+
_highVolumeGenerator = new IdGenerator(
540+
workerId: 1,
541+
datacenterId: 1,
542+
sequence: 0,
543+
workerIdBits: 2,
544+
datacenterIdBits: 2,
545+
sequenceBits: 19
546+
);
547+
}
548+
549+
public string GenerateUserId()
550+
{
551+
// Generate a compact alphanumeric ID for users
552+
return _userIdGenerator.NextIdAlphanumeric();
553+
}
554+
555+
public long GenerateOrderId()
556+
{
557+
// Generate a numeric ID for orders
558+
return _orderIdGenerator.NextId();
559+
}
560+
561+
public long GenerateHighVolumeId()
562+
{
563+
// Generate an ID optimized for high volume (up to 524,287 IDs per millisecond)
564+
return _highVolumeGenerator.NextId();
565+
}
566+
567+
public DateTime GetIdCreationTime(long id)
568+
{
569+
// Extract the timestamp from an ID
570+
var components = IdGenerator.ExtractIdComponents(id);
571+
572+
return components.Timestamp;
573+
}
574+
}
575+
```
576+
471577
### Random Test Data Generation
472578

473579
```csharp
@@ -532,6 +638,7 @@ YANLib is based on .NET 8.0 (LTS) and consists of the following main components:
532638
- Task
533639
- Process
534640
- Expression
641+
- Snowflake
535642

536643
### Project Structure
537644

@@ -581,9 +688,13 @@ YANLib/
581688
│ ├── YANProcess.Collection.cs
582689
│ └── ...
583690
└── Advanced/
584-
└── Expression/
585-
├── YANExpression.cs
586-
├── YANExpression.Implement.cs
691+
├── Expression/
692+
│ ├── YANExpression.cs
693+
│ ├── YANExpression.Implement.cs
694+
│ └── ...
695+
└── Snowflake/
696+
├── IdGenerator.Constant.cs
697+
├── IdGenerator.Constructor.cs
587698
└── ...
588699
```
589700

@@ -602,6 +713,7 @@ Each component in YANLib is implemented with careful attention to performance, m
602713
- **YANTask**: Uses HashSet<Task`<T>`> for efficient task tracking and implements async/await patterns
603714
- **YANProcess**: Uses Process.GetProcessesByName() with proper resource cleanup
604715
- **YANExpression**: Uses expression trees with thread-safe caching in ConcurrentDictionary
716+
- **YANLib.Snowflake**: Implements the Snowflake algorithm with bit manipulation for efficient ID generation and customizable bit allocation
605717

606718

607719
### Important Notes
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
namespace YANLib.Snowflake;
2+
3+
/// <summary>
4+
/// Defines the bit allocation strategies for the Snowflake ID generator.
5+
/// </summary>
6+
/// <remarks>
7+
/// Each strategy allocates the 23 available bits differently between worker ID, datacenter ID, and sequence components,
8+
/// optimizing for different use cases.
9+
/// </remarks>
10+
public enum BitAllocationStrategy
11+
{
12+
/// <summary>
13+
/// Default allocation: 5 bits for worker ID, 5 bits for datacenter ID, 13 bits for sequence.
14+
/// Supports up to 32 workers per datacenter, 32 datacenters, and 8,192 IDs per millisecond per worker.
15+
/// </summary>
16+
Default,
17+
18+
/// <summary>
19+
/// More distributed allocation: 10 bits for worker ID, 10 bits for datacenter ID, 3 bits for sequence.
20+
/// Supports up to 1,024 workers per datacenter, 1,024 datacenters, and 8 IDs per millisecond per worker.
21+
/// Optimized for highly distributed systems with many nodes.
22+
/// </summary>
23+
MoreDistributed,
24+
25+
/// <summary>
26+
/// High volume allocation: 2 bits for worker ID, 2 bits for datacenter ID, 19 bits for sequence.
27+
/// Supports up to 4 workers per datacenter, 4 datacenters, and 524,288 IDs per millisecond per worker.
28+
/// Optimized for high-throughput scenarios with few nodes.
29+
/// </summary>
30+
HighVolume,
31+
32+
/// <summary>
33+
/// Balanced allocation: 8 bits for worker ID, 8 bits for datacenter ID, 7 bits for sequence.
34+
/// Supports up to 256 workers per datacenter, 256 datacenters, and 128 IDs per millisecond per worker.
35+
/// Provides a balance between distribution and sequence capacity.
36+
/// </summary>
37+
Balanced
38+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
namespace YANLib.Snowflake;
2+
3+
/// <summary>
4+
/// Provides a distributed unique ID generator implementation based on the Snowflake algorithm.
5+
/// </summary>
6+
/// <remarks>
7+
/// This partial class contains the constant values used in the Snowflake ID generation algorithm,
8+
/// including bit allocations, maximum values, and shift operations for the different components of the ID.
9+
/// </remarks>
10+
public partial class IdGenerator
11+
{
12+
/// <summary>
13+
/// The epoch timestamp in milliseconds (January 1, 2023 00:00:00 UTC).
14+
/// </summary>
15+
/// <remarks>
16+
/// This constant represents the starting point for timestamp calculations in the Snowflake algorithm.
17+
/// </remarks>
18+
public const long TIMESTAMP_EPOCH = 1_672_531_200_000;
19+
20+
private const int TOTAL_BITS = 23;
21+
22+
// Default bit allocation (5-5-13)
23+
private const int DEFAULT_WORKER_ID_BITS = 5;
24+
private const int DEFAULT_DATACENTER_ID_BITS = 5;
25+
private const int DEFAULT_SEQUENCE_BITS = 13;
26+
27+
// More Distributed bit allocation (10-10-3)
28+
private const int MORE_DISTRIBUTED_WORKER_ID_BITS = 10;
29+
private const int MORE_DISTRIBUTED_DATACENTER_ID_BITS = 10;
30+
private const int MORE_DISTRIBUTED_SEQUENCE_BITS = 3;
31+
32+
// High Volume bit allocation (2-2-19)
33+
private const int HIGH_VOLUME_WORKER_ID_BITS = 2;
34+
private const int HIGH_VOLUME_DATACENTER_ID_BITS = 2;
35+
private const int HIGH_VOLUME_SEQUENCE_BITS = 19;
36+
37+
// Balanced bit allocation (8-8-7)
38+
private const int BALANCED_WORKER_ID_BITS = 8;
39+
private const int BALANCED_DATACENTER_ID_BITS = 8;
40+
private const int BALANCED_SEQUENCE_BITS = 7;
41+
42+
private const string BASE_ALPHABETIC_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
43+
private static readonly int BASE_ALPHABETIC_CHARS_LENGTH = BASE_ALPHABETIC_CHARS.Length;
44+
45+
private const string BASE_ALPHANUMERIC_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
46+
private static readonly int BASE_ALPHANUMERIC_CHARS_LENGTH = BASE_ALPHANUMERIC_CHARS.Length;
47+
}

0 commit comments

Comments
 (0)