Skip to content

C#: Implement transparent compression feature#213

Open
prateek-kumar-improving wants to merge 36 commits intomainfrom
csharp/implement-transparent-compression-feature
Open

C#: Implement transparent compression feature#213
prateek-kumar-improving wants to merge 36 commits intomainfrom
csharp/implement-transparent-compression-feature

Conversation

@prateek-kumar-improving
Copy link
Copy Markdown
Collaborator

@prateek-kumar-improving prateek-kumar-improving commented Feb 23, 2026

Summary

Implementing C# bindings for the transparent compression feature added in valkey-io/valkey-glide#4759

Issue Link

This pull request is linked to issue: valkey-io/valkey-glide#5120
Related Issue: valkey-io/valkey-glide#5299

Features and Behaviour Changes

  1. Adds the necessary language bindings in C# to configure a client with compression enabled.
  2. Added unit and integration tests for compression scenarios.
  3. Compression Backends Supported: Zstd and Lz4.
  4. Statistics available using BaseClient.GetStatistics().

Implementation

Rust FFI

  • rust/src/lib.rs - compress_cmd helper, get_statistics FFI export, command() integration
  • rust/src/ffi.rs - FFI bindings for compression config and statistics

C# Public API

  • sources/Valkey.Glide/CompressionConfig.cs - Compression configuration class
  • sources/Valkey.Glide/Statistics.cs - Statistics record (compression, connections, pub/sub)
  • sources/Valkey.Glide/abstract_Enums/CompressionBackend.cs - Zstd/Lz4 enum
  • sources/Valkey.Glide/ConnectionConfiguration.cs - WithCompression() builder method
  • sources/Valkey.Glide/BaseClient.cs - GetStatistics() method

C# FFI Internals

  • sources/Valkey.Glide/Internals/FFI.structs.cs - FFI structs for CompressionConfig and Statistics
  • sources/Valkey.Glide/Internals/FFI.methods.cs - FFI method bindings

Tests

  • tests/Valkey.Glide.IntegrationTests/CompressionTests.cs - Integration tests
  • tests/Valkey.Glide.UnitTests/CompressionConfigTests.cs - Unit tests

Documentation:

README.md - Added compression documentation and examples

Limitations

This feature is only limited to GET and SET for now.

Testing

All tests passing locally and in CI. Both unit tests and integration tests added.

