Channel Pipeline

The name brand does not appear to exist in .NET Framework, which is not receiving further features.
Net 5 migration #3124 is being worked on, but seems to need a lot of changes to be ready to release.

Duplicati developers have been moving away from “helper” libraries as standard capabilities emerge,
e.g. 2.0.5.1 Beta uses Long Path Support (MAXPATH) done in .NET Framework 4.6.2 and mono 5.0.0.

I guess that there are sometimes fine points that should be considered, but I’m not qualified to do that.
CoCoL: Concurrent Communications Library and related papers does some in-depth analysis of this.

Let me post a draft of a note I started about a year that attempts to trace the summary to source code:

https://forum.duplicati.com/t/alternative-ftp-failure/7822/10
In Duplicati, this is used to enabled concurrency for hashing and compressing.
Roughly the following happens:

    A process traverses the file system and writes paths to a channel
Maybe FileEnumerationProcess.cs

    A process reads paths and checks if the metadata has changed; all changed paths are written to another channel
Maybe MetadataPreProcess.cs

    Multiple processes read paths and computes block hashes; new block hashes (and data) are written to a channel
Maybe StreamBlockSplitter.cs

    Multiple processes read blocks and compresses blocks; filled volumes are written as upload requests
Maybe DataBlockProcessor.cs

    A process caps the number of active uploads
Maybe https://github.com/duplicati/duplicati/blob/63ecd1a49ff66acbd0335044ecb360c73a218468/Duplicati/Library/Main/Operation/Backup/BackendUploader.cs#L196-L199

    A process performs the spill pickup (as described above)
Maybe SpillCollectorProcess.cs

    A process performs the remote operations (upload, download, list)
Maybe BackendUploader.cs

https://github.com/duplicati/duplicati/blob/master/Duplicati/Library/Main/Operation/BackupHandler.cs
                            {
                                    Backup.DataBlockProcessor.Run(database, options, taskreader),
                                    Backup.FileBlockProcessor.Run(snapshot, options, database, stats, taskreader, token),
                                    Backup.StreamBlockSplitter.Run(options, database, taskreader),
                                    Backup.FileEnumerationProcess.Run(sources, snapshot, journalService,
                                        options.FileAttributeFilter, sourcefilter, filter, options.SymlinkPolicy,
                                        options.HardlinkPolicy, options.ExcludeEmptyFolders, options.IgnoreFilenames,
                                        options.ChangedFilelist, taskreader, token),
                                    Backup.FilePreFilterProcess.Run(snapshot, options, stats, database),
                                    Backup.MetadataPreProcess.Run(snapshot, options, database, lastfilesetid, token),
                                    Backup.SpillCollectorProcess.Run(options, database, taskreader),
                                    Backup.ProgressHandler.Run(result)
                            }
                            // Spawn additional block hashers
                            .Union(
                                Enumerable.Range(0, options.ConcurrencyBlockHashers - 1).Select(x =>
                                    Backup.StreamBlockSplitter.Run(options, database, taskreader))
                            )
                            // Spawn additional compressors
                            .Union(
                                Enumerable.Range(0, options.ConcurrencyCompressors - 1).Select(x =>
                                    Backup.DataBlockProcessor.Run(database, options, taskreader))
                            )

Duplicati\Library\Main\Operation\Backup\FileEnumerationProcess.cs
                Output = Backup.Channels.SourcePaths.ForWrite

Duplicati\Library\Main\Operation\Backup\CountFilesHandler.cs
                    Input = Backup.Channels.SourcePaths.ForRead

Duplicati\Library\Main\Operation\Backup\MetadataPreProcess.cs
                Input = Backup.Channels.SourcePaths.ForRead,
                StreamBlockChannel = Channels.StreamBlock.ForWrite,
                Output = Backup.Channels.ProcessedFiles.ForWrite,

Duplicati\Library\Main\Operation\Backup\FilePreFilterProcess.cs
                Input = Channels.ProcessedFiles.ForRead,
                Output = Channels.AcceptedChangedFile.ForWrite

Duplicati\Library\Main\Operation\Backup\FileBlockProcessor.cs
                Input = Channels.AcceptedChangedFile.ForRead,
                StreamBlockChannel = Channels.StreamBlock.ForWrite,

(multiple)
Duplicati\Library\Main\Operation\Backup\StreamBlockSplitter.cs
                Input = Channels.StreamBlock.ForRead,
                ProgressChannel = Channels.ProgressEvents.ForWrite,
                BlockOutput = Channels.OutputBlocks.ForWrite

(multiple)
Duplicati\Library\Main\Operation\Backup\DataBlockProcessor.cs
                Input = Channels.OutputBlocks.ForRead,
                Output = Channels.BackendRequest.ForWrite,
                SpillPickup = Channels.SpillPickup.ForWrite,

Duplicati\Library\Main\Operation\Backup\SpillCollectorProcess.cs
                Input = Channels.SpillPickup.ForRead,
                Output = Channels.BackendRequest.ForWrite,

Duplicati\Library\Main\Operation\Backup\RecreateMissingIndexFiles.cs
                UploadChannel = Channels.BackendRequest.ForWrite

Duplicati\Library\Main\Operation\Backup\BackendUploader.cs
                Input = Channels.BackendRequest.ForRead,

This was done just by tracing Channels references in source. I don’t do pictures well, so there are none.
If a conversion to a new way happens, it would be nice to improve the documentation while sorting it out.