Skip to main content

GeneralUpdate.Differential

Namespace: GeneralUpdate.Differential | Main Entry Points: IBinaryDiffer, BsdiffDiffer, StreamingHdiffDiffer | NuGet Package: GeneralUpdate.Differential

1. Component Overview

1.1 Introduction

GeneralUpdate.Differential is the binary differential component of GeneralUpdate, focused on solving "one old file + one patch file = one new file". It provides pluggable file-level diff algorithms (BSDIFF 4.0 / Streaming HDiff), patch compression abstractions (BZip2 / Deflate / Brotli reserved), and BSDIFF-compatible patch read/write capabilities.

Directory-level comparison, batch patch generation, parallel scheduling, deleted file handling, and update workflow orchestration are handled by GeneralUpdate.Core's DiffPipeline or GeneralUpdate.Tools.

Core Capabilities:

CapabilityDescription
File-Level Diff GenerationCleanAsync(oldFile, newFile, patchFile) — compare old & new files to generate .patch
File-Level Diff ApplicationDirtyAsync(oldFile, newFile, patchFile) — old file + patch → new file
Pluggable Diff AlgorithmsBsdiffDiffer (BSDIFF 4.0, suffix sort) and StreamingHdiffDiffer (block hash indexing)
Pluggable CompressionBZip2 (0x00), Deflate (0x01), .NET 6+ Brotli (0x02) available via conditional compilation
BSDIFF Compatible Format33-byte extended header (32-byte BSDIFF40 + 1-byte compression format), 32-byte legacy compatible
Thread SafetyBuilt-in differ and compression providers support concurrent calls

Business Problems Solved:

  • Full updates have high bandwidth costs; differential updates can reduce packages from GB to MB or KB
  • Different file types and change patterns need different diff strategies
  • Compression algorithm choice affects client decompression speed vs patch size trade-off

Use Cases:

  • Incremental updates for large desktop apps (multiple DLLs, resource files)
  • Binary differential distribution for firmware/driver packages
  • Game resource hot updates
  • Automated incremental patch generation in CI/CD pipelines

1.2 Environment & Dependencies

ItemDescription
Version10.5.0-beta.2
Target Frameworknetstandard2.0 (.NET Framework 4.6.1+ / .NET Core 2.0+ / .NET 5+)
DependenciesNone (pure .NET BCL)
CompatibilityAll .NET Standard 2.0 platforms

2. Feature List

FeatureDescriptionTypeRequiredNotes
BSDIFF 4.0 Diff GenerationClassic suffix-sort diff algorithm with stable patch sizesCoreOptionalBsdiffDiffer, default BZip2
BSDIFF 4.0 Patch ApplicationApply BSDIFF format patches to old filesCoreOptionalSupports both 32/33 byte headers
Streaming HDiff GenerationFNV-1a block hash-based fast diffCoreOptionalStreamingHdiffDiffer, default Deflate
BZip2 CompressionBZip2 compression for patch segmentsCoreOptionalFormat byte 0x00, BsdiffDiffer default
Deflate CompressionDeflate compression for patch segments, faster decompressionCoreOptionalFormat byte 0x01, StreamingHdiffDiffer default
Custom Diff AlgorithmImplement IBinaryDiffer for proprietary algorithmsExtendedOptionalMust ensure Clean/Dirty consistency
Custom Compression ProviderImplement ICompressionProvider to swap compressionExtendedOptionalNew format bytes require patch reader extension

3. API Configuration Reference

3.1 Configuration Properties (Props)

Differential is a low-level library with no configuration classes. All parameters are passed via constructors.

BsdiffDiffer Constructor Parameters:

ParameterTypeDefaultRequiredValuesDescription
compressionProviderICompressionProviderBZip2CompressionProviderOptionalBZip2CompressionProvider / DeflateCompressionProviderPatch compression provider

StreamingHdiffDiffer Constructor Parameters:

