From dd0f384ec3b2fd86ec03aa0fb42387091b5430a7 Mon Sep 17 00:00:00 2001 From: vnugent Date: Sun, 10 Mar 2024 16:03:08 -0400 Subject: Squashed commit of the following: commit df1fed9e668d9e629354b209fd9dba18301db5d7 Author: vnugent Date: Sun Mar 10 16:01:29 2024 -0400 refactor: primary constructor for HttpRequest commit 795e7d307b5aa90321f9867d3b6b2630e3d8f29b Author: vnugent Date: Sat Mar 9 16:30:43 2024 -0500 package updates commit c826c9f99d9ccd43e056bc7b7283146868733e85 Author: vnugent Date: Sat Mar 9 14:58:58 2024 -0500 feat: Some docs, and updated clr string erasure functionality commit cefe2c38d9093bff553aa46c2fcf08380c6e2aed Author: vnugent Date: Wed Mar 6 21:37:59 2024 -0500 chore: removed bad oauth token function, abstracted HttpServer commit d2ef0e78b27c68fb83d183d50beeeb7a5ba7cba8 Author: vnugent Date: Wed Mar 6 19:49:55 2024 -0500 chore: pluginbase logging, consitent proj files, some outdated readmes commit b7537cd283431f684b16d3008d3b45f8b063d489 Author: vnugent Date: Sat Mar 2 15:12:48 2024 -0500 feat: session handle, endpoints, and helper functions --- lib/Net.Messaging.FBM/README.md | 10 +- lib/Net.Messaging.FBM/src/Client/FBMClient.cs | 9 +- .../src/Client/FBMClientFactory.cs | 13 +- .../src/Client/FBMFallbackClientWsFactory.cs | 19 ++- lib/Net.Messaging.FBM/src/Client/FBMRequest.cs | 33 ++++- lib/Net.Messaging.FBM/src/Client/README.md | 122 ------------------ .../src/FallbackFBMMemoryManager.cs | 140 --------------------- lib/Net.Messaging.FBM/src/Server/readme.md | 17 --- .../src/SharedHeapFBMMemoryManager.cs | 137 ++++++++++++++++++++ 9 files changed, 190 insertions(+), 310 deletions(-) delete mode 100644 lib/Net.Messaging.FBM/src/Client/README.md delete mode 100644 lib/Net.Messaging.FBM/src/FallbackFBMMemoryManager.cs delete mode 100644 lib/Net.Messaging.FBM/src/Server/readme.md create mode 100644 lib/Net.Messaging.FBM/src/SharedHeapFBMMemoryManager.cs (limited to 'lib/Net.Messaging.FBM') diff --git a/lib/Net.Messaging.FBM/README.md b/lib/Net.Messaging.FBM/README.md index 3b7713e..022ef51 100644 --- a/lib/Net.Messaging.FBM/README.md +++ b/lib/Net.Messaging.FBM/README.md @@ -1,18 +1,18 @@ # VNLib.Net.Messaging.FBM -High performance structured web-socket based asynchronous request/response messaging library for .NET. +*High performance structured websocket based asynchronous request/response messaging library for .NET.* -[**Client Lib**](src/Client/#) - FBM Fixed Buffer Messaging client library -[**Server Lib**](src/Server/#) - FBM Fixed Buffer Messaging server/listener helper library +The protocol specification and library usage is on my website at the docs link below. ## Builds -Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my website (link below). All tar-gzip (.tgz) files will have an associated .sha384 appended checksum of the desired download file. +Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my website (link below). ## Docs and Guides Documentation, specifications, and setup guides are available on my website. [Docs and Articles](https://www.vaughnnugent.com/resources/software/articles?tags=docs,_VNLib.Net.Messaging.FBM) [Builds and Source](https://www.vaughnnugent.com/resources/software/modules/VNLib.Core) +[Nuget Feeds](https://www.vaughnnugent.com/resources/software/modules) ## License -The software in this repository is licensed under the GNU Affero General Public License (or any later version). See the [LICENSE](LICENSE.txt) file for more information. \ No newline at end of file +The software for this library is licensed under the GNU Affero General Public License (or any later version). See the [LICENSE](LICENSE.txt) file for more information. \ No newline at end of file diff --git a/lib/Net.Messaging.FBM/src/Client/FBMClient.cs b/lib/Net.Messaging.FBM/src/Client/FBMClient.cs index d3b6b55..fb9e3b4 100644 --- a/lib/Net.Messaging.FBM/src/Client/FBMClient.cs +++ b/lib/Net.Messaging.FBM/src/Client/FBMClient.cs @@ -106,11 +106,11 @@ namespace VNLib.Net.Messaging.FBM.Client /// /// The client config /// The websocket instance used to comunicate with an FBMServer - public FBMClient(in FBMClientConfig config, IFbmClientWebsocket websocket) + public FBMClient(ref readonly FBMClientConfig config, IFbmClientWebsocket websocket) :this(in config, websocket, null) { } - internal FBMClient(in FBMClientConfig config, IFbmClientWebsocket websocket, IObjectRental? requestRental) + internal FBMClient(ref readonly FBMClientConfig config, IFbmClientWebsocket websocket, IObjectRental? requestRental) { ArgumentNullException.ThrowIfNull(websocket); ArgumentNullException.ThrowIfNull(config.MemoryManager, nameof(config.MemoryManager)); @@ -118,7 +118,7 @@ namespace VNLib.Net.Messaging.FBM.Client _config = config; _socket = websocket; - //Create new request rental if none supplied + //Create new request rental if none supplied, it will have to be disposed when the client exits if(requestRental is null) { _ownsObjectRenal = true; @@ -129,7 +129,7 @@ namespace VNLib.Net.Messaging.FBM.Client _requestRental = requestRental; } - Headers = new(); + Headers = []; SendLock = new(1); ConnectionStatusHandle = new(true); ActiveRequests = new(Environment.ProcessorCount, 100); @@ -232,6 +232,7 @@ namespace VNLib.Net.Messaging.FBM.Client /// /// When awaited, yields the server response /// + /// /// /// /// diff --git a/lib/Net.Messaging.FBM/src/Client/FBMClientFactory.cs b/lib/Net.Messaging.FBM/src/Client/FBMClientFactory.cs index 51d3768..25c8cd8 100644 --- a/lib/Net.Messaging.FBM/src/Client/FBMClientFactory.cs +++ b/lib/Net.Messaging.FBM/src/Client/FBMClientFactory.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Vaughn Nugent +* Copyright (c) 2024 Vaughn Nugent * * Library: VNLib * Package: VNLib.Net.Messaging.FBM @@ -43,13 +43,16 @@ namespace VNLib.Net.Messaging.FBM.Client /// /// The configuration state /// The client websocket factory + /// The maximum number of clients expected to be connected concurrently /// - public FBMClientFactory(in FBMClientConfig config, IFbmWebsocketFactory webSocketManager) + public FBMClientFactory(ref readonly FBMClientConfig config, IFbmWebsocketFactory webSocketManager, int maxClients) { + ArgumentNullException.ThrowIfNull(config.MemoryManager, nameof(config.MemoryManager)); + ArgumentNullException.ThrowIfNull(webSocketManager); + _config = config; - _ = config.MemoryManager ?? throw new ArgumentException("The client memory manager must not be null", nameof(config)); - _socketMan = webSocketManager ?? throw new ArgumentNullException(nameof(webSocketManager)); - _internalRequestPool = ObjectRental.CreateReusable(ReuseableRequestConstructor, 1000); + _socketMan = webSocketManager; + _internalRequestPool = ObjectRental.CreateReusable(ReuseableRequestConstructor, maxClients); } /// diff --git a/lib/Net.Messaging.FBM/src/Client/FBMFallbackClientWsFactory.cs b/lib/Net.Messaging.FBM/src/Client/FBMFallbackClientWsFactory.cs index 5ee4142..a6cfbbd 100644 --- a/lib/Net.Messaging.FBM/src/Client/FBMFallbackClientWsFactory.cs +++ b/lib/Net.Messaging.FBM/src/Client/FBMFallbackClientWsFactory.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Vaughn Nugent +* Copyright (c) 2024 Vaughn Nugent * * Library: VNLib * Package: VNLib.Net.Messaging.FBM @@ -36,17 +36,12 @@ namespace VNLib.Net.Messaging.FBM.Client /// Creates a new that builds new client websockets /// on demand using the .NET default implementation /// - public class FBMFallbackClientWsFactory : IFbmWebsocketFactory + /// + /// Initalizes a new instance + /// + /// A callback function that allows users to configure sockets when created + public class FBMFallbackClientWsFactory(Action? onConfigureSocket = null) : IFbmWebsocketFactory { - private readonly Action? _onConfigure; - - /// - /// Initalizes a new instance - /// - /// A callback function that allows users to configure sockets when created - public FBMFallbackClientWsFactory(Action? onConfigureSocket = null) - => _onConfigure = onConfigureSocket; - /// public IFbmClientWebsocket CreateWebsocket(in FBMClientConfig clientConfig) { @@ -65,7 +60,7 @@ namespace VNLib.Net.Messaging.FBM.Client } //invoke client configuration user callback - _onConfigure?.Invoke(socket.Options); + onConfigureSocket?.Invoke(socket.Options); return new FBMWebsocket(socket, poolBuffer); } diff --git a/lib/Net.Messaging.FBM/src/Client/FBMRequest.cs b/lib/Net.Messaging.FBM/src/Client/FBMRequest.cs index 1787941..f16a490 100644 --- a/lib/Net.Messaging.FBM/src/Client/FBMRequest.cs +++ b/lib/Net.Messaging.FBM/src/Client/FBMRequest.cs @@ -40,6 +40,7 @@ using VNLib.Utils.Memory.Caching; namespace VNLib.Net.Messaging.FBM.Client { + /// /// /// A reusable Fixed Buffer Message request container. This class is not thread-safe @@ -50,6 +51,28 @@ namespace VNLib.Net.Messaging.FBM.Client /// public sealed class FBMRequest : VnDisposeable, IReusable, IFBMMessage, IStringSerializeable { + /* + * Important impl notes. + * + * In order to conserve memory and types, the FBMRequest stores all state information + * and memory required for an FBM transaction. That is, the request headers, the + * message waiting state (the wait handles for async/await), and the response message + * headers and body. + * + * Okay, the buffer is used for 3 purposes. + * - Store request headers + * - Store request body if not streaming + * - Store response headers once message has been sent + * + * Since a request is no longer needed when a response is received, it's buffer is used + * to store response header data. (it becomes tri-use). + * + * During response header parsing, FBMMessageHeader structures are stored in the + * ResponseHeaderList field that are simply pointers to consecutive memory locations + * in the buffer. This is done to avoid allocating multiple memory segments for each + * header key-value pair, and internal copy overhead. + */ + #pragma warning disable CA2213 // Disposable fields should be disposed private readonly FBMBuffer Buffer; #pragma warning restore CA2213 // Disposable fields should be disposed @@ -62,7 +85,7 @@ namespace VNLib.Net.Messaging.FBM.Client * in the reused buffer (in response "mode") cast to a * character buffer. */ - private readonly List ResponseHeaderList = new(); + private readonly List ResponseHeaderList = []; /// @@ -88,7 +111,7 @@ namespace VNLib.Net.Messaging.FBM.Client /// and a random messageid /// /// The fbm client config storing required config variables - public FBMRequest(in FBMClientConfig config) : this(Helpers.RandomMessageId, in config) + public FBMRequest(ref readonly FBMClientConfig config) : this(Helpers.RandomMessageId, in config) { } /// @@ -96,7 +119,7 @@ namespace VNLib.Net.Messaging.FBM.Client /// /// The custom message id /// The fbm client config storing required config variables - public FBMRequest(int messageId, in FBMClientConfig config) + public FBMRequest(int messageId, ref readonly FBMClientConfig config) :this(messageId, config.MemoryManager, config.MessageBufferSize, config.HeaderEncoding) { } @@ -358,7 +381,7 @@ namespace VNLib.Net.Messaging.FBM.Client if (cancellation.CanBeCanceled) { //Register cancellation - _token = cancellation.Register(OnCancelled, this, false); + _token = cancellation.Register(OnCancelled, null, false); } } @@ -366,7 +389,7 @@ namespace VNLib.Net.Messaging.FBM.Client } /// - public void ManualCancellation() => OnCancelled(this); + public void ManualCancellation() => OnCancelled(null); //Set cancelled state if exists, the task may have already completed private void OnCancelled(object? state) => _tcs?.TrySetCanceled(); diff --git a/lib/Net.Messaging.FBM/src/Client/README.md b/lib/Net.Messaging.FBM/src/Client/README.md deleted file mode 100644 index ea76a46..0000000 --- a/lib/Net.Messaging.FBM/src/Client/README.md +++ /dev/null @@ -1,122 +0,0 @@ -# VNLib.Net.Messaging.FBM.Client - -Fixed Buffer Messaging Protocol client library. High performance stateful messaging protocol built on top of HTTP web-sockets. Low/no allocation, completely asynchronous while providing a TPL API. This library provides a simple asynchronous request/response architecture to web-sockets. This was initially designed to provide an alternative to complete HTTP request/response overhead, but allow a simple control flow for work across a network. - -The base of the library relies on creating message objects that allocate fixed size buffers are configured when the IFBMMessageis constructed. All data is written to the internal buffer adhering to the [FBM protocol](../../#) - -This client library allows for messages to be streamed to the server, however this library is optimized for fixed buffers, so streaming will not be the most efficient, and will likely cause slow-downs in message transmission. However, since FBM relies on a streaming protocol, -so it was silly not to provide it. Streams add overhead of additional buffer allocation, additional copy, and message fragmentation (multiple writes to the web-socket). Since frames written to the web-socket must be synchronized, a mutex is held during transmission, which means the more message overhead, the longer the blocking period on new messages. Mutex acquisition will wait asynchronously when necessary. - -## Fundamentals -The main implementation is the FBMClient class. This class provides the means for creating the stateful connection to the remote server. It also provides an internal FBMRequest message rental (object cache) that created initialized FBMRequest messages. This class may be derived to provide additional functionality, such as handling control frames that may dynamically alter the state of the connection (negotiation etc). A mechanism to do so is provided. - -### FBMClient layout - -``` C# - public class FBMClient : VnDisposeable, IStatefulConnection, ICacheHolder - { - //Raised when an error occurs during receiving or parsing - public event EventHandler? ConnectionClosedOnError; - - //Raised when connection is closed, regardless of the cause - public event EventHandler? ConnectionClosed; - - //Connects to the remote server at the specified websocket address (ws:// or wss://) - public Task ConnectAsync(Uri address, CancellationToken cancellation = default); - - //When connected, sends the specified message to the remote server, with the default timeout - public Task SendAsync(FBMRequest request, CancellationToken cancellationToken = default); - - //When connected, sends the specified message to the remote server, with the specified timeout, -1 or 0 to disable timeout - public Task SendAsync(FBMRequest request, TimeSpan timeout, CancellationToken cancellationToken = default); - - //When connected, streams a message to the remote server, * the message payload must not be configured * - public Task StreamDataAsync(FBMRequest request, Stream payload, ContentType ct, CancellationToken cancellationToken = default); - - //Disconnects from the remote server - public async Task DisconnectAsync(CancellationToken cancellationToken = default); - - //Releases all held resourses - public void Dispose(); //Inherrited from VnDisposeable - - ICacheHolder.CacheClear(); //Inherited member, clears cached FBMRequest objects - ICacheHolder.CacheHardClear(); //Inherited member, clears cached FBMRequest objects - } -``` - -### Example usage -``` C# - - FBMClientConfig config = new() - { - //The unmanaged heap the allocate buffers from - BufferHeap = MemoryUtil.Shared, - //The absolute maximum message size to buffer from the server - MaxMessageSize = 10 * 1024 * 1024, //10KiB, - //The size of the buffer used for buffering incoming messages server messages - RecvBufferSize = maxExtra, - //The FBMRequest internal buffer size, should be max message + headers - MessageBufferSize = (int)Helpers.ToNearestKb(maxMessageSize + MAX_FBM_MESSAGE_HEADER_SIZE), - //The space reserved in the FBM request buffer used for header storage - MaxHeaderBufferSize = 1024, - //Set the web-socket subprotocol - SubProtocol = "object-cache", - //Use the default encoding (UTF-8) - HeaderEncoding = Helpers.DefaultEncoding, - //How frequently to send web-socket keepalive messages - KeepAliveInterval = TimeSpan.FromSeconds(30), - //The default request message timeout - RequestTimeout = TimeSpan.FromSeconds(10), - //optional debug log, write message debug information if set - DebugLog = null - }; - - //Create client from the config - using (FBMClient client = new(config)) - { - //Usually set some type of authentication headers before connecting - - /* - client.ClientSocket.SetHeader("Authorization", "Authorization token"); - */ - - //Connect to server - Uri address = new Uri("wss://localhost:8080/some/fbm/endpoint"); - await client.ConnectAsync(address, CancellationToken.None); - - do - { - //Rent request message - FBMRequest request = client.RentRequest(); - //Some arbitrary header value (or preconfigured header) - request.WriteHeader(0x10, "Hello"); - //Some arbitrary payload - request.WriteBody(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A }, ContentType.Binary); - //Send request message - using (FBMResponse response = await client.SendAsync(request, CancellationToken.None)) - { - //Extension method to raise exception if an invalid response was received (also use the response.IsSet flag) - response.ThrowIfNotSet(); - - //Check header parse status - //response.StatusFlags - - //Check headers (using Linq to get first header) - string header1 = response.Headers.First().Value.ToString(); - - //Get payload, data is valid until the response is disposed - ReadOnlySpan body = response.ResponseBody; - } - //Return request - client.ReturnRequest(request); - //request.Dispose(); //Alternativly dispose message - - await Task.Delay(1000); - } - while(true); - //You should probably cleanup by asynchronously closing the connection before disposing - } -``` - -## Builds -Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my [website](https://www.vaughnnugent.com/resources/software). All tar-gzip (.tgz) files will have an associated .sha384 appended checksum of the desired download file. \ No newline at end of file diff --git a/lib/Net.Messaging.FBM/src/FallbackFBMMemoryManager.cs b/lib/Net.Messaging.FBM/src/FallbackFBMMemoryManager.cs deleted file mode 100644 index 260cbd6..0000000 --- a/lib/Net.Messaging.FBM/src/FallbackFBMMemoryManager.cs +++ /dev/null @@ -1,140 +0,0 @@ -/* -* Copyright (c) 2023 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Net.Messaging.FBM -* File: FallbackFBMMemoryManager.cs -* -* FallbackFBMMemoryManager.cs is part of VNLib.Net.Messaging.FBM which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Net.Messaging.FBM is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Net.Messaging.FBM is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.Buffers; -using System.Diagnostics.CodeAnalysis; - -using VNLib.Utils.Memory; -using VNLib.Utils.Extensions; - -namespace VNLib.Net.Messaging.FBM -{ - /// - /// A default/fallback implementation of a that - /// uses an to allocate buffers from - /// - public sealed class FallbackFBMMemoryManager : IFBMMemoryManager - { - private readonly IUnmangedHeap _heap; - - /// - /// Initializes a new instance of allocationg - /// memory from the specified - /// - /// The heap to allocate memory from - /// - public FallbackFBMMemoryManager(IUnmangedHeap heap) => _heap = heap ?? throw new ArgumentNullException(nameof(heap)); - - /// - public void AllocBuffer(IFBMSpanOnlyMemoryHandle state, int size) - { - _ = state ?? throw new ArgumentNullException(nameof(state)); - (state as IFBMBufferHolder)!.AllocBuffer(size); - } - - /// - public void FreeBuffer(IFBMSpanOnlyMemoryHandle state) - { - _ = state ?? throw new ArgumentNullException(nameof(state)); - (state as IFBMBufferHolder)!.FreeBuffer(); - } - - /// - public IFBMMemoryHandle InitHandle() => new FBMMemHandle(_heap); - - /// - public IFBMSpanOnlyMemoryHandle InitSpanOnly() => new FBMSpanOnlyMemHandle(_heap); - - /// - public bool TryGetHeap([NotNullWhen(true)] out IUnmangedHeap? heap) - { - heap = _heap; - return true; - } - - interface IFBMBufferHolder - { - void AllocBuffer(int size); - - void FreeBuffer(); - } - - private sealed record class FBMMemHandle(IUnmangedHeap Heap) : IFBMMemoryHandle, IFBMBufferHolder - { - private MemoryHandle? _handle; - private IMemoryOwner? _memHandle; - - /// - public Memory GetMemory() - { - _ = _memHandle ?? throw new InvalidOperationException("Buffer has not allocated"); - return _memHandle.Memory; - } - - /// - public Span GetSpan() - { - _ = _handle ?? throw new InvalidOperationException("Buffer has not allocated"); - return _handle.Span; - } - - /// - public void AllocBuffer(int size) - { - //Alloc buffer and memory manager to wrap it - _handle = Heap.Alloc(size, false); - _memHandle = _handle.ToMemoryManager(false); - } - - /// - public void FreeBuffer() - { - _handle?.Dispose(); - _memHandle?.Dispose(); - - _handle = null; - _memHandle = null; - } - } - - private sealed record class FBMSpanOnlyMemHandle(IUnmangedHeap Heap) : IFBMSpanOnlyMemoryHandle, IFBMBufferHolder - { - private MemoryHandle? _handle; - - /// - public void AllocBuffer(int size) => _handle = Heap.Alloc(size, false); - - /// - public void FreeBuffer() => _handle?.Dispose(); - - /// - public Span GetSpan() - { - _ = _handle ?? throw new InvalidOperationException("Buffer has not allocated"); - return _handle.Span; - } - } - } -} diff --git a/lib/Net.Messaging.FBM/src/Server/readme.md b/lib/Net.Messaging.FBM/src/Server/readme.md deleted file mode 100644 index cd6f53e..0000000 --- a/lib/Net.Messaging.FBM/src/Server/readme.md +++ /dev/null @@ -1,17 +0,0 @@ -# VNLib.Net.Messaging.FBM.Server - -Please see [FBM Protocol spec](../../#) for architecture details - -## Usage -This library exports a main type called `FBMListener` it is the "entry point" so to speak for your server development. It listens on an active web-socket session that has been accepted an negotiated by your http server and passed to the `FBMListener.ListenAsync()` method. This call only returns once the connection is disconnected, has an error, or the session is closed. The listener listens for FBM messages on the web-socket, buffers them, and when message has been pre-processed, calls your request handler delegate if the message is valid. If the message exceeds the maximum size, the socket is gracefully closed and the method returns. - -Your `RequestHandler` delegate method accepts a type `FBMContext` that holds the request instance, and the `FBMResponseMessage` instance you will use to respond to the client. **Context instances are pooled, so you may not save them or any of their properties once your request handler returns.** Response objects implement the `IFBMMessage` interface, for your consumption. You may also use the "streaming" api, to reduce buffering and copying, implementing your own `IAsyncMessageBody` objects which allows reading data into a buffer asynchronously. Keep in mind a mutex is held while this streaming process occurs, and can cause performance issues, you should generally write a copy of your data to the internal response buffer. - -A `FBMListenerSessionParams` structure must be passed on every call `ListenAsync()` to define the buffer sizes and limits per-session. - -The `FBMListenerBase` is an abstract type that provides some scaffolding for implementing your own message handler, by handling some plumbing and giving you an abstract method to process incoming messages. - -Calls to your `RequestHandler` method are invoked on a background queuing task, to avoid blocking, or delaying the receive task. However it is still task, not a background thread, so you should try **not** to synchronously block in your request handling routine to avoid blocking a threadpool thread. - -## Builds -Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my [website](https://www.vaughnnugent.com/resources/software). All tar-gzip (.tgz) files will have an associated .sha384 appended checksum of the desired download file. \ No newline at end of file diff --git a/lib/Net.Messaging.FBM/src/SharedHeapFBMMemoryManager.cs b/lib/Net.Messaging.FBM/src/SharedHeapFBMMemoryManager.cs new file mode 100644 index 0000000..f32c084 --- /dev/null +++ b/lib/Net.Messaging.FBM/src/SharedHeapFBMMemoryManager.cs @@ -0,0 +1,137 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.Net.Messaging.FBM +* File: SharedHeapFBMMemoryManager.cs +* +* SharedHeapFBMMemoryManager.cs is part of VNLib.Net.Messaging.FBM which +* is part of the larger VNLib collection of libraries and utilities. +* +* VNLib.Net.Messaging.FBM is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* VNLib.Net.Messaging.FBM is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +*/ + +using System; +using System.Buffers; +using System.Diagnostics.CodeAnalysis; + +using VNLib.Utils.Memory; +using VNLib.Utils.Extensions; + +namespace VNLib.Net.Messaging.FBM +{ + /// + /// A default/fallback implementation of a that + /// uses an to allocate buffers from + /// + /// + /// Initializes a new instance of allocating + /// memory from the specified + /// + /// The heap to allocate memory from + /// + public sealed class SharedHeapFBMMemoryManager(IUnmangedHeap heap) : IFBMMemoryManager + { + private readonly IUnmangedHeap _heap = heap ?? throw new ArgumentNullException(nameof(heap)); + + /// + public void AllocBuffer(IFBMSpanOnlyMemoryHandle state, int size) + { + ArgumentNullException.ThrowIfNull(state); + (state as IFBMBufferHolder)!.AllocBuffer(size); + } + + /// + public void FreeBuffer(IFBMSpanOnlyMemoryHandle state) + { + ArgumentNullException.ThrowIfNull(state); + (state as IFBMBufferHolder)!.FreeBuffer(); + } + + /// + public IFBMMemoryHandle InitHandle() => new FBMMemHandle(_heap); + + /// + public IFBMSpanOnlyMemoryHandle InitSpanOnly() => new FBMSpanOnlyMemHandle(_heap); + + /// + public bool TryGetHeap([NotNullWhen(true)] out IUnmangedHeap? heap) + { + heap = _heap; + return true; + } + + interface IFBMBufferHolder + { + void AllocBuffer(int size); + + void FreeBuffer(); + } + + private sealed record class FBMMemHandle(IUnmangedHeap Heap) : IFBMMemoryHandle, IFBMBufferHolder + { + private MemoryHandle? _handle; + private MemoryManager? _memHandle; + + /// + public Memory GetMemory() + { + _ = _memHandle ?? throw new InvalidOperationException("Buffer has not allocated"); + return _memHandle.Memory; + } + + /// + public Span GetSpan() + { + _ = _handle ?? throw new InvalidOperationException("Buffer has not allocated"); + return _handle.Span; + } + + /// + public void AllocBuffer(int size) + { + //Alloc buffer and memory manager to wrap it + _handle = Heap.Alloc(size, false); + _memHandle = _handle.ToMemoryManager(false); + } + + /// + public void FreeBuffer() + { + _handle?.Dispose(); + + _handle = null; + _memHandle = null; + } + } + + private sealed record class FBMSpanOnlyMemHandle(IUnmangedHeap Heap) : IFBMSpanOnlyMemoryHandle, IFBMBufferHolder + { + private MemoryHandle? _handle; + + /// + public void AllocBuffer(int size) => _handle = Heap.Alloc(size, false); + + /// + public void FreeBuffer() => _handle?.Dispose(); + + /// + public Span GetSpan() + { + _ = _handle ?? throw new InvalidOperationException("Buffer has not allocated"); + return _handle.Span; + } + } + } +} -- cgit