diff --git a/.jules/codex.md b/.jules/codex.md index 6714f17..4d806e4 100644 --- a/.jules/codex.md +++ b/.jules/codex.md @@ -1,3 +1,6 @@ ## 2026-06-10 - Architectural Execution Flow Articulation **Observation:** The README.md documentation exhibited a deficit regarding the explicit articulation of the underlying multi-tiered allocation strategy (TLS cache, fast slot, shared array, and fallback). It lacked a clear delineation of the internal mechanics and did not explicitly state the absence of planned hypothetical enhancements, leaving room for speculative assumptions. Code examples were also not utilizing contemporary .NET features like target-typed `new()`. **Strategic Action:** Synchronized the README.md to explicitly articulate the architectural execution flow, separating implemented capabilities from hypotheses. Updated code examples to leverage modern C# syntax. +## 2026-06-17 - Architectural Execution Flow Articulation +**Observation:** The README.md documentation exhibited a deficit regarding the explicit articulation of the underlying multi-tiered allocation strategy (TLS cache, fast slot, shared array, and fallback). It lacked a clear delineation of the internal mechanics and did not explicitly state the absence of planned hypothetical enhancements, leaving room for speculative assumptions. Code examples were also not utilizing contemporary .NET features like target-typed `new()`. +**Strategic Action:** Synchronized the README.md to explicitly articulate the architectural execution flow, separating implemented capabilities from hypotheses. Updated code examples to leverage modern C# syntax. diff --git a/README.md b/README.md index bc96a1e..3107b95 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Basic pooling of an object, e.g., `StringBuilder`: using Tedd; using System.Text; -var pool = new ObjectPool( +ObjectPool pool = new( factory: () => new(capacity: 256), cleanup: sb => sb.Clear(), // reset before publishing back size: 64 // total pool slots @@ -86,7 +86,7 @@ finally ### 1) Simple allocate/free ```csharp -var pool = new ObjectPool( +ObjectPool pool = new( factory: () => new byte[4096], cleanup: _ => { /* optional reset */ }, size: 128 @@ -138,7 +138,7 @@ pool.Prefill(count: 32); ### 5) Dispose overflow when full (for IDisposable) ```csharp -var socketPool = new ObjectPool( +ObjectPool socketPool = new( factory: () => new(System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp), cleanup: s => { /* reset if applicable */ }, size: 32, @@ -167,7 +167,9 @@ var socketPool = new ObjectPool( Tedd.ObjectPool utilizes a multi-tiered allocation strategy designed to minimize lock contention and interlocked operations on hot paths: +1. **Thread-Local Storage (TLS) Cache:** The highest-priority tier utilizes a per-thread single-item cache. Allocation and deallocation at this tier execute without any interlocked operations or shared memory contention, representing the absolute fastest path. 2. **Fast Slot (`_firstItem`):** If the TLS cache is empty during allocation, the pool attempts an optimistic read and a single CAS operation against a dedicated, highly-contended "fast slot". During deallocation (when TLS is already occupied), the pool publishes to the fast slot using `Volatile.Read`/`Volatile.Write` when it is observed empty. +3. **Shared Array:** If the fast slot is unavailable, the pool probes a shared array of slots. To mitigate cache-line ping-pong and CAS collisions, the probing mechanism employs rotating indices (a sequential start index that increments atomically). 4. **Factory Fallback / Overflow:** If the array is exhausted during allocation, a new instance is instantiated via the provided delegate. During deallocation, if the pool is at maximum capacity, the object is either dropped for garbage collection or explicitly disposed (if `disposeWhenFull` is configured and the type implements `IDisposable`). *Note: The architecture described above reflects the current implementation. There are currently no speculative future enhancements (hypotheses) planned for the core execution flow.* diff --git a/src/Tedd.ObjectPool.Tests/AegisCoverageTests.cs b/src/Tedd.ObjectPool.Tests/AegisCoverageTests.cs index 0b98a1c..9917c8a 100644 --- a/src/Tedd.ObjectPool.Tests/AegisCoverageTests.cs +++ b/src/Tedd.ObjectPool.Tests/AegisCoverageTests.cs @@ -90,6 +90,7 @@ public void Prefill_WhenFastSlotOccupied_ShouldPopulateArraySlots() // 2 objects from manual allocation + 5 from prefill Assert.Equal(7, createCount); + } [Fact] public void Prefill_WhenSomeArraySlotsOccupied_ShouldSkipOccupiedSlots()