ParameterTypeDefaultRequiredValuesDescription
compressionProviderICompressionProviderDeflateCompressionProviderOptionalBZip2CompressionProvider / DeflateCompressionProviderPatch compression provider
blockSizeint65536 (64 KB)OptionalPositive integer bytesBlock size for old file hash indexing
maxWindowSizeint134217728 (128 MB)OptionalPositive integer bytesMax memory window for computation

ICompressionProvider Format Identifiers:

ProviderFormat ByteAvailabilityDescription
BZip2CompressionProvider0x00Fully availableLegacy BSDIFF compatible, higher decompression cost
DeflateCompressionProvider0x01Fully availableFaster decompression, better for client batch apply
BrotliCompressionProvider0x02.NET 6+ only (full implementation in source behind #if NET6_0_OR_GREATER conditional compilation)Not included in current netstandard2.0 package; not recommended for production

3.2 Instance Methods

IBinaryDiffer:

MethodParametersReturnsUse CaseNotes
CleanAsync(string, string, string, CancellationToken)oldFilePath, newFilePath, patchFilePath, cancellationTokenTaskGenerate patch during build/releaseLarge file cancellation not immediate
DirtyAsync(string, string, string, CancellationToken)oldFilePath, newFilePath (restored output), patchFilePath, cancellationTokenTaskApply patch during client upgradeResult written to newFilePath, not overwriting old file

3.3 Callback Events

Differential does not publish events. Progress reporting and event notifications are implemented by Core's DiffPipeline via DiffProgress and EventManager.


4. Advanced Examples

4.1 Extension Points Overview

Extension InterfaceDescription
IBinaryDifferCustom file-level diff algorithm; can integrate native libraries or proprietary algorithms
ICompressionProviderCustom patch segment compression

4.2 Examples by Scenario

Scenario 1: Custom Diff Algorithm

Description: Integrate an in-house high-compression-ratio diff algorithm.

using GeneralUpdate.Differential.Abstractions;

public sealed class HighRatioDiffer : IBinaryDiffer
{
public Task CleanAsync(
string oldFilePath, string newFilePath, string patchFilePath,
CancellationToken cancellationToken = default)
{
// Call proprietary algorithm to generate patch
return Task.CompletedTask;
}

public Task DirtyAsync(
string oldFilePath, string newFilePath, string patchFilePath,
CancellationToken cancellationToken = default)
{
// Call proprietary algorithm to apply patch
return Task.CompletedTask;
}
}

// Use in Core DiffPipeline
var pipeline = new DiffPipelineBuilder()
.UseDiffer(new HighRatioDiffer())
.WithParallelism(4)
.Build();

Scenario 2: Custom Compression Provider + BsdiffDiffer

Description: Use BsdiffDiffer's precise matching with Deflate's fast decompression for better client-side patch application speed.

using GeneralUpdate.Differential.Abstractions;
using GeneralUpdate.Differential.Differ;

var differ = new BsdiffDiffer(
new DeflateCompressionProvider(optimalLevel: false));

await differ.CleanAsync(oldFile, newFile, patchFile);
await differ.DirtyAsync(oldFile, outputFile, patchFile);

Scenario 3: StreamingHdiffDiffer Parameter Tuning

Description: Large single files (200MB+) need adjusted window budget to avoid OOM.

var differ = new StreamingHdiffDiffer(
compressionProvider: new DeflateCompressionProvider(optimalLevel: true),
blockSize: 32 * 1024, // 32 KB blocks for denser hash indexing
maxWindowSize: 256 * 1024 * 1024); // 256 MB for large files

await differ.CleanAsync(oldLargeFile, newLargeFile, patchFile);

5. Basic Usage Examples

5.1 Quick Start (Minimal Demo)

using GeneralUpdate.Differential.Abstractions;
using GeneralUpdate.Differential.Differ;

IBinaryDiffer differ = new BsdiffDiffer();

var oldFile = @"D:\releases\1.0.0\app.dll";
var newFile = @"D:\releases\1.0.1\app.dll";
var patchFile = @"D:\patches\app.dll.patch";
var outputFile = @"D:\restore\app.dll";

// Generate patch: oldFile + newFile → patchFile
await differ.CleanAsync(oldFile, newFile, patchFile);

// Apply patch: oldFile + patchFile → outputFile
await differ.DirtyAsync(oldFile, outputFile, patchFile);

5.2 Basic Parameter Combination

// Option A: Classic BSDIFF + BZip2 → smallest patch size
var differA = new BsdiffDiffer();

// Option B: Classic BSDIFF + Deflate → small patch + faster apply
var differB = new BsdiffDiffer(new DeflateCompressionProvider(optimalLevel: true));

// Option C: Streaming HDiff + Deflate → fast generation + fastest apply
var differC = new StreamingHdiffDiffer(
new DeflateCompressionProvider(optimalLevel: true),
blockSize: 64 * 1024,
maxWindowSize: 128 * 1024 * 1024);

5.3 Production Usage (via Core DiffPipeline)

Most scenarios use Differential indirectly through Core's DiffPipeline:

using GeneralUpdate.Core;
using GeneralUpdate.Core.Pipeline;
using GeneralUpdate.Core.Models;
using GeneralUpdate.Differential.Differ;

// Build side: compare old/new version directories, generate patches
var pipeline = new DiffPipelineBuilder()
.UseDiffer(new StreamingHdiffDiffer())
.WithParallelism(8)
.WithProgress(new Progress<DiffProgress>(p =>
Console.WriteLine($"[Build] {p.Completed}/{p.Total} {p.CurrentFile}")))
.Build();

await pipeline.CleanAsync(@"D:\builds\v1.0.0", @"D:\builds\v1.0.1", @"D:\patches\v1.0.0-to-v1.0.1");

// Client side: via GeneralUpdateBootstrap
await new GeneralUpdateBootstrap()
.SetSource(updateUrl: "https://update.mycompany.com/api/upgrade/verification", appSecretKey: "prod-key")
.SetOption(Option.AppType, AppType.Client)
.SetOption(Option.PatchEnabled, true)
.UseDiffPipeline(builder => builder
.UseDiffer(new StreamingHdiffDiffer())
.WithParallelism(4))
.LaunchAsync();

6. Algorithm Selection Guide

Clean vs Dirty Semantics

TermMethodInputOutputTypical Location
CleanCleanAsyncOld file, new file, patch output path.patch fileBuild/release phase
DirtyDirtyAsyncOld file, output new file path, patch pathRestored new fileClient upgrade phase

Algorithm Comparison

DimensionBsdiffDifferStreamingHdiffDiffer
Core ApproachClassic BSDIFF 4.0, suffix sort + longest matchFNV-1a block hash indexing + byte-level extension
Default CompressionBZip2 (0x00)Deflate (0x01)
Patch ApplicationSelf-implemented BSDIFF DirtyDelegates to BsdiffDiffer (BSDIFF compatible)
Patch SizeMore stable, typically smallerSensitive to change distribution
Client Apply SpeedBZip2 decompression slowerDeflate decompression faster (~1.5-5x)
Generation MemoryFull read of old & new filesBudgeted by maxWindowSize
CompatibilityCompatible with legacy BSDIFF/BZip2 patchesBetter for new projects

Recommendations by Scenario

ScenarioRecommendation
Patch size priorityBsdiffDiffer + BZip2
Client apply speed priorityStreamingHdiffDiffer (default Deflate)
Legacy patch format compatibilityBsdiffDiffer (32-byte legacy header auto-treated as BZip2)
Large files (>500MB)Benchmark first; may need StreamingHdiffDiffer + larger maxWindowSize
Directory-level batch diffVia Core DiffPipeline with WithParallelism
New projectRun baseline with defaults, adjust based on size/speed needs