blob: 127a890c3503cbb2c6eb7e361b9b21dfcf5dedae [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using K4os.Compression.LZ4.Streams;
namespace Apache.Arrow.Adbc.Drivers.Databricks
{
/// <summary>
/// Utility class for LZ4 compression/decompression operations.
/// </summary>
internal static class Lz4Utilities
{
/// <summary>
/// Default buffer size for LZ4 decompression operations (80KB).
/// </summary>
private const int DefaultBufferSize = 81920;
/// <summary>
/// Decompresses LZ4 compressed data into memory.
/// </summary>
/// <param name="compressedData">The compressed data bytes.</param>
/// <returns>A ReadOnlyMemory containing the decompressed data.</returns>
/// <exception cref="AdbcException">Thrown when decompression fails.</exception>
public static ReadOnlyMemory<byte> DecompressLz4(byte[] compressedData)
{
return DecompressLz4(compressedData, DefaultBufferSize);
}
/// <summary>
/// Decompresses LZ4 compressed data into memory with a specified buffer size.
/// </summary>
/// <param name="compressedData">The compressed data bytes.</param>
/// <param name="bufferSize">The buffer size to use for decompression operations.</param>
/// <returns>A ReadOnlyMemory containing the decompressed data.</returns>
/// <exception cref="AdbcException">Thrown when decompression fails.</exception>
public static ReadOnlyMemory<byte> DecompressLz4(byte[] compressedData, int bufferSize)
{
try
{
using (var outputStream = new MemoryStream())
{
using (var inputStream = new MemoryStream(compressedData))
using (var decompressor = LZ4Stream.Decode(inputStream))
{
decompressor.CopyTo(outputStream, bufferSize);
}
// Get the underlying buffer and its valid length without copying
// The buffer remains valid after MemoryStream disposal since we hold a reference to it
byte[] buffer = outputStream.GetBuffer();
return new ReadOnlyMemory<byte>(buffer, 0, (int)outputStream.Length);
}
}
catch (Exception ex)
{
throw new AdbcException($"Failed to decompress LZ4 data: {ex.Message}", ex);
}
}
/// <summary>
/// Asynchronously decompresses LZ4 compressed data into memory.
/// Returns the buffer and length as a tuple for efficient wrapping in a MemoryStream.
/// </summary>
/// <param name="compressedData">The compressed data bytes.</param>
/// <param name="cancellationToken">Cancellation token for the async operation.</param>
/// <returns>A tuple containing the decompressed buffer and its valid length.</returns>
/// <exception cref="AdbcException">Thrown when decompression fails.</exception>
public static Task<(byte[] buffer, int length)> DecompressLz4Async(
byte[] compressedData,
CancellationToken cancellationToken = default)
{
return DecompressLz4Async(compressedData, DefaultBufferSize, cancellationToken);
}
/// <summary>
/// Asynchronously decompresses LZ4 compressed data into memory with a specified buffer size.
/// Returns the buffer and length as a tuple for efficient wrapping in a MemoryStream.
/// </summary>
/// <param name="compressedData">The compressed data bytes.</param>
/// <param name="bufferSize">The buffer size to use for decompression operations.</param>
/// <param name="cancellationToken">Cancellation token for the async operation.</param>
/// <returns>A tuple containing the decompressed buffer and its valid length.</returns>
/// <exception cref="AdbcException">Thrown when decompression fails.</exception>
public static async Task<(byte[] buffer, int length)> DecompressLz4Async(
byte[] compressedData,
int bufferSize,
CancellationToken cancellationToken = default)
{
try
{
using (var outputStream = new MemoryStream())
{
using (var inputStream = new MemoryStream(compressedData))
using (var decompressor = LZ4Stream.Decode(inputStream))
{
await decompressor.CopyToAsync(outputStream, bufferSize, cancellationToken).ConfigureAwait(false);
}
// Get the underlying buffer and its valid length without copying
// The buffer remains valid after MemoryStream disposal since we hold a reference to it
byte[] buffer = outputStream.GetBuffer();
int length = (int)outputStream.Length;
return (buffer, length);
}
}
catch (Exception ex)
{
throw new AdbcException($"Failed to decompress LZ4 data: {ex.Message}", ex);
}
}
}
}