Checklist

  • This Pull Request is related to one issue.
  • Commit message has a detailed description of what changed and why.
  • Tests are added or updated and all checks pass.
  • CHANGELOG.md, README.md, DEVELOPER.md, and other documentation files are updated.
  • Destination branch is correct - main or release
  • Create merge commit if merging release branch into main, squash otherwise.

Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
…rc/ffi.rs

Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
…rc/ffi.rs

Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Updated submodule from 2ea4018f6 to 0429c1201 to include:
- Transparent Compression Feature (#4759)
- Go bindings for compression (#5359)

This update enables compression functionality in the Rust core.

Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
@prateek-kumar-improving prateek-kumar-improving force-pushed the csharp/implement-transparent-compression-feature branch from 4bb939e to 34ff162 Compare February 26, 2026 17:12
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
@currantw
Copy link
Copy Markdown
Collaborator

C# example for compression added to README

C# documentation is being shifted to valkey-glide-docs. Can you please raise a pull request to add that documentation there (and remove it here)? Please update the description accordingly.

Copy link
Copy Markdown
Collaborator

@currantw currantw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed implementation. Will review tests once addressed.

rust/src/ffi.rs Outdated
Comment on lines +276 to +296
compression_config: if config.has_compression_config {
Some(glide_core::compression::CompressionConfig {
enabled: config.compression_config.enabled,
min_compression_size: config.compression_config.min_compression_size,
compression_level: if config.compression_config.compression_level == 0 {
None
} else {
Some(config.compression_config.compression_level)
},
backend: match config.compression_config.backend {
CompressionBackend::Zstd => {
glide_core::compression::CompressionBackendType::Zstd
}
CompressionBackend::Lz4 => {
glide_core::compression::CompressionBackendType::Lz4
}
},
})
} else {
None
},
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be simplified quite a bit using then_some (this also removes the unnecessary brackets from the match block):

Suggested change
compression_config: if config.has_compression_config {
Some(glide_core::compression::CompressionConfig {
enabled: config.compression_config.enabled,
min_compression_size: config.compression_config.min_compression_size,
compression_level: if config.compression_config.compression_level == 0 {
None
} else {
Some(config.compression_config.compression_level)
},
backend: match config.compression_config.backend {
CompressionBackend::Zstd => {
glide_core::compression::CompressionBackendType::Zstd
}
CompressionBackend::Lz4 => {
glide_core::compression::CompressionBackendType::Lz4
}
},
})
} else {
None
},
compression_config: config.has_compression_config.then_some(
glide_core::compression::CompressionConfig {
enabled: config.compression_config.enabled,
min_compression_size: config.compression_config.min_compression_size,
compression_level: (config.compression_config.compression_level != 0)
.then_some(config.compression_config.compression_level),
backend: match config.compression_config.backend {
CompressionBackend::Zstd => glide_core::compression::CompressionBackendType::Zstd,
CompressionBackend::Lz4 => glide_core::compression::CompressionBackendType::Lz4,
},
},
),

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

Comment on lines +59 to +62
if (minCompressionSize < MinCompressionSizeLimit)
{
throw new ArgumentException($"minCompressionSize must be at least {MinCompressionSizeLimit} bytes", nameof(minCompressionSize));
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think ArgumentOutOfRangeException might be better here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these StackExchange.Redis-compatible types? Otherwise, I think they should just be in sources rather than sources/abstract_APITypes. The distinction between these is certainly not clear, but that is my understanding of the separation!

Moreover, I think we should generally endeavour to have one class (excepting private classes) per file? That seems to be the pattern (loosely followed) in the code base.

See the refactoring PR I just raised along these lines: #246

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

/// Enables automatic compression of values before sending to the server
/// and decompression when receiving from the server.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marshalling related code should be isolated in FFI.structs.cs, not exposed in public APIs. We probably need to split this into two separate classes? See #246

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

/// <summary>
/// Zstandard (zstd) compression backend.
/// Provides high compression ratios with good performance.
/// Default compression level: 3
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think we need to specify the default compression level here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

/// <summary>
/// Statistics structure containing telemetry data from Rust core.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned elsewhere, we need to separate the FFI classes from the API ones.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

Comment on lines +1175 to +1182
public ulong TotalConnections;
public ulong TotalClients;
public ulong TotalValuesCompressed;
public ulong TotalValuesDecompressed;
public ulong TotalOriginalBytes;
public ulong TotalBytesCompressed;
public ulong TotalBytesDecompressed;
public ulong CompressionSkippedCount;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can these be documented please?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

/// Statistics structure containing telemetry data from Rust core.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct Statistics
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be readonly like others in this class? Similarly, should fields also be readonly?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

README.md Outdated
- **[Cluster Scan](https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#cluster-scan)** – Unified key iteration across shards using a consistent, high-level API
- **[Batching (Pipeline and Transaction)](https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#batching-pipeline-and-transaction)** – Execute multiple commands efficiently in a single network roundtrip
- **[OpenTelemetry](https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#opentelemetry)** – Integrated tracing support for enhanced observability
- **[Transparent Compression](#compression-operations)** – Automatic value compression with Zstd and LZ4 backends to reduce bandwidth and storage
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably also need to update CHANGELOG.md?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

README.md Outdated
Comment on lines +225 to +250
### Compression Operations

```csharp
// Enable transparent compression with Zstd
var config = new StandaloneClientConfigurationBuilder()
.WithAddress("localhost", 6379)
.WithCompression(CompressionConfig.Zstd())
.Build();

await using var client = await GlideClient.CreateClient(config);

// Values are automatically compressed/decompressed
await client.StringSetAsync("large_data", new string('a', 10000));
var retrieved = await client.StringGetAsync("large_data");

// Monitor compression statistics
var stats = BaseClient.GetCompressionStatistics();
Console.WriteLine($"Compression ratio: {stats.CompressionRatio:F2}x");
Console.WriteLine($"Space saved: {stats.SpaceSavedPercent:F2}%");

// Use LZ4 for faster compression
var lz4Config = new StandaloneClientConfigurationBuilder()
.WithAddress("localhost", 6379)
.WithCompression(CompressionConfig.Lz4(compressionLevel: 5, minCompressionSize: 128))
.Build();
```
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be part of valkey-glide-docs instead. Please raise PR for that and link here (as described in other comment).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed readme.md update from this PR. Documentation is not updated for compression feature for now. Will be updated later after all work related to the feature is done.

Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
…ics.cs

Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
…ture

Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Signed-off-by: Prateek Kumar <prateek.kumar@improving.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants