feat(compress): move MT overlap window policy to Rust
Move construction of the external-dictionary and active-prefix ranges into a narrow Rust ABI while retaining the C window and logging surface. Preserve byte-range half-open overlap semantics and leave the input-range overlap wrapper available to its other C caller. Test Plan: cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression (180 passed); root and CLI clippy; make -B -C lib -j2 lib; make -C tests -j2 test-cli-tests (41 passed); make -B -C tests -j2 test-zstream (84 named tests plus 6,845 and 9,628 fuzz cases passed).
This commit is contained in:
@@ -141,6 +141,9 @@ size_t ZSTDMT_rust_computeOverlapSize(unsigned windowLog, unsigned chainLog,
|
|||||||
int strategy, int overlapLog, int enableLdm);
|
int strategy, int overlapLog, int enableLdm);
|
||||||
int ZSTDMT_rust_isOverlapped(const void* bufferStart, size_t bufferCapacity,
|
int ZSTDMT_rust_isOverlapped(const void* bufferStart, size_t bufferCapacity,
|
||||||
const void* rangeStart, size_t rangeSize);
|
const void* rangeStart, size_t rangeSize);
|
||||||
|
int ZSTDMT_rust_doesOverlapWindow(const void* bufferStart, size_t bufferCapacity,
|
||||||
|
const void* nextSrc, const void* base,
|
||||||
|
const void* dictBase, U32 dictLimit, U32 lowLimit);
|
||||||
|
|
||||||
typedef struct ZSTDMT_bufferPool_s {
|
typedef struct ZSTDMT_bufferPool_s {
|
||||||
ZSTDMT_RustBufferPool* rustPool;
|
ZSTDMT_RustBufferPool* rustPool;
|
||||||
@@ -1539,24 +1542,18 @@ static int ZSTDMT_isOverlapped(Buffer buffer, Range range)
|
|||||||
|
|
||||||
static int ZSTDMT_doesOverlapWindow(Buffer buffer, ZSTD_window_t window)
|
static int ZSTDMT_doesOverlapWindow(Buffer buffer, ZSTD_window_t window)
|
||||||
{
|
{
|
||||||
Range extDict;
|
|
||||||
Range prefix;
|
|
||||||
|
|
||||||
DEBUGLOG(5, "ZSTDMT_doesOverlapWindow");
|
DEBUGLOG(5, "ZSTDMT_doesOverlapWindow");
|
||||||
extDict.start = window.dictBase + window.lowLimit;
|
|
||||||
extDict.size = window.dictLimit - window.lowLimit;
|
|
||||||
|
|
||||||
prefix.start = window.base + window.dictLimit;
|
|
||||||
prefix.size = window.nextSrc - (window.base + window.dictLimit);
|
|
||||||
DEBUGLOG(5, "extDict [0x%zx, 0x%zx)",
|
DEBUGLOG(5, "extDict [0x%zx, 0x%zx)",
|
||||||
(size_t)extDict.start,
|
(size_t)window.dictBase + window.lowLimit,
|
||||||
(size_t)extDict.start + extDict.size);
|
(size_t)window.dictBase + window.dictLimit);
|
||||||
DEBUGLOG(5, "prefix [0x%zx, 0x%zx)",
|
DEBUGLOG(5, "prefix [0x%zx, 0x%zx)",
|
||||||
(size_t)prefix.start,
|
(size_t)window.base + window.dictLimit,
|
||||||
(size_t)prefix.start + prefix.size);
|
(size_t)window.nextSrc);
|
||||||
|
|
||||||
return ZSTDMT_isOverlapped(buffer, extDict)
|
return ZSTDMT_rust_doesOverlapWindow(buffer.start, buffer.capacity,
|
||||||
|| ZSTDMT_isOverlapped(buffer, prefix);
|
window.nextSrc, window.base,
|
||||||
|
window.dictBase, window.dictLimit,
|
||||||
|
window.lowLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ZSTDMT_waitForLdmComplete(ZSTDMT_CCtx* mtctx, Buffer buffer)
|
static void ZSTDMT_waitForLdmComplete(ZSTDMT_CCtx* mtctx, Buffer buffer)
|
||||||
|
|||||||
@@ -250,6 +250,43 @@ pub extern "C" fn ZSTDMT_rust_isOverlapped(
|
|||||||
is_overlapped(bufferStart, bufferCapacity, rangeStart, rangeSize)
|
is_overlapped(bufferStart, bufferCapacity, rangeStart, rangeSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return non-zero when a buffer overlaps either the external dictionary or
|
||||||
|
/// the active prefix represented by a C `ZSTD_window_t`.
|
||||||
|
///
|
||||||
|
/// The C window stores the two ranges as pointer/index pairs. Passing those
|
||||||
|
/// scalar fields separately keeps the private C struct out of the Rust ABI;
|
||||||
|
/// the byte-distance arithmetic mirrors the original pointer subtraction.
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn ZSTDMT_rust_doesOverlapWindow(
|
||||||
|
bufferStart: *const c_void,
|
||||||
|
bufferCapacity: usize,
|
||||||
|
nextSrc: *const c_void,
|
||||||
|
base: *const c_void,
|
||||||
|
dictBase: *const c_void,
|
||||||
|
dictLimit: u32,
|
||||||
|
lowLimit: u32,
|
||||||
|
) -> c_int {
|
||||||
|
let ext_dict_start = dictBase.cast::<u8>().wrapping_add(lowLimit as usize);
|
||||||
|
let ext_dict_size = dictLimit.wrapping_sub(lowLimit) as usize;
|
||||||
|
let prefix_start = base.cast::<u8>().wrapping_add(dictLimit as usize);
|
||||||
|
let prefix_size = (nextSrc as usize)
|
||||||
|
.wrapping_sub(base as usize)
|
||||||
|
.wrapping_sub(dictLimit as usize);
|
||||||
|
|
||||||
|
(is_overlapped(
|
||||||
|
bufferStart,
|
||||||
|
bufferCapacity,
|
||||||
|
ext_dict_start.cast(),
|
||||||
|
ext_dict_size,
|
||||||
|
) != 0
|
||||||
|
|| is_overlapped(
|
||||||
|
bufferStart,
|
||||||
|
bufferCapacity,
|
||||||
|
prefix_start.cast(),
|
||||||
|
prefix_size,
|
||||||
|
) != 0) as c_int
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct BufferPoolState {
|
struct BufferPoolState {
|
||||||
buffer_size: usize,
|
buffer_size: usize,
|
||||||
@@ -926,6 +963,51 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn overlap_window_checks_external_dictionary_and_prefix() {
|
||||||
|
let bytes = [0u8; 32];
|
||||||
|
let base = bytes.as_ptr();
|
||||||
|
let next_src = base.wrapping_add(16);
|
||||||
|
let dict_base = base.wrapping_add(16);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
ZSTDMT_rust_doesOverlapWindow(
|
||||||
|
base.wrapping_add(20).cast(),
|
||||||
|
4,
|
||||||
|
next_src.cast(),
|
||||||
|
base.cast(),
|
||||||
|
dict_base.cast(),
|
||||||
|
8,
|
||||||
|
4,
|
||||||
|
),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ZSTDMT_rust_doesOverlapWindow(
|
||||||
|
base.wrapping_add(12).cast(),
|
||||||
|
4,
|
||||||
|
next_src.cast(),
|
||||||
|
base.cast(),
|
||||||
|
dict_base.cast(),
|
||||||
|
8,
|
||||||
|
4,
|
||||||
|
),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ZSTDMT_rust_doesOverlapWindow(
|
||||||
|
base.cast(),
|
||||||
|
4,
|
||||||
|
next_src.cast(),
|
||||||
|
base.cast(),
|
||||||
|
dict_base.cast(),
|
||||||
|
8,
|
||||||
|
4,
|
||||||
|
),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn buffer_pool_reuses_and_resizes_buffers() {
|
fn buffer_pool_reuses_and_resizes_buffers() {
|
||||||
let pool = unsafe { ZSTDMT_rust_buffer_pool_create(2, DEFAULT_MEM) };
|
let pool = unsafe { ZSTDMT_rust_buffer_pool_create(2, DEFAULT_MEM) };
|
||||||
|
|||||||
Reference in New Issue
Block a user